From 7847ab8270efab472b7b6a4bf9a57f5b83cb7212 Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Tue, 17 Oct 2017 18:10:54 -0700 Subject: fmt almost done --- cmd/errors.go | 2 +- cmd/format.go | 79 +++++++++------ cmd/fscrypt/commands.go | 200 ------------------------------------- cmd/fscrypt/flags.go | 73 +++++--------- cmd/fscrypt/fscrypt.go | 257 +++++++++++++++++++++++++++++++++++++++++------- cmd/fscrypt/keys.go | 29 +++--- cmd/fscrypt/prompt.go | 50 +++++----- cmd/fscrypt/setup.go | 4 +- cmd/fscrypt/status.go | 12 ++- cmd/run.go | 34 ++++++- pam/constants.go | 5 +- pam/login.go | 26 +++-- util/util.go | 10 -- 13 files changed, 388 insertions(+), 393 deletions(-) diff --git a/cmd/errors.go b/cmd/errors.go index d4aca6d..c67c0f1 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -109,7 +109,7 @@ func (ctx *Context) processError(err error) { // Errors with a help text should print it out. if helpText := ctx.getHelpText(err); helpText != "" { fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, WrapText(helpText, 0)) + fmt.Fprintln(os.Stderr, helpText) } os.Exit(FailureCode) return diff --git a/cmd/format.go b/cmd/format.go index 877938c..993b955 100644 --- a/cmd/format.go +++ b/cmd/format.go @@ -20,6 +20,7 @@ package cmd import ( + "bufio" "bytes" "fmt" "io" @@ -45,11 +46,9 @@ var ( // LineLength is the maximum length of any output. If not set, the width // of the terminal be detected and assigned to LineLength. LineLength int - // FallbackLineLength is the LineLength used if detection fails. By - // default we fall back to punch cards. - FallbackLineLength = 80 - // MaxLineLength is the maximum allowed detected value of LineLength. - MaxLineLength = 120 + // DefaultLineLength is the LineLength we use if we cannot detect the + // terminal width. By default we fall back to punch cards. + DefaultLineLength = 80 // Output is the io.Writer all commands should use for their normal // output (errors should just return the appropriate error). If not set, // it is automatically set based on the provided flags. @@ -58,26 +57,34 @@ var ( // We use the width of the terminal unless we cannot get the width. func init() { - if LineLength > 0 { - return + if LineLength == 0 { + var err error + LineLength, _, err = terminal.GetSize(int(os.Stdout.Fd())) + if err != nil { + LineLength = DefaultLineLength + } } - width, _, err := terminal.GetSize(int(os.Stdout.Fd())) - if err != nil { - LineLength = FallbackLineLength - } else { - LineLength = util.MinInt(width, MaxLineLength) +} + +// MaxSubcommandLength returns the length of the longest subcommand (where the +// length of the command is Name + Title). Return 0 if there aren't subcommands. +func (c *Command) MaxNameLength() (max int) { + for _, s := range c.SubCommands { + max = util.MaxInt(max, len(s.Name)) } + return } // WrapText wraps an input string so that each line begins with numTabs tabs // (except the first line) and ends with a newline (except the last line), and // each line has length less than lineLength. If the text contains a word which -// is too long, that word gets its own line. -func WrapText(text string, numTabs int) string { +// is too long, that word gets its own line. The first line's calculated length +// is startSpaces less (to account for strange offsets on the first line). +func WrapText(startSpaces, numTabs int, text string) string { // We use a buffer to format the wrapped text so we get O(n) runtime var buffer bytes.Buffer spaceLeft := 0 - maxTextLen := LineLength - numTabs*TabWidth + maxTextLen := LineLength - startSpaces delimiter := strings.Repeat("\t", numTabs) for i, word := range strings.Fields(text) { wordLen := utf8.RuneCountInString(word) @@ -119,14 +126,23 @@ func Pluralize(count int, word string) string { return fmt.Sprintf("%d %ss", count, word) } +// ReadLine returns a line of input from standard input. An empty string is +// returned if the user didn't insert anything, we're in quiet mode or on error. +// This function should be the only way user input is acquired from an +// application (except for passwords). +func ReadLine() (string, error) { + if QuietFlag.Value { + return "", nil + } + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + return scanner.Text(), scanner.Err() +} + // AskQuestion asks the user a yes or no question. Returning a boolean on a // successful answer and an error if there was not a response from the user. // Returns the defaultChoice on empty input (or in quiet mode). func AskQuestion(question string, defaultChoice bool) (bool, error) { - // If in quiet mode, we just use the default. - if QuietFlag.Value { - return defaultChoice, nil - } // Loop until failure or valid input. for { if defaultChoice { @@ -135,7 +151,7 @@ func AskQuestion(question string, defaultChoice bool) (bool, error) { fmt.Fprintf(Output, "%s %s ", question, defaultNoSuffix) } - input, err := util.ReadLine() + input, err := ReadLine() if err != nil { return false, err } @@ -159,16 +175,8 @@ func AskConfirmation(question, warning string, defaultChoice bool) error { return nil } - // Defaults of "no" require forcing. - if QuietFlag.Value { - if defaultChoice { - return nil - } - return ErrMustForce - } - if warning != "" { - fmt.Fprintln(Output, WrapText("WARNING: "+warning, 0)) + fmt.Fprintln(Output, "WARNING: "+warning) } confirmed, err := AskQuestion(question, defaultChoice) @@ -176,6 +184,10 @@ func AskConfirmation(question, warning string, defaultChoice bool) error { return err } if !confirmed { + // To override a "false" default, use ForceFlag. + if QuietFlag.Value { + return ErrMustForce + } return ErrCanceled } return nil @@ -185,7 +197,14 @@ func AskConfirmation(question, warning string, defaultChoice bool) error { // the provided Context and writer. Panics if text cannot be executed. func ExecuteTemplate(w io.Writer, text string, ctx *Context) { tmpl := template.Must(template.New("").Funcs(template.FuncMap{ - "WrapText": WrapText, + "WrapText": WrapText, + "LineLength": func() int { return LineLength }, + "add": func(nums ...int) (sum int) { + for _, num := range nums { + sum += num + } + return + }, }).Parse(text)) if err := tmpl.Execute(w, ctx); err != nil { panic(err) diff --git a/cmd/fscrypt/commands.go b/cmd/fscrypt/commands.go index bbfcf2b..b29435a 100644 --- a/cmd/fscrypt/commands.go +++ b/cmd/fscrypt/commands.go @@ -408,79 +408,6 @@ func unlockPath(path string) error { // Action: destoryMetadataAction, // } -// func destoryMetadataAction(c *cli.Context) error { -// switch c.NArg() { -// case 0: -// switch { -// case protectorFlag.Value != "": -// // Case (1) - protector destroy -// protector, err := getProtectorFromFlag(protectorFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } - -// prompt := fmt.Sprintf("Destroy protector %s on %q?", -// protector.Descriptor(), protector.Context.Mount.Path) -// warning := "All files protected only with this protector will be lost!!" -// if err := askConfirmation(prompt, false, warning); err != nil { -// return newExitError(c, err) -// } -// if err := protector.Destroy(); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "Protector %s deleted from filesystem %q.\n", -// protector.Descriptor(), protector.Context.Mount.Path) -// case policyFlag.Value != "": -// // Case (2) - policy destroy -// policy, err := getPolicyFromFlag(policyFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } - -// prompt := fmt.Sprintf("Destroy policy %s on %q?", -// policy.Descriptor(), policy.Context.Mount.Path) -// warning := "All files using this policy will be lost!!" -// if err := askConfirmation(prompt, false, warning); err != nil { -// return newExitError(c, err) -// } -// if err := policy.Destroy(); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "Policy %s deleted from filesystem %q.\n", -// policy.Descriptor(), policy.Context.Mount.Path) -// default: -// message := fmt.Sprintf("Must specify one of: %s, %s, or %s", -// mountpointArg, -// shortDisplay(protectorFlag), -// shortDisplay(policyFlag)) -// return &usageError{c, message} -// } -// case 1: -// // Case (3) - mountpoint destroy -// path := c.Args().Get(0) -// ctx, err := actions.NewContextFromMountpoint(path, nil) -// if err != nil { -// return newExitError(c, err) -// } - -// prompt := fmt.Sprintf("Destroy all the metadata on %q?", ctx.Mount.Path) -// warning := "All the encrypted files on this filesystem will be lost!!" -// if err := askConfirmation(prompt, false, warning); err != nil { -// return newExitError(c, err) -// } -// if err := ctx.Mount.RemoveAllMetadata(); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "All metadata on %q deleted.\n", ctx.Mount.Path) -// default: -// return expectedArgsErr(c, 1, true) -// } -// return nil -// } - // var changePassphrase = cli.Command{ // Name: "change-passphrase", // ArgsUsage: shortDisplay(protectorFlag), @@ -492,31 +419,6 @@ func unlockPath(path string) error { // Action: changePassphraseAction, // } -// func changePassphraseAction(c *cli.Context) error { -// if c.NArg() != 0 { -// return expectedArgsErr(c, 0, false) -// } -// if err := checkRequiredFlags(c, []*stringFlag{protectorFlag}); err != nil { -// return err -// } - -// protector, err := getProtectorFromFlag(protectorFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } -// if err := protector.Unlock(oldExistingKeyFn); err != nil { -// return newExitError(c, err) -// } -// defer protector.Lock() -// if err := protector.Rewrap(newCreateKeyFn); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "Passphrase for protector %s successfully changed.\n", -// protector.Descriptor()) -// return nil -// } - // var addProtectorToPolicy = cli.Command{ // Name: "add-protector-to-policy", // ArgsUsage: fmt.Sprintf("%s %s", shortDisplay(protectorFlag), shortDisplay(policyFlag)), @@ -530,49 +432,6 @@ func unlockPath(path string) error { // Action: addProtectorAction, // } -// func addProtectorAction(c *cli.Context) error { -// if c.NArg() != 0 { -// return expectedArgsErr(c, 0, false) -// } -// if err := checkRequiredFlags(c, []*stringFlag{protectorFlag, policyFlag}); err != nil { -// return err -// } - -// protector, err := getProtectorFromFlag(protectorFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } -// policy, err := getPolicyFromFlag(policyFlag.Value, protector.Context.TargetUser) -// if err != nil { -// return newExitError(c, err) -// } -// // Sanity check before unlocking everything -// if err := policy.AddProtector(protector); errors.Cause(err) != actions.ErrLocked { -// return newExitError(c, err) -// } - -// prompt := fmt.Sprintf("Protect policy %s with protector %s?", -// policy.Descriptor(), protector.Descriptor()) -// warning := "All files using this policy will be accessible with this protector!!" -// if err := askConfirmation(prompt, true, warning); err != nil { -// return newExitError(c, err) -// } - -// if err := protector.Unlock(existingKeyFn); err != nil { -// return newExitError(c, err) -// } -// if err := policy.Unlock(optionFn, existingKeyFn); err != nil { -// return newExitError(c, err) -// } -// if err := policy.AddProtector(protector); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "Protector %s now protecting policy %s.\n", -// protector.Descriptor(), policy.Descriptor()) -// return nil -// } - // var removeProtectorFromPolicy = cli.Command{ // Name: "remove-protector-from-policy", // ArgsUsage: fmt.Sprintf("%s %s", shortDisplay(protectorFlag), shortDisplay(policyFlag)), @@ -587,40 +446,6 @@ func unlockPath(path string) error { // Action: removeProtectorAction, // } -// func removeProtectorAction(c *cli.Context) error { -// if c.NArg() != 0 { -// return expectedArgsErr(c, 0, false) -// } -// if err := checkRequiredFlags(c, []*stringFlag{protectorFlag, policyFlag}); err != nil { -// return err -// } - -// // We do not need to unlock anything for this operation -// protector, err := getProtectorFromFlag(protectorFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } -// policy, err := getPolicyFromFlag(policyFlag.Value, protector.Context.TargetUser) -// if err != nil { -// return newExitError(c, err) -// } - -// prompt := fmt.Sprintf("Stop protecting policy %s with protector %s?", -// policy.Descriptor(), protector.Descriptor()) -// warning := "All files using this policy will NO LONGER be accessible with this protector!!" -// if err := askConfirmation(prompt, false, warning); err != nil { -// return newExitError(c, err) -// } - -// if err := policy.RemoveProtector(protector); err != nil { -// return newExitError(c, err) -// } - -// fmt.Fprintf(c.App.Writer, "Protector %s no longer protecting policy %s.\n", -// protector.Descriptor(), policy.Descriptor()) -// return nil -// } - // var dumpMetadata = cli.Command{ // Name: "dump", // ArgsUsage: fmt.Sprintf("[%s | %s]", shortDisplay(protectorFlag), shortDisplay(policyFlag)), @@ -635,28 +460,3 @@ func unlockPath(path string) error { // Flags: []cli.Flag{protectorFlag, policyFlag}, // Action: dumpMetadataAction, // } - -// func dumpMetadataAction(c *cli.Context) error { -// switch { -// case protectorFlag.Value != "": -// // Case (1) - protector print -// protector, err := getProtectorFromFlag(protectorFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } -// fmt.Fprintln(c.App.Writer, protector) -// case policyFlag.Value != "": -// // Case (2) - policy print -// policy, err := getPolicyFromFlag(policyFlag.Value, nil) -// if err != nil { -// return newExitError(c, err) -// } -// fmt.Fprintln(c.App.Writer, policy) -// default: -// message := fmt.Sprintf("Must specify one of: %s or %s", -// shortDisplay(protectorFlag), -// shortDisplay(policyFlag)) -// return &usageError{c, message} -// } -// return nil -// } diff --git a/cmd/fscrypt/flags.go b/cmd/fscrypt/flags.go index 5983053..084fa19 100644 --- a/cmd/fscrypt/flags.go +++ b/cmd/fscrypt/flags.go @@ -37,23 +37,18 @@ import ( // Bool flags: used to switch some behavior on or off var ( legacyFlag = &cmd.BoolFlag{ - Name: "legacy", - Usage: `Allow for support of older kernels with ext4 (before - v4.8) and F2FS (before v4.6) filesystems.`, + Name: "legacy", + Usage: `Configure fscrypt to support older kernels.`, Default: true, } skipUnlockFlag = &cmd.BoolFlag{ - Name: "skip-unlock", - Usage: `Leave the directory in a locked state after setup. - "fscrypt unlock" will need to be run in order to use the - directory.`, + Name: "skip-unlock", + Usage: "Leave the directory in a locked state after setup.", } dropCachesFlag = &cmd.BoolFlag{ Name: "drop-caches", Usage: `After purging the keys from the keyring, drop the - associated caches for the purge to take effect. Without - this flag, cached encrypted files may still have their - plaintext visible. Requires root privileges.`, + associated caches for the purge to take effect.`, Default: true, } ) @@ -62,78 +57,62 @@ var ( var ( timeTargetFlag = &cmd.DurationFlag{ Name: "time", - ArgName: "TIME", + ArgName: "time", Usage: `Set the global options so that passphrase hashing takes - TIME long. TIME should be formatted as a sequence of - decimal numbers, each with optional fraction and a unit - suffix, such as "300ms", "1.5s" or "2h45m". Valid time - units are "ms", "s", "m", and "h".`, +