514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * 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 plugin
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 
 | |
| 	api "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
 | |
| 	"github.com/coze-dev/coze-studio/backend/domain/plugin/utils"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/errorx"
 | |
| 	"github.com/coze-dev/coze-studio/backend/types/errno"
 | |
| 
 | |
| 	"github.com/bytedance/sonic"
 | |
| )
 | |
| 
 | |
| type PluginManifest struct {
 | |
| 	SchemaVersion       string                                         `json:"schema_version" yaml:"schema_version"`
 | |
| 	NameForModel        string                                         `json:"name_for_model" yaml:"name_for_model"`
 | |
| 	NameForHuman        string                                         `json:"name_for_human" yaml:"name_for_human"`
 | |
| 	DescriptionForModel string                                         `json:"description_for_model" yaml:"description_for_model"`
 | |
| 	DescriptionForHuman string                                         `json:"description_for_human" yaml:"description_for_human"`
 | |
| 	Auth                *AuthV2                                        `json:"auth" yaml:"auth"`
 | |
| 	LogoURL             string                                         `json:"logo_url" yaml:"logo_url"`
 | |
| 	API                 APIDesc                                        `json:"api" yaml:"api"`
 | |
| 	CommonParams        map[HTTPParamLocation][]*api.CommonParamSchema `json:"common_params" yaml:"common_params"`
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) Copy() (*PluginManifest, error) {
 | |
| 	if mf == nil {
 | |
| 		return mf, nil
 | |
| 	}
 | |
| 
 | |
| 	b, err := json.Marshal(mf)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	mf_ := &PluginManifest{}
 | |
| 	err = json.Unmarshal(b, mf_)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return mf_, err
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) EncryptAuthPayload() (*PluginManifest, error) {
 | |
| 	if mf == nil || mf.Auth == nil {
 | |
| 		return mf, nil
 | |
| 	}
 | |
| 
 | |
| 	mf_, err := mf.Copy()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if mf_.Auth.Payload == "" {
 | |
| 		return mf_, nil
 | |
| 	}
 | |
| 
 | |
| 	payload_, err := utils.EncryptByAES([]byte(mf_.Auth.Payload), utils.AuthSecretKey)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	mf_.Auth.Payload = payload_
 | |
| 
 | |
| 	return mf_, nil
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) Validate(skipAuthPayload bool) (err error) {
 | |
| 	if mf.SchemaVersion != "v1" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid schema version '%s'", mf.SchemaVersion))
 | |
| 	}
 | |
| 	if mf.NameForModel == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"name for model is required"))
 | |
| 	}
 | |
| 	if mf.NameForHuman == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"name for human is required"))
 | |
| 	}
 | |
| 	if mf.DescriptionForModel == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"description for model is required"))
 | |
| 	}
 | |
| 	if mf.DescriptionForHuman == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"description for human is required"))
 | |
| 	}
 | |
| 	if mf.API.Type != PluginTypeOfCloud {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid api type '%s'", mf.API.Type))
 | |
| 	}
 | |
| 
 | |
| 	err = mf.validateAuthInfo(skipAuthPayload)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	for loc := range mf.CommonParams {
 | |
| 		if loc != ParamInBody &&
 | |
| 			loc != ParamInHeader &&
 | |
| 			loc != ParamInQuery &&
 | |
| 			loc != ParamInPath {
 | |
| 			return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 				"invalid location '%s' in common params", loc))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) validateAuthInfo(skipAuthPayload bool) (err error) {
 | |
| 	if mf.Auth == nil {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"auth is required"))
 | |
| 	}
 | |
| 
 | |
| 	if mf.Auth.Payload != "" {
 | |
| 		js := json.RawMessage{}
 | |
| 		err = sonic.UnmarshalString(mf.Auth.Payload, &js)
 | |
| 		if err != nil {
 | |
| 			return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 				"invalid auth payload"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if mf.Auth.Type == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"auth type is required"))
 | |
| 	}
 | |
| 
 | |
| 	if mf.Auth.Type != AuthzTypeOfNone &&
 | |
| 		mf.Auth.Type != AuthzTypeOfOAuth &&
 | |
| 		mf.Auth.Type != AuthzTypeOfService {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid auth type '%s'", mf.Auth.Type))
 | |
| 	}
 | |
| 
 | |
