package database // SignatureScheme names the way an entrypoint authenticates inbound // requests. A scheme fixes both the header the signature arrives in // and the algorithm used to check it, so an operator cannot pair one // sender's header with another sender's comparison. type SignatureScheme string // Signature scheme values. The empty scheme means the entrypoint // performs no inbound verification: it is the default, and it is the // state every entrypoint created before this column existed migrates // to, so an existing deployment keeps accepting the requests it // accepted before. const ( SignatureSchemeNone SignatureScheme = "" SignatureSchemeGitHub SignatureScheme = "github" SignatureSchemeGitLab SignatureScheme = "gitlab" ) // Entrypoint represents an inbound URL endpoint that feeds into a webhook type Entrypoint struct { BaseModel WebhookID string `gorm:"type:uuid;not null" json:"webhookId"` // Path is the URL path for this entrypoint. Path string `gorm:"uniqueIndex;not null" json:"path"` Description string `json:"description"` Active bool `gorm:"default:true" json:"active"` // SignatureScheme selects how inbound requests to this // entrypoint are authenticated. Empty means unauthenticated, // which is what a UUID-only entrypoint has always been. SignatureScheme SignatureScheme `gorm:"default:''" json:"signatureScheme"` // SignatureSecret is the secret shared with the sender. // // It is stored in the clear because HMAC verification needs the // key itself: a hash of it cannot recompute the sender's digest. // It is therefore a live credential, and json:"-" keeps it out of // any handler that marshals the model, the way APIKey.Key and // Target.Config are kept out. handlers.EntrypointView is the // matching barrier for the HTML path. SignatureSecret string `gorm:"default:''" json:"-"` // Relations Webhook Webhook `json:"webhook,omitzero"` } // SignatureConfigured reports whether this entrypoint verifies // inbound requests. Both halves must be present: a scheme without a // secret, or a secret without a scheme, is a broken configuration // rather than a configured one, and signature.Verify fails those // closed rather than treating them as "off". func (e *Entrypoint) SignatureConfigured() bool { return e.SignatureScheme != SignatureSchemeNone && e.SignatureSecret != "" } // SignatureHalfConfigured reports whether exactly one half of the // scheme/secret pair is present. The receiver refuses such a row on // every request, so the UI must not describe it as unverified. It // reports the state without exposing the secret, which is why it // lives here rather than in the display projection. func (e *Entrypoint) SignatureHalfConfigured() bool { hasScheme := e.SignatureScheme != SignatureSchemeNone hasSecret := e.SignatureSecret != "" return hasScheme != hasSecret }