diff options
author | Gibheer <gibheer@gmail.com> | 2015-02-15 01:34:25 +0100 |
---|---|---|
committer | Gibheer <gibheer@gmail.com> | 2015-02-15 01:34:25 +0100 |
commit | 16eb14db9f9b228ef88bcf1beb09cf823256dac1 (patch) | |
tree | 414ed9ba9f3e5679a7b0ae7b120e752d3f8ee2f6 /flags.go | |
parent | 2f9126dc6a2eab32316ec90e21688d31159f9e80 (diff) |
redesign cli
This is a major rebuilding of the CLI. The library part is split out
into pkilib and the cli handles only the communication with the user,
I/O and the library.
The API will still look the same, but the code should be much better to
grasp. Instead of repeating everything, more will be grouped together
and reused.
Diffstat (limited to 'flags.go')
-rw-r--r-- | flags.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/flags.go b/flags.go new file mode 100644 index 0000000..d7dc2ef --- /dev/null +++ b/flags.go @@ -0,0 +1,168 @@ +package main + +// This file handles the complete parameter assignment, as some parameters are +// often used by multiple functions. + +import ( + "crypto/elliptic" + "flag" + "fmt" + "io" + "os" + + "github.com/gibheer/pkilib" +) + +const ( + RsaLowerLength = 2048 + RsaUpperLength = 16384 +) + +var ( + EcdsaCurves = []int{224, 256, 384, 521} +) + +type ( + // holds all certificate related flags, which need parsing afterwards + certFlagsContainer struct { + serialNumber int // the serial number for the cert + commonName string // the common name used in the cert + dnsNames string // all alternative names in the certificate (comma separated list) + ipAddresses string // all IP addresses in the certificate (comma separated list) + country string // the country names which should end up in the cert (comma separated list) + organization string // the organization names (comma separated list) + organizationalUnit string // the organizational units (comma separated list) + locality string // the city or locality (comma separated list) + province string // the province name (comma separated list) + streetAddress string // the street addresses of the organization (comma separated list) + postalCode string // the postal codes of the locality + } + + // a container go gather all incoming flags for further processing + paramContainer struct { + outputPath string // path to output whatever is generated + cryptType string // type of something (private key) + length int // the length of something (private key) + privateKeyPath string // path to the private key + publicKeyPath string // path to the public key + signRequestPath string // path to the certificate sign request + certificateFlags *certFlagsContainer // container for certificate related flags + } + + // a container for the refined flags + flagSet struct { + PrivateKey pkilib.PrivateKey + Output io.WriteCloser + + // private key specific stuff + PrivateKeyGenerationFlags privateKeyGenerationFlags + } + + privateKeyGenerationFlags struct { + Type string // type of the private key (rsa, ecdsa) + Curve elliptic.Curve // curve for ecdsa + Size int // bitsize for rsa + } + + Flags struct { + flagset *flag.FlagSet // the flagset reference for printing the help + flag_container *paramContainer + Flags *flagSet // the end result of the flag setting + + check_list []flagCheck // list of all checks + } + + flagCheck func()(error) +) + +// create a new flag handler with the name of the subfunction +func NewFlags(method_name string) *Flags { + return &Flags{ + Flags: &flagSet{}, + flagset: flag.NewFlagSet(method_name, flag.ExitOnError), + check_list: make([]flagCheck, 0), + flag_container: ¶mContainer{}, + } +} + +// check all parameters for validity +func (f *Flags) Parse(options []string) error { + f.flagset.Parse(options) + for _, check := range f.check_list { + // TODO handle error in a betetr way (output specific help, not command help) + if err := check(); err != nil { return err } + } + return nil +} + +// add the private key option to the requested flags +func (f *Flags) AddPrivateKey() { + f.check_list = append(f.check_list, f.parsePrivateKey) + f.flagset.StringVar(&f.flag_container.privateKeyPath, "private-key", "", "path to the private key") +} + +// check the private key flag and load the private key +func (f *Flags) parsePrivateKey() error { + // check permissions of private key file + info, err := os.Stat(f.flag_container.privateKeyPath) + if err != nil { return fmt.Errorf("Error reading private key: %s", err) } + if info.Mode().Perm().String()[4:] != "------" { + return fmt.Errorf("private key file modifyable by others!") + } + + pk, err := ReadPrivateKeyFile(f.flag_container.privateKeyPath) + if err != nil { return fmt.Errorf("Error reading private key: %s", err) } + f.Flags.PrivateKey = pk + return nil +} + +// add the output parameter to the checklist +func (f *Flags) AddOutput() { + f.check_list = append(f.check_list, f.parseOutput) + f.flagset.StringVar(&f.flag_container.outputPath, "output", "STDOUT", "path to the output or STDOUT") +} + +// parse the output parameter and open the file handle +func (f *Flags) parseOutput() error { + if f.flag_container.outputPath == "STDOUT" { + f.Flags.Output = os.Stdout + return nil + } + var err error + f.Flags.Output, err = os.OpenFile( + f.flag_container.outputPath, + os.O_WRONLY | os.O_APPEND | os.O_CREATE, // do not kill users files! + 0600, + ) + if err != nil { return err } + return nil +} + +// This function adds the private key generation flags. +func (f *Flags) AddPrivateKeyGenerationFlags() { + f.check_list = append(f.check_list, f.parsePrivateKeyGenerationFlags) + f.flagset.StringVar(&f.flag_container.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)") + f.flagset.IntVar( + &f.flag_container.length, + "length", 521, + fmt.Sprintf("%d - %d for rsa; %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaCurves), + ) +} + +func (f *Flags) parsePrivateKeyGenerationFlags() error { + pk_type := f.flag_container.cryptType + f.Flags.PrivateKeyGenerationFlags.Type = pk_type + switch pk_type { + case "ecdsa": + switch f.flag_container.length { + case 224: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P224() + case 256: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P256() + case 384: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P384() + case 521: f.Flags.PrivateKeyGenerationFlags.Curve = elliptic.P521() + default: return fmt.Errorf("Curve %d unknown!", f.flag_container.length) + } + case "rsa": f.Flags.PrivateKeyGenerationFlags.Size = f.flag_container.length + default: return fmt.Errorf("Type %s is unknown!", pk_type) + } + return nil +} |