package apperror import ( "fmt" "net/http" ) // The constructors in this file keep public messages, statuses, and details in one place func AlreadyInUse(property string) *Error { return New(CodeAlreadyInUse, http.StatusConflict, property+" is already in use").WithDetail("property", property) } func NotFound(resource string) *Error { return New(CodeNotFound, http.StatusNotFound, resource+" not found").WithDetail("resource", resource) } func InvalidRequestBody(cause error) *Error { return Wrap(cause, CodeInvalidRequestBody, http.StatusBadRequest, "Request body is invalid") } func MissingField(field string) *Error { return InvalidField(field, "required", "is required") } func InvalidField(field, code, message string) *Error { return New(CodeValidationFailed, http.StatusBadRequest, fmt.Sprintf("%s %s", field, message)).WithFields([]FieldError{{ Field: field, Code: code, Message: message, }}) } func SetupNotAvailable() *Error { return New(CodeSetupNotAvailable, http.StatusNotFound, "Not found") } func SetupAlreadyCompleted() *Error { return New(CodeSetupAlreadyCompleted, http.StatusConflict, "Initial setup has already been completed") } func TokenInvalidOrExpired() *Error { return New(CodeTokenInvalidOrExpired, http.StatusUnauthorized, "Token is invalid or expired") } func DeviceCodeInvalid() *Error { return New(CodeDeviceCodeInvalid, http.StatusUnauthorized, "One-time access code must be used on the device it was generated for") } func TokenInvalid() *Error { return New(CodeInvalidToken, http.StatusUnauthorized, "Token is invalid") } func OidcMissingAuthorization() *Error { return New(CodeOidcMissingAuthorization, http.StatusForbidden, "Authorization is missing") } func OidcInvalidCallbackURL() *Error { return New(CodeOidcInvalidCallbackURL, http.StatusBadRequest, "Callback URL is invalid and may need to be corrected by an administrator") } func InvalidCIMDURLPattern(pattern string) *Error { return New(CodeValidationFailed, http.StatusBadRequest, "Metadata document URL pattern is invalid"). WithDetail("pattern", pattern). WithFields([]FieldError{{ Field: "cimdUrlAllowlist", Code: "invalid_value", Message: "contains an invalid URL pattern", }}) } func UnsupportedFileType(expected string) *Error { if expected == "" { return New(CodeFileTypeNotSupported, http.StatusUnsupportedMediaType, "File type is not supported") } return New(CodeFileTypeNotSupported, http.StatusUnsupportedMediaType, "File must be of type "+expected). WithDetail("expected_file_type", expected) } func FileTooLarge(maxSize string) *Error { return New(CodeFileTooLarge, http.StatusRequestEntityTooLarge, fmt.Sprintf("File must not exceed %s", maxSize)).WithDetail("max_size", maxSize) } func NotSignedIn() *Error { return New(CodeNotSignedIn, http.StatusUnauthorized, "You are not signed in") } func MissingPermission() *Error { return New(CodeForbidden, http.StatusForbidden, "You don't have permission to perform this action") } func TooManyRequests() *Error { return New(CodeRateLimited, http.StatusTooManyRequests, "Too many requests") } func UserNotFound() *Error { return New(CodeUserNotFound, http.StatusNotFound, "User not found") } func InvalidImage(cause error) *Error { return Wrap(cause, CodeInvalidImage, http.StatusBadRequest, "File is not a valid image") } func MissingSessionID() *Error { return New(CodeMissingSessionID, http.StatusBadRequest, "Session ID is missing") } func InvalidWebAuthnSession() *Error { return New(CodeInvalidWebAuthnSession, http.StatusBadRequest, "Your passkey request has expired") } func InvalidWebAuthnResponse(cause error) *Error { return Wrap(cause, CodeInvalidWebAuthnResponse, http.StatusBadRequest, "We couldn't process the response from your passkey") } func WebAuthnAuthenticationFailed(cause error) *Error { return Wrap(cause, CodeWebAuthnAuthenticationFailed, http.StatusUnauthorized, "We couldn't verify your passkey") } func PasskeyUserVerificationRequired(cause error) *Error { return Wrap(cause, CodePasskeyUserVerificationRequired, http.StatusBadRequest, "Your passkey couldn't verify you. If you're using a security key, configure a FIDO2 PIN and try again") } func SyncedPasskeyNotAllowed() *Error { return New(CodeSyncedPasskeyNotAllowed, http.StatusBadRequest, "Synced passkeys are not allowed") } func ReservedClaim(key string) *Error { return New(CodeReservedClaim, http.StatusBadRequest, fmt.Sprintf("Claim %s is reserved and can't be used", key)). WithDetail("key", key). WithFields([]FieldError{{ Field: "key", Code: "reserved", Message: "is reserved", }}) } func DuplicateClaim(key string) *Error { return New(CodeDuplicateClaim, http.StatusBadRequest, fmt.Sprintf("Claim %s is already defined", key)). WithDetail("key", key). WithFields([]FieldError{{ Field: "key", Code: "duplicate", Message: "is listed more than once", }}) } func LdapDisabled() *Error { return New(CodeLdapDisabled, http.StatusConflict, "LDAP is not enabled") } func LdapUserUpdate() *Error { return New(CodeLdapUserUpdate, http.StatusForbidden, "LDAP users can't be updated") } func LdapUserGroupUpdate() *Error { return New(CodeLdapUserGroupUpdate, http.StatusForbidden, "LDAP user groups can't be updated") } func OidcAccessDenied() *Error { return New(CodeOidcAccessDenied, http.StatusForbidden, "You're not allowed to access this service") } func OidcInteractionNotFound() *Error { return New(CodeNotFound, http.StatusNotFound, "OIDC interaction not found or expired"). WithDetail("resource", "OIDC interaction") } func OidcClientIDNotMatching() *Error { return New(CodeOidcClientIDNotMatching, http.StatusBadRequest, "Client ID in request doesn't match client ID in token") } func UIConfigDisabled() *Error { return New(CodeUIConfigDisabled, http.StatusForbidden, "The configuration can't be changed since the UI configuration is disabled") } func InvalidUserID() *Error { return Validation([]FieldError{{ Field: "userId", Code: "invalid_format", Message: "must be a valid UUID", }}) } func OneTimeAccessDisabled() *Error { return New(CodeOneTimeAccessDisabled, http.StatusForbidden, "One-time access is disabled") } func DeviceLoginRequestInvalidOrExpired() *Error { return New(CodeDeviceLoginExpired, http.StatusUnauthorized, "Device login request is invalid or expired") } func DeviceLoginDenied() *Error { return New(CodeDeviceLoginDenied, http.StatusForbidden, "Device login request was denied") } func InvalidAPIKey() *Error { return New(CodeInvalidAPIKey, http.StatusUnauthorized, "API key is invalid") } func NoAPIKeyProvided() *Error { return New(CodeNoAPIKeyProvided, http.StatusUnauthorized, "API key is missing") } func APIKeyNotFound() *Error { return New(CodeAPIKeyNotFound, http.StatusNotFound, "API key not found") } func APIKeyNotExpired() *Error { return New(CodeAPIKeyNotExpired, http.StatusConflict, "API key is not expired yet") } func InvalidAPIKeyExpiration() *Error { return New(CodeInvalidAPIKeyExpiration, http.StatusBadRequest, "API key expiration time must be in the future").WithFields([]FieldError{{ Field: "expiresAt", Code: "invalid_value", Message: "must be in the future", }}) } func APIKeyAuthNotAllowed() *Error { return New(CodeAPIKeyAuthNotAllowed, http.StatusForbidden, "API key authentication is not allowed for this endpoint") } func UserDisabled() *Error { return New(CodeUserDisabled, http.StatusForbidden, "User account is disabled") } func ValidationMessage(message string) *Error { return New(CodeValidationFailed, http.StatusBadRequest, message) } func OidcDeviceCodeExpired() *Error { return New(CodeOidcDeviceCodeExpired, http.StatusBadRequest, "Device code has expired") } func OidcInvalidDeviceCode() *Error { return New(CodeOidcInvalidDeviceCode, http.StatusBadRequest, "Device code is invalid") } func ReauthenticationRequired() *Error { return New(CodeReauthenticationRequired, http.StatusUnauthorized, "Reauthentication is required") } func ReauthenticationRequiredWithCause(cause error) *Error { return Wrap(cause, CodeReauthenticationRequired, http.StatusUnauthorized, "Reauthentication is required") } func OpenSignupDisabled() *Error { return New(CodeOpenSignupDisabled, http.StatusForbidden, "Open user signup is not enabled") } func ClientIDAlreadyExists() *Error { return New(CodeClientIDAlreadyExists, http.StatusConflict, "Client ID is already in use") } func UserEmailNotSet() *Error { return New(CodeUserEmailNotSet, http.StatusConflict, "The user does not have an email address set") } func ImageNotFound() *Error { return New(CodeImageNotFound, http.StatusNotFound, "Image not found") } func LogoDownloadFailed(cause error) *Error { return Wrap(cause, CodeLogoDownloadFailed, http.StatusUnprocessableEntity, "Logo could not be downloaded") } func LogoTypeNotSupported() *Error { return New(CodeLogoTypeNotSupported, http.StatusUnprocessableEntity, "Downloaded logo has an unsupported file type") } func LogoTooLarge(maxSize string) *Error { return New(CodeLogoTooLarge, http.StatusUnprocessableEntity, fmt.Sprintf("Downloaded logo must not exceed %s", maxSize)). WithDetail("max_size", maxSize) } func InvalidLogoURL(cause error) *Error { return Wrap(cause, CodeValidationFailed, http.StatusBadRequest, "Logo URL is not allowed").WithFields([]FieldError{{ Field: "logoUrl", Code: "invalid_value", Message: "must be a public HTTP or HTTPS URL", }}) } func OidcPARRequired() *Error { return New(CodeOidcPARRequired, http.StatusBadRequest, "This client requires pushed authorization requests") } func InvalidEmailVerificationToken() *Error { return New(CodeEmailVerificationTokenInvalid, http.StatusBadRequest, "Email verification token is invalid") }