-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
License: MIT Signed-off-by: Jeromy <why@ipfs.io>
- Loading branch information
1 parent
4511a4a
commit fee2b7f
Showing
8 changed files
with
383 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package commands | ||
|
||
import ( | ||
"crypto/rand" | ||
"fmt" | ||
"io" | ||
"sort" | ||
"strings" | ||
|
||
cmds "github.com/ipfs/go-ipfs/commands" | ||
|
||
peer "gx/ipfs/QmfMmLGoKzCHDN7cGgk64PJr4iipzidDRME8HABSJqvmhC/go-libp2p-peer" | ||
ci "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" | ||
) | ||
|
||
var KeyCmd = &cmds.Command{ | ||
Helptext: cmds.HelpText{ | ||
Tagline: "Create and manipulate keypairs", | ||
}, | ||
Subcommands: map[string]*cmds.Command{ | ||
"gen": KeyGenCmd, | ||
"list": KeyListCmd, | ||
}, | ||
} | ||
|
||
type KeyOutput struct { | ||
Name string | ||
Id string | ||
} | ||
|
||
var KeyGenCmd = &cmds.Command{ | ||
Helptext: cmds.HelpText{ | ||
Tagline: "Create a new keypair", | ||
}, | ||
Options: []cmds.Option{ | ||
cmds.StringOption("type", "t", "type of the key to create"), | ||
cmds.IntOption("size", "s", "size of the key to generate"), | ||
}, | ||
Arguments: []cmds.Argument{ | ||
cmds.StringArg("name", true, false, "name of key to create"), | ||
}, | ||
Run: func(req cmds.Request, res cmds.Response) { | ||
n, err := req.InvocContext().GetNode() | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
typ, f, err := req.Option("type").String() | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
if !f { | ||
res.SetError(fmt.Errorf("please specify a key type with --type"), cmds.ErrNormal) | ||
return | ||
} | ||
|
||
size, sizefound, err := req.Option("size").Int() | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
name := req.Arguments()[0] | ||
if name == "self" { | ||
res.SetError(fmt.Errorf("cannot create key with name 'self'"), cmds.ErrNormal) | ||
return | ||
} | ||
|
||
var sk ci.PrivKey | ||
var pk ci.PubKey | ||
|
||
switch typ { | ||
case "rsa": | ||
if !sizefound { | ||
res.SetError(fmt.Errorf("please specify a key size with --size"), cmds.ErrNormal) | ||
return | ||
} | ||
|
||
priv, pub, err := ci.GenerateKeyPairWithReader(ci.RSA, size, rand.Reader) | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
sk = priv | ||
pk = pub | ||
case "ed25519": | ||
priv, pub, err := ci.GenerateEd25519Key(rand.Reader) | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
sk = priv | ||
pk = pub | ||
default: | ||
res.SetError(fmt.Errorf("unrecognized key type: %s", typ), cmds.ErrNormal) | ||
return | ||
} | ||
|
||
err = n.Repo.Keystore().Put(name, sk) | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
pid, err := peer.IDFromPublicKey(pk) | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
res.SetOutput(&KeyOutput{ | ||
Name: name, | ||
Id: pid.Pretty(), | ||
}) | ||
}, | ||
Marshalers: cmds.MarshalerMap{ | ||
cmds.Text: func(res cmds.Response) (io.Reader, error) { | ||
k, ok := res.Output().(*KeyOutput) | ||
if !ok { | ||
return nil, fmt.Errorf("expected a KeyOutput as command result") | ||
} | ||
|
||
return strings.NewReader(k.Id), nil | ||
}, | ||
}, | ||
Type: KeyOutput{}, | ||
} | ||
|
||
var KeyListCmd = &cmds.Command{ | ||
Helptext: cmds.HelpText{ | ||
Tagline: "List all local keypairs", | ||
}, | ||
Run: func(req cmds.Request, res cmds.Response) { | ||
n, err := req.InvocContext().GetNode() | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
keys, err := n.Repo.Keystore().List() | ||
if err != nil { | ||
res.SetError(err, cmds.ErrNormal) | ||
return | ||
} | ||
|
||
sort.Strings(keys) | ||
res.SetOutput(&stringList{keys}) | ||
}, | ||
Marshalers: cmds.MarshalerMap{ | ||
cmds.Text: stringListMarshaler, | ||
}, | ||
Type: stringList{}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package keystore | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
ci "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" | ||
) | ||
|
||
type Keystore interface { | ||
Put(string, ci.PrivKey) error | ||
Get(string) (ci.PrivKey, error) | ||
Delete(string) error | ||
List() ([]string, error) | ||
} | ||
|
||
var ErrNoSuchKey = fmt.Errorf("no key by the given name was found") | ||
var ErrKeyExists = fmt.Errorf("key by that name already exists, refusing to overwrite") | ||
|
||
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 | ||
} | ||
|
||
func NewFSKeystore(dir string) (*FSKeystore, error) { | ||
_, err := os.Stat(dir) | ||
if err != nil { | ||
if !os.IsNotExist(err) { | ||
return nil, err | ||
} | ||
if err := os.Mkdir(dir, 0700); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return &FSKeystore{dir}, nil | ||
} | ||
|
||
func (ks *FSKeystore) Put(name string, k ci.PrivKey) error { | ||
if err := validateName(name); err != nil { | ||
return err | ||
} | ||
|
||
b, err := k.Bytes() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
kp := filepath.Join(ks.dir, name) | ||
|
||
_, err = os.Stat(kp) | ||
if err == nil { | ||
return ErrKeyExists | ||
} | ||
|
||
fi, err := os.Create(kp) | ||
if err != nil { | ||
return err | ||
} | ||
defer fi.Close() | ||
|
||
_, err = fi.Write(b) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (ks *FSKeystore) Get(name string) (ci.PrivKey, error) { | ||
if err := validateName(name); err != nil { | ||
return nil, err | ||
} | ||
|
||
kp := filepath.Join(ks.dir, name) | ||
|
||
data, err := ioutil.ReadFile(kp) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
return nil, ErrNoSuchKey | ||
} | ||
return nil, err | ||
} | ||
|
||
return ci.UnmarshalPrivateKey(data) | ||
} | ||
|
||
func (ks *FSKeystore) Delete(name string) error { | ||
if err := validateName(name); err != nil { | ||
return err | ||
} | ||
|
||
kp := filepath.Join(ks.dir, name) | ||
|
||
return os.Remove(kp) | ||
} | ||
|
||
func (ks *FSKeystore) List() ([]string, error) { | ||
dir, err := os.Open(ks.dir) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return dir.Readdirnames(0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package keystore | ||
|
||
import ci "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" | ||
|
||
type MemKeystore struct { | ||
keys map[string]ci.PrivKey | ||
} | ||
|
||
func NewMemKeystore() *MemKeystore { | ||
return &MemKeystore{make(map[string]ci.PrivKey)} | ||
} | ||
|
||
func (mk *MemKeystore) Put(name string, k ci.PrivKey) error { | ||
if err := validateName(name); err != nil { | ||
return err | ||
} | ||
|
||
_, ok := mk.keys[name] | ||
if ok { | ||
return ErrKeyExists | ||
} | ||
|
||
mk.keys[name] = k | ||
return nil | ||
} | ||
|
||
func (mk *MemKeystore) Get(name string) (ci.PrivKey, error) { | ||
if err := validateName(name); err != nil { | ||
return nil, err | ||
} | ||
|
||
k, ok := mk.keys[name] | ||
if !ok { | ||
return nil, ErrNoSuchKey | ||
} | ||
|
||
return k, nil | ||
} | ||
|
||
func (mk *MemKeystore) Delete(name string) error { | ||
if err := validateName(name); err != nil { | ||
return err | ||
} | ||
|
||
delete(mk.keys, name) | ||
return nil | ||
} | ||
|
||
func (mk *MemKeystore) List() ([]string, error) { | ||
out := make([]string, 0, len(mk.keys)) | ||
for k, _ := range mk.keys { | ||
out = append(out, k) | ||
} | ||
return out, nil | ||
} |
Oops, something went wrong.