Add go-openapi dependencies and update Godeps

This commit is contained in:
mbohlool
2016-08-16 02:24:10 -07:00
parent ca7180e2b0
commit 0c51663aac
240 changed files with 60328 additions and 1 deletions

1
vendor/github.com/go-openapi/validate/.drone.sec generated vendored Normal file
View 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
View 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
View File

@@ -0,0 +1,4 @@
secrets.yml
coverage.out
*.cov
*.out

13
vendor/github.com/go-openapi/validate/.pullapprove.yml generated vendored Normal file
View 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

View 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
View 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
View File

@@ -0,0 +1,3 @@
# Validation helpers [![Build Status](https://ci.vmware.run/api/badges/go-openapi/validate/status.svg)](https://ci.vmware.run/go-openapi/validate) [![Coverage](https://coverage.vmware.run/badges/go-openapi/validate/coverage.svg)](https://coverage.vmware.run/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/validate/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/validate?status.svg)](http://godoc.org/github.com/go-openapi/validate)

69
vendor/github.com/go-openapi/validate/formats.go generated vendored Normal file
View 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
}

View 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
View 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
View 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
View 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
}

View 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
View 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(&param, s.KnownFormats).Validate(param.Default))
}
if param.Items != nil {
res.Merge(s.validateDefaultValueItemsAgainstSchema(param.Name, param.In, &param, 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
View 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
View 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
View 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
}