Add go-openapi dependencies and update Godeps
This commit is contained in:
1
vendor/github.com/go-openapi/validate/.drone.sec
generated
vendored
Normal file
1
vendor/github.com/go-openapi/validate/.drone.sec
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.lisG21ATunZSCBP6vaqK_AZCIR18tN563RdqkAb6PGOipqTeg8R7VwZQIeDqS-2Vond6NX_KSC_D_uxxv0hBf2DiGXmwMUmP4nRXrsmbzT2qQKKIHYRDC_6jb2-FSfK14ezIe1Q07UiiJecDsN3CFEccS8E68Tdnp78p7yDwbTvpumnZmwYfyhlImtjFQv2YpyFVsjEHWK0R4e9T3ONQWcx6D2rSoxABbutrS03QwsJhHCeD9joL_gxfkFKm3CW8yWPSk2QYtx_Q1hu-tZR4IPb2tQPXPX3mtyhwBqziWgmJRDFCEjlCO5aCobiMm_9K5X05gue_DcgW163zh1P9jg.nleER2An8CUn_OuR.b77RFEFp0gC8j5yCAoARNKYmQIvWq99ibmf5ffJgdhQBF3sRYJLt_XflJ_2lsaiFOxvc45T2fnkMVy2lHFcri7F9f1BRiT_0AcDthxsecGzG8BZ9QvaM6b4Dn0rhjrOq8rsF0m3ZnbPBkkg3LV5EkbHWstMo2fgJPJhJswlGWhqJPJBDecG1nMBC8SMH32X-zVlSM-BLiaghvOGNxyb_RLZJZ3CLczIdQ2JO2UeYkOGCPGzernvkHDMpqQXc-8cmulDdHgCy87qFLy5ttGFgYbnTm92h_ChOGKZixeX0PL0pQY5wXd2xTO7Tg_Ov5E5FoVwIkwOextedVsF9iz_b_mwtCY3LXrvbJTW7zWrwBVsVyAXxT5iu0HyQ3tBVxT2GxS-yM5ApqLozcZCQg9flMyfSgThu82FfzEr0fI5vKw8zo0GdO4GBuVSppM9m6ToG6hlwyHD9g2YTZw9068hyq1_kZQhugJRjgGbpa2gyGqzx16fg0zVoupVIiq5KfvRlAQFeOVVjQwb0BWf25tJUj5tV3O9ge6dbKSXizEca33FJJwJWoXhd7DCREXUU9pBz06NCCf495BGoVbq3oLPDQc2mpcuy0XAPxSwXcc5Ts8DNs7MrxBlYdw81wMXuztIpOY4.XjKlMWl_H40XszToi2VU5g
|
40
vendor/github.com/go-openapi/validate/.drone.yml
generated
vendored
Normal file
40
vendor/github.com/go-openapi/validate/.drone.yml
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
clone:
|
||||
path: github.com/go-openapi/validate
|
||||
|
||||
matrix:
|
||||
GO_VERSION:
|
||||
- "1.6"
|
||||
|
||||
build:
|
||||
integration:
|
||||
image: golang:$$GO_VERSION
|
||||
pull: true
|
||||
commands:
|
||||
- go get -u github.com/axw/gocov/gocov
|
||||
- go get -u gopkg.in/matm/v1/gocov-html
|
||||
- go get -u github.com/cee-dub/go-junit-report
|
||||
- go get -u github.com/stretchr/testify/assert
|
||||
- go get -u gopkg.in/yaml.v2
|
||||
- go get -u github.com/go-openapi/analysis
|
||||
- go get -u github.com/go-openapi/errors
|
||||
- go get -u github.com/go-openapi/loads
|
||||
- go get -u github.com/go-openapi/strfmt
|
||||
- go get -u github.com/go-openapi/runtime
|
||||
- go test -race
|
||||
- go test -v -cover -coverprofile=coverage.out -covermode=count
|
||||
|
||||
notify:
|
||||
slack:
|
||||
channel: bots
|
||||
webhook_url: $$SLACK_URL
|
||||
username: drone
|
||||
|
||||
publish:
|
||||
coverage:
|
||||
server: https://coverage.vmware.run
|
||||
token: $$GITHUB_TOKEN
|
||||
# threshold: 70
|
||||
# must_increase: true
|
||||
when:
|
||||
matrix:
|
||||
GO_VERSION: "1.6"
|
4
vendor/github.com/go-openapi/validate/.gitignore
generated
vendored
Normal file
4
vendor/github.com/go-openapi/validate/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
*.cov
|
||||
*.out
|
13
vendor/github.com/go-openapi/validate/.pullapprove.yml
generated
vendored
Normal file
13
vendor/github.com/go-openapi/validate/.pullapprove.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
approve_by_comment: true
|
||||
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
|
||||
reject_regex: ^[Rr]ejected
|
||||
reset_on_push: false
|
||||
reviewers:
|
||||
members:
|
||||
- casualjim
|
||||
- chancez
|
||||
- frapposelli
|
||||
- vburenin
|
||||
- pytlesk4
|
||||
name: pullapprove
|
||||
required: 1
|
74
vendor/github.com/go-openapi/validate/CODE_OF_CONDUCT.md
generated
vendored
Normal file
74
vendor/github.com/go-openapi/validate/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
202
vendor/github.com/go-openapi/validate/LICENSE
generated
vendored
Normal file
202
vendor/github.com/go-openapi/validate/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
3
vendor/github.com/go-openapi/validate/README.md
generated
vendored
Normal file
3
vendor/github.com/go-openapi/validate/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Validation helpers [](https://ci.vmware.run/go-openapi/validate) [](https://coverage.vmware.run/go-openapi/validate) [](https://slackin.goswagger.io)
|
||||
|
||||
[](https://raw.githubusercontent.com/go-openapi/validate/master/LICENSE) [](http://godoc.org/github.com/go-openapi/validate)
|
69
vendor/github.com/go-openapi/validate/formats.go
generated
vendored
Normal file
69
vendor/github.com/go-openapi/validate/formats.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
type formatValidator struct {
|
||||
Format string
|
||||
Path string
|
||||
In string
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func (f *formatValidator) SetPath(path string) {
|
||||
f.Path = path
|
||||
}
|
||||
|
||||
func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
doit := func() bool {
|
||||
if source == nil {
|
||||
return false
|
||||
}
|
||||
switch source.(type) {
|
||||
case *spec.Items:
|
||||
it := source.(*spec.Items)
|
||||
return kind == reflect.String && f.KnownFormats.ContainsName(it.Format)
|
||||
case *spec.Parameter:
|
||||
par := source.(*spec.Parameter)
|
||||
return kind == reflect.String && f.KnownFormats.ContainsName(par.Format)
|
||||
case *spec.Schema:
|
||||
sch := source.(*spec.Schema)
|
||||
return kind == reflect.String && f.KnownFormats.ContainsName(sch.Format)
|
||||
}
|
||||
return false
|
||||
}
|
||||
r := doit()
|
||||
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
|
||||
func (f *formatValidator) Validate(val interface{}) *Result {
|
||||
result := new(Result)
|
||||
|
||||
if err := FormatOf(f.Path, f.In, f.Format, val.(string), f.KnownFormats); err != nil {
|
||||
result.AddErrors(err)
|
||||
}
|
||||
|
||||
if result.HasErrors() {
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
151
vendor/github.com/go-openapi/validate/object_validator.go
generated
vendored
Normal file
151
vendor/github.com/go-openapi/validate/object_validator.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
type objectValidator struct {
|
||||
Path string
|
||||
In string
|
||||
MaxProperties *int64
|
||||
MinProperties *int64
|
||||
Required []string
|
||||
Properties map[string]spec.Schema
|
||||
AdditionalProperties *spec.SchemaOrBool
|
||||
PatternProperties map[string]spec.Schema
|
||||
Root interface{}
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func (o *objectValidator) SetPath(path string) {
|
||||
o.Path = path
|
||||
}
|
||||
|
||||
func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
// TODO: this should also work for structs
|
||||
// there is a problem in the type validator where it will be unhappy about null values
|
||||
// so that requires more testing
|
||||
r := reflect.TypeOf(source) == specSchemaType && (kind == reflect.Map || kind == reflect.Struct)
|
||||
//fmt.Printf("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
|
||||
func (o *objectValidator) Validate(data interface{}) *Result {
|
||||
val := data.(map[string]interface{})
|
||||
numKeys := int64(len(val))
|
||||
|
||||
if o.MinProperties != nil && numKeys < *o.MinProperties {
|
||||
return sErr(errors.TooFewProperties(o.Path, o.In, *o.MinProperties))
|
||||
}
|
||||
if o.MaxProperties != nil && numKeys > *o.MaxProperties {
|
||||
return sErr(errors.TooManyProperties(o.Path, o.In, *o.MaxProperties))
|
||||
}
|
||||
|
||||
res := new(Result)
|
||||
if len(o.Required) > 0 {
|
||||
for _, k := range o.Required {
|
||||
if _, ok := val[k]; !ok {
|
||||
res.AddErrors(errors.Required(o.Path+"."+k, o.In))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows {
|
||||
for k := range val {
|
||||
_, regularProperty := o.Properties[k]
|
||||
matched := false
|
||||
|
||||
for pk := range o.PatternProperties {
|
||||
if matches, _ := regexp.MatchString(pk, k); matches {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !regularProperty && k != "$schema" && k != "id" && !matched {
|
||||
res.AddErrors(errors.PropertyNotAllowed(o.Path, o.In, k))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for key, value := range val {
|
||||
_, regularProperty := o.Properties[key]
|
||||
matched, succeededOnce, _ := o.validatePatternProperty(key, value, res)
|
||||
if !(regularProperty || matched || succeededOnce) {
|
||||
if o.AdditionalProperties != nil && o.AdditionalProperties.Schema != nil {
|
||||
res.Merge(NewSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value))
|
||||
} else if regularProperty && !(matched || succeededOnce) {
|
||||
res.AddErrors(errors.FailedAllPatternProperties(o.Path, o.In, key))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for pName, pSchema := range o.Properties {
|
||||
rName := pName
|
||||
if o.Path != "" {
|
||||
rName = o.Path + "." + pName
|
||||
}
|
||||
|
||||
if v, ok := val[pName]; ok {
|
||||
res.Merge(NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v))
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range val {
|
||||
_, regularProperty := o.Properties[key]
|
||||
matched, succeededOnce, patterns := o.validatePatternProperty(key, value, res)
|
||||
if !regularProperty && (matched || succeededOnce) {
|
||||
for _, pName := range patterns {
|
||||
if v, ok := o.PatternProperties[pName]; ok {
|
||||
res.Merge(NewSchemaValidator(&v, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (o *objectValidator) validatePatternProperty(key string, value interface{}, result *Result) (bool, bool, []string) {
|
||||
matched := false
|
||||
succeededOnce := false
|
||||
var patterns []string
|
||||
|
||||
for k, schema := range o.PatternProperties {
|
||||
if match, _ := regexp.MatchString(k, key); match {
|
||||
patterns = append(patterns, k)
|
||||
matched = true
|
||||
validator := NewSchemaValidator(&schema, o.Root, o.Path+"."+key, o.KnownFormats)
|
||||
|
||||
res := validator.Validate(value)
|
||||
result.Merge(res)
|
||||
if res.IsValid() {
|
||||
succeededOnce = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if succeededOnce {
|
||||
result.Inc()
|
||||
}
|
||||
|
||||
return matched, succeededOnce, patterns
|
||||
}
|
61
vendor/github.com/go-openapi/validate/result.go
generated
vendored
Normal file
61
vendor/github.com/go-openapi/validate/result.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import "github.com/go-openapi/errors"
|
||||
|
||||
// Result represents a validation result
|
||||
type Result struct {
|
||||
Errors []error
|
||||
MatchCount int
|
||||
}
|
||||
|
||||
// Merge merges this result with the other one, preserving match counts etc
|
||||
func (r *Result) Merge(other *Result) *Result {
|
||||
if other == nil {
|
||||
return r
|
||||
}
|
||||
r.AddErrors(other.Errors...)
|
||||
r.MatchCount += other.MatchCount
|
||||
return r
|
||||
}
|
||||
|
||||
// AddErrors adds errors to this validation result
|
||||
func (r *Result) AddErrors(errors ...error) {
|
||||
r.Errors = append(r.Errors, errors...)
|
||||
}
|
||||
|
||||
// IsValid returns true when this result is valid
|
||||
func (r *Result) IsValid() bool {
|
||||
return len(r.Errors) == 0
|
||||
}
|
||||
|
||||
// HasErrors returns true when this result is invalid
|
||||
func (r *Result) HasErrors() bool {
|
||||
return !r.IsValid()
|
||||
}
|
||||
|
||||
// Inc increments the match count
|
||||
func (r *Result) Inc() {
|
||||
r.MatchCount++
|
||||
}
|
||||
|
||||
// AsError renders this result as an error interface
|
||||
func (r *Result) AsError() error {
|
||||
if r.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return errors.CompositeValidationError(r.Errors...)
|
||||
}
|
193
vendor/github.com/go-openapi/validate/schema.go
generated
vendored
Normal file
193
vendor/github.com/go-openapi/validate/schema.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
var specSchemaType = reflect.TypeOf(&spec.Schema{})
|
||||
var specParameterType = reflect.TypeOf(&spec.Parameter{})
|
||||
var specItemsType = reflect.TypeOf(&spec.Items{})
|
||||
var specHeaderType = reflect.TypeOf(&spec.Header{})
|
||||
|
||||
// SchemaValidator like param validator but for a full json schema
|
||||
type SchemaValidator struct {
|
||||
Path string
|
||||
in string
|
||||
Schema *spec.Schema
|
||||
validators []valueValidator
|
||||
Root interface{}
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
// NewSchemaValidator creates a new schema validator
|
||||
func NewSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry) *SchemaValidator {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rootSchema == nil {
|
||||
rootSchema = schema
|
||||
}
|
||||
|
||||
if schema.ID != "" || schema.Ref.String() != "" || schema.Ref.IsRoot() {
|
||||
err := spec.ExpandSchema(schema, rootSchema, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
s := SchemaValidator{Path: root, in: "body", Schema: schema, Root: rootSchema, KnownFormats: formats}
|
||||
s.validators = []valueValidator{
|
||||
s.typeValidator(),
|
||||
s.schemaPropsValidator(),
|
||||
s.stringValidator(),
|
||||
s.formatValidator(),
|
||||
s.numberValidator(),
|
||||
s.sliceValidator(),
|
||||
s.commonValidator(),
|
||||
s.objectValidator(),
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
// SetPath sets the path for this schema valdiator
|
||||
func (s *SchemaValidator) SetPath(path string) {
|
||||
s.Path = path
|
||||
}
|
||||
|
||||
// Applies returns true when this schema validator applies
|
||||
func (s *SchemaValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
_, ok := source.(*spec.Schema)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Validate validates the data against the schema
|
||||
func (s *SchemaValidator) Validate(data interface{}) *Result {
|
||||
if data == nil {
|
||||
v := s.validators[0].Validate(data)
|
||||
v.Merge(s.validators[6].Validate(data))
|
||||
return v
|
||||
}
|
||||
result := new(Result)
|
||||
|
||||
tpe := reflect.TypeOf(data)
|
||||
kind := tpe.Kind()
|
||||
for kind == reflect.Ptr {
|
||||
tpe = tpe.Elem()
|
||||
kind = tpe.Kind()
|
||||
}
|
||||
d := data
|
||||
if kind == reflect.Struct {
|
||||
d = swag.ToDynamicJSON(data)
|
||||
}
|
||||
|
||||
for _, v := range s.validators {
|
||||
if !v.Applies(s.Schema, kind) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := v.Validate(d)
|
||||
result.Merge(err)
|
||||
result.Inc()
|
||||
}
|
||||
result.Inc()
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) typeValidator() valueValidator {
|
||||
return &typeValidator{Type: s.Schema.Type, Format: s.Schema.Format, In: s.in, Path: s.Path}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) commonValidator() valueValidator {
|
||||
return &basicCommonValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
Default: s.Schema.Default,
|
||||
Enum: s.Schema.Enum,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) sliceValidator() valueValidator {
|
||||
return &schemaSliceValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
MaxItems: s.Schema.MaxItems,
|
||||
MinItems: s.Schema.MinItems,
|
||||
UniqueItems: s.Schema.UniqueItems,
|
||||
AdditionalItems: s.Schema.AdditionalItems,
|
||||
Items: s.Schema.Items,
|
||||
Root: s.Root,
|
||||
KnownFormats: s.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) numberValidator() valueValidator {
|
||||
return &numberValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
Default: s.Schema.Default,
|
||||
MultipleOf: s.Schema.MultipleOf,
|
||||
Maximum: s.Schema.Maximum,
|
||||
ExclusiveMaximum: s.Schema.ExclusiveMaximum,
|
||||
Minimum: s.Schema.Minimum,
|
||||
ExclusiveMinimum: s.Schema.ExclusiveMinimum,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) stringValidator() valueValidator {
|
||||
return &stringValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
Default: s.Schema.Default,
|
||||
MaxLength: s.Schema.MaxLength,
|
||||
MinLength: s.Schema.MinLength,
|
||||
Pattern: s.Schema.Pattern,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) formatValidator() valueValidator {
|
||||
return &formatValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
//Default: s.Schema.Default,
|
||||
Format: s.Schema.Format,
|
||||
KnownFormats: s.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) schemaPropsValidator() valueValidator {
|
||||
sch := s.Schema
|
||||
return newSchemaPropsValidator(s.Path, s.in, sch.AllOf, sch.OneOf, sch.AnyOf, sch.Not, sch.Dependencies, s.Root, s.KnownFormats)
|
||||
}
|
||||
|
||||
func (s *SchemaValidator) objectValidator() valueValidator {
|
||||
return &objectValidator{
|
||||
Path: s.Path,
|
||||
In: s.in,
|
||||
MaxProperties: s.Schema.MaxProperties,
|
||||
MinProperties: s.Schema.MinProperties,
|
||||
Required: s.Schema.Required,
|
||||
Properties: s.Schema.Properties,
|
||||
AdditionalProperties: s.Schema.AdditionalProperties,
|
||||
PatternProperties: s.Schema.PatternProperties,
|
||||
Root: s.Root,
|
||||
KnownFormats: s.KnownFormats,
|
||||
}
|
||||
}
|
182
vendor/github.com/go-openapi/validate/schema_props.go
generated
vendored
Normal file
182
vendor/github.com/go-openapi/validate/schema_props.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
type schemaPropsValidator struct {
|
||||
Path string
|
||||
In string
|
||||
AllOf []spec.Schema
|
||||
OneOf []spec.Schema
|
||||
AnyOf []spec.Schema
|
||||
Not *spec.Schema
|
||||
Dependencies spec.Dependencies
|
||||
anyOfValidators []SchemaValidator
|
||||
allOfValidators []SchemaValidator
|
||||
oneOfValidators []SchemaValidator
|
||||
notValidator *SchemaValidator
|
||||
Root interface{}
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func (s *schemaPropsValidator) SetPath(path string) {
|
||||
s.Path = path
|
||||
}
|
||||
|
||||
func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry) *schemaPropsValidator {
|
||||
var anyValidators []SchemaValidator
|
||||
for _, v := range anyOf {
|
||||
anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats))
|
||||
}
|
||||
var allValidators []SchemaValidator
|
||||
for _, v := range allOf {
|
||||
allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats))
|
||||
}
|
||||
var oneValidators []SchemaValidator
|
||||
for _, v := range oneOf {
|
||||
oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats))
|
||||
}
|
||||
|
||||
var notValidator *SchemaValidator
|
||||
if not != nil {
|
||||
notValidator = NewSchemaValidator(not, root, path, formats)
|
||||
}
|
||||
|
||||
return &schemaPropsValidator{
|
||||
Path: path,
|
||||
In: in,
|
||||
AllOf: allOf,
|
||||
OneOf: oneOf,
|
||||
AnyOf: anyOf,
|
||||
Not: not,
|
||||
Dependencies: deps,
|
||||
anyOfValidators: anyValidators,
|
||||
allOfValidators: allValidators,
|
||||
oneOfValidators: oneValidators,
|
||||
notValidator: notValidator,
|
||||
Root: root,
|
||||
KnownFormats: formats,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
r := reflect.TypeOf(source) == specSchemaType
|
||||
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *schemaPropsValidator) Validate(data interface{}) *Result {
|
||||
mainResult := new(Result)
|
||||
if len(s.anyOfValidators) > 0 {
|
||||
var bestFailures *Result
|
||||
succeededOnce := false
|
||||
for _, anyOfSchema := range s.anyOfValidators {
|
||||
result := anyOfSchema.Validate(data)
|
||||
if result.IsValid() {
|
||||
bestFailures = nil
|
||||
succeededOnce = true
|
||||
break
|
||||
}
|
||||
if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
|
||||
bestFailures = result
|
||||
}
|
||||
}
|
||||
|
||||
if !succeededOnce {
|
||||
mainResult.AddErrors(errors.New(422, "must validate at least one schema (anyOf)"))
|
||||
}
|
||||
if bestFailures != nil {
|
||||
mainResult.Merge(bestFailures)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.oneOfValidators) > 0 {
|
||||
var bestFailures *Result
|
||||
validated := 0
|
||||
|
||||
for _, oneOfSchema := range s.oneOfValidators {
|
||||
result := oneOfSchema.Validate(data)
|
||||
if result.IsValid() {
|
||||
validated++
|
||||
bestFailures = nil
|
||||
continue
|
||||
}
|
||||
if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
|
||||
bestFailures = result
|
||||
}
|
||||
}
|
||||
|
||||
if validated != 1 {
|
||||
mainResult.AddErrors(errors.New(422, "must validate one and only one schema (oneOf)"))
|
||||
if bestFailures != nil {
|
||||
mainResult.Merge(bestFailures)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.allOfValidators) > 0 {
|
||||
validated := 0
|
||||
|
||||
for _, allOfSchema := range s.allOfValidators {
|
||||
result := allOfSchema.Validate(data)
|
||||
if result.IsValid() {
|
||||
validated++
|
||||
}
|
||||
mainResult.Merge(result)
|
||||
}
|
||||
|
||||
if validated != len(s.allOfValidators) {
|
||||
mainResult.AddErrors(errors.New(422, "must validate all the schemas (allOf)"))
|
||||
}
|
||||
}
|
||||
|
||||
if s.notValidator != nil {
|
||||
result := s.notValidator.Validate(data)
|
||||
if result.IsValid() {
|
||||
mainResult.AddErrors(errors.New(422, "must not validate the schema (not)"))
|
||||
}
|
||||
}
|
||||
|
||||
if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
|
||||
val := data.(map[string]interface{})
|
||||
for key := range val {
|
||||
if dep, ok := s.Dependencies[key]; ok {
|
||||
|
||||
if dep.Schema != nil {
|
||||
mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats).Validate(data))
|
||||
continue
|
||||
}
|
||||
|
||||
if len(dep.Property) > 0 {
|
||||
for _, depKey := range dep.Property {
|
||||
if _, ok := val[depKey]; !ok {
|
||||
mainResult.AddErrors(errors.New(422, "has a dependency on %s", depKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mainResult.Inc()
|
||||
return mainResult
|
||||
}
|
103
vendor/github.com/go-openapi/validate/slice_validator.go
generated
vendored
Normal file
103
vendor/github.com/go-openapi/validate/slice_validator.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
type schemaSliceValidator struct {
|
||||
Path string
|
||||
In string
|
||||
MaxItems *int64
|
||||
MinItems *int64
|
||||
UniqueItems bool
|
||||
AdditionalItems *spec.SchemaOrBool
|
||||
Items *spec.SchemaOrArray
|
||||
Root interface{}
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func (s *schemaSliceValidator) SetPath(path string) {
|
||||
s.Path = path
|
||||
}
|
||||
|
||||
func (s *schemaSliceValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
_, ok := source.(*spec.Schema)
|
||||
r := ok && kind == reflect.Slice
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *schemaSliceValidator) Validate(data interface{}) *Result {
|
||||
result := new(Result)
|
||||
if data == nil {
|
||||
return result
|
||||
}
|
||||
val := reflect.ValueOf(data)
|
||||
size := val.Len()
|
||||
|
||||
if s.Items != nil && s.Items.Schema != nil {
|
||||
validator := NewSchemaValidator(s.Items.Schema, s.Root, s.Path, s.KnownFormats)
|
||||
for i := 0; i < size; i++ {
|
||||
validator.SetPath(fmt.Sprintf("%s.%d", s.Path, i))
|
||||
value := val.Index(i)
|
||||
result.Merge(validator.Validate(value.Interface()))
|
||||
}
|
||||
}
|
||||
|
||||
itemsSize := int64(0)
|
||||
if s.Items != nil && len(s.Items.Schemas) > 0 {
|
||||
itemsSize = int64(len(s.Items.Schemas))
|
||||
for i := int64(0); i < itemsSize; i++ {
|
||||
validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats)
|
||||
result.Merge(validator.Validate(val.Index(int(i)).Interface()))
|
||||
}
|
||||
|
||||
}
|
||||
if s.AdditionalItems != nil && itemsSize < int64(size) {
|
||||
if s.Items != nil && len(s.Items.Schemas) > 0 && !s.AdditionalItems.Allows {
|
||||
result.AddErrors(errors.New(422, "array doesn't allow for additional items"))
|
||||
}
|
||||
if s.AdditionalItems.Schema != nil {
|
||||
for i := itemsSize; i < (int64(size)-itemsSize)+1; i++ {
|
||||
validator := NewSchemaValidator(s.AdditionalItems.Schema, s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats)
|
||||
result.Merge(validator.Validate(val.Index(int(i)).Interface()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.MinItems != nil {
|
||||
if err := MinItems(s.Path, s.In, int64(size), *s.MinItems); err != nil {
|
||||
result.AddErrors(err)
|
||||
}
|
||||
}
|
||||
if s.MaxItems != nil {
|
||||
if err := MaxItems(s.Path, s.In, int64(size), *s.MaxItems); err != nil {
|
||||
result.AddErrors(err)
|
||||
}
|
||||
}
|
||||
if s.UniqueItems {
|
||||
if err := UniqueItems(s.Path, s.In, val.Interface()); err != nil {
|
||||
result.AddErrors(err)
|
||||
}
|
||||
}
|
||||
result.Inc()
|
||||
return result
|
||||
}
|
792
vendor/github.com/go-openapi/validate/spec.go
generated
vendored
Normal file
792
vendor/github.com/go-openapi/validate/spec.go
generated
vendored
Normal file
@@ -0,0 +1,792 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// Spec validates a spec document
|
||||
// It validates the spec json against the json schema for swagger
|
||||
// and then validates a number of extra rules that can't be expressed in json schema:
|
||||
//
|
||||
// - definition can't declare a property that's already defined by one of its ancestors
|
||||
// - definition's ancestor can't be a descendant of the same model
|
||||
// - each api path should be non-verbatim (account for path param names) unique per method
|
||||
// - each security reference should contain only unique scopes
|
||||
// - each security scope in a security definition should be unique
|
||||
// - each path parameter should correspond to a parameter placeholder and vice versa
|
||||
// - each referencable definition must have references
|
||||
// - each definition property listed in the required array must be defined in the properties of the model
|
||||
// - each parameter should have a unique `name` and `type` combination
|
||||
// - each operation should have only 1 parameter of type body
|
||||
// - each reference must point to a valid object
|
||||
// - every default value that is specified must validate against the schema for that property
|
||||
// - items property is required for all schemas/definitions of type `array`
|
||||
func Spec(doc *loads.Document, formats strfmt.Registry) error {
|
||||
errs, _ /*warns*/ := NewSpecValidator(doc.Schema(), formats).Validate(doc)
|
||||
if errs.HasErrors() {
|
||||
return errors.CompositeValidationError(errs.Errors...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AgainstSchema validates the specified data with the provided schema, when no schema
|
||||
// is provided it uses the json schema as default
|
||||
func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry) error {
|
||||
res := NewSchemaValidator(schema, nil, "", formats).Validate(data)
|
||||
if res.HasErrors() {
|
||||
return errors.CompositeValidationError(res.Errors...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SpecValidator validates a swagger spec
|
||||
type SpecValidator struct {
|
||||
schema *spec.Schema // swagger 2.0 schema
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
expanded *loads.Document
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
// NewSpecValidator creates a new swagger spec validator instance
|
||||
func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidator {
|
||||
return &SpecValidator{
|
||||
schema: schema,
|
||||
KnownFormats: formats,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the swagger spec
|
||||
func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Result) {
|
||||
var sd *loads.Document
|
||||
|
||||
switch v := data.(type) {
|
||||
case *loads.Document:
|
||||
sd = v
|
||||
}
|
||||
if sd == nil {
|
||||
errs = sErr(errors.New(500, "spec validator can only validate spec.Document objects"))
|
||||
return
|
||||
}
|
||||
s.spec = sd
|
||||
s.analyzer = analysis.New(sd.Spec())
|
||||
|
||||
errs = new(Result)
|
||||
warnings = new(Result)
|
||||
|
||||
schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats)
|
||||
var obj interface{}
|
||||
if err := json.Unmarshal(sd.Raw(), &obj); err != nil {
|
||||
errs.AddErrors(err)
|
||||
return
|
||||
}
|
||||
errs.Merge(schv.Validate(obj)) // error -
|
||||
if errs.HasErrors() {
|
||||
return // no point in continuing
|
||||
}
|
||||
|
||||
errs.Merge(s.validateReferencesValid()) // error -
|
||||
if errs.HasErrors() {
|
||||
return // no point in continuing
|
||||
}
|
||||
|
||||
errs.Merge(s.validateDuplicateOperationIDs())
|
||||
errs.Merge(s.validateDuplicatePropertyNames()) // error -
|
||||
errs.Merge(s.validateParameters()) // error -
|
||||
errs.Merge(s.validateItems()) // error -
|
||||
errs.Merge(s.validateRequiredDefinitions()) // error -
|
||||
errs.Merge(s.validateDefaultValueValidAgainstSchema()) // error -
|
||||
errs.Merge(s.validateExamplesValidAgainstSchema()) // error -
|
||||
errs.Merge(s.validateNonEmptyPathParamNames())
|
||||
|
||||
warnings.Merge(s.validateUniqueSecurityScopes()) // warning
|
||||
warnings.Merge(s.validateReferenced()) // warning
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateNonEmptyPathParamNames() *Result {
|
||||
res := new(Result)
|
||||
for k := range s.spec.Spec().Paths.Paths {
|
||||
if strings.Contains(k, "{}") {
|
||||
res.AddErrors(errors.New(422, "%q contains an empty path parameter", k))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateDuplicateOperationIDs() *Result {
|
||||
res := new(Result)
|
||||
known := make(map[string]int)
|
||||
for _, v := range s.analyzer.OperationIDs() {
|
||||
if v != "" {
|
||||
known[v]++
|
||||
}
|
||||
}
|
||||
for k, v := range known {
|
||||
if v > 1 {
|
||||
res.AddErrors(errors.New(422, "%q is defined %d times", k, v))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type dupProp struct {
|
||||
Name string
|
||||
Definition string
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateDuplicatePropertyNames() *Result {
|
||||
// definition can't declare a property that's already defined by one of its ancestors
|
||||
res := new(Result)
|
||||
for k, sch := range s.spec.Spec().Definitions {
|
||||
if len(sch.AllOf) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
knownanc := map[string]struct{}{
|
||||
"#/definitions/" + k: struct{}{},
|
||||
}
|
||||
|
||||
ancs := s.validateCircularAncestry(k, sch, knownanc)
|
||||
if len(ancs) > 0 {
|
||||
res.AddErrors(errors.New(422, "definition %q has circular ancestry: %v", k, ancs))
|
||||
return res
|
||||
}
|
||||
|
||||
knowns := make(map[string]struct{})
|
||||
dups := s.validateSchemaPropertyNames(k, sch, knowns)
|
||||
if len(dups) > 0 {
|
||||
var pns []string
|
||||
for _, v := range dups {
|
||||
pns = append(pns, v.Definition+"."+v.Name)
|
||||
}
|
||||
res.AddErrors(errors.New(422, "definition %q contains duplicate properties: %v", k, pns))
|
||||
}
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, knowns map[string]struct{}) []dupProp {
|
||||
var dups []dupProp
|
||||
|
||||
schn := nm
|
||||
schc := &sch
|
||||
for schc.Ref.String() != "" {
|
||||
// gather property names
|
||||
reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
schc = reso
|
||||
schn = sch.Ref.String()
|
||||
}
|
||||
|
||||
if len(schc.AllOf) > 0 {
|
||||
for _, chld := range schc.AllOf {
|
||||
dups = append(dups, s.validateSchemaPropertyNames(schn, chld, knowns)...)
|
||||
}
|
||||
return dups
|
||||
}
|
||||
|
||||
for k := range schc.Properties {
|
||||
_, ok := knowns[k]
|
||||
if ok {
|
||||
dups = append(dups, dupProp{Name: k, Definition: schn})
|
||||
} else {
|
||||
knowns[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return dups
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, knowns map[string]struct{}) []string {
|
||||
if sch.Ref.String() == "" && len(sch.AllOf) == 0 {
|
||||
return nil
|
||||
}
|
||||
var ancs []string
|
||||
|
||||
schn := nm
|
||||
schc := &sch
|
||||
for schc.Ref.String() != "" {
|
||||
reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
schc = reso
|
||||
schn = sch.Ref.String()
|
||||
}
|
||||
|
||||
if schn != nm && schn != "" {
|
||||
if _, ok := knowns[schn]; ok {
|
||||
ancs = append(ancs, schn)
|
||||
}
|
||||
knowns[schn] = struct{}{}
|
||||
|
||||
if len(ancs) > 0 {
|
||||
return ancs
|
||||
}
|
||||
}
|
||||
|
||||
if len(schc.AllOf) > 0 {
|
||||
for _, chld := range schc.AllOf {
|
||||
if chld.Ref.String() != "" || len(chld.AllOf) > 0 {
|
||||
ancs = append(ancs, s.validateCircularAncestry(schn, chld, knowns)...)
|
||||
if len(ancs) > 0 {
|
||||
return ancs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ancs
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateItems() *Result {
|
||||
// validate parameter, items, schema and response objects for presence of item if type is array
|
||||
res := new(Result)
|
||||
|
||||
// TODO: implement support for lookups of refs
|
||||
for method, pi := range s.analyzer.Operations() {
|
||||
for path, op := range pi {
|
||||
for _, param := range s.analyzer.ParamsFor(method, path) {
|
||||
if param.TypeName() == "array" && param.ItemsTypeName() == "" {
|
||||
res.AddErrors(errors.New(422, "param %q for %q is a collection without an element type", param.Name, op.ID))
|
||||
continue
|
||||
}
|
||||
if param.In != "body" {
|
||||
if param.Items != nil {
|
||||
items := param.Items
|
||||
for items.TypeName() == "array" {
|
||||
if items.ItemsTypeName() == "" {
|
||||
res.AddErrors(errors.New(422, "param %q for %q is a collection without an element type", param.Name, op.ID))
|
||||
break
|
||||
}
|
||||
items = items.Items
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := s.validateSchemaItems(*param.Schema, fmt.Sprintf("body param %q", param.Name), op.ID); err != nil {
|
||||
res.AddErrors(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var responses []spec.Response
|
||||
if op.Responses != nil {
|
||||
if op.Responses.Default != nil {
|
||||
responses = append(responses, *op.Responses.Default)
|
||||
}
|
||||
for _, v := range op.Responses.StatusCodeResponses {
|
||||
responses = append(responses, v)
|
||||
}
|
||||
}
|
||||
|
||||
for _, resp := range responses {
|
||||
for hn, hv := range resp.Headers {
|
||||
if hv.TypeName() == "array" && hv.ItemsTypeName() == "" {
|
||||
res.AddErrors(errors.New(422, "header %q for %q is a collection without an element type", hn, op.ID))
|
||||
}
|
||||
}
|
||||
if resp.Schema != nil {
|
||||
if err := s.validateSchemaItems(*resp.Schema, "response body", op.ID); err != nil {
|
||||
res.AddErrors(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) error {
|
||||
if !schema.Type.Contains("array") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if schema.Items == nil || schema.Items.Len() == 0 {
|
||||
return errors.New(422, "%s for %q is a collection without an element type", prefix, opID)
|
||||
}
|
||||
|
||||
schemas := schema.Items.Schemas
|
||||
if schema.Items.Schema != nil {
|
||||
schemas = []spec.Schema{*schema.Items.Schema}
|
||||
}
|
||||
for _, sch := range schemas {
|
||||
if err := s.validateSchemaItems(sch, prefix, opID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateUniqueSecurityScopes() *Result {
|
||||
// Each authorization/security reference should contain only unique scopes.
|
||||
// (Example: For an oauth2 authorization/security requirement, when listing the required scopes,
|
||||
// each scope should only be listed once.)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOperation []string) *Result {
|
||||
// Each defined operation path parameters must correspond to a named element in the API's path pattern.
|
||||
// (For example, you cannot have a path parameter named id for the following path /pets/{petId} but you must have a path parameter named petId.)
|
||||
res := new(Result)
|
||||
for _, l := range fromPath {
|
||||
var matched bool
|
||||
for _, r := range fromOperation {
|
||||
if l == "{"+r+"}" {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
res.Errors = append(res.Errors, errors.New(422, "path param %q has no parameter definition", l))
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range fromOperation {
|
||||
var matched bool
|
||||
for _, r := range fromPath {
|
||||
if "{"+p+"}" == r {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
res.AddErrors(errors.New(422, "path param %q is not present in path %q", p, path))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateReferenced() *Result {
|
||||
var res Result
|
||||
res.Merge(s.validateReferencedParameters())
|
||||
res.Merge(s.validateReferencedResponses())
|
||||
res.Merge(s.validateReferencedDefinitions())
|
||||
return &res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateReferencedParameters() *Result {
|
||||
// Each referenceable definition must have references.
|
||||
params := s.spec.Spec().Parameters
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
expected := make(map[string]struct{})
|
||||
for k := range params {
|
||||
expected["#/parameters/"+jsonpointer.Escape(k)] = struct{}{}
|
||||
}
|
||||
for _, k := range s.analyzer.AllParameterReferences() {
|
||||
if _, ok := expected[k]; ok {
|
||||
delete(expected, k)
|
||||
}
|
||||
}
|
||||
|
||||
if len(expected) == 0 {
|
||||
return nil
|
||||
}
|
||||
var result Result
|
||||
for k := range expected {
|
||||
result.AddErrors(errors.New(422, "parameter %q is not used anywhere", k))
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateReferencedResponses() *Result {
|
||||
// Each referenceable definition must have references.
|
||||
responses := s.spec.Spec().Responses
|
||||
if len(responses) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
expected := make(map[string]struct{})
|
||||
for k := range responses {
|
||||
expected["#/responses/"+jsonpointer.Escape(k)] = struct{}{}
|
||||
}
|
||||
for _, k := range s.analyzer.AllResponseReferences() {
|
||||
if _, ok := expected[k]; ok {
|
||||
delete(expected, k)
|
||||
}
|
||||
}
|
||||
|
||||
if len(expected) == 0 {
|
||||
return nil
|
||||
}
|
||||
var result Result
|
||||
for k := range expected {
|
||||
result.AddErrors(errors.New(422, "response %q is not used anywhere", k))
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateReferencedDefinitions() *Result {
|
||||
// Each referenceable definition must have references.
|
||||
defs := s.spec.Spec().Definitions
|
||||
if len(defs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
expected := make(map[string]struct{})
|
||||
for k := range defs {
|
||||
expected["#/definitions/"+jsonpointer.Escape(k)] = struct{}{}
|
||||
}
|
||||
for _, k := range s.analyzer.AllDefinitionReferences() {
|
||||
if _, ok := expected[k]; ok {
|
||||
delete(expected, k)
|
||||
}
|
||||
}
|
||||
|
||||
if len(expected) == 0 {
|
||||
return nil
|
||||
}
|
||||
var result Result
|
||||
for k := range expected {
|
||||
result.AddErrors(errors.New(422, "definition %q is not used anywhere", k))
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateRequiredDefinitions() *Result {
|
||||
// Each definition property listed in the required array must be defined in the properties of the model
|
||||
res := new(Result)
|
||||
for d, v := range s.spec.Spec().Definitions {
|
||||
REQUIRED:
|
||||
for _, pn := range v.Required {
|
||||
if _, ok := v.Properties[pn]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for pp := range v.PatternProperties {
|
||||
re := regexp.MustCompile(pp)
|
||||
if re.MatchString(pn) {
|
||||
continue REQUIRED
|
||||
}
|
||||
}
|
||||
|
||||
if v.AdditionalProperties != nil {
|
||||
if v.AdditionalProperties.Allows {
|
||||
continue
|
||||
}
|
||||
if v.AdditionalProperties.Schema != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
res.AddErrors(errors.New(422, "%q is present in required but not defined as property in definition %q", pn, d))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateParameters() *Result {
|
||||
// each parameter should have a unique `name` and `type` combination
|
||||
// each operation should have only 1 parameter of type body
|
||||
// each api path should be non-verbatim (account for path param names) unique per method
|
||||
res := new(Result)
|
||||
for method, pi := range s.analyzer.Operations() {
|
||||
knownPaths := make(map[string]string)
|
||||
for path, op := range pi {
|
||||
segments, params := parsePath(path)
|
||||
knowns := make([]string, 0, len(segments))
|
||||
for _, s := range segments {
|
||||
knowns = append(knowns, s)
|
||||
}
|
||||
var fromPath []string
|
||||
for _, i := range params {
|
||||
fromPath = append(fromPath, knowns[i])
|
||||
knowns[i] = "!"
|
||||
}
|
||||
knownPath := strings.Join(knowns, "/")
|
||||
if orig, ok := knownPaths[knownPath]; ok {
|
||||
res.AddErrors(errors.New(422, "path %s overlaps with %s", path, orig))
|
||||
} else {
|
||||
knownPaths[knownPath] = path
|
||||
}
|
||||
|
||||
ptypes := make(map[string]map[string]struct{})
|
||||
var firstBodyParam string
|
||||
sw := s.spec.Spec()
|
||||
var paramNames []string
|
||||
PARAMETERS:
|
||||
for _, ppr := range op.Parameters {
|
||||
pr := ppr
|
||||
for pr.Ref.String() != "" {
|
||||
obj, _, err := pr.Ref.GetPointer().Get(sw)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
res.AddErrors(err)
|
||||
break PARAMETERS
|
||||
}
|
||||
pr = obj.(spec.Parameter)
|
||||
}
|
||||
pnames, ok := ptypes[pr.In]
|
||||
if !ok {
|
||||
pnames = make(map[string]struct{})
|
||||
ptypes[pr.In] = pnames
|
||||
}
|
||||
|
||||
_, ok = pnames[pr.Name]
|
||||
if ok {
|
||||
res.AddErrors(errors.New(422, "duplicate parameter name %q for %q in operation %q", pr.Name, pr.In, op.ID))
|
||||
}
|
||||
pnames[pr.Name] = struct{}{}
|
||||
}
|
||||
|
||||
PARAMETERS2:
|
||||
for _, ppr := range s.analyzer.ParamsFor(method, path) {
|
||||
pr := ppr
|
||||
for pr.Ref.String() != "" {
|
||||
obj, _, err := pr.Ref.GetPointer().Get(sw)
|
||||
if err != nil {
|
||||
res.AddErrors(err)
|
||||
break PARAMETERS2
|
||||
}
|
||||
pr = obj.(spec.Parameter)
|
||||
}
|
||||
|
||||
if pr.In == "body" {
|
||||
if firstBodyParam != "" {
|
||||
res.AddErrors(errors.New(422, "operation %q has more than 1 body param (accepted: %q, dropped: %q)", op.ID, firstBodyParam, pr.Name))
|
||||
}
|
||||
firstBodyParam = pr.Name
|
||||
}
|
||||
|
||||
if pr.In == "path" {
|
||||
paramNames = append(paramNames, pr.Name)
|
||||
}
|
||||
}
|
||||
res.Merge(s.validatePathParamPresence(path, fromPath, paramNames))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func parsePath(path string) (segments []string, params []int) {
|
||||
for i, p := range strings.Split(path, "/") {
|
||||
segments = append(segments, p)
|
||||
if len(p) > 0 && p[0] == '{' && p[len(p)-1] == '}' {
|
||||
params = append(params, i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateReferencesValid() *Result {
|
||||
// each reference must point to a valid object
|
||||
res := new(Result)
|
||||
for _, r := range s.analyzer.AllRefs() {
|
||||
if !r.IsValidURI() {
|
||||
res.AddErrors(errors.New(404, "invalid ref %q", r.String()))
|
||||
}
|
||||
}
|
||||
if !res.HasErrors() {
|
||||
exp, err := s.spec.Expanded()
|
||||
if err != nil {
|
||||
res.AddErrors(err)
|
||||
}
|
||||
s.expanded = exp
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateResponseExample(path string, r *spec.Response) *Result {
|
||||
res := new(Result)
|
||||
if r.Ref.String() != "" {
|
||||
nr, _, err := r.Ref.GetPointer().Get(s.spec.Spec())
|
||||
if err != nil {
|
||||
res.AddErrors(err)
|
||||
return res
|
||||
}
|
||||
rr := nr.(spec.Response)
|
||||
return s.validateResponseExample(path, &rr)
|
||||
}
|
||||
|
||||
if r.Examples != nil {
|
||||
if r.Schema != nil {
|
||||
if example, ok := r.Examples["application/json"]; ok {
|
||||
res.Merge(NewSchemaValidator(r.Schema, s.spec.Spec(), path, s.KnownFormats).Validate(example))
|
||||
}
|
||||
|
||||
// TODO: validate other media types too
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateExamplesValidAgainstSchema() *Result {
|
||||
res := new(Result)
|
||||
|
||||
for _, pathItem := range s.analyzer.Operations() {
|
||||
for path, op := range pathItem {
|
||||
if op.Responses.Default != nil {
|
||||
dr := op.Responses.Default
|
||||
res.Merge(s.validateResponseExample(path, dr))
|
||||
}
|
||||
for _, r := range op.Responses.StatusCodeResponses {
|
||||
res.Merge(s.validateResponseExample(path, &r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result {
|
||||
// every default value that is specified must validate against the schema for that property
|
||||
// headers, items, parameters, schema
|
||||
|
||||
res := new(Result)
|
||||
|
||||
for method, pathItem := range s.analyzer.Operations() {
|
||||
for path, op := range pathItem {
|
||||
// parameters
|
||||
var hasForm, hasBody bool
|
||||
PARAMETERS:
|
||||
for _, pr := range s.analyzer.ParamsFor(method, path) {
|
||||
// expand ref is necessary
|
||||
param := pr
|
||||
for param.Ref.String() != "" {
|
||||
obj, _, err := param.Ref.GetPointer().Get(s.spec.Spec())
|
||||
if err != nil {
|
||||
res.AddErrors(err)
|
||||
break PARAMETERS
|
||||
}
|
||||
param = obj.(spec.Parameter)
|
||||
}
|
||||
if param.In == "formData" {
|
||||
if hasBody && !hasForm {
|
||||
res.AddErrors(errors.New(422, "operation %q has both formData and body parameters", op.ID))
|
||||
}
|
||||
hasForm = true
|
||||
}
|
||||
if param.In == "body" {
|
||||
if hasForm && !hasBody {
|
||||
res.AddErrors(errors.New(422, "operation %q has both body and formData parameters", op.ID))
|
||||
}
|
||||
hasBody = true
|
||||
}
|
||||
// check simple paramters first
|
||||
if param.Default != nil && param.Schema == nil {
|
||||
//fmt.Println(param.Name, "in", param.In, "has a default without a schema")
|
||||
// check param valid
|
||||
res.Merge(NewParamValidator(¶m, s.KnownFormats).Validate(param.Default))
|
||||
}
|
||||
|
||||
if param.Items != nil {
|
||||
res.Merge(s.validateDefaultValueItemsAgainstSchema(param.Name, param.In, ¶m, param.Items))
|
||||
}
|
||||
|
||||
if param.Schema != nil {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(param.Name, param.In, param.Schema))
|
||||
}
|
||||
}
|
||||
|
||||
if op.Responses.Default != nil {
|
||||
dr := op.Responses.Default
|
||||
for nm, h := range dr.Headers {
|
||||
if h.Default != nil {
|
||||
res.Merge(NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Default))
|
||||
}
|
||||
if h.Items != nil {
|
||||
res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items))
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, r := range op.Responses.StatusCodeResponses {
|
||||
for nm, h := range r.Headers {
|
||||
if h.Default != nil {
|
||||
res.Merge(NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Default))
|
||||
}
|
||||
if h.Items != nil {
|
||||
res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for nm, sch := range s.spec.Spec().Definitions {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("definitions.%s", nm), "body", &sch))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateDefaultValueSchemaAgainstSchema(path, in string, schema *spec.Schema) *Result {
|
||||
res := new(Result)
|
||||
if schema != nil {
|
||||
if schema.Default != nil {
|
||||
res.Merge(NewSchemaValidator(schema, s.spec.Spec(), path, s.KnownFormats).Validate(schema.Default))
|
||||
}
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(path+".items", in, schema.Items.Schema))
|
||||
}
|
||||
for i, sch := range schema.Items.Schemas {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d]", path, i), in, &sch))
|
||||
}
|
||||
}
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalItems", path), in, schema.AdditionalItems.Schema))
|
||||
}
|
||||
for propName, prop := range schema.Properties {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop))
|
||||
}
|
||||
for propName, prop := range schema.PatternProperties {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop))
|
||||
}
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalProperties", path), in, schema.AdditionalProperties.Schema))
|
||||
}
|
||||
for i, aoSch := range schema.AllOf {
|
||||
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.allOf[%d]", path, i), in, &aoSch))
|
||||
}
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateDefaultValueItemsAgainstSchema(path, in string, root interface{}, items *spec.Items) *Result {
|
||||
res := new(Result)
|
||||
if items != nil {
|
||||
if items.Default != nil {
|
||||
res.Merge(newItemsValidator(path, in, items, root, s.KnownFormats).Validate(0, items.Default))
|
||||
}
|
||||
if items.Items != nil {
|
||||
res.Merge(s.validateDefaultValueItemsAgainstSchema(path+"[0]", in, root, items.Items))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
160
vendor/github.com/go-openapi/validate/type.go
generated
vendored
Normal file
160
vendor/github.com/go-openapi/validate/type.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
type typeValidator struct {
|
||||
Type spec.StringOrArray
|
||||
Format string
|
||||
In string
|
||||
Path string
|
||||
}
|
||||
|
||||
var jsonTypeNames = map[string]struct{}{
|
||||
"array": struct{}{},
|
||||
"boolean": struct{}{},
|
||||
"integer": struct{}{},
|
||||
"null": struct{}{},
|
||||
"number": struct{}{},
|
||||
"object": struct{}{},
|
||||
"string": struct{}{},
|
||||
}
|
||||
|
||||
func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) {
|
||||
switch data.(type) {
|
||||
case []byte:
|
||||
return "string", "byte"
|
||||
case strfmt.Date, *strfmt.Date:
|
||||
return "string", "date"
|
||||
case strfmt.DateTime, *strfmt.DateTime:
|
||||
return "string", "datetime"
|
||||
case runtime.File, *runtime.File:
|
||||
return "file", ""
|
||||
case strfmt.URI, *strfmt.URI:
|
||||
return "string", "uri"
|
||||
case strfmt.Email, *strfmt.Email:
|
||||
return "string", "email"
|
||||
case strfmt.Hostname, *strfmt.Hostname:
|
||||
return "string", "hostname"
|
||||
case strfmt.IPv4, *strfmt.IPv4:
|
||||
return "string", "ipv4"
|
||||
case strfmt.IPv6, *strfmt.IPv6:
|
||||
return "string", "ipv6"
|
||||
case strfmt.UUID, *strfmt.UUID:
|
||||
return "string", "uuid"
|
||||
case strfmt.UUID3, *strfmt.UUID3:
|
||||
return "string", "uuid3"
|
||||
case strfmt.UUID4, *strfmt.UUID4:
|
||||
return "string", "uuid4"
|
||||
case strfmt.UUID5, *strfmt.UUID5:
|
||||
return "string", "uuid5"
|
||||
case strfmt.ISBN, *strfmt.ISBN:
|
||||
return "string", "isbn"
|
||||
case strfmt.ISBN10, *strfmt.ISBN10:
|
||||
return "string", "isbn10"
|
||||
case strfmt.ISBN13, *strfmt.ISBN13:
|
||||
return "string", "isbn13"
|
||||
case strfmt.CreditCard, *strfmt.CreditCard:
|
||||
return "string", "creditcard"
|
||||
case strfmt.SSN, *strfmt.SSN:
|
||||
return "string", "ssn"
|
||||
case strfmt.HexColor, *strfmt.HexColor:
|
||||
return "string", "hexcolor"
|
||||
case strfmt.RGBColor, *strfmt.RGBColor:
|
||||
return "string", "rgbcolor"
|
||||
default:
|
||||
val := reflect.ValueOf(data)
|
||||
tpe := val.Type()
|
||||
switch tpe.Kind() {
|
||||
case reflect.Bool:
|
||||
return "boolean", ""
|
||||
case reflect.String:
|
||||
return "string", ""
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
return "integer", "int32"
|
||||
case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64:
|
||||
return "integer", "int64"
|
||||
case reflect.Float32:
|
||||
return "number", "float32"
|
||||
case reflect.Float64:
|
||||
return "number", "float64"
|
||||
case reflect.Slice:
|
||||
return "array", ""
|
||||
case reflect.Map, reflect.Struct:
|
||||
return "object", ""
|
||||
case reflect.Interface:
|
||||
// What to do here?
|
||||
panic("dunno what to do here")
|
||||
case reflect.Ptr:
|
||||
return t.schemaInfoForType(reflect.Indirect(val).Interface())
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func (t *typeValidator) SetPath(path string) {
|
||||
t.Path = path
|
||||
}
|
||||
|
||||
func (t *typeValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
stpe := reflect.TypeOf(source)
|
||||
r := (len(t.Type) > 0 || t.Format != "") && (stpe == specSchemaType || stpe == specParameterType || stpe == specHeaderType)
|
||||
//fmt.Printf("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
|
||||
func (t *typeValidator) Validate(data interface{}) *Result {
|
||||
result := new(Result)
|
||||
result.Inc()
|
||||
if data == nil || reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)), reflect.ValueOf(data)) {
|
||||
if len(t.Type) > 0 && !t.Type.Contains("null") { // TODO: if a property is not required it also passes this
|
||||
return sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), "null"))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// check if the type matches, should be used in every validator chain as first item
|
||||
val := reflect.Indirect(reflect.ValueOf(data))
|
||||
kind := val.Kind()
|
||||
|
||||
schType, format := t.schemaInfoForType(data)
|
||||
//fmt.Println("path:", t.Path, "schType:", schType, "format:", format, "expType:", t.Type, "expFmt:", t.Format, "kind:", val.Kind().String())
|
||||
isLowerInt := t.Format == "int64" && format == "int32"
|
||||
isLowerFloat := t.Format == "float64" && format == "float32"
|
||||
isFloatInt := schType == "number" && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains("integer")
|
||||
isIntFloat := schType == "integer" && t.Type.Contains("number")
|
||||
|
||||
if kind != reflect.String && kind != reflect.Slice && t.Format != "" && !(t.Type.Contains(schType) || format == t.Format || isFloatInt || isIntFloat || isLowerInt || isLowerFloat) {
|
||||
return sErr(errors.InvalidType(t.Path, t.In, t.Format, format))
|
||||
}
|
||||
if !(t.Type.Contains("number") || t.Type.Contains("integer")) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) {
|
||||
return result
|
||||
}
|
||||
|
||||
if !(t.Type.Contains(schType) || isFloatInt || isIntFloat) {
|
||||
return sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), schType))
|
||||
}
|
||||
return result
|
||||
}
|
573
vendor/github.com/go-openapi/validate/validator.go
generated
vendored
Normal file
573
vendor/github.com/go-openapi/validate/validator.go
generated
vendored
Normal file
@@ -0,0 +1,573 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// An EntityValidator is an interface for things that can validate entities
|
||||
type EntityValidator interface {
|
||||
Validate(interface{}) *Result
|
||||
}
|
||||
|
||||
type valueValidator interface {
|
||||
SetPath(path string)
|
||||
Applies(interface{}, reflect.Kind) bool
|
||||
Validate(interface{}) *Result
|
||||
}
|
||||
|
||||
type itemsValidator struct {
|
||||
items *spec.Items
|
||||
root interface{}
|
||||
path string
|
||||
in string
|
||||
validators []valueValidator
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func newItemsValidator(path, in string, items *spec.Items, root interface{}, formats strfmt.Registry) *itemsValidator {
|
||||
iv := &itemsValidator{path: path, in: in, items: items, root: root, KnownFormats: formats}
|
||||
iv.validators = []valueValidator{
|
||||
&typeValidator{
|
||||
Type: spec.StringOrArray([]string{items.Type}),
|
||||
Format: items.Format,
|
||||
In: in,
|
||||
Path: path,
|
||||
},
|
||||
iv.stringValidator(),
|
||||
iv.formatValidator(),
|
||||
iv.numberValidator(),
|
||||
iv.sliceValidator(),
|
||||
iv.commonValidator(),
|
||||
}
|
||||
return iv
|
||||
}
|
||||
|
||||
func (i *itemsValidator) Validate(index int, data interface{}) *Result {
|
||||
tpe := reflect.TypeOf(data)
|
||||
kind := tpe.Kind()
|
||||
mainResult := new(Result)
|
||||
path := fmt.Sprintf("%s.%d", i.path, index)
|
||||
|
||||
for _, validator := range i.validators {
|
||||
validator.SetPath(path)
|
||||
if validator.Applies(i.root, kind) {
|
||||
result := validator.Validate(data)
|
||||
mainResult.Merge(result)
|
||||
mainResult.Inc()
|
||||
if result != nil && result.HasErrors() {
|
||||
return mainResult
|
||||
}
|
||||
}
|
||||
}
|
||||
return mainResult
|
||||
}
|
||||
|
||||
func (i *itemsValidator) commonValidator() valueValidator {
|
||||
return &basicCommonValidator{
|
||||
In: i.in,
|
||||
Default: i.items.Default,
|
||||
Enum: i.items.Enum,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *itemsValidator) sliceValidator() valueValidator {
|
||||
return &basicSliceValidator{
|
||||
In: i.in,
|
||||
Default: i.items.Default,
|
||||
MaxItems: i.items.MaxItems,
|
||||
MinItems: i.items.MinItems,
|
||||
UniqueItems: i.items.UniqueItems,
|
||||
Source: i.root,
|
||||
Items: i.items.Items,
|
||||
KnownFormats: i.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *itemsValidator) numberValidator() valueValidator {
|
||||
return &numberValidator{
|
||||
In: i.in,
|
||||
Default: i.items.Default,
|
||||
MultipleOf: i.items.MultipleOf,
|
||||
Maximum: i.items.Maximum,
|
||||
ExclusiveMaximum: i.items.ExclusiveMaximum,
|
||||
Minimum: i.items.Minimum,
|
||||
ExclusiveMinimum: i.items.ExclusiveMinimum,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *itemsValidator) stringValidator() valueValidator {
|
||||
return &stringValidator{
|
||||
In: i.in,
|
||||
Default: i.items.Default,
|
||||
MaxLength: i.items.MaxLength,
|
||||
MinLength: i.items.MinLength,
|
||||
Pattern: i.items.Pattern,
|
||||
AllowEmptyValue: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *itemsValidator) formatValidator() valueValidator {
|
||||
return &formatValidator{
|
||||
In: i.in,
|
||||
//Default: i.items.Default,
|
||||
Format: i.items.Format,
|
||||
KnownFormats: i.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
type basicCommonValidator struct {
|
||||
Path string
|
||||
In string
|
||||
Default interface{}
|
||||
Enum []interface{}
|
||||
}
|
||||
|
||||
func (b *basicCommonValidator) SetPath(path string) {
|
||||
b.Path = path
|
||||
}
|
||||
|
||||
func (b *basicCommonValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
switch source.(type) {
|
||||
case *spec.Parameter, *spec.Schema, *spec.Header:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *basicCommonValidator) Validate(data interface{}) (res *Result) {
|
||||
if len(b.Enum) > 0 {
|
||||
for _, enumValue := range b.Enum {
|
||||
if data != nil && reflect.DeepEqual(enumValue, data) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return sErr(errors.EnumFail(b.Path, b.In, data, b.Enum))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A HeaderValidator has very limited subset of validations to apply
|
||||
type HeaderValidator struct {
|
||||
name string
|
||||
header *spec.Header
|
||||
validators []valueValidator
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
// NewHeaderValidator creates a new header validator object
|
||||
func NewHeaderValidator(name string, header *spec.Header, formats strfmt.Registry) *HeaderValidator {
|
||||
p := &HeaderValidator{name: name, header: header, KnownFormats: formats}
|
||||
p.validators = []valueValidator{
|
||||
&typeValidator{
|
||||
Type: spec.StringOrArray([]string{header.Type}),
|
||||
Format: header.Format,
|
||||
In: "header",
|
||||
Path: name,
|
||||
},
|
||||
p.stringValidator(),
|
||||
p.formatValidator(),
|
||||
p.numberValidator(),
|
||||
p.sliceValidator(),
|
||||
p.commonValidator(),
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Validate the value of the header against its schema
|
||||
func (p *HeaderValidator) Validate(data interface{}) *Result {
|
||||
result := new(Result)
|
||||
tpe := reflect.TypeOf(data)
|
||||
kind := tpe.Kind()
|
||||
|
||||
for _, validator := range p.validators {
|
||||
if validator.Applies(p.header, kind) {
|
||||
if err := validator.Validate(data); err != nil {
|
||||
result.Merge(err)
|
||||
if err.HasErrors() {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *HeaderValidator) commonValidator() valueValidator {
|
||||
return &basicCommonValidator{
|
||||
Path: p.name,
|
||||
In: "response",
|
||||
Default: p.header.Default,
|
||||
Enum: p.header.Enum,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HeaderValidator) sliceValidator() valueValidator {
|
||||
return &basicSliceValidator{
|
||||
Path: p.name,
|
||||
In: "response",
|
||||
Default: p.header.Default,
|
||||
MaxItems: p.header.MaxItems,
|
||||
MinItems: p.header.MinItems,
|
||||
UniqueItems: p.header.UniqueItems,
|
||||
Items: p.header.Items,
|
||||
Source: p.header,
|
||||
KnownFormats: p.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HeaderValidator) numberValidator() valueValidator {
|
||||
return &numberValidator{
|
||||
Path: p.name,
|
||||
In: "response",
|
||||
Default: p.header.Default,
|
||||
MultipleOf: p.header.MultipleOf,
|
||||
Maximum: p.header.Maximum,
|
||||
ExclusiveMaximum: p.header.ExclusiveMaximum,
|
||||
Minimum: p.header.Minimum,
|
||||
ExclusiveMinimum: p.header.ExclusiveMinimum,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HeaderValidator) stringValidator() valueValidator {
|
||||
return &stringValidator{
|
||||
Path: p.name,
|
||||
In: "response",
|
||||
Default: p.header.Default,
|
||||
Required: true,
|
||||
MaxLength: p.header.MaxLength,
|
||||
MinLength: p.header.MinLength,
|
||||
Pattern: p.header.Pattern,
|
||||
AllowEmptyValue: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HeaderValidator) formatValidator() valueValidator {
|
||||
return &formatValidator{
|
||||
Path: p.name,
|
||||
In: "response",
|
||||
//Default: p.header.Default,
|
||||
Format: p.header.Format,
|
||||
KnownFormats: p.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
// A ParamValidator has very limited subset of validations to apply
|
||||
type ParamValidator struct {
|
||||
param *spec.Parameter
|
||||
validators []valueValidator
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
// NewParamValidator creates a new param validator object
|
||||
func NewParamValidator(param *spec.Parameter, formats strfmt.Registry) *ParamValidator {
|
||||
p := &ParamValidator{param: param, KnownFormats: formats}
|
||||
p.validators = []valueValidator{
|
||||
&typeValidator{
|
||||
Type: spec.StringOrArray([]string{param.Type}),
|
||||
Format: param.Format,
|
||||
In: param.In,
|
||||
Path: param.Name,
|
||||
},
|
||||
p.stringValidator(),
|
||||
p.formatValidator(),
|
||||
p.numberValidator(),
|
||||
p.sliceValidator(),
|
||||
p.commonValidator(),
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Validate the data against the description of the parameter
|
||||
func (p *ParamValidator) Validate(data interface{}) *Result {
|
||||
result := new(Result)
|
||||
tpe := reflect.TypeOf(data)
|
||||
kind := tpe.Kind()
|
||||
|
||||
// TODO: validate type
|
||||
for _, validator := range p.validators {
|
||||
if validator.Applies(p.param, kind) {
|
||||
if err := validator.Validate(data); err != nil {
|
||||
result.Merge(err)
|
||||
if err.HasErrors() {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ParamValidator) commonValidator() valueValidator {
|
||||
return &basicCommonValidator{
|
||||
Path: p.param.Name,
|
||||
In: p.param.In,
|
||||
Default: p.param.Default,
|
||||
Enum: p.param.Enum,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParamValidator) sliceValidator() valueValidator {
|
||||
return &basicSliceValidator{
|
||||
Path: p.param.Name,
|
||||
In: p.param.In,
|
||||
Default: p.param.Default,
|
||||
MaxItems: p.param.MaxItems,
|
||||
MinItems: p.param.MinItems,
|
||||
UniqueItems: p.param.UniqueItems,
|
||||
Items: p.param.Items,
|
||||
Source: p.param,
|
||||
KnownFormats: p.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParamValidator) numberValidator() valueValidator {
|
||||
return &numberValidator{
|
||||
Path: p.param.Name,
|
||||
In: p.param.In,
|
||||
Default: p.param.Default,
|
||||
MultipleOf: p.param.MultipleOf,
|
||||
Maximum: p.param.Maximum,
|
||||
ExclusiveMaximum: p.param.ExclusiveMaximum,
|
||||
Minimum: p.param.Minimum,
|
||||
ExclusiveMinimum: p.param.ExclusiveMinimum,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParamValidator) stringValidator() valueValidator {
|
||||
return &stringValidator{
|
||||
Path: p.param.Name,
|
||||
In: p.param.In,
|
||||
Default: p.param.Default,
|
||||
AllowEmptyValue: p.param.AllowEmptyValue,
|
||||
Required: p.param.Required,
|
||||
MaxLength: p.param.MaxLength,
|
||||
MinLength: p.param.MinLength,
|
||||
Pattern: p.param.Pattern,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParamValidator) formatValidator() valueValidator {
|
||||
return &formatValidator{
|
||||
Path: p.param.Name,
|
||||
In: p.param.In,
|
||||
//Default: p.param.Default,
|
||||
Format: p.param.Format,
|
||||
KnownFormats: p.KnownFormats,
|
||||
}
|
||||
}
|
||||
|
||||
type basicSliceValidator struct {
|
||||
Path string
|
||||
In string
|
||||
Default interface{}
|
||||
MaxItems *int64
|
||||
MinItems *int64
|
||||
UniqueItems bool
|
||||
Items *spec.Items
|
||||
Source interface{}
|
||||
itemsValidator *itemsValidator
|
||||
KnownFormats strfmt.Registry
|
||||
}
|
||||
|
||||
func (s *basicSliceValidator) SetPath(path string) {
|
||||
s.Path = path
|
||||
}
|
||||
|
||||
func (s *basicSliceValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
switch source.(type) {
|
||||
case *spec.Parameter, *spec.Items, *spec.Header:
|
||||
return kind == reflect.Slice
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func sErr(err errors.Error) *Result {
|
||||
return &Result{Errors: []error{err}}
|
||||
}
|
||||
|
||||
func (s *basicSliceValidator) Validate(data interface{}) *Result {
|
||||
val := reflect.ValueOf(data)
|
||||
|
||||
size := int64(val.Len())
|
||||
if s.MinItems != nil {
|
||||
if err := MinItems(s.Path, s.In, size, *s.MinItems); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.MaxItems != nil {
|
||||
if err := MaxItems(s.Path, s.In, size, *s.MaxItems); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.UniqueItems {
|
||||
if err := UniqueItems(s.Path, s.In, data); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.itemsValidator == nil && s.Items != nil {
|
||||
s.itemsValidator = newItemsValidator(s.Path, s.In, s.Items, s.Source, s.KnownFormats)
|
||||
}
|
||||
|
||||
if s.itemsValidator != nil {
|
||||
for i := 0; i < int(size); i++ {
|
||||
ele := val.Index(i)
|
||||
if err := s.itemsValidator.Validate(i, ele.Interface()); err != nil && err.HasErrors() {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *basicSliceValidator) hasDuplicates(value reflect.Value, size int) bool {
|
||||
dict := make(map[interface{}]struct{})
|
||||
for i := 0; i < size; i++ {
|
||||
ele := value.Index(i)
|
||||
if _, ok := dict[ele.Interface()]; ok {
|
||||
return true
|
||||
}
|
||||
dict[ele.Interface()] = struct{}{}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type numberValidator struct {
|
||||
Path string
|
||||
In string
|
||||
Default interface{}
|
||||
MultipleOf *float64
|
||||
Maximum *float64
|
||||
ExclusiveMaximum bool
|
||||
Minimum *float64
|
||||
ExclusiveMinimum bool
|
||||
}
|
||||
|
||||
func (n *numberValidator) SetPath(path string) {
|
||||
n.Path = path
|
||||
}
|
||||
|
||||
func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
switch source.(type) {
|
||||
case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header:
|
||||
isInt := kind >= reflect.Int && kind <= reflect.Uint64
|
||||
isFloat := kind == reflect.Float32 || kind == reflect.Float64
|
||||
r := isInt || isFloat
|
||||
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind)
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *numberValidator) convertToFloat(val interface{}) float64 {
|
||||
v := reflect.ValueOf(val)
|
||||
switch v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return float64(v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return float64(v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (n *numberValidator) Validate(val interface{}) *Result {
|
||||
data := n.convertToFloat(val)
|
||||
|
||||
if n.MultipleOf != nil {
|
||||
if err := MultipleOf(n.Path, n.In, data, *n.MultipleOf); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
if n.Maximum != nil {
|
||||
if err := Maximum(n.Path, n.In, data, *n.Maximum, n.ExclusiveMaximum); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
if n.Minimum != nil {
|
||||
if err := Minimum(n.Path, n.In, data, *n.Minimum, n.ExclusiveMinimum); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
result := new(Result)
|
||||
result.Inc()
|
||||
return result
|
||||
}
|
||||
|
||||
type stringValidator struct {
|
||||
Default interface{}
|
||||
Required bool
|
||||
AllowEmptyValue bool
|
||||
MaxLength *int64
|
||||
MinLength *int64
|
||||
Pattern string
|
||||
Path string
|
||||
In string
|
||||
}
|
||||
|
||||
func (s *stringValidator) SetPath(path string) {
|
||||
s.Path = path
|
||||
}
|
||||
|
||||
func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool {
|
||||
switch source.(type) {
|
||||
case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header:
|
||||
r := kind == reflect.String
|
||||
// fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
|
||||
return r
|
||||
}
|
||||
// fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind)
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *stringValidator) Validate(val interface{}) *Result {
|
||||
data := val.(string)
|
||||
|
||||
if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") {
|
||||
if err := RequiredString(s.Path, s.In, data); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.MaxLength != nil {
|
||||
if err := MaxLength(s.Path, s.In, data, *s.MaxLength); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.MinLength != nil {
|
||||
if err := MinLength(s.Path, s.In, data, *s.MinLength); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.Pattern != "" {
|
||||
if err := Pattern(s.Path, s.In, data, s.Pattern); err != nil {
|
||||
return sErr(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
218
vendor/github.com/go-openapi/validate/values.go
generated
vendored
Normal file
218
vendor/github.com/go-openapi/validate/values.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Enum validates if the data is a member of the enum
|
||||
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
|
||||
val := reflect.ValueOf(enum)
|
||||
if val.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
|
||||
var values []interface{}
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
ele := val.Index(i)
|
||||
enumValue := ele.Interface()
|
||||
if data != nil {
|
||||
if reflect.DeepEqual(data, enumValue) {
|
||||
return nil
|
||||
}
|
||||
actualType := reflect.TypeOf(enumValue)
|
||||
if actualType == nil {
|
||||
continue
|
||||
}
|
||||
expectedValue := reflect.ValueOf(data)
|
||||
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
||||
// Attempt comparison after type conversion
|
||||
if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
values = append(values, enumValue)
|
||||
}
|
||||
return errors.EnumFail(path, in, data, values)
|
||||
}
|
||||
|
||||
// MinItems validates that there are at least n items in a slice
|
||||
func MinItems(path, in string, size, min int64) *errors.Validation {
|
||||
if size < min {
|
||||
return errors.TooFewItems(path, in, min)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaxItems validates that there are at most n items in a slice
|
||||
func MaxItems(path, in string, size, max int64) *errors.Validation {
|
||||
if size > max {
|
||||
return errors.TooManyItems(path, in, max)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UniqueItems validates that the provided slice has unique elements
|
||||
func UniqueItems(path, in string, data interface{}) *errors.Validation {
|
||||
val := reflect.ValueOf(data)
|
||||
if val.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
var unique []interface{}
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
v := val.Index(i).Interface()
|
||||
for _, u := range unique {
|
||||
if reflect.DeepEqual(v, u) {
|
||||
return errors.DuplicateItems(path, in)
|
||||
}
|
||||
}
|
||||
unique = append(unique, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MinLength validates a string for minimum length
|
||||
func MinLength(path, in, data string, minLength int64) *errors.Validation {
|
||||
strLen := int64(utf8.RuneCount([]byte(data)))
|
||||
if strLen < minLength {
|
||||
return errors.TooShort(path, in, minLength)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaxLength validates a string for maximum length
|
||||
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
|
||||
strLen := int64(utf8.RuneCount([]byte(data)))
|
||||
if strLen > maxLength {
|
||||
return errors.TooLong(path, in, maxLength)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Required validates an interface for requiredness
|
||||
func Required(path, in string, data interface{}) *errors.Validation {
|
||||
val := reflect.ValueOf(data)
|
||||
if val.IsValid() {
|
||||
if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) {
|
||||
return errors.Required(path, in)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.Required(path, in)
|
||||
}
|
||||
|
||||
// RequiredString validates a string for requiredness
|
||||
func RequiredString(path, in, data string) *errors.Validation {
|
||||
if data == "" {
|
||||
return errors.Required(path, in)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequiredNumber validates a number for requiredness
|
||||
func RequiredNumber(path, in string, data float64) *errors.Validation {
|
||||
if data == 0 {
|
||||
return errors.Required(path, in)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pattern validates a string against a regular expression
|
||||
func Pattern(path, in, data, pattern string) *errors.Validation {
|
||||
re := regexp.MustCompile(pattern)
|
||||
if !re.MatchString(data) {
|
||||
return errors.FailedPattern(path, in, pattern)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaximumInt validates if a number is smaller than a given maximum
|
||||
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data > max) || (exclusive && data >= max) {
|
||||
return errors.ExceedsMaximumInt(path, in, max, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaximumUint validates if a number is smaller than a given maximum
|
||||
func MaximumUint(path, in string, data, max uint64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data > max) || (exclusive && data >= max) {
|
||||
return errors.ExceedsMaximumUint(path, in, max, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Maximum validates if a number is smaller than a given maximum
|
||||
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data > max) || (exclusive && data >= max) {
|
||||
return errors.ExceedsMaximum(path, in, max, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Minimum validates if a number is smaller than a given minimum
|
||||
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data < min) || (exclusive && data <= min) {
|
||||
return errors.ExceedsMinimum(path, in, min, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MinimumInt validates if a number is smaller than a given minimum
|
||||
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data < min) || (exclusive && data <= min) {
|
||||
return errors.ExceedsMinimumInt(path, in, min, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MinimumUint validates if a number is smaller than a given minimum
|
||||
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
|
||||
if (!exclusive && data < min) || (exclusive && data <= min) {
|
||||
return errors.ExceedsMinimumUint(path, in, min, exclusive)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MultipleOf validates if the provided number is a multiple of the factor
|
||||
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
|
||||
if !swag.IsFloat64AJSONInteger(data / factor) {
|
||||
return errors.NotMultipleOf(path, in, factor)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatOf validates if a string matches a format in the format registry
|
||||
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
|
||||
if registry == nil {
|
||||
registry = strfmt.Default
|
||||
}
|
||||
if ok := registry.ContainsName(format); !ok {
|
||||
return errors.InvalidTypeName(format)
|
||||
}
|
||||
if ok := registry.Validates(format, data); !ok {
|
||||
return errors.InvalidType(path, in, format, data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user