Files
2026-03-13 15:51:59 +08:00

142 lines
3.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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_idapp_ + 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 字节随机 secret64位hex
func generateSecret() string {
b := make([]byte, 32)
_, _ = rand.Read(b)
return strings.ToUpper(hex.EncodeToString(b))
}