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 }