@cryptotaxi247 / kubo / commits / 7193f950d

Escape non-printable characters in user output

Replaces control characters and non-printable characters with escape sequences, in any fields that are printed by the CLI, which could have been user input. Output from `ipfs cat` is unchanged.

gammazero committed Dec 17, 2020 at 17:08 UTC 7193f950d795bb87c075edf1d9e41e7c131d7d8b
11 files changed +29 -16
core/commands/add.go
+1 -1
@@ -353,7 +353,7 @@ only-hash, and progress/status related flags) will change the final hash.
353 if quiet {
354 fmt.Fprintf(os.Stdout, "%s\n", output.Hash)
355 } else {
356 - fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name)
356 + fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, cmdenv.EscNonPrint(output.Name))
357 }
358
359 } else {
core/commands/cmdenv/env.go
+12
@@ -2,6 +2,7 @@ package cmdenv
2
3 import (
4 "fmt"
5 + "strconv"
6 "strings"
7
8 "github.com/ipfs/go-ipfs/commands"
@@ -70,3 +71,14 @@ func GetConfigRoot(env cmds.Environment) (string, error) {
71
72 return ctx.ConfigRoot, nil
73 }
74 +
75 +// EscNonPrint converts control characters and non-printable characters into Go
76 +// escape sequences, if the given string contains any.
77 +func EscNonPrint(s string) string {
78 + for _, r := range s {
79 + if !strconv.IsPrint(r) {
80 + return strings.Trim(strconv.Quote(s), "\"")
81 + }
82 + }
83 + return s
84 +}
core/commands/dns.go
+2 -1
@@ -4,6 +4,7 @@ import (
4 "fmt"
5 "io"
6
7 + cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
8 ncmd "github.com/ipfs/go-ipfs/core/commands/name"
9 namesys "github.com/ipfs/go-ipfs/namesys"
10 nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
@@ -77,7 +78,7 @@ The resolver can recursively resolve:
78 },
79 Encoders: cmds.EncoderMap{
80 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error {
80 - fmt.Fprintln(w, out.Path.String())
81 + fmt.Fprintln(w, cmdenv.EscNonPrint(out.Path.String()))
82 return nil
83 }),
84 },
core/commands/keystore.go
+4 -4
@@ -383,9 +383,9 @@ var keyRenameCmd = &cmds.Command{
383 Encoders: cmds.EncoderMap{
384 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, kro *KeyRenameOutput) error {
385 if kro.Overwrite {
386 - fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, kro.Now)
386 + fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
387 } else {
388 - fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, kro.Now)
388 + fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
389 }
390 return nil
391 }),
@@ -547,9 +547,9 @@ func keyOutputListEncoders() cmds.EncoderFunc {
547 tw := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
548 for _, s := range list.Keys {
549 if withID {
550 - fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, s.Name)
550 + fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, cmdenv.EscNonPrint(s.Name))
551 } else {
552 - fmt.Fprintf(tw, "%s\n", s.Name)
552 + fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(s.Name))
553 }
554 }
555 tw.Flush()
core/commands/ls.go
+1 -1
@@ -251,7 +251,7 @@ func tabularOutput(req *cmds.Request, w io.Writer, out *LsOutput, lastObjectHash
251 }
252 }
253
254 - fmt.Fprintf(tw, s, link.Hash, link.Size, link.Name)
254 + fmt.Fprintf(tw, s, link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
255 }
256 }
257 tw.Flush()
core/commands/mount_unix.go
+2 -2
@@ -119,8 +119,8 @@ baz
119 Type: config.Mounts{},
120 Encoders: cmds.EncoderMap{
121 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, mounts *config.Mounts) error {
122 - fmt.Fprintf(w, "IPFS mounted at: %s\n", mounts.IPFS)
123 - fmt.Fprintf(w, "IPNS mounted at: %s\n", mounts.IPNS)
122 + fmt.Fprintf(w, "IPFS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPFS))
123 + fmt.Fprintf(w, "IPNS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPNS))
124
125 return nil
126 }),
core/commands/name/publish.go
+2 -2
@@ -152,9 +152,9 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
152 var err error
153 quieter, _ := req.Options[quieterOptionName].(bool)
154 if quieter {
155 - _, err = fmt.Fprintln(w, ie.Name)
155 + _, err = fmt.Fprintln(w, cmdenv.EscNonPrint(ie.Name))
156 } else {
157 - _, err = fmt.Fprintf(w, "Published to %s: %s\n", ie.Name, ie.Value)
157 + _, err = fmt.Fprintf(w, "Published to %s: %s\n", cmdenv.EscNonPrint(ie.Name), ie.Value)
158 }
159 return err
160 }),
core/commands/object/object.go
+1 -1
@@ -167,7 +167,7 @@ multihash.
167 fmt.Fprintln(tw, "Hash\tSize\tName")
168 }
169 for _, link := range out.Links {
170 - fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, link.Name)
170 + fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
171 }
172 tw.Flush()
173
core/commands/pin/remotepin.go
+1 -1
@@ -254,7 +254,7 @@ Returns a list of objects that are pinned to a remote pinning service.
254 Encoders: cmds.EncoderMap{
255 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RemotePinOutput) error {
256 // pin remote ls produces a flat output similar to legacy pin ls
257 - fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, out.Name)
257 + fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, cmdenv.EscNonPrint(out.Name))
258 return nil
259 }),
260 },
core/commands/pubsub.go
+1 -1
@@ -205,7 +205,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
205
206 func stringListEncoder(req *cmds.Request, w io.Writer, list *stringList) error {
207 for _, str := range list.Strings {
208 - _, err := fmt.Fprintf(w, "%s\n", str)
208 + _, err := fmt.Fprintf(w, "%s\n", cmdenv.EscNonPrint(str))
209 if err != nil {
210 return err
211 }
core/commands/unixfs/ls.go
+2 -2
@@ -213,12 +213,12 @@ If possible, please use 'ipfs ls' instead.
213 if len(out.Arguments) > 1 {
214 for _, arg := range directories[i:] {
215 if out.Arguments[arg] == hash {
216 - fmt.Fprintf(tw, "%s:\n", arg)
216 + fmt.Fprintf(tw, "%s:\n", cmdenv.EscNonPrint(arg))
217 }
218 }
219 }
220 for _, link := range object.Links {
221 - fmt.Fprintf(tw, "%s\n", link.Name)
221 + fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(link.Name))
222 }
223 }
224 tw.Flush()