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.
This commit is contained in:
gammazero 2020-12-17 17:08:48 -08:00
parent 2ed9254426
commit 7193f950d7
11 changed files with 29 additions and 16 deletions

View File

@ -353,7 +353,7 @@ only-hash, and progress/status related flags) will change the final hash.
if quiet {
fmt.Fprintf(os.Stdout, "%s\n", output.Hash)
} else {
fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name)
fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, cmdenv.EscNonPrint(output.Name))
}
} else {

View File

@ -2,6 +2,7 @@ package cmdenv
import (
"fmt"
"strconv"
"strings"
"github.com/ipfs/go-ipfs/commands"
@ -70,3 +71,14 @@ func GetConfigRoot(env cmds.Environment) (string, error) {
return ctx.ConfigRoot, nil
}
// EscNonPrint converts control characters and non-printable characters into Go
// escape sequences, if the given string contains any.
func EscNonPrint(s string) string {
for _, r := range s {
if !strconv.IsPrint(r) {
return strings.Trim(strconv.Quote(s), "\"")
}
}
return s
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
namesys "github.com/ipfs/go-ipfs/namesys"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
@ -77,7 +78,7 @@ The resolver can recursively resolve:
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error {
fmt.Fprintln(w, out.Path.String())
fmt.Fprintln(w, cmdenv.EscNonPrint(out.Path.String()))
return nil
}),
},

View File

@ -383,9 +383,9 @@ var keyRenameCmd = &cmds.Command{
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, kro *KeyRenameOutput) error {
if kro.Overwrite {
fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, kro.Now)
fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
} else {
fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, kro.Now)
fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
}
return nil
}),
@ -547,9 +547,9 @@ func keyOutputListEncoders() cmds.EncoderFunc {
tw := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
for _, s := range list.Keys {
if withID {
fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, s.Name)
fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, cmdenv.EscNonPrint(s.Name))
} else {
fmt.Fprintf(tw, "%s\n", s.Name)
fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(s.Name))
}
}
tw.Flush()

View File

@ -251,7 +251,7 @@ func tabularOutput(req *cmds.Request, w io.Writer, out *LsOutput, lastObjectHash
}
}
fmt.Fprintf(tw, s, link.Hash, link.Size, link.Name)
fmt.Fprintf(tw, s, link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
}
}
tw.Flush()

View File

@ -119,8 +119,8 @@ baz
Type: config.Mounts{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, mounts *config.Mounts) error {
fmt.Fprintf(w, "IPFS mounted at: %s\n", mounts.IPFS)
fmt.Fprintf(w, "IPNS mounted at: %s\n", mounts.IPNS)
fmt.Fprintf(w, "IPFS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPFS))
fmt.Fprintf(w, "IPNS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPNS))
return nil
}),

View File

@ -152,9 +152,9 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
var err error
quieter, _ := req.Options[quieterOptionName].(bool)
if quieter {
_, err = fmt.Fprintln(w, ie.Name)
_, err = fmt.Fprintln(w, cmdenv.EscNonPrint(ie.Name))
} else {
_, err = fmt.Fprintf(w, "Published to %s: %s\n", ie.Name, ie.Value)
_, err = fmt.Fprintf(w, "Published to %s: %s\n", cmdenv.EscNonPrint(ie.Name), ie.Value)
}
return err
}),

View File

@ -167,7 +167,7 @@ multihash.
fmt.Fprintln(tw, "Hash\tSize\tName")
}
for _, link := range out.Links {
fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, link.Name)
fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
}
tw.Flush()

View File

@ -254,7 +254,7 @@ Returns a list of objects that are pinned to a remote pinning service.
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RemotePinOutput) error {
// pin remote ls produces a flat output similar to legacy pin ls
fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, out.Name)
fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, cmdenv.EscNonPrint(out.Name))
return nil
}),
},

View File

@ -205,7 +205,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
func stringListEncoder(req *cmds.Request, w io.Writer, list *stringList) error {
for _, str := range list.Strings {
_, err := fmt.Fprintf(w, "%s\n", str)
_, err := fmt.Fprintf(w, "%s\n", cmdenv.EscNonPrint(str))
if err != nil {
return err
}

View File

@ -213,12 +213,12 @@ If possible, please use 'ipfs ls' instead.
if len(out.Arguments) > 1 {
for _, arg := range directories[i:] {
if out.Arguments[arg] == hash {
fmt.Fprintf(tw, "%s:\n", arg)
fmt.Fprintf(tw, "%s:\n", cmdenv.EscNonPrint(arg))
}
}
}
for _, link := range object.Links {
fmt.Fprintf(tw, "%s\n", link.Name)
fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(link.Name))
}
}
tw.Flush()