tls_fingerprint_profile_service.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package service
  2. import (
  3. "context"
  4. "math/rand/v2"
  5. "sync"
  6. "time"
  7. "github.com/Wei-Shaw/sub2api/internal/config"
  8. "github.com/Wei-Shaw/sub2api/internal/model"
  9. "github.com/Wei-Shaw/sub2api/internal/pkg/logger"
  10. "github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
  11. )
  12. // TLSFingerprintProfileRepository 定义 TLS 指纹模板的数据访问接口
  13. type TLSFingerprintProfileRepository interface {
  14. List(ctx context.Context) ([]*model.TLSFingerprintProfile, error)
  15. GetByID(ctx context.Context, id int64) (*model.TLSFingerprintProfile, error)
  16. Create(ctx context.Context, profile *model.TLSFingerprintProfile) (*model.TLSFingerprintProfile, error)
  17. Update(ctx context.Context, profile *model.TLSFingerprintProfile) (*model.TLSFingerprintProfile, error)
  18. Delete(ctx context.Context, id int64) error
  19. }
  20. // TLSFingerprintProfileCache 定义 TLS 指纹模板的缓存接口
  21. type TLSFingerprintProfileCache interface {
  22. Get(ctx context.Context) ([]*model.TLSFingerprintProfile, bool)
  23. Set(ctx context.Context, profiles []*model.TLSFingerprintProfile) error
  24. Invalidate(ctx context.Context) error
  25. NotifyUpdate(ctx context.Context) error
  26. SubscribeUpdates(ctx context.Context, handler func())
  27. }
  28. // TLSFingerprintProfileService TLS 指纹模板管理服务
  29. type TLSFingerprintProfileService struct {
  30. repo TLSFingerprintProfileRepository
  31. cache TLSFingerprintProfileCache
  32. cfg *config.Config
  33. // 本地 ID→Profile 映射缓存,用于 DoWithTLS 热路径快速查找
  34. localCache map[int64]*model.TLSFingerprintProfile
  35. localMu sync.RWMutex
  36. }
  37. // NewTLSFingerprintProfileService 创建 TLS 指纹模板服务
  38. func NewTLSFingerprintProfileService(
  39. repo TLSFingerprintProfileRepository,
  40. cache TLSFingerprintProfileCache,
  41. cfgs ...*config.Config,
  42. ) *TLSFingerprintProfileService {
  43. var cfg *config.Config
  44. if len(cfgs) > 0 {
  45. cfg = cfgs[0]
  46. }
  47. svc := &TLSFingerprintProfileService{
  48. repo: repo,
  49. cache: cache,
  50. cfg: cfg,
  51. localCache: make(map[int64]*model.TLSFingerprintProfile),
  52. }
  53. ctx := context.Background()
  54. if err := svc.reloadFromDB(ctx); err != nil {
  55. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to load profiles from DB on startup: %v", err)
  56. if fallbackErr := svc.refreshLocalCache(ctx); fallbackErr != nil {
  57. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to load profiles from cache fallback on startup: %v", fallbackErr)
  58. }
  59. }
  60. if cache != nil {
  61. cache.SubscribeUpdates(ctx, func() {
  62. if err := svc.refreshLocalCache(context.Background()); err != nil {
  63. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to refresh cache on notification: %v", err)
  64. }
  65. })
  66. }
  67. return svc
  68. }
  69. // --- CRUD ---
  70. // List 获取所有模板
  71. func (s *TLSFingerprintProfileService) List(ctx context.Context) ([]*model.TLSFingerprintProfile, error) {
  72. return s.repo.List(ctx)
  73. }
  74. // GetByID 根据 ID 获取模板
  75. func (s *TLSFingerprintProfileService) GetByID(ctx context.Context, id int64) (*model.TLSFingerprintProfile, error) {
  76. return s.repo.GetByID(ctx, id)
  77. }
  78. // Create 创建模板
  79. func (s *TLSFingerprintProfileService) Create(ctx context.Context, profile *model.TLSFingerprintProfile) (*model.TLSFingerprintProfile, error) {
  80. if err := profile.Validate(); err != nil {
  81. return nil, err
  82. }
  83. created, err := s.repo.Create(ctx, profile)
  84. if err != nil {
  85. return nil, err
  86. }
  87. refreshCtx, cancel := s.newCacheRefreshContext()
  88. defer cancel()
  89. s.invalidateAndNotify(refreshCtx)
  90. return created, nil
  91. }
  92. // Update 更新模板
  93. func (s *TLSFingerprintProfileService) Update(ctx context.Context, profile *model.TLSFingerprintProfile) (*model.TLSFingerprintProfile, error) {
  94. if err := profile.Validate(); err != nil {
  95. return nil, err
  96. }
  97. updated, err := s.repo.Update(ctx, profile)
  98. if err != nil {
  99. return nil, err
  100. }
  101. refreshCtx, cancel := s.newCacheRefreshContext()
  102. defer cancel()
  103. s.invalidateAndNotify(refreshCtx)
  104. return updated, nil
  105. }
  106. // Delete 删除模板
  107. func (s *TLSFingerprintProfileService) Delete(ctx context.Context, id int64) error {
  108. if err := s.repo.Delete(ctx, id); err != nil {
  109. return err
  110. }
  111. refreshCtx, cancel := s.newCacheRefreshContext()
  112. defer cancel()
  113. s.invalidateAndNotify(refreshCtx)
  114. return nil
  115. }
  116. // --- 热路径:运行时 Profile 查找 ---
  117. // GetProfileByID 根据 ID 从本地缓存获取 Profile(用于 DoWithTLS 热路径)
  118. // 返回 nil 表示未找到,调用方应 fallback 到内置默认 Profile
  119. func (s *TLSFingerprintProfileService) GetProfileByID(id int64) *tlsfingerprint.Profile {
  120. s.localMu.RLock()
  121. p, ok := s.localCache[id]
  122. s.localMu.RUnlock()
  123. if ok && p != nil {
  124. return p.ToTLSProfile()
  125. }
  126. return nil
  127. }
  128. // getRandomProfile 从本地缓存中随机选择一个 Profile
  129. func (s *TLSFingerprintProfileService) getRandomProfile() *tlsfingerprint.Profile {
  130. s.localMu.RLock()
  131. defer s.localMu.RUnlock()
  132. if len(s.localCache) == 0 {
  133. return nil
  134. }
  135. // 收集所有 profile
  136. profiles := make([]*model.TLSFingerprintProfile, 0, len(s.localCache))
  137. for _, p := range s.localCache {
  138. if p != nil {
  139. profiles = append(profiles, p)
  140. }
  141. }
  142. if len(profiles) == 0 {
  143. return nil
  144. }
  145. return profiles[rand.IntN(len(profiles))].ToTLSProfile()
  146. }
  147. // ResolveTLSProfile 根据 Account 的配置解析出运行时 TLS Profile
  148. //
  149. // 逻辑:
  150. // 1. 未启用 TLS 指纹 → 返回 nil(不伪装)
  151. // 2. 启用 + 绑定了 profile_id → 从缓存查找对应 profile
  152. // 3. 启用 + 未绑定或找不到 → 返回空 Profile(使用代码内置默认值)
  153. func (s *TLSFingerprintProfileService) ResolveTLSProfile(account *Account) *tlsfingerprint.Profile {
  154. if account == nil || !account.IsTLSFingerprintEnabled() {
  155. return nil
  156. }
  157. // The account flag is an explicit opt-in, while the global config is the
  158. // deployment-level kill switch. Keep the nil-config behavior for isolated
  159. // tests and non-server callers that do not load application config.
  160. if s != nil && s.cfg != nil && !s.cfg.Gateway.TLSFingerprint.Enabled {
  161. return nil
  162. }
  163. if account.Extra != nil {
  164. if name, ok := account.Extra["tls_fingerprint_builtin"].(string); ok {
  165. if p := tlsfingerprint.BuiltinProfile(name); p != nil {
  166. return p
  167. }
  168. }
  169. }
  170. id := account.GetTLSFingerprintProfileID()
  171. if id > 0 {
  172. if p := s.GetProfileByID(id); p != nil {
  173. return p
  174. }
  175. }
  176. if id == -1 {
  177. // 随机选择一个 profile
  178. if p := s.getRandomProfile(); p != nil {
  179. return p
  180. }
  181. }
  182. // TLS 启用但无绑定 profile → 空 Profile → dialer 使用内置默认值
  183. return &tlsfingerprint.Profile{Name: "Built-in Default (Node.js 24.x)"}
  184. }
  185. // --- 缓存管理 ---
  186. func (s *TLSFingerprintProfileService) refreshLocalCache(ctx context.Context) error {
  187. if s.cache != nil {
  188. if profiles, ok := s.cache.Get(ctx); ok {
  189. s.setLocalCache(profiles)
  190. return nil
  191. }
  192. }
  193. return s.reloadFromDB(ctx)
  194. }
  195. func (s *TLSFingerprintProfileService) reloadFromDB(ctx context.Context) error {
  196. profiles, err := s.repo.List(ctx)
  197. if err != nil {
  198. return err
  199. }
  200. if s.cache != nil {
  201. if err := s.cache.Set(ctx, profiles); err != nil {
  202. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to set cache: %v", err)
  203. }
  204. }
  205. s.setLocalCache(profiles)
  206. return nil
  207. }
  208. func (s *TLSFingerprintProfileService) setLocalCache(profiles []*model.TLSFingerprintProfile) {
  209. m := make(map[int64]*model.TLSFingerprintProfile, len(profiles))
  210. for _, p := range profiles {
  211. m[p.ID] = p
  212. }
  213. s.localMu.Lock()
  214. s.localCache = m
  215. s.localMu.Unlock()
  216. }
  217. func (s *TLSFingerprintProfileService) newCacheRefreshContext() (context.Context, context.CancelFunc) {
  218. return context.WithTimeout(context.Background(), 3*time.Second)
  219. }
  220. func (s *TLSFingerprintProfileService) invalidateAndNotify(ctx context.Context) {
  221. if s.cache != nil {
  222. if err := s.cache.Invalidate(ctx); err != nil {
  223. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to invalidate cache: %v", err)
  224. }
  225. }
  226. if err := s.reloadFromDB(ctx); err != nil {
  227. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to refresh local cache: %v", err)
  228. s.localMu.Lock()
  229. s.localCache = make(map[int64]*model.TLSFingerprintProfile)
  230. s.localMu.Unlock()
  231. }
  232. if s.cache != nil {
  233. if err := s.cache.NotifyUpdate(ctx); err != nil {
  234. logger.LegacyPrintf("service.tls_fp_profile", "[TLSFPProfileService] Failed to notify cache update: %v", err)
  235. }
  236. }
  237. }