1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17
18
19
20 import (
21 "reflect"
22 "strconv"
23 "strings"
24
25 "github.com/go-openapi/errors"
26 "github.com/go-openapi/spec"
27 )
28
29 const (
30 swaggerBody = "body"
31 swaggerExample = "example"
32 swaggerExamples = "examples"
33 )
34
35 const (
36 objectType = "object"
37 arrayType = "array"
38 stringType = "string"
39 integerType = "integer"
40 numberType = "number"
41 booleanType = "boolean"
42 fileType = "file"
43 nullType = "null"
44 )
45
46 const (
47 jsonProperties = "properties"
48 jsonItems = "items"
49 jsonType = "type"
50
51 jsonDefault = "default"
52 )
53
54 const (
55 stringFormatDate = "date"
56 stringFormatDateTime = "date-time"
57 stringFormatPassword = "password"
58 stringFormatByte = "byte"
59
60 stringFormatCreditCard = "creditcard"
61 stringFormatDuration = "duration"
62 stringFormatEmail = "email"
63 stringFormatHexColor = "hexcolor"
64 stringFormatHostname = "hostname"
65 stringFormatIPv4 = "ipv4"
66 stringFormatIPv6 = "ipv6"
67 stringFormatISBN = "isbn"
68 stringFormatISBN10 = "isbn10"
69 stringFormatISBN13 = "isbn13"
70 stringFormatMAC = "mac"
71 stringFormatBSONObjectID = "bsonobjectid"
72 stringFormatRGBColor = "rgbcolor"
73 stringFormatSSN = "ssn"
74 stringFormatURI = "uri"
75 stringFormatUUID = "uuid"
76 stringFormatUUID3 = "uuid3"
77 stringFormatUUID4 = "uuid4"
78 stringFormatUUID5 = "uuid5"
79
80 integerFormatInt32 = "int32"
81 integerFormatInt64 = "int64"
82 integerFormatUInt32 = "uint32"
83 integerFormatUInt64 = "uint64"
84
85 numberFormatFloat32 = "float32"
86 numberFormatFloat64 = "float64"
87 numberFormatFloat = "float"
88 numberFormatDouble = "double"
89 )
90
91
92 var (
93 pathHelp *pathHelper
94 valueHelp *valueHelper
95 errorHelp *errorHelper
96 paramHelp *paramHelper
97 responseHelp *responseHelper
98 )
99
100 type errorHelper struct {
101
102 }
103
104 func (h *errorHelper) sErr(err errors.Error, recycle bool) *Result {
105
106 var result *Result
107 if recycle {
108 result = pools.poolOfResults.BorrowResult()
109 } else {
110 result = new(Result)
111 }
112 result.Errors = []error{err}
113
114 return result
115 }
116
117 func (h *errorHelper) addPointerError(res *Result, err error, ref string, fromPath string) *Result {
118
119
120 if err != nil {
121 res.AddErrors(cannotResolveRefMsg(fromPath, ref, err))
122 }
123 return res
124 }
125
126 type pathHelper struct {
127
128 }
129
130 func (h *pathHelper) stripParametersInPath(path string) string {
131
132
133
134
135
136
137
138
139 rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`)
140 strippedSegments := []string{}
141
142 for _, segment := range strings.Split(path, "/") {
143 strippedSegments = append(strippedSegments, rexParsePathParam.ReplaceAllString(segment, "X"))
144 }
145 return strings.Join(strippedSegments, "/")
146 }
147
148 func (h *pathHelper) extractPathParams(path string) (params []string) {
149
150 rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`)
151
152 for _, segment := range strings.Split(path, "/") {
153 for _, v := range rexParsePathParam.FindAllStringSubmatch(segment, -1) {
154 params = append(params, v...)
155 }
156 }
157 return
158 }
159
160 type valueHelper struct {
161
162 }
163
164 func (h *valueHelper) asInt64(val interface{}) int64 {
165
166
167 v := reflect.ValueOf(val)
168 switch v.Kind() {
169 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
170 return v.Int()
171 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
172 return int64(v.Uint())
173 case reflect.Float32, reflect.Float64:
174 return int64(v.Float())
175 default:
176
177 return 0
178 }
179 }
180
181 func (h *valueHelper) asUint64(val interface{}) uint64 {
182
183
184 v := reflect.ValueOf(val)
185 switch v.Kind() {
186 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
187 return uint64(v.Int())
188 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
189 return v.Uint()
190 case reflect.Float32, reflect.Float64:
191 return uint64(v.Float())
192 default:
193
194 return 0
195 }
196 }
197
198
199 func (h *valueHelper) asFloat64(val interface{}) float64 {
200
201
202 v := reflect.ValueOf(val)
203 switch v.Kind() {
204 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
205 return float64(v.Int())
206 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
207 return float64(v.Uint())
208 case reflect.Float32, reflect.Float64:
209 return v.Float()
210 default:
211
212 return 0
213 }
214 }
215
216 type paramHelper struct {
217
218 }
219
220 func (h *paramHelper) safeExpandedParamsFor(path, method, operationID string, res *Result, s *SpecValidator) (params []spec.Parameter) {
221 operation, ok := s.expandedAnalyzer().OperationFor(method, path)
222 if ok {
223
224 resolvedParams := []spec.Parameter{}
225 for _, ppr := range operation.Parameters {
226 resolvedParam, red := h.resolveParam(path, method, operationID, &ppr, s)
227 res.Merge(red)
228 if resolvedParam != nil {
229 resolvedParams = append(resolvedParams, *resolvedParam)
230 }
231 }
232
233 operation.Parameters = resolvedParams
234
235 for _, ppr := range s.expandedAnalyzer().SafeParamsFor(method, path,
236 func(_ spec.Parameter, err error) bool {
237
238 res.AddErrors(someParametersBrokenMsg(path, method, operationID))
239
240 res.AddErrors(err)
241 return true
242 }) {
243 params = append(params, ppr)
244 }
245 }
246 return
247 }
248
249 func (h *paramHelper) resolveParam(path, method, operationID string, param *spec.Parameter, s *SpecValidator) (*spec.Parameter, *Result) {
250
251 var err error
252 res := new(Result)
253 isRef := param.Ref.String() != ""
254 if s.spec.SpecFilePath() == "" {
255 err = spec.ExpandParameterWithRoot(param, s.spec.Spec(), nil)
256 } else {
257 err = spec.ExpandParameter(param, s.spec.SpecFilePath())
258
259 }
260 if err != nil {
261
262 refPath := strings.Join([]string{"\"" + path + "\"", method}, ".")
263 errorHelp.addPointerError(res, err, param.Ref.String(), refPath)
264 return nil, res
265 }
266 res.Merge(h.checkExpandedParam(param, param.Name, param.In, operationID, isRef))
267 return param, res
268 }
269
270 func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation string, isRef bool) *Result {
271
272 res := new(Result)
273 simpleZero := spec.SimpleSchema{}
274
275 switch {
276 case pr.In == swaggerBody && (pr.SimpleSchema != simpleZero && pr.SimpleSchema.Type != objectType):
277 if isRef {
278
279
280
281 res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
282 }
283 res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
284 case pr.In != swaggerBody && pr.Schema != nil:
285 if isRef {
286 res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
287 }
288 res.AddErrors(invalidParameterDefinitionAsSchemaMsg(path, in, operation))
289 case (pr.In == swaggerBody && pr.Schema == nil) || (pr.In != swaggerBody && pr.SimpleSchema == simpleZero):
290
291 res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
292 }
293 return res
294 }
295
296 type responseHelper struct {
297
298 }
299
300 func (r *responseHelper) expandResponseRef(
301 response *spec.Response,
302 path string, s *SpecValidator) (*spec.Response, *Result) {
303
304 var err error
305 res := new(Result)
306 if s.spec.SpecFilePath() == "" {
307
308 err = spec.ExpandResponseWithRoot(response, s.spec.Spec(), nil)
309 } else {
310 err = spec.ExpandResponse(response, s.spec.SpecFilePath())
311 }
312 if err != nil {
313
314 errorHelp.addPointerError(res, err, response.Ref.String(), path)
315 return nil, res
316 }
317
318 return response, res
319 }
320
321 func (r *responseHelper) responseMsgVariants(
322 responseType string,
323 responseCode int) (responseName, responseCodeAsStr string) {
324
325 if responseType == jsonDefault {
326 responseCodeAsStr = jsonDefault
327 responseName = "default response"
328 } else {
329 responseCodeAsStr = strconv.Itoa(responseCode)
330 responseName = "response " + responseCodeAsStr
331 }
332 return
333 }
334
View as plain text