// // AppSecrets.swift // ylgamehall // // 应用级凭证(跨渠道相同):从 Bundle 内的 AppSecrets.plist 读 3 个 string 值。 // // ⚠️ 客户端硬编码 = 父项目 CLAUDE.md「已识别但接受的安全风险」, // 集中放进 plist 仅做"单一真相源"管理,不缓解安全面 —— msext IPA 已分发数年, // 这些凭证等价泄露;沿用同一份不引入新攻击面,也无需后台中转。 // // 与 ChannelConfig.plist 的语义边界: // - ChannelConfig.plist:渠道差异化字段(每个渠道签名包不同值) // - AppSecrets.plist:跨渠道相同凭证(一份硬编码,多渠道共用) // // 字段对应: // - wxAppSecret : 微信 OAuth2 access_token 换取(msext SGDefineInfo.h:107) // - qiniuAccessKey : 七牛 putPolicy 签名 + 上传 token 前缀 // - qiniuSecretKey : 七牛 HMAC-SHA1 签名 putPolicy // // 注:微信 AppID 不在此 plist,唯一来源是 Info.plist 的 CFBundleURLTypes // (URLName=weixin 的 first scheme)。详见 WeChatSDK.swift。 // import Foundation nonisolated public final class AppSecrets: Sendable { public static let shared = AppSecrets() public let wxAppSecret: String public let qiniuAccessKey: String public let qiniuSecretKey: String public init(bundle: Bundle = .main) { let dict = Self.loadPlist(bundle: bundle) wxAppSecret = dict["wxAppSecret"] ?? "" qiniuAccessKey = dict["qiniuAccessKey"] ?? "" qiniuSecretKey = dict["qiniuSecretKey"] ?? "" } private static func loadPlist(bundle: Bundle) -> [String: String] { guard let url = bundle.url(forResource: "AppSecrets", withExtension: "plist"), let data = try? Data(contentsOf: url), let plist = try? PropertyListSerialization.propertyList( from: data, format: nil) as? [String: String] else { return [:] } return plist } }