keyctl/pkg/api/v1/schema/schema.go

222 lines
4.8 KiB
Go

// Copyright (C) 2023 Marius Schellenberger
package schema
import (
"cmp"
"encoding/hex"
"errors"
"fmt"
"slices"
"git.giftfish.de/ston1th/keyctl/pkg/api/types"
"git.giftfish.de/ston1th/keyctl/pkg/core"
)
const (
Version = "v1"
KeyName = "key"
ReqName = "req"
KeyPath = "/" + Version + "/" + KeyName
ReqPath = "/" + Version + "/" + ReqName
SSH = "ssh"
AccessPath = "/" + Version + "/" + SSH
)
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")
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 (
MinKeySize = 1
MaxKeySize = 1024
)
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
}
if nk.Size > MaxKeySize || nk.Size < MinKeySize {
return ErrInvalidKeySize
}
return nil
}
func ApproveURL(id, aid string) string {
return KeyPath + "/" + id + "/" + aid
}
func AccessURL(host, user, aid string) string {
return AccessPath + "/" + host + "/" + user + "/" + aid
}
type Key struct {
ID string `json:"id"`
Name string `json:"name"`
Size int `json:"size"`
Encoding core.Encoding `json:"encoding"`
Type core.Type `json:"type"`
Key string `json:"key,omitempty"`
}
func (k Key) Print(share string) (string, error) {
switch k.Type {
case core.Shamir:
part1, err := k.Encoding.Decode(k.Key)
if err != nil {
return "", err
}
part2, err := hex.DecodeString(share)
if err != nil {
return "", err
}
dec, err := k.Type.Decode(append(part1, part2...))
if err != nil {
return "", err
}
return k.Encoding.EncodeToString(dec), nil
}
return k.Key, nil
}
type Keys []Key
func (Keys) Less(a, b Key) int { return cmp.Compare(a.Name, b.Name) }
func (k Keys) Sort() { slices.SortStableFunc(k, k.Less) }
func (k Keys) Len() int { return len(k) }
func (k Keys) Fields() string {
return "Key ID\t Name\t Size\t Encoding\t Type"
}
func (k Keys) Values() []string {
vals := make([]string, len(k))
for i, v := range k {
vals[i] = fmt.Sprintf("%s\t %s\t %d\t %s\t %s",
v.ID,
v.Name,
v.Size,
v.Encoding,
v.Type,
)
}
return vals
}
func NewKeys(keys core.Keys) (k Keys) {
for _, key := range keys {
k = append(k, Key(key))
}
k.Sort()
return
}
type Approval struct {
ID string `json:"id"`
AID string `json:"aid"`
Name string `json:"name"`
IP string `json:"ip"`
Status types.Status `json:"status"`
}
type Approvals []Approval
func (Approvals) Less(a, b Approval) int { return cmp.Compare(a.Name, b.Name) }
func (a Approvals) Sort() { slices.SortStableFunc(a, a.Less) }
func (a Approvals) Len() int { return len(a) }
func (a Approvals) Fields() string {
return "Key ID\t Approval ID\t Name\t Status\t IP"
}
func (a Approvals) Values() []string {
vals := make([]string, len(a))
for i, v := range a {
vals[i] = fmt.Sprintf("%s\t %s\t %s\t %s\t %s",
v.ID,
v.AID,
v.Name,
v.Status,
v.IP,
)
}
return vals
}
func NewApprovals(m types.ApprovalMap) (a Approvals) {
for k, v := range m {
a = append(a, Approval{
ID: v.ID,
AID: k,
Name: v.Name,
IP: v.IP,
Status: v.Status,
})
}
a.Sort()
return
}
type Access struct {
Host string `json:"host"`
User string `json:"user"`
AID string `json:"aid"`
IP string `json:"ip"`
Status types.Status `json:"status"`
}
type AccessList []Access
func (AccessList) Less(a, b Access) int { return cmp.Compare(a.Host, b.Host) }
func (a AccessList) Sort() { slices.SortStableFunc(a, a.Less) }
func (a AccessList) Len() int { return len(a) }
func (a AccessList) Fields() string {
return "Host\t User\t Approval ID\t IP\t Status"
}
func (a AccessList) Values() []string {
vals := make([]string, len(a))
for i, v := range a {
vals[i] = fmt.Sprintf("%s\t %s\t %s\t %s\t %s",
v.Host,
v.User,
v.AID,
v.IP,
v.Status,
)
}
return vals
}
func NewAccessList(m types.SSHMap) (a AccessList) {
for k, v := range m {
a = append(a, Access{
Host: v.Host,
User: v.User,
AID: k,
IP: v.IP,
Status: v.Status,
})
}
a.Sort()
return
}