Skip to content

Commit

Permalink
keystore: finish addressing encodedFSKeystore
Browse files Browse the repository at this point in the history
* Use Go's base32 library
* Set repo to version 9
* Resolve linting problems and docs.
* Merge EncodedFSKeystore into FSKeystore
* Remove name limitations and adjust tests
  • Loading branch information
hsanjuan committed Mar 16, 2020
1 parent e3468ee commit cbb4017
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 248 deletions.
158 changes: 29 additions & 129 deletions keystore/keystore.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
"path/filepath"
"strings"

base32 "encoding/base32"

logging "github.com/ipfs/go-log"
ci "github.com/libp2p/go-libp2p-core/crypto"
base32 "github.com/whyrusleeping/base32"
)

var log = logging.Logger("keystore")

var codec = base32.StdEncoding.WithPadding(base32.NoPadding)

// Keystore provides a key management interface
type Keystore interface {
// Has returns whether or not a key exist in the Keystore
Expand All @@ -29,46 +32,20 @@ type Keystore interface {
List() ([]string, error)
}

// ErrNoSuchKey is an error message returned when no key of a given name was found.
var ErrNoSuchKey = fmt.Errorf("no key by the given name was found")

// ErrKeyExists is an error message returned when a key already exists
var ErrKeyExists = fmt.Errorf("key by that name already exists, refusing to overwrite")

const keyFilenamePrefix = "key_"

// FSKeystore is a keystore backed by files in a given directory stored on disk.
type FSKeystore struct {
dir string
}

func validateName(name string) error {
if name == "" {
return fmt.Errorf("key names must be at least one character")
}

if strings.Contains(name, "/") {
return fmt.Errorf("key names may not contain slashes")
}

if strings.HasPrefix(name, ".") {
return fmt.Errorf("key names may not begin with a period")
}

return nil
}

// NewKeystore is a factory for getting instance of Keystore interface implementation
func NewKeystore(dir string) (Keystore, error) {
return NewEncodedFSKeystore(dir)
}

// NewEncodedFSKeystore is a factory for getting instance of EncodedFSKeystore
func NewEncodedFSKeystore(dir string) (*EncodedFSKeystore, error) {
keystore, err := NewFSKeystore(dir)

if err != nil {
return nil, err
}

return &EncodedFSKeystore{keystore}, nil
}

// NewFSKeystore returns a new filesystem-backed keystore.
func NewFSKeystore(dir string) (*FSKeystore, error) {
_, err := os.Stat(dir)
if err != nil {
Expand All @@ -85,28 +62,25 @@ func NewFSKeystore(dir string) (*FSKeystore, error) {

// Has returns whether or not a key exist in the Keystore
func (ks *FSKeystore) Has(name string) (bool, error) {
name, err := encode(name)
if err != nil {
return false, err
}

kp := filepath.Join(ks.dir, name)

_, err := os.Stat(kp)
_, err = os.Stat(kp)

if os.IsNotExist(err) {
return false, nil
}

if err != nil {
return false, err
}

if err := validateName(name); err != nil {
return false, err
}

return true, nil
return err == nil, err
}

// Put stores a key in the Keystore, if a key with the same name already exists, returns ErrKeyExists
func (ks *FSKeystore) Put(name string, k ci.PrivKey) error {
if err := validateName(name); err != nil {
name, err := encode(name)
if err != nil {
return err
}

Expand Down Expand Up @@ -138,7 +112,8 @@ func (ks *FSKeystore) Put(name string, k ci.PrivKey) error {
// Get retrieves a key from the Keystore if it exists, and returns ErrNoSuchKey
// otherwise.
func (ks *FSKeystore) Get(name string) (ci.PrivKey, error) {
if err := validateName(name); err != nil {
name, err := encode(name)
if err != nil {
return nil, err
}

Expand All @@ -157,7 +132,8 @@ func (ks *FSKeystore) Get(name string) (ci.PrivKey, error) {

// Delete removes a key from the Keystore
func (ks *FSKeystore) Delete(name string) error {
if err := validateName(name); err != nil {
name, err := encode(name)
if err != nil {
return err
}

Expand All @@ -181,25 +157,23 @@ func (ks *FSKeystore) List() ([]string, error) {
list := make([]string, 0, len(dirs))

for _, name := range dirs {
err := validateName(name)
decodedName, err := decode(name)
if err == nil {
list = append(list, name)
list = append(list, decodedName)
} else {
log.Warnf("Ignoring the invalid keyfile: %s", name)
log.Errorf("Ignoring keyfile with invalid encoded filename: %s", name)
}
}

return list, nil
}

const keyFilenamePrefix = "key_"

func encode(name string) (string, error) {
if name == "" {
return "", fmt.Errorf("key name must be at least one character")
}

encodedName := base32.RawStdEncoding.EncodeToString([]byte(name))
encodedName := codec.EncodeToString([]byte(name))
log.Debugf("Encoded key name: %s to: %s", name, encodedName)

return keyFilenamePrefix + strings.ToLower(encodedName), nil
Expand All @@ -211,86 +185,12 @@ func decode(name string) (string, error) {
}

nameWithoutPrefix := strings.ToUpper(name[len(keyFilenamePrefix):])
data, err := base32.RawStdEncoding.DecodeString(nameWithoutPrefix)

decodedName, err := codec.DecodeString(nameWithoutPrefix)
if err != nil {
return "", err
}

decodedName := string(data[:])

log.Debugf("Decoded key name: %s to: %s", name, decodedName)

return decodedName, nil
}

// EncodedFSKeystore is extension of FSKeystore that encodes the key filenames in base32
type EncodedFSKeystore struct {
*FSKeystore
}

// Has indicates if key is in keystore
func (ks *EncodedFSKeystore) Has(name string) (bool, error) {
encodedName, err := encode(name)

if err != nil {
return false, err
}

return ks.FSKeystore.Has(encodedName)
}

// Put places key into the keystore
func (ks *EncodedFSKeystore) Put(name string, k ci.PrivKey) error {
encodedName, err := encode(name)

if err != nil {
return err
}

return ks.FSKeystore.Put(encodedName, k)
}

// Get retrieves key by its name from the keystore
func (ks *EncodedFSKeystore) Get(name string) (ci.PrivKey, error) {
encodedName, err := encode(name)

if err != nil {
return nil, err
}

return ks.FSKeystore.Get(encodedName)
}

// Delete removes key from the keystore
func (ks *EncodedFSKeystore) Delete(name string) error {
encodedName, err := encode(name)

if err != nil {
return err
}

return ks.FSKeystore.Delete(encodedName)
}

// List returns list of all keys in keystore
func (ks *EncodedFSKeystore) List() ([]string, error) {
dirs, err := ks.FSKeystore.List()

if err != nil {
return nil, err
}

list := make([]string, 0, len(dirs))

for _, name := range dirs {
decodedName, err := decode(name)
if err == nil {
list = append(list, decodedName)
} else {
log.Warningf("Ignoring keyfile with invalid encoded filename: %s", name)
}
}

return list, nil
return string(decodedName), nil
}
Loading

0 comments on commit cbb4017

Please sign in to comment.