diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index d0848f1e4..37782dffb 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -4,7 +4,6 @@ import ( "bufio" "encoding/hex" "fmt" - "io/ioutil" "net" "net/http" "net/url" @@ -91,6 +90,10 @@ type tufCommander struct { roles []string sha256 string sha512 string + + input string + output string + quiet bool } func (t *tufCommander) AddToCommand(cmd *cobra.Command) { @@ -98,7 +101,6 @@ func (t *tufCommander) AddToCommand(cmd *cobra.Command) { cmd.AddCommand(cmdTufStatusTemplate.ToCommand(t.tufStatus)) cmd.AddCommand(cmdTufPublishTemplate.ToCommand(t.tufPublish)) cmd.AddCommand(cmdTufLookupTemplate.ToCommand(t.tufLookup)) - cmd.AddCommand(cmdTufVerifyTemplate.ToCommand(t.tufVerify)) cmdTufList := cmdTufListTemplate.ToCommand(t.tufList) cmdTufList.Flags().StringSliceVarP( @@ -118,6 +120,12 @@ func (t *tufCommander) AddToCommand(cmd *cobra.Command) { cmdTufAddHash.Flags().StringVar(&t.sha256, notary.SHA256, "", "hex encoded sha256 of the target to add") cmdTufAddHash.Flags().StringVar(&t.sha512, notary.SHA512, "", "hex encoded sha512 of the target to add") cmd.AddCommand(cmdTufAddHash) + + cmdTufVerify := cmdTufVerifyTemplate.ToCommand(t.tufVerify) + cmdTufVerify.Flags().StringVarP(&t.input, "input", "i", "", "Read from a file, instead of STDIN") + cmdTufVerify.Flags().StringVarP(&t.output, "output", "o", "", "Write to a file, instead of STDOUT") + cmdTufVerify.Flags().BoolVarP(&t.quiet, "quiet", "q", false, "No output except for errors") + cmd.AddCommand(cmdTufVerify) } func (t *tufCommander) tufAddByHash(cmd *cobra.Command, args []string) error { @@ -482,10 +490,9 @@ func (t *tufCommander) tufVerify(cmd *cobra.Command, args []string) error { return err } - // Reads all of the data on STDIN - payload, err := ioutil.ReadAll(os.Stdin) + payload, err := getPayload(t) if err != nil { - return fmt.Errorf("Error reading content from STDIN: %v", err) + return err } gun := args[0] @@ -516,8 +523,7 @@ func (t *tufCommander) tufVerify(cmd *cobra.Command, args []string) error { return fmt.Errorf("data not present in the trusted collection, %v", err) } - _, _ = os.Stdout.Write(payload) - return nil + return feedback(t, payload) } type passwordStore struct { diff --git a/cmd/notary/util.go b/cmd/notary/util.go new file mode 100644 index 000000000..887204f08 --- /dev/null +++ b/cmd/notary/util.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +// getPayload is a helper function to get the content used to be verified +// either from an existing file or STDIN. +func getPayload(t *tufCommander) ([]byte, error) { + + // Reads from the given file + if t.input != "" { + // Please note that ReadFile will cut off the size if it was over 1e9. + // Thus, if the size of the file exceeds 1GB, the over part will not be + // loaded into the buffer. + payload, err := ioutil.ReadFile(t.input) + if err != nil { + return nil, err + } + return payload, nil + } + + // Reads all of the data on STDIN + payload, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return nil, fmt.Errorf("Error reading content from STDIN: %v", err) + } + return payload, nil +} + +// feedback is a helper function to print the payload to a file or STDOUT or keep quiet +// due to the value of flag "quiet" and "output". +func feedback(t *tufCommander, payload []byte) error { + // We only get here when everything goes well, since the flag "quiet" was + // provided, we output nothing but just return. + if t.quiet { + return nil + } + + // Flag "quiet" was not "true", that's why we get here. + if t.output != "" { + return ioutil.WriteFile(t.output, payload, 0644) + } + + os.Stdout.Write(payload) + return nil +} diff --git a/cmd/notary/util_test.go b/cmd/notary/util_test.go new file mode 100644 index 000000000..8949ffd4c --- /dev/null +++ b/cmd/notary/util_test.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetPayload(t *testing.T) { + tempDir, err := ioutil.TempDir("", "test-get-payload") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + file, err := os.Create(filepath.Join(tempDir, "content.txt")) + require.NoError(t, err) + + fmt.Fprintf(file, "Release date: June 10, 2016 - Director: Duncan Jones") + file.Close() + + commander := &tufCommander{ + input: file.Name(), + } + + payload, err := getPayload(commander) + require.NoError(t, err) + require.Equal(t, "Release date: June 10, 2016 - Director: Duncan Jones", string(payload)) +} + +func TestFeedback(t *testing.T) { + tempDir, err := ioutil.TempDir("", "test-feedback") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + file, err := os.Create(filepath.Join(tempDir, "content.txt")) + require.NoError(t, err) + + // Expect it to print nothing since "quiet" takes priority. + commander := &tufCommander{ + output: file.Name(), + quiet: true, + } + + payload := []byte("Release date: June 10, 2016 - Director: Duncan Jones") + err = feedback(commander, payload) + require.NoError(t, err) + + content, err := ioutil.ReadFile(file.Name()) + require.NoError(t, err) + require.Equal(t, "", string(content)) +}