Skip to content

Commit

Permalink
feat: add 'ipfs multibase' commands (#8180)
Browse files Browse the repository at this point in the history
* add multibase helper commands (encode, decode, list)

Co-authored-by: Marcin Rataj <lidel@lidel.org>
  • Loading branch information
Cory Schwartz and lidel authored Aug 18, 2021
1 parent 7448340 commit 7db27bf
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 13 deletions.
30 changes: 17 additions & 13 deletions core/commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,26 @@ func TestCommands(t *testing.T) {
"/bootstrap/rm",
"/bootstrap/rm/all",
"/cat",
"/cid",
"/cid/base32",
"/cid/bases",
"/cid/codecs",
"/cid/format",
"/cid/hashes",
"/commands",
"/commands/completion",
"/commands/completion/bash",
"/config",
"/config/edit",
"/config/replace",
"/config/show",
"/config/profile",
"/config/profile/apply",
"/config/replace",
"/config/show",
"/dag",
"/dag/get",
"/dag/export",
"/dag/put",
"/dag/get",
"/dag/import",
"/dag/put",
"/dag/resolve",
"/dag/stat",
"/dht",
Expand Down Expand Up @@ -132,16 +138,16 @@ func TestCommands(t *testing.T) {
"/files/read",
"/files/rm",
"/files/stat",
"/files/write",
"/filestore",
"/filestore/dups",
"/filestore/ls",
"/filestore/verify",
"/files/write",
"/get",
"/id",
"/key",
"/key/gen",
"/key/export",
"/key/gen",
"/key/import",
"/key/list",
"/key/rename",
Expand All @@ -153,12 +159,16 @@ func TestCommands(t *testing.T) {
"/log/tail",
"/ls",
"/mount",
"/multibase",
"/multibase/decode",
"/multibase/encode",
"/multibase/list",
"/name",
"/name/publish",
"/name/pubsub",
"/name/pubsub/cancel",
"/name/pubsub/state",
"/name/pubsub/subs",
"/name/pubsub/cancel",
"/name/resolve",
"/object",
"/object/data",
Expand Down Expand Up @@ -235,12 +245,6 @@ func TestCommands(t *testing.T) {
"/urlstore/add",
"/version",
"/version/deps",
"/cid",
"/cid/format",
"/cid/base32",
"/cid/codecs",
"/cid/bases",
"/cid/hashes",
}

cmdSet := make(map[string]struct{})
Expand Down
118 changes: 118 additions & 0 deletions core/commands/multibase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package commands

import (
"bytes"
"fmt"
"io/ioutil"
"strings"

cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
mbase "github.com/multiformats/go-multibase"
)

var MbaseCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Encode and decode files or stdin with multibase format",
},
Subcommands: map[string]*cmds.Command{
"encode": mbaseEncodeCmd,
"decode": mbaseDecodeCmd,
"list": basesCmd,
},
Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
}

const (
mbaseOptionName = "b"
)

var mbaseEncodeCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Encode data into multibase string",
LongDescription: `
This command expects a file name or data provided via stdin.
By default it will use URL-safe base64url encoding,
but one can customize used base with -b:
> echo hello | ipfs multibase encode -b base16 > output_file
> cat output_file
f68656c6c6f0a
> echo hello > input_file
> ipfs multibase encode -b base16 input_file
f68656c6c6f0a
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("file", true, false, "data to encode").EnableStdin(),
},
Options: []cmds.Option{
cmds.StringOption(mbaseOptionName, "multibase encoding").WithDefault("base64url"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
if err := req.ParseBodyArgs(); err != nil {
return err
}
encoderName, _ := req.Options[mbaseOptionName].(string)
encoder, err := mbase.EncoderByName(encoderName)
if err != nil {
return err
}
files := req.Files.Entries()
file, err := cmdenv.GetFileArg(files)
if err != nil {
return fmt.Errorf("failed to access file: %w", err)
}
buf, err := ioutil.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read file contents: %w", err)
}
encoded := encoder.Encode(buf)
reader := strings.NewReader(encoded)
return resp.Emit(reader)
},
}

var mbaseDecodeCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Decode multibase string",
LongDescription: `
This command expects multibase inside of a file or via stdin:
> echo -n hello | ipfs multibase encode -b base16 > file
> cat file
f68656c6c6f
> ipfs multibase decode file
hello
> cat file | ipfs multibase decode
hello
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("encoded_file", true, false, "encoded data to decode").EnableStdin(),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
if err := req.ParseBodyArgs(); err != nil {
return err
}
files := req.Files.Entries()
file, err := cmdenv.GetFileArg(files)
if err != nil {
return fmt.Errorf("failed to access file: %w", err)
}
encoded_data, err := ioutil.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read file contents: %w", err)
}
_, data, err := mbase.Decode(string(encoded_data))
if err != nil {
return fmt.Errorf("failed to decode multibase: %w", err)
}
reader := bytes.NewReader(data)
return resp.Emit(reader)
},
}
4 changes: 4 additions & 0 deletions core/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ DATA STRUCTURE COMMANDS
dag Interact with IPLD DAG nodes
files Interact with files as if they were a unix filesystem
block Interact with raw blocks in the datastore
TEXT ENCODING COMMANDS
cid Convert and discover properties of CIDs
multibase Encode and decode data with Multibase format
ADVANCED COMMANDS
daemon Start a long-running daemon process
Expand Down Expand Up @@ -151,6 +154,7 @@ var rootSubcommands = map[string]*cmds.Command{
"version": VersionCmd,
"shutdown": daemonShutdownCmd,
"cid": CidCmd,
"multibase": MbaseCmd,
}

