github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/cloudflare/cfssl/cli/cli.go (about)

     1  // Package cli provides the template for adding new cfssl commands
     2  package cli
     3  
     4  /*
     5  cfssl is the command line tool to issue/sign/bundle client certificate. It's
     6  also a tool to start a HTTP server to handle web requests for signing, bundling
     7  and verification.
     8  
     9  Usage:
    10  	cfssl command [-flags] arguments
    11  
    12  The commands are defined in the cli subpackages and include
    13  
    14  	bundle	 create a certificate bundle
    15  	sign	 signs a certificate signing request (CSR)
    16  	serve	 starts a HTTP server handling sign and bundle requests
    17  	version	 prints the current cfssl version
    18  	genkey   generates a key and an associated CSR
    19  	gencert  generates a key and a signed certificate
    20  	gencsr   generates a certificate request
    21  	selfsign generates a self-signed certificate
    22  	ocspsign signs an OCSP response
    23  
    24  Use "cfssl [command] -help" to find out more about a command.
    25  */
    26  
    27  import (
    28  	"encoding/base64"
    29  	"encoding/json"
    30  	"errors"
    31  	"flag"
    32  	"fmt"
    33  	"io/ioutil"
    34  	"os"
    35  
    36  	"github.com/hellobchain/third_party/cloudflare/cfssl/config"
    37  )
    38  
    39  // Command holds the implementation details of a cfssl command.
    40  type Command struct {
    41  	// The Usage Text
    42  	UsageText string
    43  	// Flags to look up in the global table
    44  	Flags []string
    45  	// Main runs the command, args are the arguments after flags
    46  	Main func(args []string, c Config) error
    47  }
    48  
    49  var cmdName string
    50  
    51  // usage is the cfssl usage heading. It will be appended with names of defined commands in cmds
    52  // to form the final usage message of cfssl.
    53  const usage = `Usage:
    54  Available commands:
    55  `
    56  
    57  // printDefaultValue is a helper function to print out a user friendly
    58  // usage message of a flag. It's useful since we want to write customized
    59  // usage message on selected subsets of the global flag set. It is
    60  // borrowed from standard library source code. Since flag value type is
    61  // not exported, default string flag values are printed without
    62  // quotes. The only exception is the empty string, which is printed as "".
    63  func printDefaultValue(f *flag.Flag) {
    64  	format := "  -%s=%s: %s\n"
    65  	if f.DefValue == "" {
    66  		format = "  -%s=%q: %s\n"
    67  	}
    68  	fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
    69  }
    70  
    71  // PopFirstArgument returns the first element and the rest of a string
    72  // slice and return error if failed to do so. It is a helper function
    73  // to parse non-flag arguments previously used in cfssl commands.
    74  func PopFirstArgument(args []string) (string, []string, error) {
    75  	if len(args) < 1 {
    76  		return "", nil, errors.New("not enough arguments are supplied --- please refer to the usage")
    77  	}
    78  	return args[0], args[1:], nil
    79  }
    80  
    81  // Start is the entrance point of cfssl command line tools.
    82  func Start(cmds map[string]*Command) error {
    83  	// cfsslFlagSet is the flag sets for cfssl.
    84  	var cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ExitOnError)
    85  	var c Config
    86  
    87  	registerFlags(&c, cfsslFlagSet)
    88  	// Initial parse of command line arguments. By convention, only -h/-help is supported.
    89  	if flag.Usage == nil {
    90  		flag.Usage = func() {
    91  			fmt.Fprintf(os.Stderr, usage)
    92  			for name := range cmds {
    93  				fmt.Fprintf(os.Stderr, "\t%s\n", name)
    94  			}
    95  			fmt.Fprintf(os.Stderr, "Top-level flags:\n")
    96  			flag.PrintDefaults()
    97  		}
    98  	}
    99  
   100  	flag.Parse()
   101  
   102  	if flag.NArg() < 1 {
   103  		fmt.Fprintf(os.Stderr, "No command is given.\n")
   104  		flag.Usage()
   105  		return errors.New("no command was given")
   106  	}
   107  
   108  	// Clip out the command name and args for the command
   109  	cmdName = flag.Arg(0)
   110  	args := flag.Args()[1:]
   111  	cmd, found := cmds[cmdName]
   112  	if !found {
   113  		fmt.Fprintf(os.Stderr, "Command %s is not defined.\n", cmdName)
   114  		flag.Usage()
   115  		return errors.New("undefined command")
   116  	}
   117  	// always have flag 'loglevel' for each command
   118  	cmd.Flags = append(cmd.Flags, "loglevel")
   119  	// The usage of each individual command is re-written to mention
   120  	// flags defined and referenced only in that command.
   121  	cfsslFlagSet.Usage = func() {
   122  		fmt.Fprintf(os.Stderr, "\t%s", cmd.UsageText)
   123  		for _, name := range cmd.Flags {
   124  			if f := cfsslFlagSet.Lookup(name); f != nil {
   125  				printDefaultValue(f)
   126  			}
   127  		}
   128  	}
   129  
   130  	// Parse all flags and take the rest as argument lists for the command
   131  	cfsslFlagSet.Parse(args)
   132  	args = cfsslFlagSet.Args()
   133  
   134  	var err error
   135  	if c.ConfigFile != "" {
   136  		c.CFG, err = config.LoadFile(c.ConfigFile)
   137  		if err != nil {
   138  			fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err)
   139  			return errors.New("failed to load config file")
   140  		}
   141  	}
   142  
   143  	if err := cmd.Main(args, c); err != nil {
   144  		fmt.Fprintln(os.Stderr, err)
   145  		return err
   146  	}
   147  
   148  	return nil
   149  }
   150  
   151  // ReadStdin reads from stdin if the file is "-"
   152  func ReadStdin(filename string) ([]byte, error) {
   153  	if filename == "-" {
   154  		return ioutil.ReadAll(os.Stdin)
   155  	}
   156  	return ioutil.ReadFile(filename)
   157  }
   158  
   159  // PrintCert outputs a cert, key and csr to stdout
   160  func PrintCert(key, csrBytes, cert []byte) {
   161  	out := map[string]string{}
   162  	if cert != nil {
   163  		out["cert"] = string(cert)
   164  	}
   165  
   166  	if key != nil {
   167  		out["key"] = string(key)
   168  	}
   169  
   170  	if csrBytes != nil {
   171  		out["csr"] = string(csrBytes)
   172  	}
   173  
   174  	jsonOut, err := json.Marshal(out)
   175  	if err != nil {
   176  		return
   177  	}
   178  	fmt.Printf("%s\n", jsonOut)
   179  }
   180  
   181  // PrintOCSPResponse outputs an OCSP response to stdout
   182  // ocspResponse is base64 encoded
   183  func PrintOCSPResponse(resp []byte) {
   184  	b64Resp := base64.StdEncoding.EncodeToString(resp)
   185  
   186  	out := map[string]string{"ocspResponse": b64Resp}
   187  	jsonOut, err := json.Marshal(out)
   188  	if err != nil {
   189  		return
   190  	}
   191  	fmt.Printf("%s\n", jsonOut)
   192  }
   193  
   194  // PrintCRL outputs the CRL to stdout
   195  func PrintCRL(certList []byte) {
   196  	b64Resp := base64.StdEncoding.EncodeToString(certList)
   197  
   198  	fmt.Printf("%s\n", b64Resp)
   199  }