| 	if mf.Auth.Type == AuthzTypeOfNone {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if mf.Auth.SubType == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"sub-auth type is required"))
 | |
| 	}
 | |
| 
 | |
| 	switch mf.Auth.SubType {
 | |
| 	case AuthzSubTypeOfServiceAPIToken:
 | |
| 		err = mf.validateServiceToken(skipAuthPayload)
 | |
| 	//case AuthzSubTypeOfOAuthClientCredentials:
 | |
| 	//	err = mf.validateClientCredentials()
 | |
| 	case AuthzSubTypeOfOAuthAuthorizationCode:
 | |
| 		err = mf.validateAuthCode(skipAuthPayload)
 | |
| 	default:
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid sub-auth type '%s'", mf.Auth.SubType))
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) validateServiceToken(skipAuthPayload bool) (err error) {
 | |
| 	if mf.Auth.AuthOfAPIToken == nil {
 | |
| 		err = sonic.UnmarshalString(mf.Auth.Payload, &mf.Auth.AuthOfAPIToken)
 | |
| 		if err != nil {
 | |
| 			return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 				"invalid auth payload"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if skipAuthPayload {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	apiToken := mf.Auth.AuthOfAPIToken
 | |
| 
 | |
| 	if apiToken.ServiceToken == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"service token is required"))
 | |
| 	}
 | |
| 	if apiToken.Key == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"key is required"))
 | |
| 	}
 | |
| 
 | |
| 	loc := HTTPParamLocation(strings.ToLower(string(apiToken.Location)))
 | |
| 	if loc != ParamInHeader && loc != ParamInQuery {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid location '%s'", apiToken.Location))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) validateClientCredentials() (err error) {
 | |
| 	if mf.Auth.AuthOfOAuthClientCredentials == nil {
 | |
| 		err = sonic.UnmarshalString(mf.Auth.Payload, &mf.Auth.AuthOfOAuthClientCredentials)
 | |
| 		if err != nil {
 | |
| 			return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 				"invalid auth payload"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	clientCredentials := mf.Auth.AuthOfOAuthClientCredentials
 | |
| 
 | |
| 	if clientCredentials.ClientID == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client id is required"))
 | |
| 	}
 | |
| 	if clientCredentials.ClientSecret == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client secret is required"))
 | |
| 	}
 | |
| 	if clientCredentials.TokenURL == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"token url is required"))
 | |
| 	}
 | |
| 
 | |
| 	urlParse, err := url.Parse(clientCredentials.TokenURL)
 | |
| 	if err != nil || urlParse.Hostname() == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"invalid token url"))
 | |
| 	}
 | |
| 	if urlParse.Scheme != "https" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"token url scheme must be 'https'"))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (mf *PluginManifest) validateAuthCode(skipAuthPayload bool) (err error) {
 | |
| 	if mf.Auth.AuthOfOAuthAuthorizationCode == nil {
 | |
| 		err = sonic.UnmarshalString(mf.Auth.Payload, &mf.Auth.AuthOfOAuthAuthorizationCode)
 | |
| 		if err != nil {
 | |
| 			return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 				"invalid auth payload"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if skipAuthPayload {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	authCode := mf.Auth.AuthOfOAuthAuthorizationCode
 | |
| 
 | |
| 	if authCode.ClientID == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client id is required"))
 | |
| 	}
 | |
| 	if authCode.ClientSecret == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client secret is required"))
 | |
| 	}
 | |
| 	if authCode.AuthorizationContentType != MediaTypeJson {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"authorization content type must be 'application/json'"))
 | |
| 	}
 | |
| 	if authCode.AuthorizationURL == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"token url is required"))
 | |
| 	}
 | |
| 	if authCode.ClientURL == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client url is required"))
 | |
| 	}
 | |
| 
 | |
| 	urlParse, err := url.Parse(authCode.AuthorizationURL)
 | |
| 	if err != nil || urlParse.Hostname() == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"invalid authorization url"))
 | |
| 	}
 | |
| 	if urlParse.Scheme != "https" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"authorization url scheme must be 'https'"))
 | |
| 	}
 | |
| 
 | |
| 	urlParse, err = url.Parse(authCode.ClientURL)
 | |
| 	if err != nil || urlParse.Hostname() == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"invalid client url"))
 | |
