...

Source file src/github.com/letsencrypt/boulder/errors/errors.go

Documentation: github.com/letsencrypt/boulder/errors

     1  // Package errors provides internal-facing error types for use in Boulder. Many
     2  // of these are transformed directly into Problem Details documents by the WFE.
     3  // Some, like NotFound, may be handled internally. We avoid using Problem
     4  // Details documents as part of our internal error system to avoid layering
     5  // confusions.
     6  //
     7  // These errors are specifically for use in errors that cross RPC boundaries.
     8  // An error type that does not need to be passed through an RPC can use a plain
     9  // Go type locally. Our gRPC code is aware of these error types and will
    10  // serialize and deserialize them automatically.
    11  package errors
    12  
    13  import (
    14  	"fmt"
    15  	"time"
    16  
    17  	"github.com/letsencrypt/boulder/identifier"
    18  	"google.golang.org/grpc/codes"
    19  	"google.golang.org/grpc/status"
    20  )
    21  
    22  // ErrorType provides a coarse category for BoulderErrors.
    23  // Objects of type ErrorType should never be directly returned by other
    24  // functions; instead use the methods below to create an appropriate
    25  // BoulderError wrapping one of these types.
    26  type ErrorType int
    27  
    28  // These numeric constants are used when sending berrors through gRPC.
    29  const (
    30  	// InternalServer is deprecated. Instead, pass a plain Go error. That will get
    31  	// turned into a probs.InternalServerError by the WFE.
    32  	InternalServer ErrorType = iota
    33  	_
    34  	Malformed
    35  	Unauthorized
    36  	NotFound
    37  	RateLimit
    38  	RejectedIdentifier
    39  	InvalidEmail
    40  	ConnectionFailure
    41  	_ // Reserved, previously WrongAuthorizationState
    42  	CAA
    43  	MissingSCTs
    44  	Duplicate
    45  	OrderNotReady
    46  	DNS
    47  	BadPublicKey
    48  	BadCSR
    49  	AlreadyRevoked
    50  	BadRevocationReason
    51  	UnsupportedContact
    52  	// The requesteed serial number does not exist in the `serials` table.
    53  	UnknownSerial
    54  )
    55  
    56  func (ErrorType) Error() string {
    57  	return "urn:ietf:params:acme:error"
    58  }
    59  
    60  // BoulderError represents internal Boulder errors
    61  type BoulderError struct {
    62  	Type      ErrorType
    63  	Detail    string
    64  	SubErrors []SubBoulderError
    65  
    66  	// RetryAfter the duration a client should wait before retrying the request
    67  	// which resulted in this error.
    68  	RetryAfter time.Duration
    69  }
    70  
    71  // SubBoulderError represents sub-errors specific to an identifier that are
    72  // related to a top-level internal Boulder error.
    73  type SubBoulderError struct {
    74  	*BoulderError
    75  	Identifier identifier.ACMEIdentifier
    76  }
    77  
    78  func (be *BoulderError) Error() string {
    79  	return be.Detail
    80  }
    81  
    82  func (be *BoulderError) Unwrap() error {
    83  	return be.Type
    84  }
    85  
    86  // GRPCStatus implements the interface implicitly defined by gRPC's
    87  // status.FromError, which uses this function to detect if the error produced
    88  // by the gRPC server implementation code is a gRPC status.Status. Implementing
    89  // this means that BoulderErrors serialized in gRPC response metadata can be
    90  // accompanied by a gRPC status other than "UNKNOWN".
    91  func (be *BoulderError) GRPCStatus() *status.Status {
    92  	var c codes.Code
    93  	switch be.Type {
    94  	case InternalServer:
    95  		c = codes.Internal
    96  	case Malformed:
    97  		c = codes.InvalidArgument
    98  	case Unauthorized:
    99  		c = codes.PermissionDenied
   100  	case NotFound:
   101  		c = codes.NotFound
   102  	case RateLimit:
   103  		c = codes.Unknown
   104  	case RejectedIdentifier:
   105  		c = codes.InvalidArgument
   106  	case InvalidEmail:
   107  		c = codes.InvalidArgument
   108  	case ConnectionFailure:
   109  		c = codes.Unavailable
   110  	case CAA:
   111  		c = codes.FailedPrecondition
   112  	case MissingSCTs:
   113  		c = codes.Internal
   114  	case Duplicate:
   115  		c = codes.AlreadyExists
   116  	case OrderNotReady:
   117  		c = codes.FailedPrecondition
   118  	case DNS:
   119  		c = codes.Unknown
   120  	case BadPublicKey:
   121  		c = codes.InvalidArgument
   122  	case BadCSR:
   123  		c = codes.InvalidArgument
   124  	case AlreadyRevoked:
   125  		c = codes.AlreadyExists
   126  	case BadRevocationReason:
   127  		c = codes.InvalidArgument
   128  	case UnsupportedContact:
   129  		c = codes.InvalidArgument
   130  	default:
   131  		c = codes.Unknown
   132  	}
   133  	return status.New(c, be.Error())
   134  }
   135  
   136  // WithSubErrors returns a new BoulderError instance created by adding the
   137  // provided subErrs to the existing BoulderError.
   138  func (be *BoulderError) WithSubErrors(subErrs []SubBoulderError) *BoulderError {
   139  	return &BoulderError{
   140  		Type:       be.Type,
   141  		Detail:     be.Detail,
   142  		SubErrors:  append(be.SubErrors, subErrs...),
   143  		RetryAfter: be.RetryAfter,
   144  	}
   145  }
   146  
   147  // New is a convenience function for creating a new BoulderError
   148  func New(errType ErrorType, msg string, args ...interface{}) error {
   149  	return &BoulderError{
   150  		Type:   errType,
   151  		Detail: fmt.Sprintf(msg, args...),
   152  	}
   153  }
   154  
   155  func InternalServerError(msg string, args ...interface{}) error {
   156  	return New(InternalServer, msg, args...)
   157  }
   158  
   159  func MalformedError(msg string, args ...interface{}) error {
   160  	return New(Malformed, msg, args...)
   161  }
   162  
   163  func UnauthorizedError(msg string, args ...interface{}) error {
   164  	return New(Unauthorized, msg, args...)
   165  }
   166  
   167  func NotFoundError(msg string, args ...interface{}) error {
   168  	return New(NotFound, msg, args...)
   169  }
   170  
   171  func RateLimitError(retryAfter time.Duration, msg string, args ...interface{}) error {
   172  	return &BoulderError{
   173  		Type:       RateLimit,
   174  		Detail:     fmt.Sprintf(msg+": see https://letsencrypt.org/docs/rate-limits/", args...),
   175  		RetryAfter: retryAfter,
   176  	}
   177  }
   178  
   179  func DuplicateCertificateError(retryAfter time.Duration, msg string, args ...interface{}) error {
   180  	return &BoulderError{
   181  		Type:       RateLimit,
   182  		Detail:     fmt.Sprintf(msg+": see https://letsencrypt.org/docs/duplicate-certificate-limit/", args...),
   183  		RetryAfter: retryAfter,
   184  	}
   185  }
   186  
   187  func FailedValidationError(retryAfter time.Duration, msg string, args ...interface{}) error {
   188  	return &BoulderError{
   189  		Type:       RateLimit,
   190  		Detail:     fmt.Sprintf(msg+": see https://letsencrypt.org/docs/failed-validation-limit/", args...),
   191  		RetryAfter: retryAfter,
   192  	}
   193  }
   194  
   195  func RegistrationsPerIPError(retryAfter time.Duration, msg string, args ...interface{}) error {
   196  	return &BoulderError{
   197  		Type:       RateLimit,
   198  		Detail:     fmt.Sprintf(msg+": see https://letsencrypt.org/docs/too-many-registrations-for-this-ip/", args...),
   199  		RetryAfter: retryAfter,
   200  	}
   201  }
   202  
   203  func RejectedIdentifierError(msg string, args ...interface{}) error {
   204  	return New(RejectedIdentifier, msg, args...)
   205  }
   206  
   207  func InvalidEmailError(msg string, args ...interface{}) error {
   208  	return New(InvalidEmail, msg, args...)
   209  }
   210  
   211  func UnsupportedContactError(msg string, args ...interface{}) error {
   212  	return New(UnsupportedContact, msg, args...)
   213  }
   214  
   215  func ConnectionFailureError(msg string, args ...interface{}) error {
   216  	return New(ConnectionFailure, msg, args...)
   217  }
   218  
   219  func CAAError(msg string, args ...interface{}) error {
   220  	return New(CAA, msg, args...)
   221  }
   222  
   223  func MissingSCTsError(msg string, args ...interface{}) error {
   224  	return New(MissingSCTs, msg, args...)
   225  }
   226  
   227  func DuplicateError(msg string, args ...interface{}) error {
   228  	return New(Duplicate, msg, args...)
   229  }
   230  
   231  func OrderNotReadyError(msg string, args ...interface{}) error {
   232  	return New(OrderNotReady, msg, args...)
   233  }
   234  
   235  func DNSError(msg string, args ...interface{}) error {
   236  	return New(DNS, msg, args...)
   237  }
   238  
   239  func BadPublicKeyError(msg string, args ...interface{}) error {
   240  	return New(BadPublicKey, msg, args...)
   241  }
   242  
   243  func BadCSRError(msg string, args ...interface{}) error {
   244  	return New(BadCSR, msg, args...)
   245  }
   246  
   247  func AlreadyRevokedError(msg string, args ...interface{}) error {
   248  	return New(AlreadyRevoked, msg, args...)
   249  }
   250  
   251  func BadRevocationReasonError(reason int64) error {
   252  	return New(BadRevocationReason, "disallowed revocation reason: %d", reason)
   253  }
   254  
   255  func UnknownSerialError() error {
   256  	return New(UnknownSerial, "unknown serial")
   257  }
   258  

View as plain text