1 package probs
2
3 import (
4 "fmt"
5 "net/http"
6
7 "github.com/letsencrypt/boulder/identifier"
8 )
9
10 const (
11
12
13
14
15 AccountDoesNotExistProblem = ProblemType("accountDoesNotExist")
16 AlreadyRevokedProblem = ProblemType("alreadyRevoked")
17 BadCSRProblem = ProblemType("badCSR")
18 BadNonceProblem = ProblemType("badNonce")
19 BadPublicKeyProblem = ProblemType("badPublicKey")
20 BadRevocationReasonProblem = ProblemType("badRevocationReason")
21 BadSignatureAlgorithmProblem = ProblemType("badSignatureAlgorithm")
22 CAAProblem = ProblemType("caa")
23 ConnectionProblem = ProblemType("connection")
24 DNSProblem = ProblemType("dns")
25 InvalidContactProblem = ProblemType("invalidContact")
26 MalformedProblem = ProblemType("malformed")
27 OrderNotReadyProblem = ProblemType("orderNotReady")
28 RateLimitedProblem = ProblemType("rateLimited")
29 RejectedIdentifierProblem = ProblemType("rejectedIdentifier")
30 ServerInternalProblem = ProblemType("serverInternal")
31 TLSProblem = ProblemType("tls")
32 UnauthorizedProblem = ProblemType("unauthorized")
33 UnsupportedContactProblem = ProblemType("unsupportedContact")
34 UnsupportedIdentifierProblem = ProblemType("unsupportedIdentifier")
35
36 ErrorNS = "urn:ietf:params:acme:error:"
37 )
38
39
40 type ProblemType string
41
42
43
44 type ProblemDetails struct {
45 Type ProblemType `json:"type,omitempty"`
46 Detail string `json:"detail,omitempty"`
47
48
49 HTTPStatus int `json:"status,omitempty"`
50
51
52 SubProblems []SubProblemDetails `json:"subproblems,omitempty"`
53 }
54
55
56
57
58 type SubProblemDetails struct {
59 ProblemDetails
60 Identifier identifier.ACMEIdentifier `json:"identifier"`
61 }
62
63 func (pd *ProblemDetails) Error() string {
64 return fmt.Sprintf("%s :: %s", pd.Type, pd.Detail)
65 }
66
67
68
69 func (pd *ProblemDetails) WithSubProblems(subProbs []SubProblemDetails) *ProblemDetails {
70 return &ProblemDetails{
71 Type: pd.Type,
72 Detail: pd.Detail,
73 HTTPStatus: pd.HTTPStatus,
74 SubProblems: append(pd.SubProblems, subProbs...),
75 }
76 }
77
78
79
80
81
82
83 func AccountDoesNotExist(detail string) *ProblemDetails {
84 return &ProblemDetails{
85 Type: AccountDoesNotExistProblem,
86 Detail: detail,
87 HTTPStatus: http.StatusBadRequest,
88 }
89 }
90
91
92
93 func AlreadyRevoked(detail string, a ...any) *ProblemDetails {
94 return &ProblemDetails{
95 Type: AlreadyRevokedProblem,
96 Detail: fmt.Sprintf(detail, a...),
97 HTTPStatus: http.StatusBadRequest,
98 }
99 }
100
101
102 func BadCSR(detail string, a ...any) *ProblemDetails {
103 return &ProblemDetails{
104 Type: BadCSRProblem,
105 Detail: fmt.Sprintf(detail, a...),
106 HTTPStatus: http.StatusBadRequest,
107 }
108 }
109
110
111
112 func BadNonce(detail string) *ProblemDetails {
113 return &ProblemDetails{
114 Type: BadNonceProblem,
115 Detail: detail,
116 HTTPStatus: http.StatusBadRequest,
117 }
118 }
119
120
121
122 func BadPublicKey(detail string, a ...any) *ProblemDetails {
123 return &ProblemDetails{
124 Type: BadPublicKeyProblem,
125 Detail: fmt.Sprintf(detail, a...),
126 HTTPStatus: http.StatusBadRequest,
127 }
128 }
129
130
131
132 func BadRevocationReason(detail string, a ...any) *ProblemDetails {
133 return &ProblemDetails{
134 Type: BadRevocationReasonProblem,
135 Detail: fmt.Sprintf(detail, a...),
136 HTTPStatus: http.StatusBadRequest,
137 }
138 }
139
140
141
142 func BadSignatureAlgorithm(detail string, a ...any) *ProblemDetails {
143 return &ProblemDetails{
144 Type: BadSignatureAlgorithmProblem,
145 Detail: fmt.Sprintf(detail, a...),
146 HTTPStatus: http.StatusBadRequest,
147 }
148 }
149
150
151 func CAA(detail string) *ProblemDetails {
152 return &ProblemDetails{
153 Type: CAAProblem,
154 Detail: detail,
155 HTTPStatus: http.StatusForbidden,
156 }
157 }
158
159
160
161 func Connection(detail string) *ProblemDetails {
162 return &ProblemDetails{
163 Type: ConnectionProblem,
164 Detail: detail,
165 HTTPStatus: http.StatusBadRequest,
166 }
167 }
168
169
170 func DNS(detail string) *ProblemDetails {
171 return &ProblemDetails{
172 Type: DNSProblem,
173 Detail: detail,
174 HTTPStatus: http.StatusBadRequest,
175 }
176 }
177
178
179 func InvalidContact(detail string) *ProblemDetails {
180 return &ProblemDetails{
181 Type: InvalidContactProblem,
182 Detail: detail,
183 HTTPStatus: http.StatusBadRequest,
184 }
185 }
186
187
188
189 func Malformed(detail string, a ...any) *ProblemDetails {
190 if len(a) > 0 {
191 detail = fmt.Sprintf(detail, a...)
192 }
193 return &ProblemDetails{
194 Type: MalformedProblem,
195 Detail: detail,
196 HTTPStatus: http.StatusBadRequest,
197 }
198 }
199
200
201 func OrderNotReady(detail string, a ...any) *ProblemDetails {
202 return &ProblemDetails{
203 Type: OrderNotReadyProblem,
204 Detail: fmt.Sprintf(detail, a...),
205 HTTPStatus: http.StatusForbidden,
206 }
207 }
208
209
210 func RateLimited(detail string) *ProblemDetails {
211 return &ProblemDetails{
212 Type: RateLimitedProblem,
213 Detail: detail,
214 HTTPStatus: http.StatusTooManyRequests,
215 }
216 }
217
218
219
220 func RejectedIdentifier(detail string) *ProblemDetails {
221 return &ProblemDetails{
222 Type: RejectedIdentifierProblem,
223 Detail: detail,
224 HTTPStatus: http.StatusBadRequest,
225 }
226 }
227
228
229
230 func ServerInternal(detail string) *ProblemDetails {
231 return &ProblemDetails{
232 Type: ServerInternalProblem,
233 Detail: detail,
234 HTTPStatus: http.StatusInternalServerError,
235 }
236 }
237
238
239 func TLS(detail string) *ProblemDetails {
240 return &ProblemDetails{
241 Type: TLSProblem,
242 Detail: detail,
243 HTTPStatus: http.StatusBadRequest,
244 }
245 }
246
247
248
249 func Unauthorized(detail string) *ProblemDetails {
250 return &ProblemDetails{
251 Type: UnauthorizedProblem,
252 Detail: detail,
253 HTTPStatus: http.StatusForbidden,
254 }
255 }
256
257
258
259 func UnsupportedContact(detail string) *ProblemDetails {
260 return &ProblemDetails{
261 Type: UnsupportedContactProblem,
262 Detail: detail,
263 HTTPStatus: http.StatusBadRequest,
264 }
265 }
266
267
268
269 func UnsupportedIdentifier(detail string, a ...any) *ProblemDetails {
270 return &ProblemDetails{
271 Type: UnsupportedIdentifierProblem,
272 Detail: fmt.Sprintf(detail, a...),
273 HTTPStatus: http.StatusBadRequest,
274 }
275 }
276
277
278
279
280
281
282 func Canceled(detail string, a ...any) *ProblemDetails {
283 if len(a) > 0 {
284 detail = fmt.Sprintf(detail, a...)
285 }
286 return &ProblemDetails{
287 Type: MalformedProblem,
288 Detail: detail,
289 HTTPStatus: http.StatusRequestTimeout,
290 }
291 }
292
293
294
295 func Conflict(detail string) *ProblemDetails {
296 return &ProblemDetails{
297 Type: MalformedProblem,
298 Detail: detail,
299 HTTPStatus: http.StatusConflict,
300 }
301 }
302
303
304
305 func ContentLengthRequired() *ProblemDetails {
306 return &ProblemDetails{
307 Type: MalformedProblem,
308 Detail: "missing Content-Length header",
309 HTTPStatus: http.StatusLengthRequired,
310 }
311 }
312
313
314
315 func InvalidContentType(detail string) *ProblemDetails {
316 return &ProblemDetails{
317 Type: MalformedProblem,
318 Detail: detail,
319 HTTPStatus: http.StatusUnsupportedMediaType,
320 }
321 }
322
323
324
325 func MethodNotAllowed() *ProblemDetails {
326 return &ProblemDetails{
327 Type: MalformedProblem,
328 Detail: "Method not allowed",
329 HTTPStatus: http.StatusMethodNotAllowed,
330 }
331 }
332
333
334
335 func NotFound(detail string) *ProblemDetails {
336 return &ProblemDetails{
337 Type: MalformedProblem,
338 Detail: detail,
339 HTTPStatus: http.StatusNotFound,
340 }
341 }
342
View as plain text