keyctl/pkg/api/v1/server/handler.go

213 lines
4.5 KiB
Go

// Copyright (C) 2023 Marius Schellenberger
package server
import (
"encoding/json"
"net/http"
"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) {
ip := ctx.ClientIP()
if ip == "@" {
h(ctx)
return
}
ctx.Err(types.ErrForbidden)
}
}
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.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)
return
}
ctx.JSON(schema.Key(key))
}
}
func keyHandler(ctx *types.Context) {
id := ctx.Var("id")
ip := ctx.ClientIP()
db := ctx.DB()
k, err := db.GetKey(id)
if err != nil {
ctx.Log.Error(err, "error reading key", "id", id)
if err == store.ErrKeyNotFound {
ctx.Err(types.ErrKeyNotFound)
return
}
ctx.Err(types.ErrISE)
return
}
switch ctx.Method() {
case "GET":
a := ctx.Approver()
aid := ctx.Var("aid")
if aid == "" {
aid, err = a.New(id, k.Name, ip)
if err != nil {
ctx.Log.Error(err, "error creating approval", "id", id, "name", k.Name)
ctx.Err(types.ErrTooManyApprovals)
return
}
ctx.Redirect(schema.ApproveURL(id, aid), http.StatusFound)
return
}
s := a.Status(id, aid, ip)
switch s {
case types.Pending:
ctx.Redirect(schema.ApproveURL(id, aid), http.StatusFound)
return
case types.Rejected:
ctx.Err(types.ErrKeyRequestRejected)
return
case types.NotFound:
ctx.Err(types.ErrReqNotFound)
return
}
k, err := 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 = 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.Approver().List()
ctx.JSON(schema.NewApprovals(l))
}
func keyListHandler(ctx *types.Context) {
k, err := ctx.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
}
err := ctx.Approver().Update(id, status)
if err != nil {
ctx.Log.Error(err, "error updating key request")
ctx.Err(types.ErrReqNotFound)
return
}
ctx.OK()
}
func accessHandler(ctx *types.Context) {
host := ctx.Var("host")
user := ctx.Var("user")
ip := ctx.ClientIP()
ssh := ctx.SSH()
aid := ctx.Var("aid")
var err error
if aid == "" {
aid, err = ssh.New(host, user, ip)
if err != nil {
ctx.Log.Error(err, "error creating access", "host", host, "user", user)
ctx.Err(types.ErrTooManyApprovals)
return
}
ctx.Redirect(schema.AccessURL(host, user, aid), http.StatusFound)
return
}
s := ssh.Status(aid, host, user, ip)
switch s {
case types.Pending:
ctx.Redirect(schema.AccessURL(host, user, aid), http.StatusFound)
return
case types.Rejected:
ctx.Err(types.ErrAccessRequestRejected)
return
case types.NotFound:
ctx.Err(types.ErrAccessReqNotFound)
return
}
ctx.JSON(true)
}
func accessReqHandler(ctx *types.Context) {
id := ctx.Var("id")
status := types.Pending
switch ctx.Method() {
case "PUT":
status = types.Approved
case "DELETE":
status = types.Rejected
}
err := ctx.SSH().Update(id, status)
if err != nil {
ctx.Log.Error(err, "error updating ssh request")
ctx.Err(types.ErrAccessReqNotFound)
return
}
ctx.OK()
}
func accessListHandler(ctx *types.Context) {
l := ctx.SSH().List()
ctx.JSON(schema.NewAccessList(l))
}