keyctl/pkg/cli/cli.go
2023-03-21 01:00:13 +01:00

198 lines
3.8 KiB
Go

// 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)
}
switch k.Type {
case core.Plain:
fmt.Println("Key ID:", k.ID)
case core.Shamir:
fmt.Println("Key ID:", k.ID)
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)
}
key.Key = out
if json {
jsonOutput(key) // does not return
}
fmt.Println(key.Key)
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")
}
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()
}