// Copyright (C) 2023 Marius Schellenberger package cli import ( "context" "encoding/json" "errors" "flag" "fmt" "os" "text/tabwriter" apiclient "git.giftfish.de/ston1th/keyctl/pkg/api/client" clientv1 "git.giftfish.de/ston1th/keyctl/pkg/api/v1/client" "git.giftfish.de/ston1th/keyctl/pkg/api/v1/schema" "git.giftfish.de/ston1th/keyctl/pkg/core" ) var fs = flag.NewFlagSet("", flag.ExitOnError) func exit(err error) { fmt.Println(err) os.Exit(1) } func Run(arg string) { ctx := context.Background() switch arg { case "new": name, encoding, t, size, err := newKeyFlags() if err != nil { exit(err) } newKey := schema.NewKey{ Name: name, Size: size, Encoding: core.EncodingFromString(encoding), Type: core.TypeFromString(t), } c := client() k, err := c.CreateKey(ctx, newKey) if err != nil { exit(err) } fmt.Println("Key ID:", k.ID) if k.Type == core.Shamir { fmt.Println("Key Share:", k.Key) } case "del": id, err := idFlags("key id") if err != nil { exit(err) } c := client() err = c.DeleteKey(ctx, id) if err != nil { exit(err) } case "approve": id, err := idFlags("approval id") if err != nil { exit(err) } c := client() err = c.AcceptApproval(ctx, id) if err != nil { exit(err) } case "reject": id, err := idFlags("approval id") if err != nil { exit(err) } c := client() err = c.RejectApproval(ctx, id) if err != nil { exit(err) } case "get": id, share, json, err := getFlags() if err != nil { exit(err) } c := client() key, err := c.GetKey(ctx, id) if err != nil { exit(err) } out, err := key.Print(share) if err != nil { exit(err) } if json { key.Key = out jsonOutput(key) // does not return } fmt.Println(out) case "ls": json := outputFlags() c := client() keys, err := c.GetKeys(ctx) if err != nil { exit(err) } if json { jsonOutput(keys) // does not return } print(keys) case "req": json := outputFlags() c := client() approvals, err := c.GetApprovals(ctx) if err != nil { exit(err) } if json { jsonOutput(approvals) // does not return } print(approvals) } os.Exit(0) } func client() (c *clientv1.Client) { opts, err := apiclient.ClientOptionsFromEnv() if err != nil { exit(err) } apic := apiclient.NewClient(opts...) c, err = clientv1.NewClient(apic) if err != nil { exit(err) } return } func jsonOutput(v any) { b, err := json.Marshal(v) if err != nil { exit(err) } fmt.Println(string(b)) os.Exit(0) } func idFlags(desc string) (id string, err error) { fs.StringVar(&id, "id", "", desc) fs.Parse(os.Args[2:]) if id == "" { err = errors.New("missing flag: id") } return } func getFlags() (id, share string, json bool, err error) { fs.StringVar(&id, "id", "", "key id") fs.StringVar(&share, "share", "", "shamir key share") fs.BoolVar(&json, "json", false, "json output") fs.Parse(os.Args[2:]) if id == "" { err = errors.New("missing flag: id") } if share == "" { share = os.Getenv("KEYCTL_SHARE") } return } func outputFlags() (json bool) { fs.BoolVar(&json, "json", false, "json output") fs.Parse(os.Args[2:]) return } func newKeyFlags() (name, encoding, t string, size int, err error) { fs.StringVar(&name, "name", "", "key name") fs.StringVar(&encoding, "enc", "hex", "key encoding scheme [hex|base32|base64|base64url]") fs.StringVar(&t, "type", "plain", "key type [plain|shamir]") fs.IntVar(&size, "size", 16, "key size in bytes") fs.Parse(os.Args[2:]) if name == "" { err = errors.New("missing flag: name") } return } func print(tw core.TableWriter) { if tw.Len() == 0 { return } w := tabwriter.NewWriter(os.Stdout, 1, 0, 1, ' ', tabwriter.Debug) fmt.Fprintln(w, tw.Fields()) for _, v := range tw.Values() { fmt.Fprintln(w, v) } w.Flush() }