// Copyright (C) 2023 Marius Schellenberger package server import ( "encoding/json" "net/http" "net/netip" "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 { return func(ctx *types.Context) { addr, err := netip.ParseAddr(ctx.ClientIP()) if err != nil { ctx.Err(types.ErrForbidden) return } if !addr.IsLoopback() { ctx.Err(types.ErrForbidden) return } h(ctx) } } func healthzHandler(ctx *types.Context) { ctx.OK() } func newHandler(ctx *types.Context) { if ctx.Method() == "POST" { b, err := ctx.ReadBody() if err != nil { ctx.Log.Error(err, "error reading request body") ctx.Err(types.ErrISE) return } var newKey schema.NewKey err = json.Unmarshal(b, &newKey) if err != nil { ctx.Log.Error(err, "error decoding request body") ctx.Err(types.ErrInvalid) return } err = newKey.Validate() if err != nil { ctx.Log.Error(err, "error empty name for new key") ctx.Err(types.ErrInvalid) return } key, err := ctx.Data.DB.CreateKey(newKey.Name, newKey.Size, newKey.Encoding) if err != nil { ctx.Log.Error(err, "error writing key", "name", newKey.Name) ctx.Err(types.ErrISE) return } ctx.JSON(schema.Key(key)) } } func keyHandler(ctx *types.Context) { id := ctx.Var("id") k, err := ctx.Data.DB.GetKey(id) if err != nil { ctx.Log.Error(err, "error reading key", "id", id) if err == store.ErrKeyNotFound { ctx.Err(types.ErrNotFound) return } ctx.Err(types.ErrISE) return } switch ctx.Method() { case "GET": aid := ctx.Var("aid") if aid == "" { 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) return } ctx.Redirect(schema.ApproveURL(id, aid), http.StatusFound) return } 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 { ctx.Log.Error(err, "error reading key", "id", id) if err == store.ErrKeyNotFound { ctx.Err(types.ErrNotFound) return } ctx.Err(types.ErrISE) return } ctx.JSON(schema.Key(k)) case "DELETE": 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 } ctx.OK() } } func reqListHandler(ctx *types.Context) { l := ctx.Data.Approver.List() ctx.JSON(schema.NewApprovals(l)) } func keyListHandler(ctx *types.Context) { k, err := ctx.Data.DB.GetKeys() if err != nil { ctx.Log.Error(err, "error reading keys") ctx.Err(types.ErrISE) return } ctx.JSON(schema.NewKeys(k)) } func reqHandler(ctx *types.Context) { id := ctx.Var("id") status := types.Pending switch ctx.Method() { case "PUT": status = types.Approved case "DELETE": status = types.Rejected } ctx.Data.Approver.Update(id, status) ctx.OK() }