added existing key option
This commit is contained in:
parent
84937cc3a1
commit
13e4e4de07
6 changed files with 112 additions and 14 deletions
|
|
@ -22,15 +22,18 @@ const (
|
|||
|
||||
type NewKey struct {
|
||||
Name string `json:"name"`
|
||||
Existing string `json:"existing,omitempty"`
|
||||
Size int `json:"size"`
|
||||
Encoding core.Encoding `json:"encoding"`
|
||||
Type core.Type `json:"type"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrEmptyKeyName = errors.New("empty key name")
|
||||
ErrInvalidKeyName = errors.New("invalid key name")
|
||||
ErrInvalidKeySize = errors.New("invalid key size")
|
||||
ErrEmptyKeyName = errors.New("empty key name")
|
||||
ErrExistingKeyType = errors.New("invalid key type for existing key")
|
||||
ErrExistingKeyEncoding = errors.New("invalid key encoding for existing key")
|
||||
ErrInvalidKeyName = errors.New("invalid key name")
|
||||
ErrInvalidKeySize = errors.New("invalid key size")
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -42,6 +45,15 @@ func (nk NewKey) Validate() error {
|
|||
if nk.Name == "" {
|
||||
return ErrEmptyKeyName
|
||||
}
|
||||
if nk.Existing != "" {
|
||||
if nk.Type == core.Xor {
|
||||
return ErrExistingKeyType
|
||||
}
|
||||
_, err := hex.DecodeString(nk.Existing)
|
||||
if err != nil {
|
||||
return ErrExistingKeyEncoding
|
||||
}
|
||||
}
|
||||
if core.NameRe.MatchString(nk.Name) {
|
||||
return ErrInvalidKeyName
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func newHandler(ctx *types.Context) {
|
|||
ctx.Err(types.ErrInvalid)
|
||||
return
|
||||
}
|
||||
key, err := ctx.Data.DB.CreateKey(newKey.Name, newKey.Size, newKey.Encoding, newKey.Type)
|
||||
key, err := ctx.Data.DB.CreateKey(newKey.Name, newKey.Existing, newKey.Size, newKey.Encoding, newKey.Type)
|
||||
if err != nil {
|
||||
ctx.Log.Error(err, "error writing key", "name", newKey.Name)
|
||||
ctx.Err(types.ErrISE)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,15 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
apiclient "git.giftfish.de/ston1th/keyctl/pkg/api/client"
|
||||
|
|
@ -28,12 +31,13 @@ func Run(arg string) {
|
|||
ctx := context.Background()
|
||||
switch arg {
|
||||
case "new":
|
||||
name, encoding, t, size, err := newKeyFlags()
|
||||
name, existing, encoding, t, size, err := newKeyFlags()
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
newKey := schema.NewKey{
|
||||
Name: name,
|
||||
Existing: existing,
|
||||
Size: size,
|
||||
Encoding: core.EncodingFromString(encoding),
|
||||
Type: core.TypeFromString(t),
|
||||
|
|
@ -49,10 +53,13 @@ func Run(arg string) {
|
|||
fmt.Println("Key Share:", k.Key)
|
||||
}
|
||||
case "del":
|
||||
id, err := idFlags("key id")
|
||||
id, force, err := delFlags("key id")
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
if !force && !confirm(os.Stdin) {
|
||||
exit(errors.New("confirmation failed: secret not deleted"))
|
||||
}
|
||||
c := client()
|
||||
err = c.DeleteKey(ctx, id)
|
||||
if err != nil {
|
||||
|
|
@ -79,7 +86,7 @@ func Run(arg string) {
|
|||
exit(err)
|
||||
}
|
||||
case "get":
|
||||
id, share, loop, json, err := getFlags()
|
||||
id, share, loop, json, newline, err := getFlags()
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
|
@ -104,7 +111,11 @@ func Run(arg string) {
|
|||
key.Key = out
|
||||
jsonOutput(key) // does not return
|
||||
}
|
||||
fmt.Println(out)
|
||||
if newline {
|
||||
fmt.Println(out)
|
||||
} else {
|
||||
fmt.Print(out)
|
||||
}
|
||||
case "ls":
|
||||
json := outputFlags()
|
||||
c := client()
|
||||
|
|
@ -162,11 +173,22 @@ func idFlags(desc string) (id string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getFlags() (id, share string, loop, json bool, err error) {
|
||||
func delFlags(desc string) (id string, force bool, err error) {
|
||||
fs.StringVar(&id, "id", "", desc)
|
||||
fs.BoolVar(&force, "force", false, "do not ask for confirmation")
|
||||
fs.Parse(os.Args[2:])
|
||||
if id == "" {
|
||||
err = errors.New("missing flag: id")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getFlags() (id, share string, loop, json, newline bool, err error) {
|
||||
fs.StringVar(&id, "id", "", "key id")
|
||||
fs.StringVar(&share, "share", "", "shamir key share")
|
||||
fs.BoolVar(&loop, "loop", false, "ignore network errors and loop until key is received")
|
||||
fs.BoolVar(&json, "json", false, "json output")
|
||||
fs.BoolVar(&newline, "newline", true, "output newline after secret")
|
||||
fs.Parse(os.Args[2:])
|
||||
if id == "" {
|
||||
err = errors.New("missing flag: id")
|
||||
|
|
@ -183,8 +205,9 @@ func outputFlags() (json bool) {
|
|||
return
|
||||
}
|
||||
|
||||
func newKeyFlags() (name, encoding, t string, size int, err error) {
|
||||
func newKeyFlags() (name, existing, encoding, t string, size int, err error) {
|
||||
fs.StringVar(&name, "name", "", "key name")
|
||||
fs.StringVar(&existing, "key", "", "use existing secret key (optional; input-format: hex; types: plain, shamir)")
|
||||
fs.StringVar(&encoding, "enc", "hex", "key encoding scheme [hex|base32|base64|base64url]")
|
||||
fs.StringVar(&t, "type", "plain", "key type [plain|shamir|xor]")
|
||||
fs.IntVar(&size, "size", 16, "key size in bytes")
|
||||
|
|
@ -206,3 +229,16 @@ func print(tw core.TableWriter) {
|
|||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
func confirm(r io.Reader) (ok bool) {
|
||||
br := bufio.NewReader(r)
|
||||
fmt.Printf("confirm delete [y]: ")
|
||||
res, err := br.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(res) < 2 {
|
||||
return
|
||||
}
|
||||
return strings.TrimSpace(res)[0] == 'y'
|
||||
}
|
||||
|
|
|
|||
47
pkg/cli/cli_test.go
Normal file
47
pkg/cli/cli_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2023 Marius Schellenberger
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfirm(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
b.WriteString("\n")
|
||||
if confirm(b) {
|
||||
t.Error("invalid confirm")
|
||||
}
|
||||
b.Reset()
|
||||
|
||||
b.WriteString(" n\n")
|
||||
if confirm(b) {
|
||||
t.Error("invalid confirm")
|
||||
}
|
||||
b.Reset()
|
||||
|
||||
b.WriteString(" foo\n")
|
||||
if confirm(b) {
|
||||
t.Error("invalid confirm")
|
||||
}
|
||||
b.Reset()
|
||||
|
||||
b.WriteString("Y\n")
|
||||
if confirm(b) {
|
||||
t.Error("invalid confirm")
|
||||
}
|
||||
b.Reset()
|
||||
|
||||
b.WriteString(" y\n")
|
||||
if !confirm(b) {
|
||||
t.Error("valid confirm")
|
||||
}
|
||||
b.Reset()
|
||||
|
||||
b.WriteString("y\n")
|
||||
if !confirm(b) {
|
||||
t.Error("valid confirm")
|
||||
}
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ func (db *DB) GetKeyWithSecret(id string) (k core.Key, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (db *DB) CreateKey(name string, size int, enc core.Encoding, t core.Type) (k core.Key, err error) {
|
||||
kstore, k, err := key.Generate(name, size, enc, t)
|
||||
func (db *DB) CreateKey(name, existing string, size int, enc core.Encoding, t core.Type) (k core.Key, err error) {
|
||||
kstore, k, err := key.Generate(name, existing, size, enc, t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,16 @@ func GenerateID() (string, error) {
|
|||
return hex.EncodeToString(id), nil
|
||||
}
|
||||
|
||||
func Generate(name string, size int, enc core.Encoding, t core.Type) (kstore, k core.Key, err error) {
|
||||
func Generate(name, existing string, size int, enc core.Encoding, t core.Type) (kstore, k core.Key, err error) {
|
||||
id, err := GenerateID()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var key []byte
|
||||
if t == core.Xor {
|
||||
if existing != "" {
|
||||
key, err = hex.DecodeString(existing)
|
||||
size = len(key)
|
||||
} else if t == core.Xor {
|
||||
key, err = generate(size * 2)
|
||||
} else {
|
||||
key, err = generate(size)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue