draft
This commit is contained in:
141
backend/internal/service/app.go
Normal file
141
backend/internal/service/app.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"pay-bridge/internal/errcode"
|
||||
"pay-bridge/internal/model"
|
||||
"pay-bridge/internal/repository"
|
||||
"pay-bridge/pkg/crypto"
|
||||
)
|
||||
|
||||
// AppService 应用服务
|
||||
type AppService struct {
|
||||
repo *repository.AppRepository
|
||||
encKey string
|
||||
}
|
||||
|
||||
func NewAppService(repo *repository.AppRepository, encKey string) *AppService {
|
||||
return &AppService{repo: repo, encKey: encKey}
|
||||
}
|
||||
|
||||
// GetAppSecret 获取 appSecret(用于鉴权中间件)
|
||||
func (s *AppService) GetAppSecret(ctx context.Context, appID string) (string, error) {
|
||||
app, err := s.repo.GetByAppID(ctx, appID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if app == nil {
|
||||
return "", errors.New(errcode.ErrAppNotFound)
|
||||
}
|
||||
|
||||
secret, err := crypto.Decrypt(app.AppSecret, s.encKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decrypt app secret: %w", err)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// GetApp 获取应用信息
|
||||
func (s *AppService) GetApp(ctx context.Context, appID string) (*model.App, error) {
|
||||
return s.repo.GetByAppID(ctx, appID)
|
||||
}
|
||||
|
||||
// CreateAppResult 创建应用的返回,包含明文 secret(仅展示一次)
|
||||
type CreateAppResult struct {
|
||||
App *model.App
|
||||
PlainSecret string
|
||||
}
|
||||
|
||||
// CreateApp 创建应用,自动生成 app_id 和 app_secret
|
||||
func (s *AppService) CreateApp(ctx context.Context, appName string) (*CreateAppResult, error) {
|
||||
appID := generateAppID()
|
||||
plainSecret := generateSecret()
|
||||
|
||||
encSecret, err := crypto.Encrypt(plainSecret, s.encKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app := &model.App{
|
||||
AppID: appID,
|
||||
AppSecret: encSecret,
|
||||
AppName: appName,
|
||||
Status: 1,
|
||||
}
|
||||
if err := s.repo.Create(ctx, app); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CreateAppResult{App: app, PlainSecret: plainSecret}, nil
|
||||
}
|
||||
|
||||
// ListApps 分页查询应用列表
|
||||
func (s *AppService) ListApps(ctx context.Context, limit, offset int) ([]*model.App, error) {
|
||||
return s.repo.List(ctx, limit, offset)
|
||||
}
|
||||
|
||||
// DisableApp 禁用应用
|
||||
func (s *AppService) DisableApp(ctx context.Context, appID string) error {
|
||||
app, err := s.repo.GetByAppIDUnscoped(ctx, appID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if app == nil {
|
||||
return errors.New(errcode.ErrAppNotFound)
|
||||
}
|
||||
return s.repo.UpdateStatus(ctx, appID, 0)
|
||||
}
|
||||
|
||||
// EnableApp 启用应用
|
||||
func (s *AppService) EnableApp(ctx context.Context, appID string) error {
|
||||
app, err := s.repo.GetByAppIDUnscoped(ctx, appID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if app == nil {
|
||||
return errors.New(errcode.ErrAppNotFound)
|
||||
}
|
||||
return s.repo.UpdateStatus(ctx, appID, 1)
|
||||
}
|
||||
|
||||
// ResetSecret 重置应用密钥,返回新的明文 secret(仅此一次)
|
||||
func (s *AppService) ResetSecret(ctx context.Context, appID string) (string, error) {
|
||||
app, err := s.repo.GetByAppIDUnscoped(ctx, appID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if app == nil {
|
||||
return "", errors.New(errcode.ErrAppNotFound)
|
||||
}
|
||||
|
||||
plainSecret := generateSecret()
|
||||
encSecret, err := crypto.Encrypt(plainSecret, s.encKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := s.repo.UpdateSecret(ctx, appID, encSecret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return plainSecret, nil
|
||||
}
|
||||
|
||||
// generateAppID 生成 app_id:app_ + yyMMdd + 8位随机hex
|
||||
func generateAppID() string {
|
||||
b := make([]byte, 4)
|
||||
_, _ = rand.Read(b)
|
||||
date := time.Now().Format("060102")
|
||||
return "app_" + date + hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// generateSecret 生成 32 字节随机 secret(64位hex)
|
||||
func generateSecret() string {
|
||||
b := make([]byte, 32)
|
||||
_, _ = rand.Read(b)
|
||||
return strings.ToUpper(hex.EncodeToString(b))
|
||||
}
|
||||
Reference in New Issue
Block a user