Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing EncodedFSKeystore with base32 encoding #6012

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions keystore/keystore.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

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

var log = logging.Logger("keystore")
Expand Down Expand Up @@ -52,6 +53,22 @@ func validateName(name string) error {
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
}

func NewFSKeystore(dir string) (*FSKeystore, error) {
_, err := os.Stat(dir)
if err != nil {
Expand Down Expand Up @@ -174,3 +191,106 @@ func (ks *FSKeystore) List() ([]string, error) {

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))
log.Debugf("Encoded key name: %s to: %s", name, encodedName)

return keyFilenamePrefix + strings.ToLower(encodedName), nil
}

func decode(name string) (string, error) {
if !strings.HasPrefix(name, keyFilenamePrefix) {
return "", fmt.Errorf("key's filename has unexpected format")
}

nameWithoutPrefix := strings.ToUpper(name[len(keyFilenamePrefix):])
data, err := base32.RawStdEncoding.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
}
89 changes: 89 additions & 0 deletions keystore/keystore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,92 @@ func assertDirContents(dir string, exp []string) error {
}
return nil
}

func TestEncodedKeystoreBasics(t *testing.T) {
tdir, err := ioutil.TempDir("", "encoded-keystore-test")
if err != nil {
t.Fatal(err)
}

ks, err := NewEncodedFSKeystore(tdir)
if err != nil {
t.Fatal(err)
}

l, err := ks.List()
if err != nil {
t.Fatal(err)
}

if len(l) != 0 {
t.Fatal("expected no keys")
}

k1 := privKeyOrFatal(t)
k1Name, err := encode("foo")
if err != nil {
t.Fatal(err)
}

k2 := privKeyOrFatal(t)
k2Name, err := encode("bar")
if err != nil {
t.Fatal(err)
}

err = ks.Put("foo", k1)
if err != nil {
t.Fatal(err)
}

err = ks.Put("bar", k2)
if err != nil {
t.Fatal(err)
}

l, err = ks.List()
if err != nil {
t.Fatal(err)
}

sort.Strings(l)
if l[0] != "bar" || l[1] != "foo" {
t.Fatal("wrong entries listed")
}

if err := assertDirContents(tdir, []string{k1Name, k2Name}); err != nil {
t.Fatal(err)
}

exist, err := ks.Has("foo")
if !exist {
t.Fatal("should know it has a key named foo")
}
if err != nil {
t.Fatal(err)
}

if err := ks.Delete("bar"); err != nil {
t.Fatal(err)
}

if err := assertDirContents(tdir, []string{k1Name}); err != nil {
t.Fatal(err)
}

if err := assertGetKey(ks, "foo", k1); err != nil {
t.Fatal(err)
}

if err := ks.Put("..///foo/", k1); err != nil {
t.Fatal(err)
}

if err := ks.Put("", k1); err == nil {
t.Fatal("shouldnt be able to put a key with no name")
}

if err := ks.Put(".foo", k1); err != nil {
t.Fatal(err)
}
}
4 changes: 2 additions & 2 deletions repo/fsrepo/fsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const LockFile = "repo.lock"
var log = logging.Logger("fsrepo")

// version number that we are currently expecting to see
var RepoVersion = 7
var RepoVersion = 8

var migrationInstructions = `See https://github.com/ipfs/fs-repo-migrations/blob/master/run.md
Sorry for the inconvenience. In the future, these will run automatically.`
Expand Down Expand Up @@ -385,7 +385,7 @@ func (r *FSRepo) openConfig() error {

func (r *FSRepo) openKeystore() error {
ksp := filepath.Join(r.path, "keystore")
ks, err := keystore.NewFSKeystore(ksp)
ks, err := keystore.NewKeystore(ksp)
if err != nil {
return err
}
Expand Down