aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/letsencrypt/boulder/probs/probs.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/letsencrypt/boulder/probs/probs.go')
-rw-r--r--vendor/github.com/letsencrypt/boulder/probs/probs.go349
1 files changed, 349 insertions, 0 deletions
diff --git a/vendor/github.com/letsencrypt/boulder/probs/probs.go b/vendor/github.com/letsencrypt/boulder/probs/probs.go
new file mode 100644
index 000000000..3736e8d39
--- /dev/null
+++ b/vendor/github.com/letsencrypt/boulder/probs/probs.go
@@ -0,0 +1,349 @@
+package probs
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/letsencrypt/boulder/identifier"
+)
+
+// Error types that can be used in ACME payloads
+const (
+ ConnectionProblem = ProblemType("connection")
+ MalformedProblem = ProblemType("malformed")
+ ServerInternalProblem = ProblemType("serverInternal")
+ TLSProblem = ProblemType("tls")
+ UnauthorizedProblem = ProblemType("unauthorized")
+ RateLimitedProblem = ProblemType("rateLimited")
+ BadNonceProblem = ProblemType("badNonce")
+ InvalidEmailProblem = ProblemType("invalidEmail")
+ RejectedIdentifierProblem = ProblemType("rejectedIdentifier")
+ AccountDoesNotExistProblem = ProblemType("accountDoesNotExist")
+ CAAProblem = ProblemType("caa")
+ DNSProblem = ProblemType("dns")
+ AlreadyRevokedProblem = ProblemType("alreadyRevoked")
+ OrderNotReadyProblem = ProblemType("orderNotReady")
+ BadSignatureAlgorithmProblem = ProblemType("badSignatureAlgorithm")
+ BadPublicKeyProblem = ProblemType("badPublicKey")
+ BadRevocationReasonProblem = ProblemType("badRevocationReason")
+ BadCSRProblem = ProblemType("badCSR")
+
+ V1ErrorNS = "urn:acme:error:"
+ V2ErrorNS = "urn:ietf:params:acme:error:"
+)
+
+// ProblemType defines the error types in the ACME protocol
+type ProblemType string
+
+// ProblemDetails objects represent problem documents
+// https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00
+type ProblemDetails struct {
+ Type ProblemType `json:"type,omitempty"`
+ Detail string `json:"detail,omitempty"`
+ // HTTPStatus is the HTTP status code the ProblemDetails should probably be sent
+ // as.
+ HTTPStatus int `json:"status,omitempty"`
+ // SubProblems are optional additional per-identifier problems. See
+ // RFC 8555 Section 6.7.1: https://tools.ietf.org/html/rfc8555#section-6.7.1
+ SubProblems []SubProblemDetails `json:"subproblems,omitempty"`
+}
+
+// SubProblemDetails represents sub-problems specific to an identifier that are
+// related to a top-level ProblemDetails.
+// See RFC 8555 Section 6.7.1: https://tools.ietf.org/html/rfc8555#section-6.7.1
+type SubProblemDetails struct {
+ ProblemDetails
+ Identifier identifier.ACMEIdentifier `json:"identifier"`
+}
+
+func (pd *ProblemDetails) Error() string {
+ return fmt.Sprintf("%s :: %s", pd.Type, pd.Detail)
+}
+
+// WithSubProblems returns a new ProblemsDetails instance created by adding the
+// provided subProbs to the existing ProblemsDetail.
+func (pd *ProblemDetails) WithSubProblems(subProbs []SubProblemDetails) *ProblemDetails {
+ return &ProblemDetails{
+ Type: pd.Type,
+ Detail: pd.Detail,
+ HTTPStatus: pd.HTTPStatus,
+ SubProblems: append(pd.SubProblems, subProbs...),
+ }
+}
+
+// statusTooManyRequests is the HTTP status code meant for rate limiting
+// errors. It's not currently in the net/http library so we add it here.
+const statusTooManyRequests = 429
+
+// ProblemDetailsToStatusCode inspects the given ProblemDetails to figure out
+// what HTTP status code it should represent. It should only be used by the WFE
+// but is included in this package because of its reliance on ProblemTypes.
+func ProblemDetailsToStatusCode(prob *ProblemDetails) int {
+ if prob.HTTPStatus != 0 {
+ return prob.HTTPStatus
+ }
+ switch prob.Type {
+ case
+ ConnectionProblem,
+ MalformedProblem,
+ BadSignatureAlgorithmProblem,
+ BadPublicKeyProblem,
+ TLSProblem,
+ BadNonceProblem,
+ InvalidEmailProblem,
+ RejectedIdentifierProblem,
+ AccountDoesNotExistProblem,
+ BadRevocationReasonProblem:
+ return http.StatusBadRequest
+ case ServerInternalProblem:
+ return http.StatusInternalServerError
+ case
+ UnauthorizedProblem,
+ CAAProblem:
+ return http.StatusForbidden
+ case RateLimitedProblem:
+ return statusTooManyRequests
+ default:
+ return http.StatusInternalServerError
+ }
+}
+
+// BadNonce returns a ProblemDetails with a BadNonceProblem and a 400 Bad
+// Request status code.
+func BadNonce(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: BadNonceProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// RejectedIdentifier returns a ProblemDetails with a RejectedIdentifierProblem and a 400 Bad
+// Request status code.
+func RejectedIdentifier(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: RejectedIdentifierProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// Conflict returns a ProblemDetails with a MalformedProblem and a 409 Conflict
+// status code.
+func Conflict(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusConflict,
+ }
+}
+
+// AlreadyRevoked returns a ProblemDetails with a AlreadyRevokedProblem and a 400 Bad
+// Request status code.
+func AlreadyRevoked(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: AlreadyRevokedProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// Malformed returns a ProblemDetails with a MalformedProblem and a 400 Bad
+// Request status code.
+func Malformed(detail string, args ...interface{}) *ProblemDetails {
+ if len(args) > 0 {
+ detail = fmt.Sprintf(detail, args...)
+ }
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// Canceled returns a ProblemDetails with a MalformedProblem and a 408 Request
+// Timeout status code.
+func Canceled(detail string, args ...interface{}) *ProblemDetails {
+ if len(args) > 0 {
+ detail = fmt.Sprintf(detail, args...)
+ }
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusRequestTimeout,
+ }
+}
+
+// BadSignatureAlgorithm returns a ProblemDetails with a BadSignatureAlgorithmProblem
+// and a 400 Bad Request status code.
+func BadSignatureAlgorithm(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: BadSignatureAlgorithmProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// BadPublicKey returns a ProblemDetails with a BadPublicKeyProblem and a 400 Bad
+// Request status code.
+func BadPublicKey(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: BadPublicKeyProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// NotFound returns a ProblemDetails with a MalformedProblem and a 404 Not Found
+// status code.
+func NotFound(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusNotFound,
+ }
+}
+
+// ServerInternal returns a ProblemDetails with a ServerInternalProblem and a
+// 500 Internal Server Failure status code.
+func ServerInternal(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: ServerInternalProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusInternalServerError,
+ }
+}
+
+// Unauthorized returns a ProblemDetails with an UnauthorizedProblem and a 403
+// Forbidden status code.
+func Unauthorized(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: UnauthorizedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusForbidden,
+ }
+}
+
+// MethodNotAllowed returns a ProblemDetails representing a disallowed HTTP
+// method error.
+func MethodNotAllowed() *ProblemDetails {
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: "Method not allowed",
+ HTTPStatus: http.StatusMethodNotAllowed,
+ }
+}
+
+// ContentLengthRequired returns a ProblemDetails representing a missing
+// Content-Length header error
+func ContentLengthRequired() *ProblemDetails {
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: "missing Content-Length header",
+ HTTPStatus: http.StatusLengthRequired,
+ }
+}
+
+// InvalidContentType returns a ProblemDetails suitable for a missing
+// ContentType header, or an incorrect ContentType header
+func InvalidContentType(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: MalformedProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusUnsupportedMediaType,
+ }
+}
+
+// InvalidEmail returns a ProblemDetails representing an invalid email address
+// error
+func InvalidEmail(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: InvalidEmailProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// ConnectionFailure returns a ProblemDetails representing a ConnectionProblem
+// error
+func ConnectionFailure(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: ConnectionProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// RateLimited returns a ProblemDetails representing a RateLimitedProblem error
+func RateLimited(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: RateLimitedProblem,
+ Detail: detail,
+ HTTPStatus: statusTooManyRequests,
+ }
+}
+
+// TLSError returns a ProblemDetails representing a TLSProblem error
+func TLSError(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: TLSProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// AccountDoesNotExist returns a ProblemDetails representing an
+// AccountDoesNotExistProblem error
+func AccountDoesNotExist(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: AccountDoesNotExistProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// CAA returns a ProblemDetails representing a CAAProblem
+func CAA(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: CAAProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusForbidden,
+ }
+}
+
+// DNS returns a ProblemDetails representing a DNSProblem
+func DNS(detail string) *ProblemDetails {
+ return &ProblemDetails{
+ Type: DNSProblem,
+ Detail: detail,
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// OrderNotReady returns a ProblemDetails representing a OrderNotReadyProblem
+func OrderNotReady(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: OrderNotReadyProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusForbidden,
+ }
+}
+
+// BadRevocationReason returns a ProblemDetails representing
+// a BadRevocationReasonProblem
+func BadRevocationReason(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: BadRevocationReasonProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusBadRequest,
+ }
+}
+
+// BadCSR returns a ProblemDetails representing a BadCSRProblem.
+func BadCSR(detail string, a ...interface{}) *ProblemDetails {
+ return &ProblemDetails{
+ Type: BadCSRProblem,
+ Detail: fmt.Sprintf(detail, a...),
+ HTTPStatus: http.StatusBadRequest,
+ }
+}