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()