package registrar import ( "encoding/json" "fmt" "net/http" "github.com/google/uuid" svc "go.fixergrid.net/servicedemon/pkg/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 internalLog } 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, } 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] if r.repo.IsRegistered(name) { resp.WriteHeader(http.StatusOK) resp.Write([]byte(`{"status": "registered"}`)) } else { 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"}`) } } func (r Registrar) HandleApproval(resp http.ResponseWriter, req *http.Request) { headers := resp.Header() headers.Set("content-type", "application/json") 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 }