Key import and export cli commands
rendaw committed
Jul 16, 2020 at 22:25 UTC
a0656402ed9cb527aedee902b4e65f4cd63dfb7a
5 files changed
+338
-37
core/commands/commands_test.go
+3
@@ -133,6 +133,9 @@ func TestCommands(t *testing.T) {
133
"/id",
134
"/key",
135
"/key/gen",
136
+ "/key/export",
137
+ "/key/import",
138
+ "/key/identify",
139
"/key/list",
140
"/key/rename",
141
"/key/rm",
core/commands/keystore.go
+260
-19
@@ -7,8 +7,13 @@ import (
7
8
cmds "github.com/ipfs/go-ipfs-cmds"
9
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
10
+ "github.com/ipfs/go-ipfs/core/coreapi"
11
+ repo "github.com/ipfs/go-ipfs/repo"
12
+ fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
13
options "github.com/ipfs/interface-go-ipfs-core/options"
14
+ "github.com/libp2p/go-libp2p-core/crypto"
15
peer "github.com/libp2p/go-libp2p-core/peer"
16
+ "github.com/mr-tron/base58/base58"
17
mbase "github.com/multiformats/go-multibase"
18
)
19
@@ -30,10 +35,13 @@ publish'.
35
`,
36
},
37
Subcommands: map[string]*cmds.Command{
33
- "gen": keyGenCmd,
34
- "list": keyListCmd,
35
- "rename": keyRenameCmd,
36
- "rm": keyRmCmd,
38
+ "gen": keyGenCmd,
39
+ "export": keyExportCmd,
40
+ "import": keyImportCmd,
41
+ "identify": keyIdentifyCmd,
42
+ "list": keyListCmd,
43
+ "rename": keyRenameCmd,
44
+ "rm": keyRmCmd,
45
},
46
}
47
@@ -42,6 +50,16 @@ type KeyOutput struct {
50
Id string
51
}
52
53
+type GenerateKeyOutput struct {
54
+ Name string
55
+ Id string
56
+ Sk string
57
+}
58
+
59
+type ExportKeyOutput struct {
60
+ Sk string
61
+}
62
+
63
type KeyOutputList struct {
64
Keys []KeyOutput
65
}
@@ -58,6 +76,8 @@ const (
76
keyStoreTypeOptionName = "type"
77
keyStoreSizeOptionName = "size"
78
keyFormatOptionName = "format"
79
+ keyExportOptionName = "export"
80
+ keyNoStoreOptionName = "no-store"
81
)
82
83
var keyGenCmd = &cmds.Command{
@@ -68,24 +88,57 @@ var keyGenCmd = &cmds.Command{
88
cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault("rsa"),
89
cmds.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"),
90
cmds.StringOption(keyFormatOptionName, "f", "output format: b58mh or b36cid").WithDefault("b58mh"),
91
+ cmds.BoolOption(keyExportOptionName, "e", "return generated key for later re-import").WithDefault(false),
92
+ cmds.BoolOption(keyNoStoreOptionName, "n", "don't add the key to the keychain").WithDefault(false),
93
},
94
Arguments: []cmds.Argument{
73
- cmds.StringArg("name", true, false, "name of key to create"),
95
+ cmds.StringArg("name", false, false, "name of key to create, required unless -n specified"),
96
},
97
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
76
- api, err := cmdenv.GetApi(env, req)
77
- if err != nil {
78
- return err
79
- }
80
-
98
typ, f := req.Options[keyStoreTypeOptionName].(string)
99
if !f {
100
return fmt.Errorf("please specify a key type with --type")
101
}
102
86
- name := req.Arguments[0]
87
- if name == "self" {
88
- return fmt.Errorf("cannot create key with name 'self'")
103
+ store := !req.Options[keyNoStoreOptionName].(bool)
104
+ export := req.Options[keyExportOptionName].(bool)
105
+
106
+ var name string
107
+ var r repo.Repo = nil
108
+ defer func() {
109
+ if r != nil {
110
+ r.Close()
111
+ }
112
+ }()
113
+ if store {
114
+ if len(req.Arguments) == 0 {
115
+ return fmt.Errorf("you must specify a key name")
116
+ }
117
+
118
+ name = req.Arguments[0]
119
+
120
+ if name == "self" {
121
+ return fmt.Errorf("cannot create key with name 'self'")
122
+ }
123
+
124
+ cfgRoot, err := cmdenv.GetConfigRoot(env)
125
+ if err != nil {
126
+ return err
127
+ }
128
+
129
+ r, err = fsrepo.Open(cfgRoot)
130
+ if err != nil {
131
+ return err
132
+ }
133
+
134
+ _, err = r.Keystore().Get(name)
135
+ if err == nil {
136
+ return fmt.Errorf("key with name '%s' already exists", name)
137
+ }
138
+ }
139
+
140
+ if !store && !export {
141
+ return fmt.Errorf("you must export key if not storing")
142
}
143
144
opts := []options.KeyGenerateOption{options.Key.Type(typ)}
@@ -94,28 +147,52 @@ var keyGenCmd = &cmds.Command{
147
if sizefound {
148
opts = append(opts, options.Key.Size(size))
149
}
97
- if err = verifyFormatLabel(req.Options[keyFormatOptionName].(string)); err != nil {
150
+ if err := verifyFormatLabel(req.Options[keyFormatOptionName].(string)); err != nil {
151
return err
152
}
153
101
- key, err := api.Key().Generate(req.Context, name, opts...)
154
+ sk, pk, err := coreapi.GenerateKey(opts...)
155
+ if err != nil {
156
+ return err
157
+ }
158
+
159
+ if store {
160
+ err = r.Keystore().Put(name, sk)
161
+ if err != nil {
162
+ return err
163
+ }
164
+ }
165
166
+ pid, err := peer.IDFromPublicKey(pk)
167
if err != nil {
168
return err
169
}
170
107
- return cmds.EmitOnce(res, &KeyOutput{
171
+ var encoded string
172
+ if export {
173
+ encoded, err = encodeSKForExport(sk)
174
+ if err != nil {
175
+ return err
176
+ }
177
+ }
178
+
179
+ return cmds.EmitOnce(res, &GenerateKeyOutput{
180
Name: name,
109
- Id: formatID(key.ID(), req.Options[keyFormatOptionName].(string)),
181
+ Id: formatID(pid, req.Options[keyFormatOptionName].(string)),
182
+ Sk: encoded,
183
})
184
},
185
Encoders: cmds.EncoderMap{
113
- cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *KeyOutput) error {
186
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *GenerateKeyOutput) error {
187
+ if ko.Sk != "" {
188
+ _, err := w.Write([]byte(ko.Sk + "\n"))
189
+ return err
190
+ }
191
_, err := w.Write([]byte(ko.Id + "\n"))
192
return err
193
}),
194
},
118
- Type: KeyOutput{},
195
+ Type: GenerateKeyOutput{},
196
}
197
198
func verifyFormatLabel(formatLabel string) error {
@@ -143,6 +220,170 @@ func formatID(id peer.ID, formatLabel string) string {
220
}
221
}
222
223
+func encodeSKForExport(sk crypto.PrivKey) (string, error) {
224
+ data, err := crypto.MarshalPrivateKey(sk)
225
+ if err != nil {
226
+ return "", err
227
+ }
228
+ return base58.Encode(data), nil
229
+}
230
+
231
+var keyExportCmd = &cmds.Command{
232
+ Helptext: cmds.HelpText{
233
+ Tagline: "Export a keypair",
234
+ },
235
+ Arguments: []cmds.Argument{
236
+ cmds.StringArg("name", true, false, "name of key to export").EnableStdin(),
237
+ },
238
+ Options: []cmds.Option{},
239
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
240
+ name := req.Arguments[0]
241
+
242
+ if name == "self" {
243
+ return fmt.Errorf("exporting key 'self' is not allowed")
244
+ }
245
+
246
+ cfgRoot, err := cmdenv.GetConfigRoot(env)
247
+ if err != nil {
248
+ return err
249
+ }
250
+
251
+ r, err := fsrepo.Open(cfgRoot)
252
+ if err != nil {
253
+ return err
254
+ }
255
+ defer r.Close()
256
+
257
+ sk, err := r.Keystore().Get(name)
258
+ if err != nil {
259
+ return fmt.Errorf("key with name '%s' doesn't exist", name)
260
+ }
261
+
262
+ encoded, err := encodeSKForExport(sk)
263
+ if err != nil {
264
+ return err
265
+ }
266
+
267
+ return cmds.EmitOnce(res, &ExportKeyOutput{
268
+ Sk: encoded,
269
+ })
270
+ },
271
+ Encoders: cmds.EncoderMap{
272
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *ExportKeyOutput) error {
273
+ _, err := w.Write([]byte(ko.Sk + "\n"))
274
+ return err
275
+ }),
276
+ },
277
+ Type: ExportKeyOutput{},
278
+}
279
+
280
+var keyImportCmd = &cmds.Command{
281
+ Helptext: cmds.HelpText{
282
+ Tagline: "Import a key and prints imported key id",
283
+ },
284
+ Options: []cmds.Option{
285
+ cmds.StringOption(keyFormatOptionName, "f", "output format: b58mh or b36cid").WithDefault("b58mh"),
286
+ },
287
+ Arguments: []cmds.Argument{
288
+ cmds.StringArg("name", true, false, "name to associate with key in keychain"),
289
+ cmds.StringArg("key", true, false, "key provided by generate or export"),
290
+ },
291
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
292
+ name := req.Arguments[0]
293
+ encoded := req.Arguments[1]
294
+
295
+ data, err := base58.Decode(encoded)
296
+ if err != nil {
297
+ return err
298
+ }
299
+
300
+ sk, err := crypto.UnmarshalPrivateKey(data)
301
+ if err != nil {
302
+ return err
303
+ }
304
+
305
+ cfgRoot, err := cmdenv.GetConfigRoot(env)
306
+ if err != nil {
307
+ return err
308
+ }
309
+
310
+ r, err := fsrepo.Open(cfgRoot)
311
+ if err != nil {
312
+ return err
313
+ }
314
+ defer r.Close()
315
+
316
+ _, err = r.Keystore().Get(name)
317
+ if err == nil {
318
+ return fmt.Errorf("key with name '%s' already exists", name)
319
+ }
320
+
321
+ err = r.Keystore().Put(name, sk)
322
+ if err != nil {
323
+ return err
324
+ }
325
+
326
+ pid, err := peer.IDFromPrivateKey(sk)
327
+ if err != nil {
328
+ return err
329
+ }
330
+
331
+ return cmds.EmitOnce(res, &KeyOutput{
332
+ Name: name,
333
+ Id: formatID(pid, req.Options[keyFormatOptionName].(string)),
334
+ })
335
+ },
336
+ Encoders: cmds.EncoderMap{
337
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *KeyOutput) error {
338
+ _, err := w.Write([]byte(ko.Id + "\n"))
339
+ return err
340
+ }),
341
+ },
342
+ Type: KeyOutput{},
343
+}
344
+
345
+var keyIdentifyCmd = &cmds.Command{
346
+ Helptext: cmds.HelpText{
347
+ Tagline: "Identify an exported keypair",
348
+ },
349
+ Options: []cmds.Option{
350
+ cmds.StringOption(keyFormatOptionName, "f", "output format: b58mh or b36cid").WithDefault("b58mh"),
351
+ },
352
+ Arguments: []cmds.Argument{
353
+ cmds.StringArg("key", true, false, "key provided by generate or export"),
354
+ },
355
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
356
+ encoded := req.Arguments[0]
357
+
358
+ data, err := base58.Decode(encoded)
359
+ if err != nil {
360
+ return err
361
+ }
362
+
363
+ sk, err := crypto.UnmarshalPrivateKey(data)
364
+ if err != nil {
365
+ return err
366
+ }
367
+
368
+ pid, err := peer.IDFromPrivateKey(sk)
369
+ if err != nil {
370
+ return err
371
+ }
372
+
373
+ return cmds.EmitOnce(res, &KeyOutput{
374
+ Name: "",
375
+ Id: formatID(pid, req.Options[keyFormatOptionName].(string)),
376
+ })
377
+ },
378
+ Encoders: cmds.EncoderMap{
379
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *KeyOutput) error {
380
+ _, err := w.Write([]byte(ko.Id + "\n"))
381
+ return err
382
+ }),
383
+ },
384
+ Type: KeyOutput{},
385
+}
386
+
387
var keyListCmd = &cmds.Command{
388
Helptext: cmds.HelpText{
389
Tagline: "List all local keypairs",
core/coreapi/key.go
+26
-16
@@ -37,21 +37,11 @@ func (k *key) ID() peer.ID {
37
return k.peerID
38
}
39
40
-// Generate generates new key, stores it in the keystore under the specified
41
-// name and returns a base58 encoded multihash of its public key.
42
-func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
40
+// GenerateKey generates a new keypair and returns it
41
+func GenerateKey(opts ...caopts.KeyGenerateOption) (crypto.PrivKey, crypto.PubKey, error) {
42
options, err := caopts.KeyGenerateOptions(opts...)
43
if err != nil {
45
- return nil, err
46
- }
47
-
48
- if name == "self" {
49
- return nil, fmt.Errorf("cannot create key with name 'self'")
50
- }
51
-
52
- _, err = api.repo.Keystore().Get(name)
53
- if err == nil {
54
- return nil, fmt.Errorf("key with name '%s' already exists", name)
44
+ return nil, nil, err
45
}
46
47
var sk crypto.PrivKey
@@ -65,7 +55,7 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key
55
56
priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, options.Size, rand.Reader)
57
if err != nil {
68
- return nil, err
58
+ return nil, nil, err
59
}
60
61
sk = priv
@@ -73,13 +63,33 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key
63
case "ed25519":
64
priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
65
if err != nil {
76
- return nil, err
66
+ return nil, nil, err
67
}
68
69
sk = priv
70
pk = pub
71
default:
82
- return nil, fmt.Errorf("unrecognized key type: %s", options.Algorithm)
72
+ return nil, nil, fmt.Errorf("unrecognized key type: %s", options.Algorithm)
73
+ }
74
+
75
+ return sk, pk, nil
76
+}
77
+
78
+// Generate generates new key, stores it in the keystore under the specified
79
+// name and returns a base58 encoded multihash of its public key.
80
+func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
81
+ if name == "self" {
82
+ return nil, fmt.Errorf("cannot create key with name 'self'")
83
+ }
84
+
85
+ _, err := api.repo.Keystore().Get(name)
86
+ if err == nil {
87
+ return nil, fmt.Errorf("key with name '%s' already exists", name)
88
+ }
89
+
90
+ sk, pk, err := GenerateKey(opts...)
91
+ if err != nil {
92
+ return nil, err
93
}
94
95
err = api.repo.Keystore().Put(name, sk)
test/sharness/lib/test-lib.sh
+16
@@ -483,6 +483,22 @@ test_check_ed25519_b36cid_peerid() {
483
}
484
}
485
486
+test_check_rsa2048_sk() {
487
+ peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
488
+ test "$sklen" = "300" || {
489
+ echo "Bad RSA2048 sk '$1' with len '$sklen'"
490
+ return 1
491
+ }
492
+}
493
+
494
+test_check_ed25519_sk() {
495
+ sklen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
496
+ test "$sklen" = "300" || {
497
+ echo "Bad ED25519 sk '$1' with len '$sklen'"
498
+ return 1
499
+ }
500
+}
501
+
502
convert_tcp_maddr() {
503
echo $1 | awk -F'/' '{ printf "%s:%s", $3, $5 }'
504
}
test/sharness/t0165-keystore.sh
+33
-2
@@ -17,6 +17,11 @@ PEERID=$(ipfs key gen -f=b58mh --type=rsa --size=2048 key_rsa) &&
17
test_check_rsa2048_b58mh_peerid $PEERID
18
'
19
20
+test_expect_success "test RSA key B36CID sk export format" '
21
+PEERID=$(ipfs key export key_rsa) &&
22
+test_check_rsa2048_sk $PEERID
23
+'
24
+
25
test_expect_success "test RSA key B36CID multihash format" '
26
PEERID=$(ipfs key list -f=b36cid -l | grep key_rsa | head -n 1 | cut -d " " -f1) &&
27
test_check_rsa2048_b36cid_peerid $PEERID &&
@@ -28,6 +33,11 @@ PEERID=$(ipfs key gen -f=b36cid --type=ed25519 key_ed25519) &&
33
test_check_ed25519_b36cid_peerid $PEERID
34
'
35
36
+test_expect_success "test RSA key ED25519 sk export format" '
37
+PEERID=$(ipfs key export key_ed25519) &&
38
+test_check_ed25519_sk $PEERID
39
+'
40
+
41
test_expect_success "test ED25519 key B36CID multihash format" '
42
PEERID=$(ipfs key list -f=b36cid -l | grep key_ed25519 | head -n 1 | cut -d " " -f1) &&
43
test_check_ed25519_b36cid_peerid $PEERID &&
@@ -43,11 +53,32 @@ ipfs key rm key_ed25519
53
test_expect_success "create a new ed25519 key" '
54
edhash=$(ipfs key gen -f=b58mh bazed --type=ed25519)
55
'
56
+
57
+ test_expect_success "import an rsa key" '
58
+ imphash=$(ipfs key import -f=b58mh quxel B9bLmHeKLQU1hX23meSn2kJiNW7AZ31C6PBNSYumejXB13vxSVvViZDkEnchAH4BTs9yVnBNZKZYLwykaCohzxTntesTCVaBhZR2Br2Swav2NXwVBhfrUbaBTrR2248KfbVxSiUdkpFn8kcAmUGwp2KGMGRmq85WreGFDdAvzz8ruN2EFfWSHLc1YeUxHeUgKsQm3N13uF7q5x4qvjWM6yvMWNY7JtZrihT8BZQhgb2ezR4iYPjXZTtPZWsLbrrhUvHhxSn1NsTw6NZ7Jbs84qMXXnH56BmT8J9LugRhQQvgBquSoS1m7aeD2y1L1A7mueVDYGLDzgxRSt5CohY7VVMdheUpPiq44CicuYt5YgbbuE3wMHntn6sd9QSYw7f4SjjKdw7Jhy5fNW29SkHvpLfZKfqzBNhSfHsofXVEASDpfr5mqws1eQTztqvvZhHXQxAoxxP3PK6TfDnATdLdV3Cy5v6nLt7ppsBj54hif5EZneHMLeYP8bYLbELQ2fZdoprpnKVBsMY1nWvgrMKUTpLjoKB6bzAZYuXaYVtmrdhESmKCyE12yEyvCcD8DJQU6JjqaD1DyVSPNkL3ze26Mm3ZyiFEH7M4XirUsPLrsj41Qt1xGaVGNEdkdthihytTZxxnmgyAptZMUNfSviBfH1tVbfoXFtBGU8eYMLdSHFqxSktT1mqeiWatxMQZ8pTeA9VCvAp9RTSRFkTQR9uP6w6qTzRD9cFcH4HyCEc5TJpiZdP7u9RjaEo2S3P9VkHfmqCH4McpLgw7He9nm7rf9JA2Gh7ubTKy5e6dJUWojgYhGS4KGe3yKGFhLaNgRiME63fUEFSnN2ZvCSM9qsrj34q2h8962xBod9hCVEDfk4tfmHu1UHX5AGaW6mk3pzqKKVYTTWXi84JSH7vzKPmQuhwaAR9Ye3Jbdzehp4xhrT5aFCjnz3r5qNv2zz48Fq5bGc1RUh88PUMT3z6kuzv6B1eXTLYpeu9gGdjc5C9DQDTYPfcHWn7dSHr4AGV1sN6SwVy8W5LZdMAZaeXCDn9iXDwbeD2DYd2ozVCEzceygVzpVdnueNx5FmG6zHtGzfuStr4Jj85sbd2jUGh4ES2bMU41jw2gJ6ujjf6CrxZpCWhXz6NJpAS9njcDFXuspf7otbMjCB6TzwokJwEse31nGUZQdhQgXn23vnZtxwCV621uXFbm7xVACRZKeuXgw8VdEVaXGvf2V4DdhjZnjmePBbTeJ7WjABavLcpMqZJH7FgaLxazFqk9RXtnfUEbVAAhuZzxz6L8Z6axHwz3a4EZtALRjfFjn6xjaUtsWXYW8P6F7femM6UHx3qXMo43hKC7oxnd6Tfta972dgyQfSoBwWkWzB8cvaJreNh4bdLNkw6mty86NXGKyijv83LR1HjbnUoTwPbEMX8JyzLfMf3qiWzwf6MHrXprwygmEpNc6w8tNNivmcWyCX3wmPkMKK1bmi5TCHoUtRrxcyXKhmuyo6zzag8KyK6iZaRbMiFiUJBi5VYwidMutkexWo8SRqfSV5yp2kxswknmpeVTnXBhVEy3anMEiD6bV48AnbF6SfKAi2DGBFqxBFfpFEbYtPauHiYYzZX1epqvKxY23xA9J8FosMk4yYN4Ps7Rh)
59
+ '
60
47
- test_expect_success "both keys show up in list output" '
61
+ test_expect_success "identify an rsa key" '
62
+ gothash=$(ipfs key identify B9bLmHeKLQU1hX23meSn2kJiNW7AZ31C6PBNSYumejXB13vxSVvViZDkEnchAH4BTs9yVnBNZKZYLwykaCohzxTntesTCVaBhZR2Br2Swav2NXwVBhfrUbaBTrR2248KfbVxSiUdkpFn8kcAmUGwp2KGMGRmq85WreGFDdAvzz8ruN2EFfWSHLc1YeUxHeUgKsQm3N13uF7q5x4qvjWM6yvMWNY7JtZrihT8BZQhgb2ezR4iYPjXZTtPZWsLbrrhUvHhxSn1NsTw6NZ7Jbs84qMXXnH56BmT8J9LugRhQQvgBquSoS1m7aeD2y1L1A7mueVDYGLDzgxRSt5CohY7VVMdheUpPiq44CicuYt5YgbbuE3wMHntn6sd9QSYw7f4SjjKdw7Jhy5fNW29SkHvpLfZKfqzBNhSfHsofXVEASDpfr5mqws1eQTztqvvZhHXQxAoxxP3PK6TfDnATdLdV3Cy5v6nLt7ppsBj54hif5EZneHMLeYP8bYLbELQ2fZdoprpnKVBsMY1nWvgrMKUTpLjoKB6bzAZYuXaYVtmrdhESmKCyE12yEyvCcD8DJQU6JjqaD1DyVSPNkL3ze26Mm3ZyiFEH7M4XirUsPLrsj41Qt1xGaVGNEdkdthihytTZxxnmgyAptZMUNfSviBfH1tVbfoXFtBGU8eYMLdSHFqxSktT1mqeiWatxMQZ8pTeA9VCvAp9RTSRFkTQR9uP6w6qTzRD9cFcH4HyCEc5TJpiZdP7u9RjaEo2S3P9VkHfmqCH4McpLgw7He9nm7rf9JA2Gh7ubTKy5e6dJUWojgYhGS4KGe3yKGFhLaNgRiME63fUEFSnN2ZvCSM9qsrj34q2h8962xBod9hCVEDfk4tfmHu1UHX5AGaW6mk3pzqKKVYTTWXi84JSH7vzKPmQuhwaAR9Ye3Jbdzehp4xhrT5aFCjnz3r5qNv2zz48Fq5bGc1RUh88PUMT3z6kuzv6B1eXTLYpeu9gGdjc5C9DQDTYPfcHWn7dSHr4AGV1sN6SwVy8W5LZdMAZaeXCDn9iXDwbeD2DYd2ozVCEzceygVzpVdnueNx5FmG6zHtGzfuStr4Jj85sbd2jUGh4ES2bMU41jw2gJ6ujjf6CrxZpCWhXz6NJpAS9njcDFXuspf7otbMjCB6TzwokJwEse31nGUZQdhQgXn23vnZtxwCV621uXFbm7xVACRZKeuXgw8VdEVaXGvf2V4DdhjZnjmePBbTeJ7WjABavLcpMqZJH7FgaLxazFqk9RXtnfUEbVAAhuZzxz6L8Z6axHwz3a4EZtALRjfFjn6xjaUtsWXYW8P6F7femM6UHx3qXMo43hKC7oxnd6Tfta972dgyQfSoBwWkWzB8cvaJreNh4bdLNkw6mty86NXGKyijv83LR1HjbnUoTwPbEMX8JyzLfMf3qiWzwf6MHrXprwygmEpNc6w8tNNivmcWyCX3wmPkMKK1bmi5TCHoUtRrxcyXKhmuyo6zzag8KyK6iZaRbMiFiUJBi5VYwidMutkexWo8SRqfSV5yp2kxswknmpeVTnXBhVEy3anMEiD6bV48AnbF6SfKAi2DGBFqxBFfpFEbYtPauHiYYzZX1epqvKxY23xA9J8FosMk4yYN4Ps7Rh) &&
63
+ test $imphash = $gothash
64
+ '
65
+
66
+ test_expect_success "key import can't export self" '
67
+ test_must_fail ipfs key export self 2>&1 | tee key_exp_out &&
68
+ grep -q "Error: cannot export key with name" key_exp_out
69
+ '
70
+
71
+ test_expect_success "key import can't import self" '
72
+ test_must_fail ipfs key import self B9bLmHeKLQU1hX23meSn2kJiNW7AZ31C6PBNSYumejXB13vxSVvViZDkEnchAH4BTs9yVnBNZKZYLwykaCohzxTntesTCVaBhZR2Br2Swav2NXwVBhfrUbaBTrR2248KfbVxSiUdkpFn8kcAmUGwp2KGMGRmq85WreGFDdAvzz8ruN2EFfWSHLc1YeUxHeUgKsQm3N13uF7q5x4qvjWM6yvMWNY7JtZrihT8BZQhgb2ezR4iYPjXZTtPZWsLbrrhUvHhxSn1NsTw6NZ7Jbs84qMXXnH56BmT8J9LugRhQQvgBquSoS1m7aeD2y1L1A7mueVDYGLDzgxRSt5CohY7VVMdheUpPiq44CicuYt5YgbbuE3wMHntn6sd9QSYw7f4SjjKdw7Jhy5fNW29SkHvpLfZKfqzBNhSfHsofXVEASDpfr5mqws1eQTztqvvZhHXQxAoxxP3PK6TfDnATdLdV3Cy5v6nLt7ppsBj54hif5EZneHMLeYP8bYLbELQ2fZdoprpnKVBsMY1nWvgrMKUTpLjoKB6bzAZYuXaYVtmrdhESmKCyE12yEyvCcD8DJQU6JjqaD1DyVSPNkL3ze26Mm3ZyiFEH7M4XirUsPLrsj41Qt1xGaVGNEdkdthihytTZxxnmgyAptZMUNfSviBfH1tVbfoXFtBGU8eYMLdSHFqxSktT1mqeiWatxMQZ8pTeA9VCvAp9RTSRFkTQR9uP6w6qTzRD9cFcH4HyCEc5TJpiZdP7u9RjaEo2S3P9VkHfmqCH4McpLgw7He9nm7rf9JA2Gh7ubTKy5e6dJUWojgYhGS4KGe3yKGFhLaNgRiME63fUEFSnN2ZvCSM9qsrj34q2h8962xBod9hCVEDfk4tfmHu1UHX5AGaW6mk3pzqKKVYTTWXi84JSH7vzKPmQuhwaAR9Ye3Jbdzehp4xhrT5aFCjnz3r5qNv2zz48Fq5bGc1RUh88PUMT3z6kuzv6B1eXTLYpeu9gGdjc5C9DQDTYPfcHWn7dSHr4AGV1sN6SwVy8W5LZdMAZaeXCDn9iXDwbeD2DYd2ozVCEzceygVzpVdnueNx5FmG6zHtGzfuStr4Jj85sbd2jUGh4ES2bMU41jw2gJ6ujjf6CrxZpCWhXz6NJpAS9njcDFXuspf7otbMjCB6TzwokJwEse31nGUZQdhQgXn23vnZtxwCV621uXFbm7xVACRZKeuXgw8VdEVaXGvf2V4DdhjZnjmePBbTeJ7WjABavLcpMqZJH7FgaLxazFqk9RXtnfUEbVAAhuZzxz6L8Z6axHwz3a4EZtALRjfFjn6xjaUtsWXYW8P6F7femM6UHx3qXMo43hKC7oxnd6Tfta972dgyQfSoBwWkWzB8cvaJreNh4bdLNkw6mty86NXGKyijv83LR1HjbnUoTwPbEMX8JyzLfMf3qiWzwf6MHrXprwygmEpNc6w8tNNivmcWyCX3wmPkMKK1bmi5TCHoUtRrxcyXKhmuyo6zzag8KyK6iZaRbMiFiUJBi5VYwidMutkexWo8SRqfSV5yp2kxswknmpeVTnXBhVEy3anMEiD6bV48AnbF6SfKAi2DGBFqxBFfpFEbYtPauHiYYzZX1epqvKxY23xA9J8FosMk4yYN4Ps7Rh 2>&1 | tee key_imp_out &&
73
+ grep -q "Error: cannot import key with name" key_imp_out
74
+ '
75
+
76
+ test_expect_success "all keys show up in list output" '
77
echo bazed > list_exp &&
78
echo foobarsa >> list_exp &&
50
- echo self >> list_exp
79
+ echo quxel >> list_exp &&
80
+ echo self >> list_exp &&
81
+ sort -o list_exp list_exp
82
ipfs key list -f=b58mh | sort > list_out &&
83
test_cmp list_exp list_out
84
'