// RootRO is the readonly version of Root
Expand Down
89 changes: 89 additions & 0 deletions test/sharness/t0295-multibase.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash

test_description="Test multibase commands"

. lib/test-lib.sh

# note: all "ipfs multibase" commands should work without requiring a repo

cat <<EOF > bases_expect
0 identity
0 48 base2
b 98 base32
B 66 base32upper
c 99 base32pad
C 67 base32padupper
f 102 base16
F 70 base16upper
k 107 base36
K 75 base36upper
m 109 base64
M 77 base64pad
t 116 base32hexpad
T 84 base32hexpadupper
u 117 base64url
U 85 base64urlpad
v 118 base32hex
V 86 base32hexupper
z 122 base58btc
Z 90 base58flickr
EOF

# TODO: expose same cmd under multibase?
test_expect_success "multibase list" '
cut -c 10- bases_expect > expect &&
ipfs multibase list > actual &&
test_cmp expect actual
'

test_expect_success "multibase encode works (stdin)" '
echo -n uaGVsbG8 > expected &&
echo -n hello | ipfs multibase encode > actual &&
test_cmp actual expected
'

test_expect_success "multibase encode works (file)" '
echo -n hello > file &&
echo -n uaGVsbG8 > expected &&
ipfs multibase encode ./file > actual &&
test_cmp actual expected
'

test_expect_success "multibase encode -b (custom base)" '
echo -n f68656c6c6f > expected &&
echo -n hello | ipfs multibase encode -b base16 > actual &&
test_cmp actual expected
'

test_expect_success "multibase decode works (stdin)" '
echo -n hello > expected &&
echo -n uaGVsbG8 | ipfs multibase decode > actual &&
test_cmp actual expected
'

test_expect_success "multibase decode works (file)" '
echo -n uaGVsbG8 > file &&
echo -n hello > expected &&
ipfs multibase decode ./file > actual &&
test_cmp actual expected
'

test_expect_success "multibase encode+decode roundtrip" '
echo -n hello > expected &&
cat expected | ipfs multibase encode -b base64 | ipfs multibase decode > actual &&
test_cmp actual expected
'

test_expect_success "multibase error on unknown multibase prefix" '
echo "Error: failed to decode multibase: selected encoding not supported" > expected &&
echo -n ę-that-should-do-the-trick | ipfs multibase decode 2> actual ;
test_cmp actual expected
'

test_expect_success "multibase error on a character outside of the base" "
echo \"Error: failed to decode multibase: encoding/hex: invalid byte: U+007A 'z'\" > expected &&
echo -n f6c6f6cz | ipfs multibase decode 2> actual ;
test_cmp actual expected
"

test_done

0 comments on commit 7db27bf

Please sign in to comment.