...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package api
17
18 import (
19 "fmt"
20 "net/http"
21 "regexp"
22
23 "github.com/go-openapi/runtime/middleware"
24 "github.com/go-openapi/strfmt"
25 "github.com/mitchellh/mapstructure"
26
27 "github.com/sigstore/rekor/pkg/generated/models"
28 "github.com/sigstore/rekor/pkg/generated/restapi/operations/entries"
29 "github.com/sigstore/rekor/pkg/generated/restapi/operations/index"
30 "github.com/sigstore/rekor/pkg/generated/restapi/operations/pubkey"
31 "github.com/sigstore/rekor/pkg/generated/restapi/operations/tlog"
32 "github.com/sigstore/rekor/pkg/log"
33 )
34
35 const (
36 trillianCommunicationError = "unexpected error communicating with transparency log"
37 trillianUnexpectedResult = "unexpected result from transparency log"
38 validationError = "error processing entry: %v"
39 failedToGenerateCanonicalEntry = "error generating canonicalized entry"
40 entryAlreadyExists = "an equivalent entry already exists in the transparency log with UUID %v"
41 firstSizeLessThanLastSize = "firstSize(%d) must be less than lastSize(%d)"
42 malformedUUID = "UUID must be a 64-character hexadecimal string"
43 malformedPublicKey = "public key provided could not be parsed"
44 failedToGenerateCanonicalKey = "error generating canonicalized public key"
45 indexStorageUnexpectedResult = "unexpected result from searching index"
46 lastSizeGreaterThanKnown = "the tree size requested(%d) was greater than what is currently observable(%d)"
47 signingError = "error signing"
48 sthGenerateError = "error generating signed tree head"
49 unsupportedPKIFormat = "the PKI format requested is not supported by this server"
50 unexpectedInactiveShardError = "unexpected error communicating with inactive shard"
51 maxSearchQueryLimit = "more than max allowed %d entries in request"
52 )
53
54 func errorMsg(message string, code int) *models.Error {
55 return &models.Error{
56 Code: int64(code),
57 Message: message,
58 }
59 }
60
61 func handleRekorAPIError(params interface{}, code int, err error, message string, fields ...interface{}) middleware.Responder {
62 if message == "" {
63 message = http.StatusText(code)
64 }
65
66 re := regexp.MustCompile("^(.*)Params$")
67 typeStr := fmt.Sprintf("%T", params)
68 handler := re.FindStringSubmatch(typeStr)[1]
69
70 logMsg := func(r *http.Request) {
71 ctx := r.Context()
72 fields := append([]interface{}{"handler", handler, "statusCode", code, "clientMessage", message}, fields...)
73 if code >= 500 {
74 log.ContextLogger(ctx).Errorw(err.Error(), fields...)
75 } else {
76 log.ContextLogger(ctx).Warnw(err.Error(), fields...)
77 }
78 paramsFields := map[string]interface{}{}
79 if err := mapstructure.Decode(params, ¶msFields); err == nil {
80 log.ContextLogger(ctx).Debug(paramsFields)
81 }
82 }
83
84 switch params := params.(type) {
85 case entries.GetLogEntryByIndexParams:
86 logMsg(params.HTTPRequest)
87 switch code {
88 case http.StatusNotFound:
89 return entries.NewGetLogEntryByIndexNotFound()
90 default:
91 return entries.NewGetLogEntryByIndexDefault(code).WithPayload(errorMsg(message, code))
92 }
93 case entries.GetLogEntryByUUIDParams:
94 logMsg(params.HTTPRequest)
95 switch code {
96 case http.StatusNotFound:
97 return entries.NewGetLogEntryByUUIDNotFound()
98 default:
99 return entries.NewGetLogEntryByUUIDDefault(code).WithPayload(errorMsg(message, code))
100 }
101 case entries.CreateLogEntryParams:
102 switch code {
103
104 case http.StatusBadRequest:
105 logMsg(params.HTTPRequest)
106 return entries.NewCreateLogEntryBadRequest().WithPayload(errorMsg(message, code))
107 case http.StatusConflict:
108 resp := entries.NewCreateLogEntryConflict().WithPayload(errorMsg(message, code))
109 locationFound := false
110 for _, field := range fields {
111 if locationFound {
112 existingURL := field.(strfmt.URI)
113 resp.SetLocation(existingURL)
114 break
115 } else if field.(string) == "entryURL" {
116 locationFound = true
117 continue
118 }
119 }
120 return resp
121 default:
122 logMsg(params.HTTPRequest)
123 return entries.NewCreateLogEntryDefault(code).WithPayload(errorMsg(message, code))
124 }
125 case entries.SearchLogQueryParams:
126 logMsg(params.HTTPRequest)
127 switch code {
128 case http.StatusBadRequest:
129 return entries.NewSearchLogQueryBadRequest().WithPayload(errorMsg(message, code))
130 case http.StatusUnprocessableEntity:
131 return entries.NewSearchLogQueryUnprocessableEntity().WithPayload(errorMsg(message, code))
132 default:
133 return entries.NewSearchLogQueryDefault(code).WithPayload(errorMsg(message, code))
134 }
135 case tlog.GetLogInfoParams:
136 logMsg(params.HTTPRequest)
137 return tlog.NewGetLogInfoDefault(code).WithPayload(errorMsg(message, code))
138 case tlog.GetLogProofParams:
139 logMsg(params.HTTPRequest)
140 switch code {
141 case http.StatusBadRequest:
142 return tlog.NewGetLogProofBadRequest().WithPayload(errorMsg(message, code))
143 default:
144 return tlog.NewGetLogProofDefault(code).WithPayload(errorMsg(message, code))
145 }
146 case pubkey.GetPublicKeyParams:
147 logMsg(params.HTTPRequest)
148 return pubkey.NewGetPublicKeyDefault(code).WithPayload(errorMsg(message, code))
149 case index.SearchIndexParams:
150 logMsg(params.HTTPRequest)
151 switch code {
152 case http.StatusBadRequest:
153 return index.NewSearchIndexBadRequest().WithPayload(errorMsg(message, code))
154 default:
155 return index.NewSearchIndexDefault(code).WithPayload(errorMsg(message, code))
156 }
157 default:
158 log.Logger.Errorf("unable to find method for type %T; error: %v", params, err)
159 return middleware.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
160 }
161 }
162
View as plain text