...

Source file src/github.com/theupdateframework/go-tuf/cmd/tuf/main.go

Documentation: github.com/theupdateframework/go-tuf/cmd/tuf

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"log"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"syscall"
    12  	"time"
    13  
    14  	docopt "github.com/flynn/go-docopt"
    15  	tuf "github.com/theupdateframework/go-tuf"
    16  	"github.com/theupdateframework/go-tuf/util"
    17  	"golang.org/x/term"
    18  )
    19  
    20  func main() {
    21  	log.SetFlags(0)
    22  
    23  	usage := `usage: tuf [-h|--help] [-d|--dir=<dir>] [--insecure-plaintext] <command> [<args>...]
    24  
    25  Options:
    26    -h, --help
    27    -d <dir>              The path to the repository (defaults to the current working directory)
    28    --insecure-plaintext  Don't encrypt signing keys
    29  
    30  Commands:
    31    help               Show usage for a specific command
    32    init               Initialize a new repository
    33    add-key            Adds a new signing key for a specific role
    34    gen-key            Generate a new signing key for a specific metadata file
    35    revoke-key         Revoke a signing key
    36    add                Add target file(s)
    37    remove             Remove a target file
    38    snapshot           Update the snapshot metadata file
    39    timestamp          Update the timestamp metadata file
    40    payload            Output a role's metadata file for signing
    41    add-signatures     Adds signatures generated offline
    42    sign               Sign a role's metadata file
    43    sign-payload       Sign a file from the "payload" command.
    44    status             Check if a role's metadata has expired
    45    commit             Commit staged files to the repository
    46    regenerate         Recreate the targets metadata file [Not supported yet]
    47    set-threshold      Sets the threshold for a role
    48    get-threshold      Outputs the threshold for a role
    49    change-passphrase  Changes the passphrase for given role keys file
    50    root-keys          Output a JSON serialized array of root keys to STDOUT
    51    clean              Remove all staged metadata files
    52  
    53  See "tuf help <command>" for more information on a specific command
    54  `
    55  
    56  	args, _ := docopt.Parse(usage, nil, true, "", true)
    57  	cmd := args.String["<command>"]
    58  	cmdArgs := args.All["<args>"].([]string)
    59  
    60  	if cmd == "help" {
    61  		if len(cmdArgs) == 0 { // `tuf help`
    62  			fmt.Fprint(os.Stdout, usage)
    63  			return
    64  		} else { // `tuf help <command>`
    65  			cmd = cmdArgs[0]
    66  			cmdArgs = []string{"--help"}
    67  		}
    68  	}
    69  
    70  	dir, ok := args.String["-d"]
    71  	if !ok {
    72  		dir = args.String["--dir"]
    73  	}
    74  	if dir == "" {
    75  		var err error
    76  		dir, err = os.Getwd()
    77  		if err != nil {
    78  			log.Fatal(err)
    79  		}
    80  	}
    81  
    82  	if err := runCommand(cmd, cmdArgs, dir, args.Bool["--insecure-plaintext"]); err != nil {
    83  		log.Fatalln("ERROR:", err)
    84  	}
    85  }
    86  
    87  type cmdFunc func(*docopt.Args, *tuf.Repo) error
    88  
    89  type command struct {
    90  	usage string
    91  	f     cmdFunc
    92  }
    93  
    94  var commands = make(map[string]*command)
    95  
    96  func register(name string, f cmdFunc, usage string) {
    97  	commands[name] = &command{usage: usage, f: f}
    98  }
    99  
   100  func runCommand(name string, args []string, dir string, insecure bool) error {
   101  	argv := make([]string, 1, 1+len(args))
   102  	argv[0] = name
   103  	argv = append(argv, args...)
   104  
   105  	cmd, ok := commands[name]
   106  	if !ok {
   107  		return fmt.Errorf("%s is not a tuf command. See 'tuf help'", name)
   108  	}
   109  
   110  	parsedArgs, err := docopt.Parse(cmd.usage, argv, true, "", true)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	var p util.PassphraseFunc
   116  	if !insecure {
   117  		p = getPassphrase
   118  	}
   119  	logger := log.New(os.Stdout, "", 0)
   120  	storeOpts := tuf.StoreOpts{Logger: logger, PassFunc: p}
   121  
   122  	repo, err := tuf.NewRepoWithOpts(tuf.FileSystemStoreWithOpts(dir, storeOpts),
   123  		tuf.WithLogger(logger))
   124  	if err != nil {
   125  		return err
   126  	}
   127  	return cmd.f(parsedArgs, repo)
   128  }
   129  
   130  func parseExpires(arg string) (time.Time, error) {
   131  	days, err := strconv.Atoi(arg)
   132  	if err != nil {
   133  		return time.Time{}, fmt.Errorf("failed to parse --expires arg: %s", err)
   134  	}
   135  	return time.Now().AddDate(0, 0, days).UTC(), nil
   136  }
   137  
   138  func getPassphrase(role string, confirm bool, change bool) ([]byte, error) {
   139  	// In case of change we need to prompt explicitly for a new passphrase
   140  	// and not read it from the environment variable, if present
   141  	if pass := os.Getenv(fmt.Sprintf("TUF_%s_PASSPHRASE", strings.ToUpper(role))); pass != "" && !change {
   142  		return []byte(pass), nil
   143  	}
   144  	// Alter role string if we are prompting for a passphrase change
   145  	if change {
   146  		// Check if environment variable for new passphrase exist
   147  		if new_pass := os.Getenv(fmt.Sprintf("TUF_NEW_%s_PASSPHRASE", strings.ToUpper(role))); new_pass != "" {
   148  			// If so, just read the new passphrase from it and return
   149  			return []byte(new_pass), nil
   150  		}
   151  		// No environment variable set, so proceed prompting for new passphrase
   152  		role = fmt.Sprintf("new %s", role)
   153  	}
   154  	fmt.Fprintf(os.Stderr, "Enter %s keys passphrase: ", role)
   155  	passphrase, err := term.ReadPassword(int(syscall.Stdin))
   156  	fmt.Fprintln(os.Stderr)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	if !confirm {
   162  		return passphrase, nil
   163  	}
   164  
   165  	fmt.Fprintf(os.Stderr, "Repeat %s keys passphrase: ", role)
   166  	confirmation, err := term.ReadPassword(int(syscall.Stdin))
   167  	fmt.Fprintln(os.Stderr)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	if !bytes.Equal(passphrase, confirmation) {
   173  		return nil, errors.New("the entered passphrases do not match")
   174  	}
   175  	return passphrase, nil
   176  }
   177  

View as plain text