From b72a340c987ac7df2284983b9776d491d5aa2136 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 8 Mar 2019 18:47:02 -0800 Subject: [PATCH] pluggable keystores This patch allows keystores to be configured via the config and plugins. It's completely untested for now, but I started this so I figured I'd get it to a point where we could consider finishing it. License: MIT Signed-off-by: Steven Allen --- go.mod | 7 ++++-- go.sum | 12 ++++++++++ plugin/keystore.go | 24 +++++++++++++++++++ plugin/loader/loader.go | 10 ++++++++ repo/fsrepo/fsrepo.go | 19 +++++++++++++-- repo/fsrepo/keystores.go | 52 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 plugin/keystore.go create mode 100644 repo/fsrepo/keystores.go diff --git a/go.mod b/go.mod index 06f13475bbe..5cc68e16dd3 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/cenkalti/backoff v2.1.1+incompatible github.com/dustin/go-humanize v1.0.0 github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 + github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/fatih/color v1.7.0 // indirect github.com/fsnotify/fsnotify v1.4.7 github.com/gogo/protobuf v1.2.1 @@ -33,7 +34,7 @@ require ( github.com/ipfs/go-ipfs-chunker v0.0.1 github.com/ipfs/go-ipfs-cmdkit v0.0.1 github.com/ipfs/go-ipfs-cmds v0.0.1 - github.com/ipfs/go-ipfs-config v0.0.1 + github.com/ipfs/go-ipfs-config v0.0.0-20190309024316-a0bdc3f74854 github.com/ipfs/go-ipfs-ds-help v0.0.1 github.com/ipfs/go-ipfs-exchange-interface v0.0.1 github.com/ipfs/go-ipfs-exchange-offline v0.0.1 @@ -51,12 +52,12 @@ require ( github.com/ipfs/go-metrics-prometheus v0.0.1 github.com/ipfs/go-mfs v0.0.1 github.com/ipfs/go-path v0.0.1 + github.com/ipfs/go-prompt v0.0.1 github.com/ipfs/go-unixfs v0.0.1 github.com/ipfs/go-verifcid v0.0.1 github.com/ipfs/hang-fds v0.0.1 github.com/ipfs/interface-go-ipfs-core v0.0.2 github.com/ipfs/iptb v1.4.0 - github.com/ipfs/iptb-plugins v0.0.1 github.com/jbenet/go-is-domain v0.0.0-20160119110217-ba9815c809e0 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c github.com/jbenet/go-random-files v0.0.0-20190219210431-31b3f20ebded @@ -67,6 +68,7 @@ require ( github.com/libp2p/go-libp2p-circuit v0.0.1 github.com/libp2p/go-libp2p-connmgr v0.0.1 github.com/libp2p/go-libp2p-crypto v0.0.1 + github.com/libp2p/go-libp2p-daemon v0.0.1 // indirect github.com/libp2p/go-libp2p-host v0.0.1 github.com/libp2p/go-libp2p-interface-connmgr v0.0.1 github.com/libp2p/go-libp2p-kad-dht v0.0.3 @@ -102,6 +104,7 @@ require ( github.com/prometheus/client_golang v0.9.2 github.com/syndtr/goleveldb v1.0.0 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc + github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95 // indirect github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 diff --git a/go.sum b/go.sum index b87b29cfd97..1dafe78cbcb 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/Kubuxu/go-os-helper v0.0.1 h1:EJiD2VUQyh5A9hWJLmc6iWg6yIcJ7jpBcwC8GMG github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd h1:HNhzThEtZW714v8Eda8sWWRcu9WSzJC+oCyjRjvZgRA= github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd/go.mod h1:bqoB8kInrTeEtYAwaIXoSRqdwnjQmFhsfusnzyui6yY= +github.com/Songmu/prompter v0.0.0-20181014095714-d227c68538bd h1:WPP3dYxBYZBo0q3t14UIvD0Myr848agWCVSlScH17E0= +github.com/Songmu/prompter v0.0.0-20181014095714-d227c68538bd/go.mod h1:fNhSFBGC+sg+dZ7AqDHgq+xYiom23TeTESzUbO7PIrE= github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e h1:2Z+EBRrOJsA3psnUPcEWMIH2EIga1xHflQcr/EZslx8= github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -139,6 +141,8 @@ github.com/ipfs/go-ipfs-cmdkit v0.0.1 h1:X6YXEAjUljTzevE6DPUKXSqcgf+4FXzcn5B957F github.com/ipfs/go-ipfs-cmdkit v0.0.1/go.mod h1:9FtbMdUabcSqv/G4/8WCxSLxkZxn/aZEFrxxqnVcRbg= github.com/ipfs/go-ipfs-cmds v0.0.1 h1:wPTynLMa+JImcTsPaVmrUDP8mJ3S8HQVUWixnKi7+k4= github.com/ipfs/go-ipfs-cmds v0.0.1/go.mod h1:k7I8PptE2kCJchR3ta546LRyxl4/uBYbLQHOJM0sUQ8= +github.com/ipfs/go-ipfs-config v0.0.0-20190309024316-a0bdc3f74854 h1:/egI93XR8dai8cn+W2epdY0rCppfFsGjt8UQ741Qhy8= +github.com/ipfs/go-ipfs-config v0.0.0-20190309024316-a0bdc3f74854/go.mod h1:yqJG+KMcBiqX2v2EhxeTi30T0lLGZx6uY3f5B3gD4HI= github.com/ipfs/go-ipfs-config v0.0.1 h1:6ED08emzI1imdsAjixFi2pEyZxTVD5ECKtCOxLBx+Uc= github.com/ipfs/go-ipfs-config v0.0.1/go.mod h1:KDbHjNyg4e6LLQSQpkgQMBz6Jf4LXiWAcmnkcwmH0DU= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= @@ -182,6 +186,10 @@ github.com/ipfs/go-mfs v0.0.1 h1:EcQeaxW2DO3LmRXEtbWCGxhZ7YmMR+X7nzjYChBzG8s= github.com/ipfs/go-mfs v0.0.1/go.mod h1:rUT0dKNWkKa1T+MobpBL2zANn7p8Y6unXANC0PV2FLk= github.com/ipfs/go-path v0.0.1 h1:6UskTq8xYVs3zVnHjXDvoCqw22dKWK1BwD1cy1cuHyc= github.com/ipfs/go-path v0.0.1/go.mod h1:ztzG4iSBN2/CJa93rtHAv/I+mpK+BGALeUoJzhclhw0= +github.com/ipfs/go-prompt v0.0.0-20190309021543-60746b51630e h1:rClV9cZC54BQr25YltQRNc3a1GSxiCZSF7jwEWltFVU= +github.com/ipfs/go-prompt v0.0.0-20190309021543-60746b51630e/go.mod h1:9sBllkC9Vc4oYBP/S8iR8IRPbyVSwottiVgKsKA1atE= +github.com/ipfs/go-prompt v0.0.1 h1:yWWyaH5YKSkU9Gejgg8d41wzh5onvckStxK6CuLGSEo= +github.com/ipfs/go-prompt v0.0.1/go.mod h1:9sBllkC9Vc4oYBP/S8iR8IRPbyVSwottiVgKsKA1atE= github.com/ipfs/go-todocounter v0.0.1 h1:kITWA5ZcQZfrUnDNkRn04Xzh0YFaDFXsoO2A81Eb6Lw= github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= github.com/ipfs/go-unixfs v0.0.1 h1:CTTGqLxU5+PRkkeA+w1peStqRWFD1Kya+yZgIT4Xy1w= @@ -342,6 +350,8 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA= +github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -461,6 +471,8 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/plugin/keystore.go b/plugin/keystore.go new file mode 100644 index 00000000000..db496bc43da --- /dev/null +++ b/plugin/keystore.go @@ -0,0 +1,24 @@ +package plugin + +import ( + keystore "github.com/ipfs/go-ipfs/keystore" + prompt "github.com/ipfs/go-prompt" +) + +// PluginKeystore is an interface that can be implemented to new keystore +// backends. +type PluginKeystore interface { + Plugin + + // KeystoreTypeName returns the the keystore's type. In addition to + // loading the keystore plugin, the user must configure their go-ipfs + // node to use the specified keystore backend. + KeystoreTypeName() string + + // Open opens the keystore. Prompter may be nil if non-interactive. + Open( + repoPath string, + config map[string]interface{}, + prompter prompt.Prompter, + ) (keystore.Keystore, error) +} diff --git a/plugin/loader/loader.go b/plugin/loader/loader.go index 939edb9ad34..6085b20b1a9 100644 --- a/plugin/loader/loader.go +++ b/plugin/loader/loader.go @@ -105,6 +105,12 @@ func (loader *PluginLoader) Inject() error { return err } } + if pl, ok := pl.(plugin.PluginKeystore); ok { + err := injectKeystorePlugin(pl) + if err != nil { + return err + } + } } return nil } @@ -160,6 +166,10 @@ func injectIPLDPlugin(pl plugin.PluginIPLD) error { return pl.RegisterInputEncParsers(coredag.DefaultInputEncParsers) } +func injectKeystorePlugin(pl plugin.PluginKeystore) error { + return fsrepo.AddKeystore(pl.KeystoreTypeName(), pl.Open) +} + func injectTracerPlugin(pl plugin.PluginTracer) error { tracer, err := pl.InitTracer() if err != nil { diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index d35c97140c5..3524cbf8d84 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -384,8 +384,23 @@ func (r *FSRepo) openConfig() error { } func (r *FSRepo) openKeystore() error { - ksp := filepath.Join(r.path, "keystore") - ks, err := keystore.NewFSKeystore(ksp) + spec := r.config.Keystore + if spec == nil { + spec = map[string]interface{}{"type": "files", "path": "keystore"} + } + + ksType, ok := spec["type"] + if !ok { + return fmt.Errorf("keystore config lacks a type") + } + + ksCtor, ok := keystores[ksType] + if !ok { + return fmt.Errorf("couldn't find keystore of type %q", ksType) + } + + // TODO: feed through a prompter. + ks, err := ksCtor(r.path, spec, nil) if err != nil { return err } diff --git a/repo/fsrepo/keystores.go b/repo/fsrepo/keystores.go new file mode 100644 index 00000000000..65de1d5370c --- /dev/null +++ b/repo/fsrepo/keystores.go @@ -0,0 +1,52 @@ +package fsrepo + +import ( + "fmt" + "path/filepath" + + keystore "github.com/ipfs/go-ipfs/keystore" + + prompt "github.com/ipfs/go-prompt" +) + +type KeystoreConstructor func( + repoPath string, + cfg map[string]interface{}, + prompter prompt.Prompter, +) (keystore.Keystore, error) + +var keystores = map[string]KeystoreConstructor{ + "memory": MemKeystoreFromConfig, + "files": FSKeystoreFromConfig, +} + +func AddKeystore(name string, ctor KeystoreConstructor) error { + _, ok := keystores[name] + if ok { + return fmt.Errorf("keystore %q registered more than once", name) + } + keystores[name] = ctor + return nil +} + +func FSKeystoreFromConfig( + repo string, + cfg map[string]interface{}, + _ prompt.Prompter, +) (keystore.Keystore, error) { + path, ok := cfg["path"].(string) + if !ok { + return nil, fmt.Errorf("'path' field is missing or not a string") + } + return keystore.NewFSKeystore(filepath.Join(repo, path)) +} + +// MemKeystoreFromConfig opens an in-memory keystore based on the current +// config. +func MemKeystoreFromConfig( + _ string, + _ map[string]interface{}, + _ prompt.Prompter, +) (keystore.Keystore, error) { + return keystore.NewMemKeystore(), nil +}