From 7193f950d795bb87c075edf1d9e41e7c131d7d8b Mon Sep 17 00:00:00 2001 From: gammazero Date: Thu, 17 Dec 2020 17:08:48 -0800 Subject: [PATCH 1/5] 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. --- core/commands/add.go | 2 +- core/commands/cmdenv/env.go | 12 ++++++++++++ core/commands/dns.go | 3 ++- core/commands/keystore.go | 8 ++++---- core/commands/ls.go | 2 +- core/commands/mount_unix.go | 4 ++-- core/commands/name/publish.go | 4 ++-- core/commands/object/object.go | 2 +- core/commands/pin/remotepin.go | 2 +- core/commands/pubsub.go | 2 +- core/commands/unixfs/ls.go | 4 ++-- 11 files changed, 29 insertions(+), 16 deletions(-) diff --git a/core/commands/add.go b/core/commands/add.go index 1c4c8603004..ba0dc2ecbd5 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -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 { diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index 82df803acf8..7e847525c42 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -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 +} diff --git a/core/commands/dns.go b/core/commands/dns.go index a775f09db1f..d5dea4cf1d6 100644 --- a/core/commands/dns.go +++ b/core/commands/dns.go @@ -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 }), }, diff --git a/core/commands/keystore.go b/core/commands/keystore.go index 0e242ee96a4..5f2388ddeae 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -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() diff --git a/core/commands/ls.go b/core/commands/ls.go index 4b0114d3341..1a7b0c3fc17 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -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() diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index 1a7e0118bfc..c6678d17585 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -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 }), diff --git a/core/commands/name/publish.go b/core/commands/name/publish.go index 99f0ab3cd2b..abf1ce34e5b 100644 --- a/core/commands/name/publish.go +++ b/core/commands/name/publish.go @@ -152,9 +152,9 @@ Alternatively, publish an 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 }), diff --git a/core/commands/object/object.go b/core/commands/object/object.go index b5858546f75..ed5bbcf24d7 100644 --- a/core/commands/object/object.go +++ b/core/commands/object/object.go @@ -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() diff --git a/core/commands/pin/remotepin.go b/core/commands/pin/remotepin.go index 12a2639c998..3bd71bb3dec 100644 --- a/core/commands/pin/remotepin.go +++ b/core/commands/pin/remotepin.go @@ -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 }), }, diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index 10bddcd57be..1ec5016d6fd 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -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 } diff --git a/core/commands/unixfs/ls.go b/core/commands/unixfs/ls.go index fee64c713fd..e5fd4e0c260 100644 --- a/core/commands/unixfs/ls.go +++ b/core/commands/unixfs/ls.go @@ -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() From e777adf04d54ad61e154b2c0b2d8933466a03888 Mon Sep 17 00:00:00 2001 From: gammazero Date: Thu, 17 Dec 2020 19:32:03 -0800 Subject: [PATCH 2/5] Test ls and add with escaped character --- test/sharness/t0045-ls.sh | 68 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/test/sharness/t0045-ls.sh b/test/sharness/t0045-ls.sh index 890292b8e39..a090b0ac657 100755 --- a/test/sharness/t0045-ls.sh +++ b/test/sharness/t0045-ls.sh @@ -19,6 +19,7 @@ test_ls_cmd() { random 128 42 >testData/d1/128 && echo "world" >testData/d2/a && random 1024 42 >testData/d2/1024 && + echo "badname" >testData/d2/`echo -e "bad\x7fname.txt"` && ipfs add -r testData >actual_add ' @@ -28,30 +29,32 @@ added QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe testData/d1/128 added QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN testData/d1/a added QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd testData/d2/1024 added QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL testData/d2/a +added QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn testData/d2/bad\u007fname.txt added QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH testData/f1 added QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M testData/f2 added QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss testData/d1 -added QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy testData/d2 -added QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj testData +added Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy testData/d2 +added QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 testData EOF test_cmp expected_add actual_add ' test_expect_success "'ipfs ls ' succeeds" ' - ipfs ls QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls + ipfs ls QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls ' test_expect_success "'ipfs ls ' output looks good" ' cat <<-\EOF >expected_ls && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss - d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy - d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy - d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH 5 f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M 5 f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL 6 a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn 8 bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe 128 128 @@ -61,20 +64,21 @@ EOF ' test_expect_success "'ipfs ls --size=false ' succeeds" ' - ipfs ls --size=false QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls + ipfs ls --size=false QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls ' test_expect_success "'ipfs ls ' output looks good" ' cat <<-\EOF >expected_ls && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe 128 @@ -84,22 +88,23 @@ EOF ' test_expect_success "'ipfs ls --headers ' succeeds" ' - ipfs ls --headers QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_headers + ipfs ls --headers QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_headers ' test_expect_success "'ipfs ls --headers ' output looks good" ' cat <<-\EOF >expected_ls_headers && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: Hash Size Name QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss - d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy - d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy - d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH 5 f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M 5 f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: Hash Size Name QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL 6 a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn 8 bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: Hash Size Name @@ -110,7 +115,7 @@ EOF ' test_expect_success "'ipfs ls --size=false --cid-base=base32 ' succeeds" ' - ipfs ls --size=false --cid-base=base32 $(cid-fmt -v 1 -b base32 %s QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss) >actual_ls_base32 + ipfs ls --size=false --cid-base=base32 $(cid-fmt -v 1 -b base32 %s QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss) >actual_ls_base32 ' test_expect_success "'ipfs ls --size=false --cid-base=base32 ' output looks good" ' @@ -130,6 +135,7 @@ test_ls_cmd_streaming() { random 128 42 >testData/d1/128 && echo "world" >testData/d2/a && random 1024 42 >testData/d2/1024 && + echo "badname" >testData/d2/`echo -e "bad\x7fname.txt"` && ipfs add -r testData >actual_add ' @@ -139,30 +145,32 @@ added QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe testData/d1/128 added QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN testData/d1/a added QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd testData/d2/1024 added QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL testData/d2/a +added QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn testData/d2/bad\u007fname.txt added QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH testData/f1 added QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M testData/f2 added QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss testData/d1 -added QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy testData/d2 -added QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj testData +added Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy testData/d2 +added QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 testData EOF test_cmp expected_add actual_add ' test_expect_success "'ipfs ls --stream ' succeeds" ' - ipfs ls --stream QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream + ipfs ls --stream QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream ' test_expect_success "'ipfs ls --stream ' output looks good" ' cat <<-\EOF >expected_ls_stream && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss - d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy - d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy - d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH 5 f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M 5 f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL 6 a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn 8 bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe 128 128 @@ -172,20 +180,21 @@ EOF ' test_expect_success "'ipfs ls --size=false --stream ' succeeds" ' - ipfs ls --size=false --stream QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream + ipfs ls --size=false --stream QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream ' test_expect_success "'ipfs ls --size=false --stream ' output looks good" ' cat <<-\EOF >expected_ls_stream && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe 128 @@ -195,22 +204,23 @@ EOF ' test_expect_success "'ipfs ls --stream --headers ' succeeds" ' - ipfs ls --stream --headers QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream_headers + ipfs ls --stream --headers QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21 Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_stream_headers ' test_expect_success "'ipfs ls --stream --headers ' output looks good" ' cat <<-\EOF >expected_ls_stream_headers && -QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj: +QmRPX2PWaPGqzoVzqNcQkueijHVzPicjupnD7eLck6Rs21: Hash Size Name QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss - d1/ -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy - d2/ +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy - d2/ QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH 5 f1 QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M 5 f2 -QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy: +Qmf9nCpkCfa8Gtz5m1NJMeHBWcBozKRcbdom338LukPAjy: Hash Size Name QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd 1024 1024 QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL 6 a +QmQSLRRd1Lxn6NMsWmmj2g9W3LtSRfmVAVqU3ShneLUrbn 8 bad\u007fname.txt QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss: Hash Size Name From 306dfb34a14b0c00958b467f0df3366f816beaad Mon Sep 17 00:00:00 2001 From: gammazero Date: Fri, 18 Dec 2020 17:23:30 -0800 Subject: [PATCH 3/5] additional escape --- core/commands/name/publish.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/name/publish.go b/core/commands/name/publish.go index abf1ce34e5b..e220efa7fc7 100644 --- a/core/commands/name/publish.go +++ b/core/commands/name/publish.go @@ -154,7 +154,7 @@ Alternatively, publish an using a valid PeerID (as listed by if quieter { _, err = fmt.Fprintln(w, cmdenv.EscNonPrint(ie.Name)) } else { - _, err = fmt.Fprintf(w, "Published to %s: %s\n", cmdenv.EscNonPrint(ie.Name), ie.Value) + _, err = fmt.Fprintf(w, "Published to %s: %s\n", cmdenv.EscNonPrint(ie.Name), cmdenv.EscNonPrint(ie.Value)) } return err }), From 267d6fc4fe476afa819bb9cd40bf599e0bceb3e4 Mon Sep 17 00:00:00 2001 From: gammazero Date: Tue, 12 Jan 2021 14:54:21 -0800 Subject: [PATCH 4/5] Modify escaping --- core/commands/cmdenv/env.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index 7e847525c42..5d256810931 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -72,13 +72,27 @@ func GetConfigRoot(env cmds.Environment) (string, error) { return ctx.ConfigRoot, nil } -// EscNonPrint converts control characters and non-printable characters into Go +// EscNonPrint converts non-printable characters and backslash into Go // escape sequences, if the given string contains any. func EscNonPrint(s string) string { + // First see if escaping is needed, to avoid creating garbage. + if !needEscape(s) { + return s + } + + esc := strconv.Quote(s) + // Remove first and last quote, and unescape quotes. + return strings.ReplaceAll(esc[1:len(esc)-1], `\"`, `"`) +} + +func needEscape(s string) bool { + if strings.ContainsRune(s, '\\') { + return true + } for _, r := range s { if !strconv.IsPrint(r) { - return strings.Trim(strconv.Quote(s), "\"") + return true } } - return s + return false } From 20132a83eff4e6acccb78f2ca53bf152e8b56a7e Mon Sep 17 00:00:00 2001 From: gammazero Date: Thu, 14 Jan 2021 02:29:11 -0800 Subject: [PATCH 5/5] code review changes --- core/commands/cmdenv/env.go | 7 +++-- core/commands/cmdenv/env_test.go | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 core/commands/cmdenv/env_test.go diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index 5d256810931..c21612c3305 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -72,10 +72,11 @@ func GetConfigRoot(env cmds.Environment) (string, error) { return ctx.ConfigRoot, nil } -// EscNonPrint converts non-printable characters and backslash into Go -// escape sequences, if the given string contains any. +// EscNonPrint converts non-printable characters and backslash into Go escape +// sequences. This is done to display all characters in a string, including +// those that would otherwise not be displayed or have an undesirable effect on +// the display. func EscNonPrint(s string) string { - // First see if escaping is needed, to avoid creating garbage. if !needEscape(s) { return s } diff --git a/core/commands/cmdenv/env_test.go b/core/commands/cmdenv/env_test.go new file mode 100644 index 00000000000..1e02851870d --- /dev/null +++ b/core/commands/cmdenv/env_test.go @@ -0,0 +1,48 @@ +package cmdenv + +import ( + "strconv" + "testing" +) + +func TestEscNonPrint(t *testing.T) { + b := []byte("hello") + b[2] = 0x7f + s := string(b) + if !needEscape(s) { + t.Fatal("string needs escaping") + } + if !hasNonPrintable(s) { + t.Fatal("expected non-printable") + } + if hasNonPrintable(EscNonPrint(s)) { + t.Fatal("escaped string has non-printable") + } + if EscNonPrint(`hel\lo`) != `hel\\lo` { + t.Fatal("backslash not escaped") + } + + s = `hello` + if needEscape(s) { + t.Fatal("string does not need escaping") + } + if EscNonPrint(s) != s { + t.Fatal("string should not have changed") + } + s = `"hello"` + if EscNonPrint(s) != s { + t.Fatal("string should not have changed") + } + if EscNonPrint(`"hel\"lo"`) != `"hel\\"lo"` { + t.Fatal("did not get expected escaped string") + } +} + +func hasNonPrintable(s string) bool { + for _, r := range s { + if !strconv.IsPrint(r) { + return true + } + } + return false +}