Files
servicedemon/registrar/endpoints.go

115 lines
2.5 KiB
Go

package registrar
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"github.com/google/uuid"
svc "go.fixergrid.net/servicedemon/registrar/internal/services"
)
const (
REGISTRATION_TOPIC = "net.fixergrid.events.app.admission"
)
var validApprover string = "Nautilus Admins"
type Registrar struct {
svc.Publisher
repo svc.AppRepo
log ilogger
}
func WithLogger(l logger) RegistrarOpt {
return func(r *Registrar) {
r.log = internalLog{l}
}
}
type RegistrarOpt func(*Registrar)
func NewRegistrar(publisher svc.Publisher, repo svc.AppRepo, options ...RegistrarOpt) Registrar {
r := Registrar{
Publisher: publisher,
repo: repo,
log: log.New(os.Stderr, "servicedemon/registrar - ", log.LstdFlags|log.Lshortfile),
}
for _, opt := range options {
opt(&r)
}
return r
}
func (r Registrar) HandleRegistration(resp http.ResponseWriter, req *http.Request) {
cert := req.TLS.PeerCertificates[0]
name := cert.DNSNames[0]
app, err := r.repo.GetApp(name)
switch err {
case svc.ErrApplicationNotFound:
id := r.repo.StartAppRegistration(name)
event := map[string]string{
"id": id.String(),
"name": name,
"type": "ApplicationRegistrationSubmitted",
}
r.sendEvent(REGISTRATION_TOPIC, event)
resp.WriteHeader(http.StatusCreated)
fmt.Fprintf(resp, `{"status": "pending_approval"}`)
case nil:
resp.WriteHeader(http.StatusOK)
fmt.Fprintf(resp, `{"status": "%s"}`, app.State)
default:
resp.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(resp, `{"errors": ["%s"]}`, err)
}
}
func (r Registrar) HandleApproval(resp http.ResponseWriter, req *http.Request) {
in := req.URL.Path
cert := req.TLS.PeerCertificates[0]
OUs := cert.Subject.OrganizationalUnit
var ou string
if len(OUs) == 1 {
ou = OUs[0]
} else {
fmt.Fprintf(resp, `{"errors": ["missing OU"]}`)
resp.WriteHeader(http.StatusBadRequest)
return
}
if ou != validApprover {
fmt.Fprintf(resp, `{"errors": ["approval forbidden"]}`)
resp.WriteHeader(http.StatusForbidden)
return
}
appID := uuid.MustParse(in)
event := map[string]string{
"id": appID.String(),
"approver": ou,
"type": "ApplicationRegistrationApproved",
}
r.sendEvent(APPROVAL_TOPIC, event)
resp.WriteHeader(http.StatusOK)
fmt.Fprintf(resp, `{"status": "registered"}`)
}
func (r Registrar) sendEvent(topic string, event map[string]string) error {
b, err := json.Marshal(event)
if err != nil {
return fmt.Errorf("registrar: sendEvent: failed to marshal: %w", err)
}
r.log.Printf("sending event: %s", event)
r.Publish(topic, string(b))
return nil
}