first compiling version

This commit is contained in:
ston1th 2023-03-15 01:51:45 +01:00
commit 3d54199faa
27 changed files with 908 additions and 243 deletions

View file

@ -5,7 +5,6 @@ package client
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
@ -13,19 +12,15 @@ import (
"net/http"
"net/http/httputil"
"os"
"strconv"
"strings"
"time"
)
type Client struct {
endpoint string
username string
password string
auth bool
httpClient *http.Client
debugWriter io.Writer
insecure bool
//insecure bool
}
var (
@ -52,36 +47,21 @@ func WithHTTPClient(httpClient *http.Client) ClientOption {
}
}
func WithInsecureClient(insecure bool) ClientOption {
return func(client *Client) {
client.insecure = insecure
}
}
func WithCredentials(username, password string) ClientOption {
return func(client *Client) {
client.username = username
client.password = password
client.auth = true
}
}
//func WithInsecureClient(insecure bool) ClientOption {
// return func(client *Client) {
// client.insecure = insecure
// }
//}
var (
ErrMissingEndpointEnv = errors.New("missing environment variable HAPROXY_LB_ENDPOINT")
ErrMissingUserEnv = errors.New("missing environment variable HAPROXY_LB_USER")
ErrMissingPasswordEnv = errors.New("missing environment variable HAPROXY_LB_PASSWORD")
ErrMissingEndpointEnv = errors.New("missing environment variable KEYCTL_ENDPOINT")
ErrMissingEndpoint = errors.New("missing Endpoint in config")
ErrMissingUser = errors.New("missing User in config")
ErrMissingPassword = errors.New("missing Password in config")
)
type Config struct {
Endpoint string `json:"endpoint"`
NoAuth bool `json:"no_auth"`
User string `json:"user"`
Password string `json:"password"`
Insecure bool `json:"insecure"`
//Insecure bool `json:"insecure"`
}
func ClientOptionsFromConfig(cfg Config) (options []ClientOption, err error) {
@ -91,53 +71,23 @@ func ClientOptionsFromConfig(cfg Config) (options []ClientOption, err error) {
}
options = []ClientOption{
WithEndpoint(cfg.Endpoint),
WithInsecureClient(cfg.Insecure),
//WithInsecureClient(cfg.Insecure),
}
if cfg.NoAuth {
return
}
if cfg.User == "" {
err = ErrMissingUser
return
}
if cfg.Password == "" {
err = ErrMissingPassword
return
}
options = append(options, WithCredentials(cfg.User, cfg.Password))
return
}
func ClientOptionsFromEnv() (options []ClientOption, err error) {
endpoint := os.Getenv("HAPROXY_LB_ENDPOINT")
endpoint := os.Getenv("KEYCTL_ENDPOINT")
if endpoint == "" {
err = ErrMissingEndpointEnv
return
}
insecure, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_INSECURE"))
//insecure, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_INSECURE"))
options = []ClientOption{
WithEndpoint(endpoint),
WithInsecureClient(insecure),
//WithInsecureClient(insecure),
}
noAuth, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_NO_AUTH"))
if noAuth {
return
}
user := os.Getenv("HAPROXY_LB_USER")
if user == "" {
err = ErrMissingUserEnv
return
}
pass := os.Getenv("HAPROXY_LB_PASSWORD")
if pass == "" {
err = ErrMissingPasswordEnv
return
}
options = append(options, WithCredentials(user, pass))
return
}
@ -149,20 +99,25 @@ func NewClient(options ...ClientOption) *Client {
}
if client.httpClient == nil {
client.httpClient = &http.Client{Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: client.insecure,
client.httpClient = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}}
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
//ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
//TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
//TLSClientConfig: &tls.Config{
// InsecureSkipVerify: client.insecure,
//},
},
}
}
return client
}
@ -173,14 +128,11 @@ func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Re
if err != nil {
return nil, err
}
if c.auth {
req.SetBasicAuth(c.username, c.password)
}
req = req.WithContext(ctx)
return req, nil
}
func (c *Client) Do(r *http.Request, v interface{}) (resp *http.Response, err error) {
func (c *Client) Do(r *http.Request, v any) (resp *http.Response, err error) {
if c.debugWriter != nil {
dumpReq, err := httputil.DumpRequestOut(r, true)
if err != nil {
@ -211,3 +163,19 @@ func (c *Client) Do(r *http.Request, v interface{}) (resp *http.Response, err er
err = decodeResp(resp, v)
return
}
func (c *Client) FollowRedirect(r *http.Request, v any, delay time.Duration) (resp *http.Response, err error) {
rr := r
for {
resp, err = c.Do(rr, v)
if !errors.Is(ErrRedirect, err) {
return
}
rdr := err.(Redirect)
rr, err = c.NewRequest(r.Context(), "GET", rdr.Location, nil)
if err != nil {
return
}
time.Sleep(delay)
}
}

View file

@ -8,8 +8,8 @@ import (
)
type Error struct {
Err string `json:"error"`
Status int `json:"status"`
Err string `json:"error"`
Code int `json:"code"`
}
func (e Error) Error() string {
@ -20,7 +20,18 @@ func (e Error) Is(target error) bool {
return e.Err == target.Error()
}
func decodeResp(resp *http.Response, v interface{}) error {
type Redirect struct {
Location string
Code int
}
func (r Redirect) Error() string {
return "redirect: " + r.Location
}
var ErrRedirect = Redirect{}
func decodeResp(resp *http.Response, v any) error {
if resp.Body == nil {
return nil
}
@ -31,12 +42,16 @@ func decodeResp(resp *http.Response, v interface{}) error {
}
return json.NewDecoder(resp.Body).Decode(&v)
}
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
loc := resp.Header.Get("Location")
return Redirect{loc, resp.StatusCode}
}
var e Error
err := json.NewDecoder(resp.Body).Decode(&e)
if err != nil {
return err
}
if resp.StatusCode >= 400 && resp.StatusCode <= 599 {
if resp.StatusCode >= 400 && resp.StatusCode < 600 {
return e
}
return nil

View file

@ -24,13 +24,7 @@ type Server struct {
Data *types.ContextData
init chan struct{}
stop chan struct{}
stopKeyReset chan struct{}
listen net.Listener
db *db.DB
}
type notFoundHandler struct {
@ -46,11 +40,7 @@ func NewServer(log logr.Logger, listen string) (*Server, error) {
s := &Server{
mux: mux.NewRouter(),
log: log,
Data: &types.ContextData{},
init: make(chan struct{}),
stop: make(chan struct{}),
stopKeyReset: make(chan struct{}),
Data: &types.ContextData{Approver: types.NewApprover()},
}
l, err := net.Listen("tcp", listen)
if err != nil {
@ -62,18 +52,17 @@ func NewServer(log logr.Logger, listen string) (*Server, error) {
for _, v := range serverv1.Routes {
s.mux.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
}
s.start()
return s, nil
}
func (s *Server) start() {
func (s *Server) Start(db *db.DB) {
s.srv = &http.Server{
Handler: s.mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
s.Data.DB = db
go func() {
<-s.init
err := s.srv.Serve(s.listen)
if err != nil {
s.log.Error(err, "")
@ -89,10 +78,8 @@ func (s *Server) contextWrapper(h types.CtxHandler) http.HandlerFunc {
}
// Stop stops listening for incoming connections and closes currently open connections
func (s *Server) Stop() {
func (s *Server) Shutdown(ctx context.Context) {
s.log.Info("stopping")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
err := s.srv.Shutdown(ctx)
if err != nil {
s.log.Error(err, "")

View file

@ -58,13 +58,19 @@ func (a *Approver) Status(id, aid string) (s Status) {
s = app.Status
}
a.mu.RUnlock()
if s == Rejected {
a.mu.Lock()
delete(a.m, aid)
a.mu.Unlock()
}
return
}
func (a *Approver) Update(aid string, s Status) {
a.mu.Lock()
if _, ok := a.m[aid]; ok {
a.m[aid].Status = s
if app, ok := a.m[aid]; ok {
app.Status = s
a.m[aid] = app
}
a.mu.Unlock()
}
@ -95,9 +101,3 @@ func (s Status) String() string {
}
return "[invalid]"
}
type Route struct {
Path string
Handler CtxHandler
Methods []string
}

View file

@ -15,7 +15,8 @@ import (
)
type ContextData struct {
DB *db.DB
DB *db.DB
Approver *Approver
}
func NewContext(w http.ResponseWriter, r *http.Request, data *ContextData, log logr.Logger) *Context {

View file

@ -11,13 +11,13 @@ import (
type Error interface {
Error() string
JSON() string
Status() int
Code() int
}
// Err implements the Error interface
type Err struct {
err string
status int
err string
code int
}
// Error returns the error string
@ -27,29 +27,31 @@ func (a Err) Error() string {
// Error returns the error string as JSON format
func (a Err) JSON() string {
return `{"error":"` + a.err + `","status":` + strconv.Itoa(a.status) + `}`
return `{"error":"` + a.err + `","code":` + strconv.Itoa(a.code) + `}`
}
// Status returns the HTTP status code
func (a Err) Status() int {
return a.status
// Code returns the HTTP status code
func (a Err) Code() int {
return a.code
}
func newError(err string, status int) Error {
func newError(err string, code int) Error {
return Err{
err: err,
status: status,
err: err,
code: code,
}
}
var (
ErrInvalidAPIRoute = newError("invalid api route", http.StatusNotFound)
ErrBadreq = newError("bad request", http.StatusBadRequest)
ErrForbidden = newError("forbidden", http.StatusForbidden)
ErrNotFound = newError("not found", http.StatusNotFound)
ErrKeyNotFound = newError("key not found", http.StatusNotFound)
ErrReqNotFound = newError("key request not found", http.StatusNotFound)
ErrTooManyApprovals = newError("too many approvals pending", http.StatusConflict)
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
ErrISE = newError("internal server error", http.StatusInternalServerError)
ErrInvalidAPIRoute = newError("invalid api route", http.StatusNotFound)
ErrInvalid = newError("invalid data", http.StatusBadRequest)
ErrBadreq = newError("bad request", http.StatusBadRequest)
ErrForbidden = newError("forbidden", http.StatusForbidden)
ErrNotFound = newError("not found", http.StatusNotFound)
ErrKeyNotFound = newError("key not found", http.StatusNotFound)
ErrReqNotFound = newError("key request not found", http.StatusNotFound)
ErrTooManyApprovals = newError("too many approvals pending", http.StatusConflict)
ErrKeyRequestRejected = newError("key request rejected", http.StatusConflict)
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
ErrISE = newError("internal server error", http.StatusInternalServerError)
)

View file

@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
"time"
apiclient "git.giftfish.de/ston1th/keyctl/pkg/api/client"
"git.giftfish.de/ston1th/keyctl/pkg/api/v1/schema"
@ -15,7 +16,8 @@ import (
var (
ErrClientIsNil = errors.New("client is nil")
base = schema.LBPath
keyPath = schema.KeyPath
reqPath = schema.ReqPath
)
type Client struct {
@ -29,42 +31,66 @@ func NewClient(c *apiclient.Client) (*Client, error) {
return &Client{c}, nil
}
func (c *Client) GetLoadBalancers(ctx context.Context) (lbs map[string]*schema.LoadBalancer, err error) {
return c.GetLoadBalancersWithCluster(ctx, "")
}
func (c *Client) GetLoadBalancersWithCluster(ctx context.Context, cluster string) (lbs map[string]*schema.LoadBalancer, err error) {
path := base
if cluster != "" {
path += "/" + cluster
}
func (c *Client) GetApprovals(ctx context.Context) (approvals schema.Approvals, err error) {
path := reqPath
req, err := c.c.NewRequest(ctx, "GET", path, nil)
if err != nil {
return
}
lbs = make(map[string]*schema.LoadBalancer)
_, err = c.c.Do(req, &lbs)
_, err = c.c.Do(req, &approvals)
return
}
func (c *Client) GetLoadBalancer(ctx context.Context, cluster, name string) (lb *schema.LoadBalancer, err error) {
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
func (c *Client) RejectApproval(ctx context.Context, id string) error {
return c.sendApproval(ctx, id, false)
}
func (c *Client) AcceptApproval(ctx context.Context, id string) error {
return c.sendApproval(ctx, id, true)
}
func (c *Client) sendApproval(ctx context.Context, id string, approve bool) (err error) {
path := fmt.Sprintf("%s/%s", reqPath, id)
method := "DELETE"
if approve {
method = "PUT"
}
req, err := c.c.NewRequest(ctx, method, path, nil)
if err != nil {
return
}
_, err = c.c.Do(req, nil)
return
}
func (c *Client) GetKeys(ctx context.Context) (keys schema.Keys, err error) {
path := keyPath
req, err := c.c.NewRequest(ctx, "GET", path, nil)
if err != nil {
return
}
_, err = c.c.Do(req, &lb)
_, err = c.c.Do(req, &keys)
return
}
func (c *Client) CreateLoadBalancer(ctx context.Context, cluster, name string, lb *schema.LoadBalancer) (err error) {
func (c *Client) GetKey(ctx context.Context, id string) (key schema.Key, err error) {
path := fmt.Sprintf("%s/%s", keyPath, id)
req, err := c.c.NewRequest(ctx, "GET", path, nil)
if err != nil {
return
}
_, err = c.c.FollowRedirect(req, &key, time.Second*2)
return
}
func (c *Client) CreateKey(ctx context.Context, key schema.NewKey) (err error) {
buf := new(bytes.Buffer)
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
err = lb.ValidateClient()
path := keyPath
err = key.Validate()
if err != nil {
return
}
err = json.NewEncoder(buf).Encode(lb)
err = json.NewEncoder(buf).Encode(key)
if err != nil {
return
}
@ -76,21 +102,8 @@ func (c *Client) CreateLoadBalancer(ctx context.Context, cluster, name string, l
return
}
func (c *Client) DeleteLoadBalancer(ctx context.Context, cluster, name string) (err error) {
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
req, err := c.c.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return
}
_, err = c.c.Do(req, nil)
return
}
func (c *Client) DeleteLoadBalancersWithCluster(ctx context.Context, cluster string) (err error) {
if cluster == "" {
return errors.New("cluster value can not be empty")
}
path := base + "/" + cluster
func (c *Client) DeleteKey(ctx context.Context, id string) (err error) {
path := fmt.Sprintf("%s/%s", keyPath, id)
req, err := c.c.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return

View file

@ -54,17 +54,20 @@ type Key struct {
Created int64 `json:"created"`
Size int `json:"size"`
Encoding core.Encoding `json:"encoding"`
Key string `json:"key"`
Key string `json:"key,omitempty"`
}
type Keys []Key
func (Keys) Less(a, b Key) { return a.Name < b.Name }
func (k Keys) Sort() { slices.SortStableFunc(k, k.Less) }
func (Keys) Less(a, b Key) bool { return a.Name < b.Name }
func (k Keys) Sort() { slices.SortStableFunc(k, k.Less) }
func NewKeys(keys core.Keys) (k Keys) {
k = Keys(keys)
for _, key := range keys {
k = append(k, Key(key))
}
k.Sort()
return
}
type Approval struct {
@ -77,8 +80,8 @@ type Approval struct {
type Approvals []Approval
func (Approvals) Less(a, b Approval) { return a.Name < b.Name }
func (a Approvals) Sort() { slices.SortStableFunc(a, a.Less) }
func (Approvals) Less(a, b Approval) bool { return a.Name < b.Name }
func (a Approvals) Sort() { slices.SortStableFunc(a, a.Less) }
func NewApprovals(m types.ApprovalMap) (a Approvals) {
for k, v := range m {

View file

@ -9,6 +9,7 @@ import (
"git.giftfish.de/ston1th/keyctl/pkg/api/types"
"git.giftfish.de/ston1th/keyctl/pkg/api/v1/schema"
"git.giftfish.de/ston1th/keyctl/pkg/store"
)
func local(h types.CtxHandler) types.CtxHandler {
@ -53,7 +54,7 @@ func newHandler(ctx *types.Context) {
}
key, err := ctx.Data.DB.CreateKey(newKey.Name, newKey.Size, newKey.Encoding)
if err != nil {
ctx.Log.Error(err, "error writing loadbalancer", "cluster", cl, "name", n)
ctx.Log.Error(err, "error writing key", "name", newKey.Name)
ctx.Err(types.ErrISE)
return
}
@ -65,8 +66,11 @@ func keyHandler(ctx *types.Context) {
id := ctx.Var("id")
k, err := ctx.Data.DB.GetKey(id)
if err != nil {
//TODO error 404
ctx.Log.Error(err, "error reading key", "id", id)
if err == store.ErrKeyNotFound {
ctx.Err(types.ErrNotFound)
return
}
ctx.Err(types.ErrISE)
return
}
@ -74,7 +78,7 @@ func keyHandler(ctx *types.Context) {
case "GET":
aid := ctx.Var("aid")
if aid == "" {
aid, err = ctx.Data.Approvals.New(id, k.Name)
aid, err = ctx.Data.Approver.New(id, k.Name)
if err != nil {
ctx.Log.Error(err, "error creating approval", "id", id, "name", k.Name)
ctx.Err(types.ErrISE)
@ -83,14 +87,22 @@ func keyHandler(ctx *types.Context) {
ctx.Redirect(schema.ApproveURL(id, aid), http.StatusFound)
return
}
if !ctx.Data.Approvals.Approved(id, aid) {
s := ctx.Data.Approver.Status(id, aid)
switch s {
case types.Pending:
ctx.Redirect(schema.ApproveURL(id, aid), http.StatusFound)
return
case types.Rejected:
ctx.Err(types.ErrKeyRequestRejected)
return
}
k, err := ctx.Data.DB.GetKeyWithSecret(id)
if err != nil {
//TODO error 404
ctx.Log.Error(err, "error reading key", "id", id)
if err == store.ErrKeyNotFound {
ctx.Err(types.ErrNotFound)
return
}
ctx.Err(types.ErrISE)
return
}
@ -99,6 +111,10 @@ func keyHandler(ctx *types.Context) {
err = ctx.Data.DB.DeleteKey(id)
if err != nil {
ctx.Log.Error(err, "error deleting key", "id", id, "name", k.Name)
if err == store.ErrKeyNotFound {
ctx.Err(types.ErrNotFound)
return
}
ctx.Err(types.ErrISE)
return
}
@ -107,14 +123,13 @@ func keyHandler(ctx *types.Context) {
}
func reqListHandler(ctx *types.Context) {
l := ctx.Data.Approvals.List()
l := ctx.Data.Approver.List()
ctx.JSON(schema.NewApprovals(l))
}
func keyListHandler(ctx *types.Context) {
k, err := ctx.Data.DB.GetKeys()
if err != nil {
//TODO error 404
ctx.Log.Error(err, "error reading keys")
ctx.Err(types.ErrISE)
return
@ -131,6 +146,6 @@ func reqHandler(ctx *types.Context) {
case "DELETE":
status = types.Rejected
}
ctx.Data.Approvals.Update(id, status)
ctx.Data.Approver.Update(id, status)
ctx.OK()
}

View file

@ -1,3 +1,139 @@
// Copyright (C) 2023 Marius Schellenberger
package cli
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
apiclient "git.giftfish.de/ston1th/keyctl/pkg/api/client"
"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"
)
func exit(err error) {
fmt.Println(err)
os.Exit(1)
}
func Run(arg string) {
opts, err := apiclient.ClientOptionsFromEnv()
if err != nil {
exit(err)
}
apic := apiclient.NewClient(opts...)
c, err := client.NewClient(apic)
if err != nil {
exit(err)
}
ctx := context.Background()
switch arg {
case "new":
name, encoding, size := newKeyFlags()
newKey := schema.NewKey{
Name: name,
Size: size,
Encoding: core.EncodingFromString(encoding),
}
err = c.CreateKey(ctx, newKey)
case "del":
id := idFlags("key id")
err = c.DeleteKey(ctx, id)
case "approve":
id := idFlags("approval id")
err = c.AcceptApproval(ctx, id)
case "reject":
id := idFlags("approval id")
err = c.RejectApproval(ctx, id)
case "get":
id, json := getFlags()
key, err := c.GetKey(ctx, id)
if err != nil {
exit(err)
}
if json {
jsonOutput(key) // does not return
}
fmt.Println(key.Key)
case "ls":
json := outputFlags()
keys, err := c.GetKeys(ctx)
if err != nil {
exit(err)
}
if json {
jsonOutput(keys) // does not return
}
for _, k := range keys {
fmt.Printf("%s %s %d %d %s\n",
k.ID,
k.Name,
k.Size,
k.Encoding,
k.Created,
)
}
case "req":
json := outputFlags()
approvals, err := c.GetApprovals(ctx)
if err != nil {
exit(err)
}
if json {
jsonOutput(approvals) // does not return
}
for _, a := range approvals {
fmt.Printf("%s %s %s %d %s\n",
a.ID,
a.AID,
a.Name,
a.Status,
a.Created,
)
}
}
if err != nil {
exit(err)
}
os.Exit(0)
}
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) {
flag.StringVar(&id, "id", "", desc)
flag.Parse()
return
}
func getFlags() (id string, json bool) {
flag.StringVar(&id, "id", "", "key id")
flag.BoolVar(&json, "json", false, "json output")
flag.Parse()
return
}
func outputFlags() (json bool) {
flag.BoolVar(&json, "json", false, "json output")
flag.Parse()
return
}
func newKeyFlags() (name, encoding string, size int) {
flag.StringVar(&name, "name", "", "key name")
flag.StringVar(&encoding, "enc", "hex", "key encoding scheme [hex|base32|base64|base64url]")
flag.IntVar(&size, "size", 16, "key size in bytes")
flag.Parse()
return
}

View file

@ -7,7 +7,6 @@ import (
"path/filepath"
"git.giftfish.de/ston1th/godrop/v2"
"git.giftfish.de/ston1th/keyctl/pkg/core"
"git.giftfish.de/ston1th/keyctl/pkg/store"
"github.com/go-logr/logr"
)
@ -19,9 +18,9 @@ type DB struct {
store store.Store
}
func NewPlain(log logr.Logger, cfg *core.Config) (db *DB, err error) {
func NewPlain(log logr.Logger, dir string) (db *DB, err error) {
db = &DB{log: log}
dbFile := filepath.Join(cfg.DataDir, storeFile)
dbFile := filepath.Join(dir, storeFile)
err = godrop.Unveil(dbFile, "rwc")
if err != nil {
return
@ -30,8 +29,8 @@ func NewPlain(log logr.Logger, cfg *core.Config) (db *DB, err error) {
return
}
func New(log logr.Logger, cfg *core.Config) (db *DB, err error) {
db, err = NewPlain(log, cfg)
func New(log logr.Logger, dir string) (db *DB, err error) {
db, err = NewPlain(log, dir)
if err != nil {
return
}

View file

@ -3,9 +3,7 @@
package db
import (
"sort"
"git.giftfish.de/ston1th/goacc/pkg/core"
"git.giftfish.de/ston1th/keyctl/pkg/core"
"git.giftfish.de/ston1th/keyctl/pkg/key"
)
@ -13,13 +11,12 @@ const keyPrefix = "key/"
func (db *DB) GetKeys() (keys core.Keys, err error) {
err = db.store.ForEachPrefix(keyPrefix, func(k string, _ []byte) error {
k, err := db.GetKey(k)
key, err := db.GetKey(k)
if err == nil {
keys = append(keys, k)
keys = append(keys, key)
}
return nil
})
sort.Sort(keys)
return
}

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package db

View file

@ -40,8 +40,8 @@ func Generate(name string, size int, enc core.Encoding) (k core.Key, err error)
Name: name,
ID: id,
Size: size,
Encoding: enc.String(),
Key: enc.Encode(key),
Encoding: enc,
Key: enc.EncodeToString(key),
Created: time.Now().Unix(),
}
return

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store

View file

@ -1,4 +1,4 @@
// Copyright (C) 2022 Marius Schellenberger
// Copyright (C) 2023 Marius Schellenberger
package store