| 	}
 | |
| 	if urlParse.Scheme != "https" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"client url scheme must be 'https'"))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type Auth struct {
 | |
| 	Type                     string `json:"type" validate:"required"`
 | |
| 	AuthorizationType        string `json:"authorization_type,omitempty"`
 | |
| 	ClientURL                string `json:"client_url,omitempty"`
 | |
| 	Scope                    string `json:"scope,omitempty"`
 | |
| 	AuthorizationURL         string `json:"authorization_url,omitempty"`
 | |
| 	AuthorizationContentType string `json:"authorization_content_type,omitempty"`
 | |
| 	Platform                 string `json:"platform,omitempty"`
 | |
| 	ClientID                 string `json:"client_id,omitempty"`
 | |
| 	ClientSecret             string `json:"client_secret,omitempty"`
 | |
| 	Location                 string `json:"location,omitempty"`
 | |
| 	Key                      string `json:"key,omitempty"`
 | |
| 	ServiceToken             string `json:"service_token,omitempty"`
 | |
| 	SubType                  string `json:"sub_type"`
 | |
| 	Payload                  string `json:"payload"`
 | |
| }
 | |
| 
 | |
| type AuthV2 struct {
 | |
| 	Type    AuthzType    `json:"type" yaml:"type"`
 | |
| 	SubType AuthzSubType `json:"sub_type" yaml:"sub_type"`
 | |
| 	Payload string       `json:"payload" yaml:"payload"`
 | |
| 	// service
 | |
| 	AuthOfAPIToken *AuthOfAPIToken `json:"-"`
 | |
| 
 | |
| 	// oauth
 | |
| 	AuthOfOAuthAuthorizationCode *OAuthAuthorizationCodeConfig `json:"-"`
 | |
| 	AuthOfOAuthClientCredentials *OAuthClientCredentialsConfig `json:"-"`
 | |
| }
 | |
| 
 | |
| func (au *AuthV2) UnmarshalJSON(data []byte) error {
 | |
| 	auth := &Auth{} // 兼容老数据
 | |
| 	err := json.Unmarshal(data, auth)
 | |
| 	if err != nil {
 | |
| 		return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"invalid plugin manifest json"))
 | |
| 	}
 | |
| 
 | |
| 	au.Type = AuthzType(auth.Type)
 | |
| 	au.SubType = AuthzSubType(auth.SubType)
 | |
| 
 | |
| 	if au.Type == "" {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 			"plugin auth type is required"))
 | |
| 	}
 | |
| 
 | |
| 	if auth.Payload != "" {
 | |
| 		payload_, err := utils.DecryptByAES(auth.Payload, utils.AuthSecretKey)
 | |
| 		if err == nil {
 | |
| 			auth.Payload = string(payload_)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	switch au.Type {
 | |
| 	case AuthzTypeOfNone:
 | |
| 	case AuthzTypeOfOAuth:
 | |
| 		err = au.unmarshalOAuth(auth)
 | |
| 	case AuthzTypeOfService:
 | |
| 		err = au.unmarshalService(auth)
 | |
| 	default:
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid plugin auth type '%s'", au.Type))
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (au *AuthV2) unmarshalService(auth *Auth) (err error) {
 | |
| 	if au.SubType == "" && au.Payload == "" { // 兼容老数据
 | |
| 		au.SubType = AuthzSubTypeOfServiceAPIToken
 | |
| 	}
 | |
| 
 | |
| 	var payload []byte
 | |
| 
 | |
| 	if au.SubType == AuthzSubTypeOfServiceAPIToken {
 | |
| 		if len(auth.ServiceToken) > 0 {
 | |
| 			au.AuthOfAPIToken = &AuthOfAPIToken{
 | |
| 				Location:     HTTPParamLocation(strings.ToLower(auth.Location)),
 | |
| 				Key:          auth.Key,
 | |
| 				ServiceToken: auth.ServiceToken,
 | |
| 			}
 | |
| 		} else {
 | |
| 			token := &AuthOfAPIToken{}
 | |
| 			err = json.Unmarshal([]byte(auth.Payload), token)
 | |
| 			if err != nil {
 | |
| 				return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 					"invalid auth payload json"))
 | |
| 			}
 | |
| 			au.AuthOfAPIToken = token
 | |
| 		}
 | |
| 
 | |
| 		payload, err = json.Marshal(au.AuthOfAPIToken)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(payload) == 0 {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid plugin sub-auth type '%s'", au.SubType))
 | |
| 	}
 | |
| 
 | |
| 	au.Payload = string(payload)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (au *AuthV2) unmarshalOAuth(auth *Auth) (err error) {
 | |
| 	if au.SubType == "" { // 兼容老数据
 | |
| 		au.SubType = AuthzSubTypeOfOAuthAuthorizationCode
 | |
| 	}
 | |
| 
 | |
| 	var payload []byte
 | |
| 
 | |
| 	if au.SubType == AuthzSubTypeOfOAuthAuthorizationCode {
 | |
| 		if len(auth.ClientSecret) > 0 {
 | |
| 			au.AuthOfOAuthAuthorizationCode = &OAuthAuthorizationCodeConfig{
 | |
| 				ClientID:                 auth.ClientID,
 | |
| 				ClientSecret:             auth.ClientSecret,
 | |
| 				ClientURL:                auth.ClientURL,
 | |
| 				Scope:                    auth.Scope,
 | |
| 				AuthorizationURL:         auth.AuthorizationURL,
 | |
| 				AuthorizationContentType: auth.AuthorizationContentType,
 | |
| 			}
 | |
| 		} else {
 | |
| 			oauth := &OAuthAuthorizationCodeConfig{}
 | |
| 			err = json.Unmarshal([]byte(auth.Payload), oauth)
 | |
| 			if err != nil {
 | |
| 				return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 					"invalid auth payload json"))
 | |
| 			}
 | |
| 			au.AuthOfOAuthAuthorizationCode = oauth
 | |
| 		}
 | |
| 
 | |
| 		payload, err = json.Marshal(au.AuthOfOAuthAuthorizationCode)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if au.SubType == AuthzSubTypeOfOAuthClientCredentials {
 | |
| 		oauth := &OAuthClientCredentialsConfig{}
 | |
| 		err = json.Unmarshal([]byte(auth.Payload), oauth)
 | |
| 		if err != nil {
 | |
| 			return errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey,
 | |
| 				"invalid auth payload json"))
 | |
| 		}
 | |
| 		au.AuthOfOAuthClientCredentials = oauth
 | |
| 
 | |
| 		payload, err = json.Marshal(au.AuthOfOAuthClientCredentials)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(payload) == 0 {
 | |
| 		return errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
 | |
| 			"invalid plugin sub-auth type '%s'", au.SubType))
 | |
| 	}
 | |
| 
 | |
| 	au.Payload = string(payload)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type AuthOfAPIToken struct {
 | |
| 	// Location is the location of the parameter.
 | |
| 	// It can be "header" or "query".
 | |
| 	Location HTTPParamLocation `json:"location"`
 | |
| 	// Key is the name of the parameter.
 | |
| 	Key string `json:"key"`
 | |
| 	// ServiceToken is the simple authorization information for the service.
 | |
| 	ServiceToken string `json:"service_token"`
 | |
| }
 | |
| 
 | |
| type OAuthAuthorizationCodeConfig struct {
 | |
| 	ClientID     string `json:"client_id"`
 | |
| 	ClientSecret string `json:"client_secret"`
 | |
| 	// ClientURL is the URL of authorization endpoint.
 | |
| 	ClientURL string `json:"client_url"`
 | |
| 	// Scope is the scope of the authorization request.
 | |
| 	// If multiple scopes are requested, they must be separated by a space.
 | |
| 	Scope string `json:"scope,omitempty"`
 | |
| 	// AuthorizationURL is the URL of token exchange endpoint.
 | |
| 	AuthorizationURL string `json:"authorization_url"`
 | |
| 	// AuthorizationContentType is the content type of the authorization request, and it must be "application/json".
 | |
| 	AuthorizationContentType string `json:"authorization_content_type"`
 | |
| }
 | |
| 
 | |
| type OAuthClientCredentialsConfig struct {
 | |
| 	ClientID     string `json:"client_id"`
 | |
| 	ClientSecret string `json:"client_secret"`
 | |
| 	TokenURL     string `json:"token_url"`
 | |
| }
 | |
| 
 | |
| type APIDesc struct {
 | |
| 	Type PluginType `json:"type" validate:"required"`
 | |
| }
 |