package commands import ( "bytes" "fmt" "io" "strings" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/kubo/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, "transcode": mbaseTranscodeCmd, "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 := io.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) } encodedData, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file contents: %w", err) } _, data, err := mbase.Decode(string(encodedData)) if err != nil { return fmt.Errorf("failed to decode multibase: %w", err) } reader := bytes.NewReader(data) return resp.Emit(reader) }, } var mbaseTranscodeCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Transcode multibase string between bases", LongDescription: ` This command expects multibase inside of a file or via stdin. By default it will use URL-safe base64url encoding, but one can customize used base with -b: > echo -n hello | ipfs multibase encode > file > cat file uaGVsbG8 > ipfs multibase transcode file -b base16 > transcoded_file > cat transcoded_file f68656c6c6f `, }, Arguments: []cmds.Argument{ cmds.FileArg("encoded_file", true, false, "encoded data to decode").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) } encodedData, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file contents: %w", err) } _, data, err := mbase.Decode(string(encodedData)) if err != nil { return fmt.Errorf("failed to decode multibase: %w", err) } encoded := encoder.Encode(data) reader := strings.NewReader(encoded) return resp.Emit(reader) }, }