go.mod: bump github.com/getkin/kin-openapi to v0.131.0

As deepmap/oapi-codegen didn't work with this newer version, upgrade to
oapi-codegen/oapi-codegen v2.

Mitigating CVE-2025-30153
This commit is contained in:
Sanne Raymaekers 2025-03-21 11:50:30 +01:00 committed by Ondřej Budai
parent c5cb0d0618
commit b2700903ae
403 changed files with 44758 additions and 16347 deletions

View file

@ -2,33 +2,17 @@ package openapi3
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
"net/url"
)
type SecuritySchemes map[string]*SecuritySchemeRef
func (s SecuritySchemes) JSONLookup(token string) (interface{}, error) {
ref, ok := s[token]
if ref == nil || ok == false {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil)
// SecurityScheme is specified by OpenAPI/Swagger standard version 3.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#securitySchemeObject
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object
type SecurityScheme struct {
ExtensionProps
Extensions map[string]any `json:"-" yaml:"-"`
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
@ -67,12 +51,70 @@ func NewJWTSecurityScheme() *SecurityScheme {
}
}
func (ss *SecurityScheme) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(ss)
// MarshalJSON returns the JSON encoding of SecurityScheme.
func (ss SecurityScheme) MarshalJSON() ([]byte, error) {
x, err := ss.MarshalYAML()
if err != nil {
return nil, err
}
return json.Marshal(x)
}
// MarshalYAML returns the YAML encoding of SecurityScheme.
func (ss SecurityScheme) MarshalYAML() (any, error) {
m := make(map[string]any, 8+len(ss.Extensions))
for k, v := range ss.Extensions {
m[k] = v
}
if x := ss.Type; x != "" {
m["type"] = x
}
if x := ss.Description; x != "" {
m["description"] = x
}
if x := ss.Name; x != "" {
m["name"] = x
}
if x := ss.In; x != "" {
m["in"] = x
}
if x := ss.Scheme; x != "" {
m["scheme"] = x
}
if x := ss.BearerFormat; x != "" {
m["bearerFormat"] = x
}
if x := ss.Flows; x != nil {
m["flows"] = x
}
if x := ss.OpenIdConnectUrl; x != "" {
m["openIdConnectUrl"] = x
}
return m, nil
}
// UnmarshalJSON sets SecurityScheme to a copy of data.
func (ss *SecurityScheme) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, ss)
type SecuritySchemeBis SecurityScheme
var x SecuritySchemeBis
if err := json.Unmarshal(data, &x); err != nil {
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, originKey)
delete(x.Extensions, "type")
delete(x.Extensions, "description")
delete(x.Extensions, "name")
delete(x.Extensions, "in")
delete(x.Extensions, "scheme")
delete(x.Extensions, "bearerFormat")
delete(x.Extensions, "flows")
delete(x.Extensions, "openIdConnectUrl")
if len(x.Extensions) == 0 {
x.Extensions = nil
}
*ss = SecurityScheme(x)
return nil
}
func (ss *SecurityScheme) WithType(value string) *SecurityScheme {
@ -105,15 +147,18 @@ func (ss *SecurityScheme) WithBearerFormat(value string) *SecurityScheme {
return ss
}
func (value *SecurityScheme) Validate(ctx context.Context) error {
// Validate returns an error if SecurityScheme does not comply with the OpenAPI spec.
func (ss *SecurityScheme) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
hasIn := false
hasBearerFormat := false
hasFlow := false
switch value.Type {
switch ss.Type {
case "apiKey":
hasIn = true
case "http":
scheme := value.Scheme
scheme := ss.Scheme
switch scheme {
case "bearer":
hasBearerFormat = true
@ -124,54 +169,56 @@ func (value *SecurityScheme) Validate(ctx context.Context) error {
case "oauth2":
hasFlow = true
case "openIdConnect":
if value.OpenIdConnectUrl == "" {
return fmt.Errorf("no OIDC URL found for openIdConnect security scheme %q", value.Name)
if ss.OpenIdConnectUrl == "" {
return fmt.Errorf("no OIDC URL found for openIdConnect security scheme %q", ss.Name)
}
default:
return fmt.Errorf("security scheme 'type' can't be %q", value.Type)
return fmt.Errorf("security scheme 'type' can't be %q", ss.Type)
}
// Validate "in" and "name"
if hasIn {
switch value.In {
switch ss.In {
case "query", "header", "cookie":
default:
return fmt.Errorf("security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not %q", value.In)
return fmt.Errorf("security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not %q", ss.In)
}
if value.Name == "" {
if ss.Name == "" {
return errors.New("security scheme of type 'apiKey' should have 'name'")
}
} else if len(value.In) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'in'", value.Type)
} else if len(value.Name) > 0 {
return errors.New("security scheme of type 'apiKey' can't have 'name'")
} else if len(ss.In) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'in'", ss.Type)
} else if len(ss.Name) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'name'", ss.Type)
}
// Validate "format"
// "bearerFormat" is an arbitrary string so we only check if the scheme supports it
if !hasBearerFormat && len(value.BearerFormat) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'bearerFormat'", value.Type)
if !hasBearerFormat && len(ss.BearerFormat) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'bearerFormat'", ss.Type)
}
// Validate "flow"
if hasFlow {
flow := value.Flows
flow := ss.Flows
if flow == nil {
return fmt.Errorf("security scheme of type %q should have 'flows'", value.Type)
return fmt.Errorf("security scheme of type %q should have 'flows'", ss.Type)
}
if err := flow.Validate(ctx); err != nil {
return fmt.Errorf("security scheme 'flow' is invalid: %v", err)
return fmt.Errorf("security scheme 'flow' is invalid: %w", err)
}
} else if value.Flows != nil {
return fmt.Errorf("security scheme of type %q can't have 'flows'", value.Type)
} else if ss.Flows != nil {
return fmt.Errorf("security scheme of type %q can't have 'flows'", ss.Type)
}
return nil
return validateExtensions(ctx, ss.Extensions)
}
// OAuthFlows is specified by OpenAPI/Swagger standard version 3.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowsObject
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flows-object
type OAuthFlows struct {
ExtensionProps
Extensions map[string]any `json:"-" yaml:"-"`
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
@ -188,62 +235,208 @@ const (
oAuthFlowAuthorizationCode
)
func (flows *OAuthFlows) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(flows)
// MarshalJSON returns the JSON encoding of OAuthFlows.
func (flows OAuthFlows) MarshalJSON() ([]byte, error) {
x, err := flows.MarshalYAML()
if err != nil {
return nil, err
}
return json.Marshal(x)
}
// MarshalYAML returns the YAML encoding of OAuthFlows.
func (flows OAuthFlows) MarshalYAML() (any, error) {
m := make(map[string]any, 4+len(flows.Extensions))
for k, v := range flows.Extensions {
m[k] = v
}
if x := flows.Implicit; x != nil {
m["implicit"] = x
}
if x := flows.Password; x != nil {
m["password"] = x
}
if x := flows.ClientCredentials; x != nil {
m["clientCredentials"] = x
}
if x := flows.AuthorizationCode; x != nil {
m["authorizationCode"] = x
}
return m, nil
}
// UnmarshalJSON sets OAuthFlows to a copy of data.
func (flows *OAuthFlows) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, flows)
type OAuthFlowsBis OAuthFlows
var x OAuthFlowsBis
if err := json.Unmarshal(data, &x); err != nil {
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, originKey)
delete(x.Extensions, "implicit")
delete(x.Extensions, "password")
delete(x.Extensions, "clientCredentials")
delete(x.Extensions, "authorizationCode")
if len(x.Extensions) == 0 {
x.Extensions = nil
}
*flows = OAuthFlows(x)
return nil
}
func (flows *OAuthFlows) Validate(ctx context.Context) error {
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
func (flows *OAuthFlows) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := flows.Implicit; v != nil {
return v.Validate(ctx, oAuthFlowTypeImplicit)
if err := v.validate(ctx, oAuthFlowTypeImplicit, opts...); err != nil {
return fmt.Errorf("the OAuth flow 'implicit' is invalid: %w", err)
}
}
if v := flows.Password; v != nil {
return v.Validate(ctx, oAuthFlowTypePassword)
if err := v.validate(ctx, oAuthFlowTypePassword, opts...); err != nil {
return fmt.Errorf("the OAuth flow 'password' is invalid: %w", err)
}
}
if v := flows.ClientCredentials; v != nil {
return v.Validate(ctx, oAuthFlowTypeClientCredentials)
if err := v.validate(ctx, oAuthFlowTypeClientCredentials, opts...); err != nil {
return fmt.Errorf("the OAuth flow 'clientCredentials' is invalid: %w", err)
}
}
if v := flows.AuthorizationCode; v != nil {
return v.Validate(ctx, oAuthFlowAuthorizationCode)
if err := v.validate(ctx, oAuthFlowAuthorizationCode, opts...); err != nil {
return fmt.Errorf("the OAuth flow 'authorizationCode' is invalid: %w", err)
}
}
return errors.New("no OAuth flow is defined")
return validateExtensions(ctx, flows.Extensions)
}
// OAuthFlow is specified by OpenAPI/Swagger standard version 3.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowObject
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flow-object
type OAuthFlow struct {
ExtensionProps
Extensions map[string]any `json:"-" yaml:"-"`
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
Scopes map[string]string `json:"scopes" yaml:"scopes"`
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
Scopes StringMap `json:"scopes" yaml:"scopes"` // required
}
func (flow *OAuthFlow) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(flow)
// MarshalJSON returns the JSON encoding of OAuthFlow.
func (flow OAuthFlow) MarshalJSON() ([]byte, error) {
x, err := flow.MarshalYAML()
if err != nil {
return nil, err
}
return json.Marshal(x)
}
// MarshalYAML returns the YAML encoding of OAuthFlow.
func (flow OAuthFlow) MarshalYAML() (any, error) {
m := make(map[string]any, 4+len(flow.Extensions))
for k, v := range flow.Extensions {
m[k] = v
}
if x := flow.AuthorizationURL; x != "" {
m["authorizationUrl"] = x
}
if x := flow.TokenURL; x != "" {
m["tokenUrl"] = x
}
if x := flow.RefreshURL; x != "" {
m["refreshUrl"] = x
}
m["scopes"] = flow.Scopes
return m, nil
}
// UnmarshalJSON sets OAuthFlow to a copy of data.
func (flow *OAuthFlow) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, flow)
}
type OAuthFlowBis OAuthFlow
var x OAuthFlowBis
if err := json.Unmarshal(data, &x); err != nil {
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
func (flow *OAuthFlow) Validate(ctx context.Context, typ oAuthFlowType) error {
if typ == oAuthFlowAuthorizationCode || typ == oAuthFlowTypeImplicit {
if v := flow.AuthorizationURL; v == "" {
return errors.New("an OAuth flow is missing 'authorizationUrl in authorizationCode or implicit '")
}
}
if typ != oAuthFlowTypeImplicit {
if v := flow.TokenURL; v == "" {
return errors.New("an OAuth flow is missing 'tokenUrl in not implicit'")
}
}
if v := flow.Scopes; v == nil {
return errors.New("an OAuth flow is missing 'scopes'")
delete(x.Extensions, originKey)
delete(x.Extensions, "authorizationUrl")
delete(x.Extensions, "tokenUrl")
delete(x.Extensions, "refreshUrl")
delete(x.Extensions, "scopes")
if len(x.Extensions) == 0 {
x.Extensions = nil
}
*flow = OAuthFlow(x)
return nil
}
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
func (flow *OAuthFlow) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := flow.RefreshURL; v != "" {
if _, err := url.Parse(v); err != nil {
return fmt.Errorf("field 'refreshUrl' is invalid: %w", err)
}
}
if flow.Scopes == nil {
return errors.New("field 'scopes' is missing")
}
return validateExtensions(ctx, flow.Extensions)
}
func (flow *OAuthFlow) validate(ctx context.Context, typ oAuthFlowType, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
typeIn := func(types ...oAuthFlowType) bool {
for _, ty := range types {
if ty == typ {
return true
}
}
return false
}
if in := typeIn(oAuthFlowTypeImplicit, oAuthFlowAuthorizationCode); true {
switch {
case flow.AuthorizationURL == "" && in:
return errors.New("field 'authorizationUrl' is empty or missing")
case flow.AuthorizationURL != "" && !in:
return errors.New("field 'authorizationUrl' should not be set")
case flow.AuthorizationURL != "":
if _, err := url.Parse(flow.AuthorizationURL); err != nil {
return fmt.Errorf("field 'authorizationUrl' is invalid: %w", err)
}
}
}
if in := typeIn(oAuthFlowTypePassword, oAuthFlowTypeClientCredentials, oAuthFlowAuthorizationCode); true {
switch {
case flow.TokenURL == "" && in:
return errors.New("field 'tokenUrl' is empty or missing")
case flow.TokenURL != "" && !in:
return errors.New("field 'tokenUrl' should not be set")
case flow.TokenURL != "":
if _, err := url.Parse(flow.TokenURL); err != nil {
return fmt.Errorf("field 'tokenUrl' is invalid: %w", err)
}
}
}
return flow.Validate(ctx, opts...)
}
// UnmarshalJSON sets SecuritySchemes to a copy of data.
func (securitySchemes *SecuritySchemes) UnmarshalJSON(data []byte) (err error) {
*securitySchemes, _, err = unmarshalStringMapP[SecuritySchemeRef](data)
return
}