From b4ad66eda42c9da24926d955c39ac242ac9b74e1 Mon Sep 17 00:00:00 2001 From: Petar Maymounkov Date: Mon, 17 Aug 2020 09:46:51 -0700 Subject: [PATCH] add --ipns-base to publish and subs commands add sharness tests for --ipns-base in name publish and subs commands --- core/commands/keybase/keybase.go | 2 + core/commands/keystore.go | 57 +++++---------------------- core/commands/name/ipnsps.go | 15 +++++-- core/commands/name/publish.go | 15 ++++++- test/sharness/t0100-name.sh | 15 ++++--- test/sharness/t0183-namesys-pubsub.sh | 26 +++++++----- 6 files changed, 64 insertions(+), 66 deletions(-) diff --git a/core/commands/keybase/keybase.go b/core/commands/keybase/keybase.go index b857c8dbb99..dbc1413e888 100644 --- a/core/commands/keybase/keybase.go +++ b/core/commands/keybase/keybase.go @@ -5,6 +5,8 @@ import ( mbase "github.com/multiformats/go-multibase" ) +const KeyFormatOptionName = "ipns-base" + type KeyEncoder struct { baseEnc *mbase.Encoder } diff --git a/core/commands/keystore.go b/core/commands/keystore.go index f78bafa20bc..7aefcd37674 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -20,7 +20,6 @@ import ( options "github.com/ipfs/interface-go-ipfs-core/options" "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" - mbase "github.com/multiformats/go-multibase" ) var KeyCmd = &cmds.Command{ @@ -72,7 +71,6 @@ const ( keyStoreAlgorithmDefault = options.RSAKey keyStoreTypeOptionName = "type" keyStoreSizeOptionName = "size" - keyFormatOptionName = "ipns-base" oldKeyOptionName = "oldkey" ) @@ -83,7 +81,7 @@ var keyGenCmd = &cmds.Command{ Options: []cmds.Option{ cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault(keyStoreAlgorithmDefault), cmds.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"), - cmds.StringOption(keyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name of key to create"), @@ -110,7 +108,7 @@ var keyGenCmd = &cmds.Command{ if sizefound { opts = append(opts, options.Key.Size(size)) } - keyEnc, err := kb.KeyEncoderFromString(req.Options[keyFormatOptionName].(string)) + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) if err != nil { return err } @@ -225,7 +223,7 @@ var keyImportCmd = &cmds.Command{ Tagline: "Import a key and prints imported key id", }, Options: []cmds.Option{ - cmds.StringOption(keyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name to associate with key in keychain"), @@ -238,7 +236,7 @@ var keyImportCmd = &cmds.Command{ return fmt.Errorf("cannot import key with name 'self'") } - keyEnc, err := kb.KeyEncoderFromString(req.Options[keyFormatOptionName].(string)) + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) if err != nil { return err } @@ -305,10 +303,10 @@ var keyListCmd = &cmds.Command{ }, Options: []cmds.Option{ cmds.BoolOption("l", "Show extra information about keys."), - cmds.StringOption(keyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - keyEnc, err := kb.KeyEncoderFromString(req.Options[keyFormatOptionName].(string)) + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) if err != nil { return err } @@ -354,14 +352,14 @@ var keyRenameCmd = &cmds.Command{ }, Options: []cmds.Option{ cmds.BoolOption(keyStoreForceOptionName, "f", "Allow to overwrite an existing key."), - cmds.StringOption(keyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) if err != nil { return err } - keyEnc, err := kb.KeyEncoderFromString(req.Options[keyFormatOptionName].(string)) + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) if err != nil { return err } @@ -404,14 +402,14 @@ var keyRmCmd = &cmds.Command{ }, Options: []cmds.Option{ cmds.BoolOption("l", "Show extra information about keys."), - cmds.StringOption(keyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) if err != nil { return err } - keyEnc, err := kb.KeyEncoderFromString(req.Options[keyFormatOptionName].(string)) + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) if err != nil { return err } @@ -538,41 +536,6 @@ func doRotate(out io.Writer, repoRoot string, oldKey string, algorithm string, n return nil } -func verifyIDFormatLabel(formatLabel string) error { - switch formatLabel { - case "b58mh", "v0": - return nil - default: - _, err := mbase.EncoderByName(formatLabel) - return err - } -} - -func keyEncoderFromString(formatLabel string) (keyEncoder, error) { - switch formatLabel { - case "b58mh", "v0": - return keyEncoder{}, nil - default: - if enc, err := mbase.EncoderByName(formatLabel); err != nil { - return keyEncoder{}, err - } else { - return keyEncoder{&enc}, nil - } - } -} - -func (enc keyEncoder) FormatID(id peer.ID) string { - if enc.baseEnc == nil { - //nolint deprecated - return peer.IDB58Encode(id) - } - if s, err := peer.ToCid(id).StringOfBase(enc.baseEnc.Encoding()); err != nil { - panic(err) - } else { - return s - } -} - func keyOutputListEncoders() cmds.EncoderFunc { return cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, list *KeyOutputList) error { withID, _ := req.Options["l"].(bool) diff --git a/core/commands/name/ipnsps.go b/core/commands/name/ipnsps.go index 3511bed4aa7..ceb742aadd6 100644 --- a/core/commands/name/ipnsps.go +++ b/core/commands/name/ipnsps.go @@ -5,10 +5,11 @@ import ( "io" "strings" - "github.com/ipfs/go-ipfs-cmds" + cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs/core/commands/cmdenv" + kb "github.com/ipfs/go-ipfs/core/commands/keybase" "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-record" + record "github.com/libp2p/go-libp2p-record" ) type ipnsPubsubState struct { @@ -72,7 +73,15 @@ var ipnspsSubsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show current name subscriptions", }, + Options: []cmds.Option{ + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), + }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) + if err != nil { + return err + } + n, err := cmdenv.GetNode(env) if err != nil { return err @@ -93,7 +102,7 @@ var ipnspsSubsCmd = &cmds.Command{ log.Errorf("ipns key not a valid peer ID: %s", err) continue } - paths = append(paths, "/ipns/"+peer.Encode(pid)) + paths = append(paths, "/ipns/"+keyEnc.FormatID(pid)) } return cmds.EmitOnce(res, &stringList{paths}) diff --git a/core/commands/name/publish.go b/core/commands/name/publish.go index 6e8cf19c2bd..096eb8a9c1b 100644 --- a/core/commands/name/publish.go +++ b/core/commands/name/publish.go @@ -9,9 +9,11 @@ import ( cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" cmds "github.com/ipfs/go-ipfs-cmds" + kb "github.com/ipfs/go-ipfs/core/commands/keybase" iface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" path "github.com/ipfs/interface-go-ipfs-core/path" + peer "github.com/libp2p/go-libp2p-core/peer" ) var ( @@ -81,12 +83,17 @@ Alternatively, publish an using a valid PeerID (as listed by cmds.StringOption(ttlOptionName, "Time duration this record should be cached for. Uses the same syntax as the lifetime option. (caution: experimental)"), cmds.StringOption(keyOptionName, "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'.").WithDefault("self"), cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."), + cmds.StringOption(kb.KeyFormatOptionName, "", "Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}.").WithDefault("base36"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) if err != nil { return err } + keyEnc, err := kb.KeyEncoderFromString(req.Options[kb.KeyFormatOptionName].(string)) + if err != nil { + return err + } allowOffline, _ := req.Options[allowOfflineOptionName].(bool) kname, _ := req.Options[keyOptionName].(string) @@ -129,8 +136,14 @@ Alternatively, publish an using a valid PeerID (as listed by return err } + // parse path, extract cid, re-base cid, reconstruct path + pid, err := peer.Decode(out.Name()) + if err != nil { + return err + } + return cmds.EmitOnce(res, &IpnsEntry{ - Name: out.Name(), + Name: keyEnc.FormatID(pid), Value: out.Value().String(), }) }, diff --git a/test/sharness/t0100-name.sh b/test/sharness/t0100-name.sh index 9b7a60cd40e..df55731e9bf 100755 --- a/test/sharness/t0100-name.sh +++ b/test/sharness/t0100-name.sh @@ -116,14 +116,19 @@ test_name_with_self() { ' test_expect_success "'ipfs name publish --allow-offline --key= ' succeeds" ' - ipfs name publish --allow-offline --key=${B58MH_ID} "/ipfs/$HASH_WELCOME_DOCS" >b58mh_published_id && - ipfs name publish --allow-offline --key=${B36CID_ID} "/ipfs/$HASH_WELCOME_DOCS" >base36_published_id + ipfs name publish --allow-offline --key=${B58MH_ID} "/ipfs/$HASH_WELCOME_DOCS" >b58mh_published_id_base36 && + ipfs name publish --allow-offline --key=${B36CID_ID} "/ipfs/$HASH_WELCOME_DOCS" >base36_published_id_base36 && + ipfs name publish --allow-offline --key=${B58MH_ID} --ipns-base=b58mh "/ipfs/$HASH_WELCOME_DOCS" >b58mh_published_id_b58mh && + ipfs name publish --allow-offline --key=${B36CID_ID} --ipns-base=b58mh "/ipfs/$HASH_WELCOME_DOCS" >base36_published_id_b58mh ' test_expect_success "publish an explicit node ID as two key in B58MH and B36CID, name looks good" ' - echo "Published to ${B36CID_ID}: /ipfs/$HASH_WELCOME_DOCS" >expected_published_id && - test_cmp expected_published_id b58mh_published_id && - test_cmp expected_published_id base36_published_id + echo "Published to ${B36CID_ID}: /ipfs/$HASH_WELCOME_DOCS" >expected_published_id_base36 && + echo "Published to ${B58MH_ID}: /ipfs/$HASH_WELCOME_DOCS" >expected_published_id_b58mh && + test_cmp expected_published_id_base36 b58mh_published_id_base36 && + test_cmp expected_published_id_base36 base36_published_id_base36 && + test_cmp expected_published_id_b58mh b58mh_published_id_b58mh && + test_cmp expected_published_id_b58mh base36_published_id_b58mh ' test_expect_success "'ipfs name resolve' succeeds" ' diff --git a/test/sharness/t0183-namesys-pubsub.sh b/test/sharness/t0183-namesys-pubsub.sh index 1026b47e7c8..8161330c819 100755 --- a/test/sharness/t0183-namesys-pubsub.sh +++ b/test/sharness/t0183-namesys-pubsub.sh @@ -13,7 +13,8 @@ test_expect_success 'init iptb' ' startup_cluster $NUM_NODES --enable-namesys-pubsub test_expect_success 'peer ids' ' - PEERID_0=$(iptb attr get 0 id) + PEERID_0_BASE36=$(ipfsi 0 key list --ipns-base=base36 -l | grep self | head -n 1 | cut -d " " -f1) && + PEERID_0_B58MH=$(ipfsi 0 key list --ipns-base=b58mh -l | grep self | head -n 1 | cut -d " " -f1) ' test_expect_success 'check namesys pubsub state' ' @@ -28,17 +29,22 @@ test_expect_success 'check namesys pubsub state' ' # These commands are *expected* to fail. We haven't published anything yet. test_expect_success 'subscribe nodes to the publisher topic' ' - ipfsi 1 name resolve /ipns/$PEERID_0 --timeout=1s; - ipfsi 2 name resolve /ipns/$PEERID_0 --timeout=1s; + ipfsi 1 name resolve /ipns/$PEERID_0_BASE36 --timeout=1s; + ipfsi 2 name resolve /ipns/$PEERID_0_BASE36 --timeout=1s; true ' test_expect_success 'check subscriptions' ' - echo /ipns/$PEERID_0 > expected && + echo /ipns/$PEERID_0_BASE36 > expected_base36 && + echo /ipns/$PEERID_0_B58MH > expected_b58mh && ipfsi 1 name pubsub subs > subs1 && ipfsi 2 name pubsub subs > subs2 && - test_cmp expected subs1 && - test_cmp expected subs2 + ipfsi 1 name pubsub subs --ipns-base=b58mh > subs1_b58mh && + ipfsi 2 name pubsub subs --ipns-base=b58mh > subs2_b58mh && + test_cmp expected_base36 subs1 && + test_cmp expected_base36 subs2 && + test_cmp expected_b58mh subs1_b58mh && + test_cmp expected_b58mh subs2_b58mh ' test_expect_success 'add an object on publisher node' ' @@ -56,15 +62,15 @@ test_expect_success 'wait for the flood' ' test_expect_success 'resolve name in subscriber nodes' ' echo "/ipfs/$HASH_FILE" > expected && - ipfsi 1 name resolve /ipns/$PEERID_0 > name1 && - ipfsi 2 name resolve /ipns/$PEERID_0 > name2 && + ipfsi 1 name resolve /ipns/$PEERID_0_BASE36 > name1 && + ipfsi 2 name resolve /ipns/$PEERID_0_BASE36 > name2 && test_cmp expected name1 && test_cmp expected name2 ' test_expect_success 'cancel subscriptions to the publisher topic' ' - ipfsi 1 name pubsub cancel /ipns/$PEERID_0 && - ipfsi 2 name pubsub cancel /ipns/$PEERID_0 + ipfsi 1 name pubsub cancel /ipns/$PEERID_0_BASE36 && + ipfsi 2 name pubsub cancel /ipns/$PEERID_0_BASE36 ' test_expect_success 'check subscriptions' '