account_protection_validation.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package service
  2. import infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
  3. func antiDegradeEligibilityIssue(a *Account, mode AntiDegradeMode) string {
  4. if a == nil {
  5. return "account not found"
  6. }
  7. p := antiDegradeStrategyProfile(mode)
  8. if p.ID == "" {
  9. return "未知的账号保护策略"
  10. }
  11. if mode == AntiDegradeModeNative {
  12. return ""
  13. }
  14. if a.IsShadow() {
  15. return "影子账号仅支持通用并发保护,请在母账号配置身份策略"
  16. }
  17. if a.IsRandomProxy() {
  18. return "请先选择固定代理或直连,再应用身份保护策略"
  19. }
  20. if p.RequiresOpenAI && !isOpenAIOAuthLike(a) {
  21. return "该策略仅支持 OpenAI OAuth / Setup Token 账号"
  22. }
  23. if mode == AntiDegradeModeLegacy && !isOpenAIOAuthLike(a) && !isAnthropicOAuthLike(a) {
  24. return "初代兼容仅支持 OpenAI / Anthropic OAuth 或 Setup Token;此账号请使用通用并发保护"
  25. }
  26. return ""
  27. }
  28. // Shared with SQL preservation so new registry strategies cannot accidentally
  29. // lose protection through the key-level or bulk write paths.
  30. func RegisteredProtectionModes() []string {
  31. var modes []string
  32. for _, p := range ListAntiDegradeStrategyProfiles() {
  33. if p.ApplySupported {
  34. modes = append(modes, string(p.ID))
  35. }
  36. }
  37. return modes
  38. }
  39. func validateRegisteredProtection(a *Account) error {
  40. if !antiDegradeEnabled(a) {
  41. return nil
  42. }
  43. m := mode1Marker(a)
  44. raw, _ := m["mode"].(string)
  45. // Retain legacy unversioned rows whose original policy was not explicit.
  46. if raw == "" || raw == "generic" {
  47. return nil
  48. }
  49. mode := AntiDegradeMode(raw)
  50. invalid := func(message string) error { return infraerrors.BadRequest("PROTECTION_CONFIGURATION_INVALID", message) }
  51. if reason := antiDegradeEligibilityIssue(a, mode); reason != "" {
  52. return invalid(reason)
  53. }
  54. fp, tls, cap := antiDegradeModeSettings(mode)
  55. if cap < 1 {
  56. return invalid("无效的保护策略")
  57. }
  58. if isOpenAIOAuthLike(a) {
  59. if a.GetCodexFingerprintMode() != fp {
  60. return invalid("保护身份配置与已选策略不一致")
  61. }
  62. if _, ok := codexFingerprintSeed(a.Extra); !ok {
  63. return invalid("账号持久身份种子缺失或无效")
  64. }
  65. }
  66. if tls == "standard" {
  67. if a.IsTLSFingerprintEnabled() || a.Extra["tls_fingerprint_builtin"] != nil || a.Extra["tls_fingerprint_profile_id"] != nil {
  68. return invalid("标准传输策略不能启用实验 TLS 模板")
  69. }
  70. } else if !a.IsTLSFingerprintEnabled() || a.Extra["tls_fingerprint_builtin"] != tls {
  71. return invalid("TLS 配置与已选策略不一致")
  72. }
  73. if limit := mode1Int(m["max_concurrency"]); limit < 1 {
  74. return invalid("保护并发上限无效")
  75. }
  76. return nil
  77. }