@cryptotaxi247 / kubo / commits / 7db27bf83

feat: add 'ipfs multibase' commands (#8180)

* add multibase helper commands (encode, decode, list) Co-authored-by: Marcin Rataj <lidel@lidel.org>

Cory Schwartz committed Aug 18, 2021 at 13:48 UTC 7db27bf83a10cd9804a4be8e7421b5ed52bda461
4 files changed +228 -13
core/commands/commands_test.go
+17 -13
@@ -90,20 +90,26 @@ func TestCommands(t *testing.T) {
90 "/bootstrap/rm",
91 "/bootstrap/rm/all",
92 "/cat",
93 + "/cid",
94 + "/cid/base32",
95 + "/cid/bases",
96 + "/cid/codecs",
97 + "/cid/format",
98 + "/cid/hashes",
99 "/commands",
100 "/commands/completion",
101 "/commands/completion/bash",
102 "/config",
103 "/config/edit",
98 - "/config/replace",
99 - "/config/show",
104 "/config/profile",
105 "/config/profile/apply",
106 + "/config/replace",
107 + "/config/show",
108 "/dag",
103 - "/dag/get",
109 "/dag/export",
105 - "/dag/put",
110 + "/dag/get",
111 "/dag/import",
112 + "/dag/put",
113 "/dag/resolve",
114 "/dag/stat",
115 "/dht",
@@ -132,16 +138,16 @@ func TestCommands(t *testing.T) {
138 "/files/read",
139 "/files/rm",
140 "/files/stat",
141 + "/files/write",
142 "/filestore",
143 "/filestore/dups",
144 "/filestore/ls",
145 "/filestore/verify",
139 - "/files/write",
146 "/get",
147 "/id",
148 "/key",
143 - "/key/gen",
149 "/key/export",
150 + "/key/gen",
151 "/key/import",
152 "/key/list",
153 "/key/rename",
@@ -153,12 +159,16 @@ func TestCommands(t *testing.T) {
159 "/log/tail",
160 "/ls",
161 "/mount",
162 + "/multibase",
163 + "/multibase/decode",
164 + "/multibase/encode",
165 + "/multibase/list",
166 "/name",
167 "/name/publish",
168 "/name/pubsub",
169 + "/name/pubsub/cancel",
170 "/name/pubsub/state",
171 "/name/pubsub/subs",
161 - "/name/pubsub/cancel",
172 "/name/resolve",
173 "/object",
174 "/object/data",
@@ -235,12 +245,6 @@ func TestCommands(t *testing.T) {
245 "/urlstore/add",
246 "/version",
247 "/version/deps",
238 - "/cid",
239 - "/cid/format",
240 - "/cid/base32",
241 - "/cid/codecs",
242 - "/cid/bases",
243 - "/cid/hashes",
248 }
249
250 cmdSet := make(map[string]struct{})
core/commands/multibase.go new
+118
@@ -0,0 +1,118 @@
1 +package commands
2 +
3 +import (
4 + "bytes"
5 + "fmt"
6 + "io/ioutil"
7 + "strings"
8 +
9 + cmds "github.com/ipfs/go-ipfs-cmds"
10 + "github.com/ipfs/go-ipfs/core/commands/cmdenv"
11 + mbase "github.com/multiformats/go-multibase"
12 +)
13 +
14 +var MbaseCmd = &cmds.Command{
15 + Helptext: cmds.HelpText{
16 + Tagline: "Encode and decode files or stdin with multibase format",
17 + },
18 + Subcommands: map[string]*cmds.Command{
19 + "encode": mbaseEncodeCmd,
20 + "decode": mbaseDecodeCmd,
21 + "list": basesCmd,
22 + },
23 + Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
24 +}
25 +
26 +const (
27 + mbaseOptionName = "b"
28 +)
29 +
30 +var mbaseEncodeCmd = &cmds.Command{
31 + Helptext: cmds.HelpText{
32 + Tagline: "Encode data into multibase string",
33 + LongDescription: `
34 +This command expects a file name or data provided via stdin.
35 +
36 +By default it will use URL-safe base64url encoding,
37 +but one can customize used base with -b:
38 +
39 + > echo hello | ipfs multibase encode -b base16 > output_file
40 + > cat output_file
41 + f68656c6c6f0a
42 +
43 + > echo hello > input_file
44 + > ipfs multibase encode -b base16 input_file
45 + f68656c6c6f0a
46 + `,
47 + },
48 + Arguments: []cmds.Argument{
49 + cmds.FileArg("file", true, false, "data to encode").EnableStdin(),
50 + },
51 + Options: []cmds.Option{
52 + cmds.StringOption(mbaseOptionName, "multibase encoding").WithDefault("base64url"),
53 + },
54 + Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
55 + if err := req.ParseBodyArgs(); err != nil {
56 + return err
57 + }
58 + encoderName, _ := req.Options[mbaseOptionName].(string)
59 + encoder, err := mbase.EncoderByName(encoderName)
60 + if err != nil {
61 + return err
62 + }
63 + files := req.Files.Entries()
64 + file, err := cmdenv.GetFileArg(files)
65 + if err != nil {
66 + return fmt.Errorf("failed to access file: %w", err)
67 + }
68 + buf, err := ioutil.ReadAll(file)
69 + if err != nil {
70 + return fmt.Errorf("failed to read file contents: %w", err)
71 + }
72 + encoded := encoder.Encode(buf)
73 + reader := strings.NewReader(encoded)
74 + return resp.Emit(reader)
75 + },
76 +}
77 +
78 +var mbaseDecodeCmd = &cmds.Command{
79 + Helptext: cmds.HelpText{
80 + Tagline: "Decode multibase string",
81 + LongDescription: `
82 +This command expects multibase inside of a file or via stdin:
83 +
84 + > echo -n hello | ipfs multibase encode -b base16 > file
85 + > cat file
86 + f68656c6c6f
87 +
88 + > ipfs multibase decode file
89 + hello
90 +
91 + > cat file | ipfs multibase decode
92 + hello
93 +`,
94 + },
95 + Arguments: []cmds.Argument{
96 + cmds.FileArg("encoded_file", true, false, "encoded data to decode").EnableStdin(),
97 + },
98 + Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
99 + if err := req.ParseBodyArgs(); err != nil {
100 + return err
101 + }
102 + files := req.Files.Entries()
103 + file, err := cmdenv.GetFileArg(files)
104 + if err != nil {
105 + return fmt.Errorf("failed to access file: %w", err)
106 + }
107 + encoded_data, err := ioutil.ReadAll(file)
108 + if err != nil {
109 + return fmt.Errorf("failed to read file contents: %w", err)
110 + }
111 + _, data, err := mbase.Decode(string(encoded_data))
112 + if err != nil {
113 + return fmt.Errorf("failed to decode multibase: %w", err)
114 + }
115 + reader := bytes.NewReader(data)
116 + return resp.Emit(reader)
117 + },
118 +}
core/commands/root.go
+4
@@ -43,7 +43,10 @@ DATA STRUCTURE COMMANDS
43 dag Interact with IPLD DAG nodes
44 files Interact with files as if they were a unix filesystem
45 block Interact with raw blocks in the datastore
46 +
47 +TEXT ENCODING COMMANDS
48 cid Convert and discover properties of CIDs
49 + multibase Encode and decode data with Multibase format
50
51 ADVANCED COMMANDS
52 daemon Start a long-running daemon process
@@ -151,6 +154,7 @@ var rootSubcommands = map[string]*cmds.Command{
154 "version": VersionCmd,
155 "shutdown": daemonShutdownCmd,
156 "cid": CidCmd,
157 + "multibase": MbaseCmd,
158 }
159
160 // RootRO is the readonly version of Root
test/sharness/t0295-multibase.sh new
+89
@@ -0,0 +1,89 @@
1 +#!/usr/bin/env bash
2 +
3 +test_description="Test multibase commands"
4 +
5 +. lib/test-lib.sh
6 +
7 +# note: all "ipfs multibase" commands should work without requiring a repo
8 +
9 +cat <<EOF > bases_expect
10 + 0 identity
11 +0 48 base2
12 +b 98 base32
13 +B 66 base32upper
14 +c 99 base32pad
15 +C 67 base32padupper
16 +f 102 base16
17 +F 70 base16upper
18 +k 107 base36
19 +K 75 base36upper
20 +m 109 base64
21 +M 77 base64pad
22 +t 116 base32hexpad
23 +T 84 base32hexpadupper
24 +u 117 base64url
25 +U 85 base64urlpad
26 +v 118 base32hex
27 +V 86 base32hexupper
28 +z 122 base58btc
29 +Z 90 base58flickr
30 +EOF
31 +
32 +# TODO: expose same cmd under multibase?
33 +test_expect_success "multibase list" '
34 + cut -c 10- bases_expect > expect &&
35 + ipfs multibase list > actual &&
36 + test_cmp expect actual
37 +'
38 +
39 +test_expect_success "multibase encode works (stdin)" '
40 + echo -n uaGVsbG8 > expected &&
41 + echo -n hello | ipfs multibase encode > actual &&
42 + test_cmp actual expected
43 +'
44 +
45 +test_expect_success "multibase encode works (file)" '
46 + echo -n hello > file &&
47 + echo -n uaGVsbG8 > expected &&
48 + ipfs multibase encode ./file > actual &&
49 + test_cmp actual expected
50 +'
51 +
52 +test_expect_success "multibase encode -b (custom base)" '
53 + echo -n f68656c6c6f > expected &&
54 + echo -n hello | ipfs multibase encode -b base16 > actual &&
55 + test_cmp actual expected
56 +'
57 +
58 +test_expect_success "multibase decode works (stdin)" '
59 + echo -n hello > expected &&
60 + echo -n uaGVsbG8 | ipfs multibase decode > actual &&
61 + test_cmp actual expected
62 +'
63 +
64 +test_expect_success "multibase decode works (file)" '
65 + echo -n uaGVsbG8 > file &&
66 + echo -n hello > expected &&
67 + ipfs multibase decode ./file > actual &&
68 + test_cmp actual expected
69 +'
70 +
71 +test_expect_success "multibase encode+decode roundtrip" '
72 + echo -n hello > expected &&
73 + cat expected | ipfs multibase encode -b base64 | ipfs multibase decode > actual &&
74 + test_cmp actual expected
75 +'
76 +
77 +test_expect_success "multibase error on unknown multibase prefix" '
78 + echo "Error: failed to decode multibase: selected encoding not supported" > expected &&
79 + echo -n ę-that-should-do-the-trick | ipfs multibase decode 2> actual ;
80 + test_cmp actual expected
81 +'
82 +
83 +test_expect_success "multibase error on a character outside of the base" "
84 + echo \"Error: failed to decode multibase: encoding/hex: invalid byte: U+007A 'z'\" > expected &&
85 + echo -n f6c6f6cz | ipfs multibase decode 2> actual ;
86 + test_cmp actual expected
87 +"
88 +
89 +test_done