errors.go raw
1 package acme
2
3 import (
4 "fmt"
5 "strings"
6 )
7
8 // Errors types.
9 const (
10 errNS = "urn:ietf:params:acme:error:"
11 BadNonceErr = errNS + "badNonce"
12 AlreadyReplacedErr = errNS + "alreadyReplaced"
13 RateLimitedErr = errNS + "rateLimited"
14 )
15
16 // ProblemDetails the problem details object.
17 // - https://www.rfc-editor.org/rfc/rfc7807.html#section-3.1
18 // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3.3
19 type ProblemDetails struct {
20 Type string `json:"type,omitempty"`
21 Detail string `json:"detail,omitempty"`
22 HTTPStatus int `json:"status,omitempty"`
23 Instance string `json:"instance,omitempty"`
24 SubProblems []SubProblem `json:"subproblems,omitempty"`
25
26 // additional values to have a better error message (Not defined by the RFC)
27 Method string `json:"method,omitempty"`
28 URL string `json:"url,omitempty"`
29 }
30
31 func (p *ProblemDetails) Error() string {
32 var msg strings.Builder
33
34 msg.WriteString(fmt.Sprintf("acme: error: %d", p.HTTPStatus))
35
36 if p.Method != "" || p.URL != "" {
37 msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Method, p.URL))
38 }
39
40 msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail))
41
42 for _, sub := range p.SubProblems {
43 msg.WriteString(fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail))
44 }
45
46 if p.Instance != "" {
47 msg.WriteString(", url: " + p.Instance)
48 }
49
50 return msg.String()
51 }
52
53 // SubProblem a "subproblems".
54 // - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.7.1
55 type SubProblem struct {
56 Type string `json:"type,omitempty"`
57 Detail string `json:"detail,omitempty"`
58 Identifier Identifier `json:"identifier"`
59 }
60
61 // NonceError represents the error which is returned
62 // if the nonce sent by the client was not accepted by the server.
63 type NonceError struct {
64 *ProblemDetails
65 }
66
67 func (e *NonceError) Unwrap() error {
68 return e.ProblemDetails
69 }
70
71 // AlreadyReplacedError represents the error which is returned
72 // if the Server rejects the request because the identified certificate has already been marked as replaced.
73 // - https://www.rfc-editor.org/rfc/rfc9773.html#section-5
74 type AlreadyReplacedError struct {
75 *ProblemDetails
76 }
77
78 func (e *AlreadyReplacedError) Unwrap() error {
79 return e.ProblemDetails
80 }
81
82 // RateLimitedError represents the error which is returned
83 // if the server rejects the request because the client has exceeded the rate limit.
84 // - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.6
85 type RateLimitedError struct {
86 *ProblemDetails
87
88 RetryAfter string
89 }
90
91 func (e *RateLimitedError) Unwrap() error {
92 return e.ProblemDetails
93 }
94