Commit b7028b13 authored by Matthew Holt's avatar Matthew Holt

vendor: Update certmagic to include List fix

parent 620f9687
......@@ -18,6 +18,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"sync"
......@@ -67,16 +68,34 @@ func (fs FileStorage) Delete(key string) error {
}
// List returns all keys that match prefix.
func (fs FileStorage) List(prefix string) ([]string, error) {
d, err := os.Open(fs.Filename(prefix))
if os.IsNotExist(err) {
return nil, ErrNotExist(err)
func (fs FileStorage) List(prefix string, recursive bool) ([]string, error) {
var keys []string
walkPrefix := fs.Filename(prefix)
err := filepath.Walk(walkPrefix, func(fpath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info == nil {
return fmt.Errorf("%s: file info is nil", fpath)
}
if fpath == walkPrefix {
return nil
}
suffix, err := filepath.Rel(walkPrefix, fpath)
if err != nil {
return nil, err
return fmt.Errorf("%s: could not make path relative: %v", fpath, err)
}
defer d.Close()
return d.Readdirnames(-1)
keys = append(keys, path.Join(prefix, suffix))
if !recursive && info.IsDir() {
return filepath.SkipDir
}
return nil
})
return keys, err
}
// Stat returns information about key.
......@@ -92,6 +111,7 @@ func (fs FileStorage) Stat(key string) (KeyInfo, error) {
Key: key,
Modified: fi.ModTime(),
Size: fi.Size(),
IsTerminal: !fi.IsDir(),
}, nil
}
......
......@@ -261,7 +261,7 @@ func (certCache *Cache) updateOCSPStaples() {
// deleteOldStapleFiles deletes cached OCSP staples that have expired.
// TODO: We should do this for long-expired certificates, too.
func (certCache *Cache) deleteOldStapleFiles() {
ocspKeys, err := certCache.storage.List(prefixOCSP)
ocspKeys, err := certCache.storage.List(prefixOCSP, false)
if err != nil {
// maybe just hasn't been created yet; no big deal
return
......
// Copyright 2015 Matthew Holt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package certmagic
import (
"fmt"
"sync"
)
// MemoryLocker implements the Locker interface
// using memory. An empty value is NOT VALID,
// so you must use NewMemoryLocker() to get one.
type MemoryLocker struct {
nameLocks map[string]*MemoryWaiter
nameLocksMu *sync.Mutex
}
// NewMemoryLocker returns a valid Locker backed by fs.
func NewMemoryLocker() *MemoryLocker {
return &MemoryLocker{
nameLocks: make(map[string]*MemoryWaiter),
nameLocksMu: new(sync.Mutex),
}
}
// TryLock attempts to get a lock for name, otherwise it returns
// a Waiter value to wait until the other process is finished.
func (l *MemoryLocker) TryLock(name string) (Waiter, error) {
l.nameLocksMu.Lock()
defer l.nameLocksMu.Unlock()
// see if lock already exists within this process
w, ok := l.nameLocks[name]
if ok {
return w, nil
}
// we got the lock, so create it
w = &MemoryWaiter{wg: new(sync.WaitGroup)}
w.wg.Add(1)
l.nameLocks[name] = w
return nil, nil
}
// Unlock releases the lock for name.
func (l *MemoryLocker) Unlock(name string) error {
l.nameLocksMu.Lock()
defer l.nameLocksMu.Unlock()
w, ok := l.nameLocks[name]
if !ok {
return fmt.Errorf("MemoryLocker: no lock to release for %s", name)
}
w.wg.Done()
delete(l.nameLocks, name)
return nil
}
// MemoryWaiter implements Waiter in memory.
type MemoryWaiter struct {
wg *sync.WaitGroup
}
// Wait waits until w.wg is done.
func (w *MemoryWaiter) Wait() {
w.Wait()
}
var _ Locker = &MemoryLocker{}
var _ Waiter = &MemoryWaiter{}
......@@ -49,7 +49,11 @@ type Storage interface {
Exists(key string) bool
// List returns all keys that match prefix.
List(prefix string) ([]string, error)
// If recursive is true, non-terminal keys
// will be enumerated (i.e. "directories"
// should be walked); otherwise, only keys
// prefixed exactly by prefix will be listed.
List(prefix string, recursive bool) ([]string, error)
// Stat returns information about key.
Stat(key string) (KeyInfo, error)
......@@ -95,6 +99,7 @@ type KeyInfo struct {
Key string
Modified time.Time
Size int64
IsTerminal bool // false for keys that only contain other keys (like directories)
}
// storeTx stores all the values or none at all.
......
......@@ -24,6 +24,7 @@ import (
"fmt"
"io"
"os"
"path"
"sort"
"strings"
......@@ -240,16 +241,16 @@ func (cfg *Config) askUserAgreement(agreementURL string) bool {
// account, errors here are discarded to simplify code flow in
// the caller, and errors are not important here anyway.
func (cfg *Config) mostRecentUserEmail() string {
userList, err := cfg.certCache.storage.List(StorageKeys.UsersPrefix(cfg.CA))
userList, err := cfg.certCache.storage.List(StorageKeys.UsersPrefix(cfg.CA), false)
if err != nil || len(userList) == 0 {
return ""
}
sort.Slice(userList, func(i, j int) bool {
iInfo, _ := cfg.certCache.storage.Stat(StorageKeys.UserPrefix(cfg.CA, userList[i]))
jInfo, _ := cfg.certCache.storage.Stat(StorageKeys.UserPrefix(cfg.CA, userList[j]))
iInfo, _ := cfg.certCache.storage.Stat(userList[i])
jInfo, _ := cfg.certCache.storage.Stat(userList[j])
return jInfo.Modified.Before(iInfo.Modified)
})
user, err := cfg.getUser(userList[0])
user, err := cfg.getUser(path.Base(userList[0]))
if err != nil {
return ""
}
......
......@@ -138,7 +138,7 @@
"importpath": "github.com/mholt/certmagic",
"repository": "https://github.com/mholt/certmagic",
"vcs": "git",
"revision": "5b3085c491553887f36460365533eb5955fdeef0",
"revision": "dc98c40439d15f67021f10f0d9219a39d7cf2990",
"branch": "master",
"notests": true
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment