mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 00:00:52 +00:00
510 lines
17 KiB
Go
510 lines
17 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
"unicode/utf8"
|
|
|
|
"github.com/1Panel-dev/1Panel/core/app/auth"
|
|
"github.com/1Panel-dev/1Panel/core/app/dto"
|
|
"github.com/1Panel-dev/1Panel/core/app/model"
|
|
"github.com/1Panel-dev/1Panel/core/app/repo"
|
|
"github.com/1Panel-dev/1Panel/core/buserr"
|
|
"github.com/1Panel-dev/1Panel/core/constant"
|
|
"github.com/1Panel-dev/1Panel/core/global"
|
|
"github.com/1Panel-dev/1Panel/core/utils/apikey_audit"
|
|
"github.com/1Panel-dev/1Panel/core/utils/common"
|
|
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
|
|
terminalsession "github.com/1Panel-dev/1Panel/core/utils/terminal_session"
|
|
"github.com/1Panel-dev/1Panel/core/utils/xpack"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
var apiKeyMutationMu sync.Mutex
|
|
|
|
type APIKeyService struct {
|
|
Provider auth.APIKeyOwnerProvider
|
|
RevokeTerminals terminalsession.RevokeFunc
|
|
}
|
|
|
|
func NewAPIKeyService() *APIKeyService {
|
|
provider, _ := xpack.AuthProvider.(auth.APIKeyOwnerProvider)
|
|
return &APIKeyService{Provider: provider, RevokeTerminals: xpack.AuthProvider.RevokeTerminalSessions}
|
|
}
|
|
|
|
func (s *APIKeyService) owner(c *gin.Context) (auth.APIKeyOwner, error) {
|
|
if _, err := auth.RequireAPIKeySession(c); err != nil {
|
|
return auth.APIKeyOwner{}, err
|
|
}
|
|
if s.Provider == nil {
|
|
return auth.APIKeyOwner{}, buserr.New("ErrApiConfigStatusInvalid")
|
|
}
|
|
return s.Provider.CurrentAPIKeyOwner(c)
|
|
}
|
|
|
|
func apiKeyItem(key model.APIKey) dto.APIKeyItem {
|
|
status := key.Status
|
|
if status != "Revoked" && key.ExpiresAt != nil && !time.Now().Before(*key.ExpiresAt) {
|
|
status = "Expired"
|
|
}
|
|
return dto.APIKeyItem{ID: key.ID, Kind: "apiKey", Name: key.Name, Description: key.Description, KeyHint: key.KeyHint, Status: status, IPWhiteList: key.IPWhiteList, APITrustedProxies: key.APITrustedProxies, APIKeyValidityTime: key.APIKeyValidityTime, ExpiresAt: key.ExpiresAt, AllowAppBinding: key.AllowAppBinding, Revision: key.Revision, CreatedAt: &key.CreatedAt}
|
|
}
|
|
|
|
func (s *APIKeyService) legacy(owner auth.APIKeyOwner) (dto.APIKeyItem, auth.APIAuthConfig, model.LegacyAPIKeyPolicy, string, error) {
|
|
config, err := s.Provider.LoadLegacyAPIKey(owner)
|
|
if err != nil {
|
|
return dto.APIKeyItem{}, config, model.LegacyAPIKeyPolicy{}, "", err
|
|
}
|
|
policy, err := auth.LoadLegacyAPIKeyPolicy(owner)
|
|
if err != nil {
|
|
return dto.APIKeyItem{}, config, policy, "", err
|
|
}
|
|
fingerprint, revision := auth.LegacyAPIKeyFingerprint(owner, config, policy)
|
|
item := dto.APIKeyItem{ID: "legacy", Kind: "legacy", Name: "Legacy API Key", KeyHint: keyHint(config.ApiKey), Status: config.ApiInterfaceStatus, IPWhiteList: config.IpWhiteList, APITrustedProxies: config.ApiTrustedProxies, APIKeyValidityTime: config.ApiKeyValidityTime, AllowAppBinding: policy.AllowAppBinding, Revision: revision}
|
|
return item, config, policy, fingerprint, nil
|
|
}
|
|
|
|
func (s *APIKeyService) Search(c *gin.Context, req dto.APIKeySearch) (*dto.APIKeyPage, error) {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if req.Page < 1 || req.PageSize < 1 || req.PageSize > 100 {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
keys, err := repo.NewAPIKeyRepo().List(owner.Type, owner.ID, req.ExcludeRevoked)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items := make([]dto.APIKeyItem, 0, len(keys)+1)
|
|
legacy, config, _, _, err := s.legacy(owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if config.ApiKey != "" {
|
|
items = append(items, legacy)
|
|
}
|
|
for _, key := range keys {
|
|
items = append(items, apiKeyItem(key))
|
|
}
|
|
result := &dto.APIKeyPage{Items: []dto.APIKeyItem{}, Total: len(items)}
|
|
start := (req.Page - 1) * req.PageSize
|
|
if start >= 0 && start < len(items) {
|
|
result.Items = items[start:min(start+req.PageSize, len(items))]
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func validateAPIKeyFields(fields *dto.APIKeyFields, create bool) (*time.Time, error) {
|
|
fields.Name = strings.TrimSpace(fields.Name)
|
|
fields.Description = strings.TrimSpace(fields.Description)
|
|
if fields.Name == "" || utf8.RuneCountInString(fields.Name) > 64 || utf8.RuneCountInString(fields.Description) > 256 || fields.APIKeyValidityTime < 0 || fields.APIKeyValidityTime > 1440 || len(fields.IPWhiteList) > 4096 || len(fields.APITrustedProxies) > 4096 {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
ips, err := common.HandleIPList(fields.IPWhiteList)
|
|
if err != nil || len(ips) == 0 {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
|
|
fields.IPWhiteList = strings.Join(ips, "\n")
|
|
fields.APITrustedProxies, err = auth.NormalizeAPITrustedProxies(fields.APITrustedProxies)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(fields.ExpiresAt) == 0 {
|
|
if !create {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
expires := time.Now().UTC().Add(90 * 24 * time.Hour)
|
|
return &expires, nil
|
|
}
|
|
if bytes.Equal(bytes.TrimSpace(fields.ExpiresAt), []byte("null")) {
|
|
return nil, nil
|
|
}
|
|
var expires time.Time
|
|
if err = json.Unmarshal(fields.ExpiresAt, &expires); err != nil || !expires.After(time.Now()) {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
return &expires, nil
|
|
}
|
|
|
|
func keyHint(secret string) string {
|
|
if len(secret) < 8 {
|
|
return ""
|
|
}
|
|
return secret[:4] + "••••" + secret[len(secret)-4:]
|
|
}
|
|
|
|
func (s *APIKeyService) Create(c *gin.Context, req dto.APIKeyCreate) (*dto.APIKeyCreated, error) {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err = uuid.Parse(req.RequestID); err != nil {
|
|
return nil, buserr.New("ErrInvalidParams")
|
|
}
|
|
expires, err := validateAPIKeyFields(&req.APIKeyFields, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
encoded, _ := json.Marshal(req.APIKeyFields)
|
|
digest := sha256.Sum256(encoded)
|
|
requestHash := hex.EncodeToString(digest[:])
|
|
master, err := encrypt.APIKeyEncryptionKey()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiKeyMutationMu.Lock()
|
|
var key model.APIKey
|
|
var secret string
|
|
repeated := false
|
|
err = global.DB.Transaction(func(tx *gorm.DB) error {
|
|
q := repo.APIKeyOwnerQuery(tx, owner.Type, owner.ID)
|
|
err := q.Where("request_id = ?", req.RequestID).First(&key).Error
|
|
if err == nil {
|
|
if key.RequestHash != requestHash {
|
|
return buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
repeated = true
|
|
return nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
if err = ensureAPIKeyName(tx, owner, req.Name, ""); err != nil {
|
|
return err
|
|
}
|
|
bytes := make([]byte, 16)
|
|
if _, err = rand.Read(bytes); err != nil {
|
|
return err
|
|
}
|
|
secret = hex.EncodeToString(bytes)
|
|
key = model.APIKey{ID: uuid.NewString(), OwnerType: owner.Type, OwnerID: owner.ID, Name: req.Name, ActiveName: &req.Name, Description: req.Description, RequestID: req.RequestID, RequestHash: requestHash, SecretVersion: 1, KeyHint: keyHint(secret), Status: constant.StatusEnable, IPWhiteList: req.IPWhiteList, APITrustedProxies: req.APITrustedProxies, APIKeyValidityTime: req.APIKeyValidityTime, ExpiresAt: expires, AllowAppBinding: req.AllowAppBinding, Revision: 1}
|
|
key.SecretCiphertext, err = encrypt.EncryptAPIKey(secret, key.ID, master)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return tx.Create(&key).Error
|
|
})
|
|
apiKeyMutationMu.Unlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !repeated {
|
|
recordAPIKeyEvent(c, owner, key.ID, key.Name, "create")
|
|
}
|
|
return &dto.APIKeyCreated{Item: apiKeyItem(key), APIKey: secret, AlreadyCreated: repeated}, nil
|
|
}
|
|
|
|
func ensureAPIKeyName(tx *gorm.DB, owner auth.APIKeyOwner, name, id string) error {
|
|
var count int64
|
|
err := repo.APIKeyOwnerQuery(tx.Model(&model.APIKey{}), owner.Type, owner.ID).Where("active_name = ? AND id <> ?", name, id).Count(&count).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if count > 0 {
|
|
return buserr.New("ErrAPIKeyNameExists")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *APIKeyService) Update(c *gin.Context, req dto.APIKeyUpdate) error {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.ID == "legacy" {
|
|
return s.updateLegacy(c, owner, req.APIKeyMutation, &req.APIKeyFields, "update", "")
|
|
}
|
|
expires, err := validateAPIKeyFields(&req.APIKeyFields, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.mutate(c, owner, req.APIKeyMutation, "update", func(tx *gorm.DB, key *model.APIKey) error {
|
|
if err := ensureAPIKeyName(tx, owner, req.Name, key.ID); err != nil {
|
|
return err
|
|
}
|
|
key.Name = req.Name
|
|
key.ActiveName = &req.Name
|
|
key.Description = req.Description
|
|
key.IPWhiteList = req.IPWhiteList
|
|
key.APITrustedProxies = req.APITrustedProxies
|
|
key.APIKeyValidityTime = req.APIKeyValidityTime
|
|
key.ExpiresAt = expires
|
|
key.AllowAppBinding = req.AllowAppBinding
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *APIKeyService) Status(c *gin.Context, req dto.APIKeyStatus) error {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.Status != constant.StatusEnable && req.Status != constant.StatusDisable {
|
|
return buserr.New("ErrInvalidParams")
|
|
}
|
|
action := "disable"
|
|
if req.Status == constant.StatusEnable {
|
|
action = "enable"
|
|
}
|
|
if req.ID == "legacy" {
|
|
return s.updateLegacy(c, owner, req.APIKeyMutation, nil, action, req.Status)
|
|
}
|
|
return s.mutate(c, owner, req.APIKeyMutation, action, func(_ *gorm.DB, key *model.APIKey) error {
|
|
if req.Status == constant.StatusEnable && key.ExpiresAt != nil && !time.Now().Before(*key.ExpiresAt) {
|
|
return buserr.New("ErrApiConfigKeyExpired")
|
|
}
|
|
key.Status = req.Status
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *APIKeyService) Revoke(c *gin.Context, req dto.APIKeyMutation) error {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.ID == "legacy" {
|
|
return s.updateLegacy(c, owner, req, nil, "revoke", constant.StatusDisable)
|
|
}
|
|
return s.mutate(c, owner, req, "revoke", func(_ *gorm.DB, key *model.APIKey) error {
|
|
now := time.Now()
|
|
key.Status = "Revoked"
|
|
key.RevokedAt = &now
|
|
key.ActiveName = nil
|
|
key.SecretCiphertext = ""
|
|
key.AllowAppBinding = false
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *APIKeyService) mutate(c *gin.Context, owner auth.APIKeyOwner, req dto.APIKeyMutation, action string, change func(*gorm.DB, *model.APIKey) error) error {
|
|
if req.ID == "" || req.Revision == 0 {
|
|
return buserr.New("ErrInvalidParams")
|
|
}
|
|
apiKeyMutationMu.Lock()
|
|
var key model.APIKey
|
|
closeTerminals := action == "disable" || action == "revoke"
|
|
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
|
if err := repo.APIKeyOwnerQuery(tx, owner.Type, owner.ID).Where("id = ?", req.ID).First(&key).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return buserr.New("ErrAPIKeyNotFound")
|
|
}
|
|
return err
|
|
}
|
|
if key.Revision != req.Revision || key.Status == "Revoked" {
|
|
return buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
before := key
|
|
if err := change(tx, &key); err != nil {
|
|
return err
|
|
}
|
|
closeTerminals = closeTerminals || before.IPWhiteList != key.IPWhiteList || before.APITrustedProxies != key.APITrustedProxies || before.APIKeyValidityTime != key.APIKeyValidityTime || (key.ExpiresAt != nil && (before.ExpiresAt == nil || key.ExpiresAt.Before(*before.ExpiresAt)))
|
|
key.Revision++
|
|
result := tx.Model(&model.APIKey{}).Where("id = ? AND revision = ?", key.ID, req.Revision).Select("*").Updates(&key)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
if result.RowsAffected != 1 {
|
|
return buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
return nil
|
|
})
|
|
apiKeyMutationMu.Unlock()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
recordAPIKeyEvent(c, owner, key.ID, key.Name, action)
|
|
if closeTerminals {
|
|
s.revokeAPIKeyTerminals(c, owner, key.ID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *APIKeyService) updateLegacy(c *gin.Context, owner auth.APIKeyOwner, req dto.APIKeyMutation, fields *dto.APIKeyFields, action, status string) error {
|
|
return auth.WithLegacyAPIKeyMutation(func() error {
|
|
return s.updateLegacyLocked(c, owner, req, fields, action, status)
|
|
})
|
|
}
|
|
|
|
func (s *APIKeyService) updateLegacyLocked(c *gin.Context, owner auth.APIKeyOwner, req dto.APIKeyMutation, fields *dto.APIKeyFields, action, status string) error {
|
|
item, config, policy, _, err := s.legacy(owner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if config.ApiKey == "" {
|
|
return buserr.New("ErrAPIKeyNotFound")
|
|
}
|
|
if req.Revision == 0 || req.Revision != item.Revision {
|
|
return buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
previousConfig := config
|
|
if fields != nil {
|
|
fields.Name = "Legacy API Key"
|
|
legacyWindow := fields.APIKeyValidityTime
|
|
if legacyWindow > 1440 && legacyWindow == config.ApiKeyValidityTime {
|
|
fields.APIKeyValidityTime = 1440
|
|
}
|
|
expires, err := validateAPIKeyFields(fields, false)
|
|
fields.APIKeyValidityTime = legacyWindow
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if expires != nil {
|
|
return buserr.New("ErrInvalidParams")
|
|
}
|
|
config.IpWhiteList = fields.IPWhiteList
|
|
config.ApiTrustedProxies = fields.APITrustedProxies
|
|
config.ApiKeyValidityTime = fields.APIKeyValidityTime
|
|
policy.AllowAppBinding = fields.AllowAppBinding
|
|
}
|
|
if status != "" {
|
|
config.ApiInterfaceStatus = status
|
|
}
|
|
if action == "revoke" {
|
|
config.ApiKey = ""
|
|
policy.AllowAppBinding = false
|
|
}
|
|
allowAppBinding := policy.AllowAppBinding
|
|
policy.AllowAppBinding = false
|
|
policy.Revision++
|
|
if err = global.DB.Clauses(clause.OnConflict{UpdateAll: true}).Create(&policy).Error; err != nil {
|
|
return err
|
|
}
|
|
if err = s.Provider.SaveLegacyAPIKey(owner, config); err != nil {
|
|
return err
|
|
}
|
|
if allowAppBinding {
|
|
policy.AllowAppBinding = true
|
|
policy.Revision++
|
|
if err = global.DB.Clauses(clause.OnConflict{UpdateAll: true}).Create(&policy).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
recordAPIKeyEvent(c, owner, "legacy", item.Name, action)
|
|
if action == "disable" || action == "revoke" || previousConfig.IpWhiteList != config.IpWhiteList || previousConfig.ApiTrustedProxies != config.ApiTrustedProxies || previousConfig.ApiKeyValidityTime != config.ApiKeyValidityTime {
|
|
s.revokeAPIKeyTerminals(c, owner, "legacy")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func recordAPIKeyEvent(c *gin.Context, owner auth.APIKeyOwner, id, name, action string) {
|
|
if err := apikey_audit.Record(c, apikey_audit.Event{OwnerType: owner.Type, OwnerID: owner.ID, KeyID: id, KeyName: name, Action: action, Status: constant.StatusSuccess}); err != nil && global.LOG != nil {
|
|
global.LOG.Errorf("API key audit failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func (s *APIKeyService) AuditLegacyChange(c *gin.Context) {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
if global.LOG != nil {
|
|
global.LOG.Errorf("legacy API key audit owner unavailable: %v", err)
|
|
}
|
|
return
|
|
}
|
|
recordAPIKeyEvent(c, owner, "legacy", "Legacy API Key", "update")
|
|
}
|
|
|
|
func (s *APIKeyService) revokeAPIKeyTerminals(c *gin.Context, owner auth.APIKeyOwner, id string) {
|
|
sessionID := "api-key:" + id
|
|
if id == "legacy" {
|
|
sessionID = terminalsession.APIAuthSessionID(owner.ID)
|
|
}
|
|
if err := terminalsession.RevokeWithRetry("auth_session", owner.ID, sessionID, s.RevokeTerminals); err != nil {
|
|
c.Set("API_KEY_TERMINAL_CLOSE_PENDING", true)
|
|
}
|
|
}
|
|
|
|
func (s *APIKeyService) PrepareAppBinding(c *gin.Context, id string) (*auth.APIKeyBinding, error) {
|
|
owner, err := s.owner(c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if id == "" {
|
|
id = "legacy"
|
|
}
|
|
if id == "legacy" {
|
|
item, config, _, fingerprint, err := s.legacy(owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if config.ApiKey == "" || config.ApiInterfaceStatus != constant.StatusEnable {
|
|
return nil, buserr.New("ErrApiConfigStatusInvalid")
|
|
}
|
|
if !item.AllowAppBinding {
|
|
return nil, buserr.New("ErrAPIKeyAppBindingDisabled")
|
|
}
|
|
return &auth.APIKeyBinding{KeyID: id, KeyName: item.Name, Owner: owner, Revision: item.Revision, Fingerprint: fingerprint}, nil
|
|
}
|
|
key, err := repo.NewAPIKeyRepo().Get(id)
|
|
if err != nil || key.OwnerID != owner.ID || key.OwnerType != owner.Type {
|
|
return nil, buserr.New("ErrAPIKeyNotFound")
|
|
}
|
|
if err = auth.ValidateAPIKeyState(key, time.Now()); err != nil {
|
|
return nil, err
|
|
}
|
|
if !key.AllowAppBinding {
|
|
return nil, buserr.New("ErrAPIKeyAppBindingDisabled")
|
|
}
|
|
return &auth.APIKeyBinding{KeyID: key.ID, KeyName: key.Name, Owner: owner, Revision: key.Revision}, nil
|
|
}
|
|
|
|
func (s *APIKeyService) ResolveAppBinding(c *gin.Context, binding auth.APIKeyBinding) (string, error) {
|
|
if s.Provider == nil {
|
|
return "", buserr.New("ErrApiConfigStatusInvalid")
|
|
}
|
|
owner, err := s.Provider.ResolveAPIKeyOwner(c, binding.Owner.Type, binding.Owner.ID)
|
|
if err != nil {
|
|
return "", buserr.New("ErrApiConfigStatusInvalid")
|
|
}
|
|
if binding.KeyID == "legacy" {
|
|
item, config, _, fingerprint, err := s.legacy(owner)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if binding.Fingerprint == "" || fingerprint != binding.Fingerprint || binding.Revision != item.Revision {
|
|
return "", buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
if config.ApiKey == "" || config.ApiInterfaceStatus != constant.StatusEnable {
|
|
return "", buserr.New("ErrApiConfigStatusInvalid")
|
|
}
|
|
if !item.AllowAppBinding {
|
|
return "", buserr.New("ErrAPIKeyAppBindingDisabled")
|
|
}
|
|
if !auth.IsIPInWhiteList(auth.GetAPIClientIP(c, config.ApiTrustedProxies), config.IpWhiteList) {
|
|
return "", buserr.New("ErrApiConfigIPInvalid")
|
|
}
|
|
c.Set("API_AUTH_CLIENT_IP", auth.GetAPIClientIP(c, config.ApiTrustedProxies))
|
|
return config.ApiKey, nil
|
|
}
|
|
key, err := repo.NewAPIKeyRepo().Get(binding.KeyID)
|
|
if err != nil || key.OwnerID != owner.ID || key.OwnerType != owner.Type {
|
|
return "", buserr.New("ErrAPIKeyNotFound")
|
|
}
|
|
if key.Revision != binding.Revision {
|
|
return "", buserr.New("ErrAPIKeyConflict")
|
|
}
|
|
if err = auth.ValidateAPIKeyState(key, time.Now()); err != nil {
|
|
return "", err
|
|
}
|
|
if !key.AllowAppBinding {
|
|
return "", buserr.New("ErrAPIKeyAppBindingDisabled")
|
|
}
|
|
if !auth.IsIPInWhiteList(auth.GetAPIClientIP(c, key.APITrustedProxies), key.IPWhiteList) {
|
|
return "", buserr.New("ErrApiConfigIPInvalid")
|
|
}
|
|
c.Set("API_AUTH_CLIENT_IP", auth.GetAPIClientIP(c, key.APITrustedProxies))
|
|
return auth.APIKeySecret(key)
|
|
}
|