diff --git a/cmd/hmsecrets/main.go b/cmd/hmsecrets/main.go index 637184f..79c6f74 100644 --- a/cmd/hmsecrets/main.go +++ b/cmd/hmsecrets/main.go @@ -1,6 +1,8 @@ package main -import "git.handmadecities.com/HMC/shhh/internal/clis/hmsecrets" +import ( + "git.handmadecities.com/HMC/shhh/internal/clis/hmsecrets" +) func main() { hmsecrets.Execute() diff --git a/go.mod b/go.mod index 15f3157..a78f7fb 100644 --- a/go.mod +++ b/go.mod @@ -11,4 +11,5 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.10 // indirect golang.org/x/sys v0.45.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/clis/hmsecrets/cli.go b/internal/clis/hmsecrets/cli.go index 70f0481..3ff127a 100644 --- a/internal/clis/hmsecrets/cli.go +++ b/internal/clis/hmsecrets/cli.go @@ -2,8 +2,8 @@ package hmsecrets import "git.handmadecities.com/HMC/shhh/pkg/secretsclient" -func getClient(base, ca, cert, certKey string) secretsclient.Client { - cli, err := secretsclient.New(base, ca, cert, certKey) +func getClient() secretsclient.Client { + cli, err := secretsclient.New(conf.APIBase, conf.CA, conf.ClientCert, conf.ClientKey) if err != nil { panic(err) } diff --git a/internal/clis/hmsecrets/config.go b/internal/clis/hmsecrets/config.go new file mode 100644 index 0000000..523e1df --- /dev/null +++ b/internal/clis/hmsecrets/config.go @@ -0,0 +1,83 @@ +package hmsecrets + +import ( + "errors" + "fmt" + "os" + "path" + "runtime" + + "gopkg.in/yaml.v3" +) + +type config struct { + APIBase string `yaml:"api-base"` + CA string `yaml:"ca"` + ClientCert string `yaml:"client-cert"` + ClientKey string `yaml:"client-key"` +} + +func mustLoadConfig() config { + var baseConfigDir string + var err error + switch runtime.GOOS { + case "windows": + fallthrough + case "linux": + baseConfigDir, err = os.UserConfigDir() + if err != nil { + panic(fmt.Errorf("determining user config dir: %w", err)) + } + case "darwin": + // We want $HOME/.config in macOS. + homeDir, err := os.UserHomeDir() + if err != nil { + panic(fmt.Errorf("determining user home dir: %w", err)) + } + baseConfigDir = path.Join(homeDir, ".config") + } + + configDir := path.Join(baseConfigDir, "hmsecrets") + + configBytes, err := os.ReadFile(path.Join(configDir, "config.yaml")) + if err != nil { + panic(fmt.Errorf("reading config file: %w", err)) + } + var conf config + err = yaml.Unmarshal(configBytes, &conf) + if err != nil { + panic(fmt.Errorf("parsing config file: %w", err)) + } + + if conf.APIBase == "" { + panic(errors.New("api base must be present in config")) + } + + if conf.CA == "" { + conf.CA = path.Join(configDir, "ca.crt") + } + if !fileAccesible(conf.CA) { + panic(fmt.Errorf("ca file '%s' does not exist or is inaccesible", conf.CA)) + } + + if conf.ClientCert == "" { + conf.ClientCert = path.Join(configDir, "client.crt") + } + if !fileAccesible(conf.ClientCert) { + panic(fmt.Errorf("client cert file '%s' does not exist or is inaccesible", conf.ClientCert)) + } + + if conf.ClientKey == "" { + conf.ClientKey = path.Join(configDir, "client.key") + } + if !fileAccesible(conf.ClientKey) { + panic(fmt.Errorf("client key file '%s' does not exist or is inaccesible", conf.ClientKey)) + } + + return conf +} + +func fileAccesible(f string) bool { + _, err := os.Stat(f) + return err == nil +} diff --git a/internal/clis/hmsecrets/delete.go b/internal/clis/hmsecrets/delete.go index e4426d7..774a79f 100644 --- a/internal/clis/hmsecrets/delete.go +++ b/internal/clis/hmsecrets/delete.go @@ -13,7 +13,7 @@ var delCmd = &cobra.Command{ Short: "del [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() err := cli.Delete(args[0]) if err != nil { return err diff --git a/internal/clis/hmsecrets/get-arr.go b/internal/clis/hmsecrets/get-arr.go index 73863f4..050113c 100644 --- a/internal/clis/hmsecrets/get-arr.go +++ b/internal/clis/hmsecrets/get-arr.go @@ -15,7 +15,7 @@ var getArrCmd = &cobra.Command{ Short: "get-array [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() secret, err := cli.GetStringArr(args[0]) if err != nil { return err diff --git a/internal/clis/hmsecrets/get-map.go b/internal/clis/hmsecrets/get-map.go index 72b2db3..29103d4 100644 --- a/internal/clis/hmsecrets/get-map.go +++ b/internal/clis/hmsecrets/get-map.go @@ -15,7 +15,7 @@ var getMapCmd = &cobra.Command{ Short: "get-map [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() secret, err := cli.GetStringMap(args[0]) if err != nil { return err diff --git a/internal/clis/hmsecrets/get.go b/internal/clis/hmsecrets/get.go index 5ccd16d..9b9ce82 100644 --- a/internal/clis/hmsecrets/get.go +++ b/internal/clis/hmsecrets/get.go @@ -15,7 +15,7 @@ var getCmd = &cobra.Command{ Short: "get [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() secret, err := cli.GetString(args[0]) if err != nil { return err diff --git a/internal/clis/hmsecrets/rootcmd.go b/internal/clis/hmsecrets/rootcmd.go index 4333501..8dc2d6e 100644 --- a/internal/clis/hmsecrets/rootcmd.go +++ b/internal/clis/hmsecrets/rootcmd.go @@ -7,44 +7,7 @@ import ( "github.com/spf13/cobra" ) -var apiBase string -var caFile string -var clientCert string -var clientKey string - -func init() { - rootCmd.PersistentFlags().StringVar( - &apiBase, - "api-base", - "", - "base url for the service", - ) - rootCmd.MarkPersistentFlagRequired("api-base") - - rootCmd.PersistentFlags().StringVar( - &caFile, - "ca-file", - "", - "CA cert file", - ) - rootCmd.MarkPersistentFlagRequired("ca-file") - - rootCmd.PersistentFlags().StringVar( - &clientCert, - "client-cert", - "", - "certificate to be used for client mTLS auth", - ) - rootCmd.MarkPersistentFlagRequired("client-cert") - - rootCmd.PersistentFlags().StringVar( - &clientKey, - "client-key", - "", - "private key for the certificate to be used for client mTLS auth", - ) - rootCmd.MarkPersistentFlagRequired("client-key") -} +var conf config var rootCmd = &cobra.Command{ Use: "hmsecrets", @@ -52,6 +15,15 @@ var rootCmd = &cobra.Command{ } func Execute() { + defer func() { + if r := recover(); r != nil { + fmt.Printf("%+v\n", r) + os.Exit(1) + } + }() + + conf = mustLoadConfig() + if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/internal/clis/hmsecrets/set-arr.go b/internal/clis/hmsecrets/set-arr.go index d2168aa..eb60d6b 100644 --- a/internal/clis/hmsecrets/set-arr.go +++ b/internal/clis/hmsecrets/set-arr.go @@ -24,7 +24,7 @@ var setArrCmd = &cobra.Command{ Short: "set-array [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() err := cli.PutStringArr(args[0], arrValue) if err != nil { return err diff --git a/internal/clis/hmsecrets/set-map.go b/internal/clis/hmsecrets/set-map.go index bb25cbd..597905c 100644 --- a/internal/clis/hmsecrets/set-map.go +++ b/internal/clis/hmsecrets/set-map.go @@ -24,7 +24,7 @@ var setMapCmd = &cobra.Command{ Short: "set-map [key]", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() err := cli.PutStringMap(args[0], mapValue) if err != nil { return err diff --git a/internal/clis/hmsecrets/set.go b/internal/clis/hmsecrets/set.go index 420e176..fbc90c9 100644 --- a/internal/clis/hmsecrets/set.go +++ b/internal/clis/hmsecrets/set.go @@ -13,7 +13,7 @@ var setCmd = &cobra.Command{ Short: "set [key] [value]", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - cli := getClient(apiBase, caFile, clientCert, clientKey) + cli := getClient() err := cli.PutString(args[0], args[1]) if err != nil { return err