import 'dart:io'; import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; import 'package:flutter/foundation.dart'; import '../model/response/kr_site_config.dart'; import '../common/app_config.dart'; import '../utils/kr_log_util.dart'; import '../utils/kr_http_adapter_util.dart'; import 'singbox_imp/kr_sing_box_imp.dart'; import 'api_service/kr_api.user.dart'; /// 网站配置服务 class KRSiteConfigService extends ChangeNotifier { static final KRSiteConfigService _instance = KRSiteConfigService._internal(); factory KRSiteConfigService() => _instance; KRSiteConfigService._internal() { // 🔧 Android 15 优化:增加超时时间以适应移动网络(5秒 → 20秒) _dio.options.connectTimeout = const Duration(seconds: 20); _dio.options.sendTimeout = const Duration(seconds: 20); _dio.options.receiveTimeout = const Duration(seconds: 20); // 🔧 关键修复:添加 SSL 证书验证跳过,强制直连 _dio.httpClientAdapter = KRHttpAdapterUtil.createAdapter( useSingBoxProxy: false, forceDirect: true, timeout: const Duration(seconds: 20), ); if (kDebugMode) { print('🌐 网站配置服务:使用直连模式,避免 SingBox 未初始化问题'); } } KRSiteConfig? _siteConfig; bool _isInitialized = false; final Dio _dio = Dio(); /// 获取站点配置 KRSiteConfig? get siteConfig => _siteConfig; /// 是否已初始化 bool get isInitialized => _isInitialized; Future initialize() async { return await initializeDomains(); } Future initializeDomains() async { try { await KRDomain.kr_loadBaseDomain(); _isInitialized = true; notifyListeners(); return true; } catch (_) { return false; } } Future fetchSiteConfig() async { try { final result = await KRUserApi().kr_config(); return await result.fold( (error) async { return false; }, (cfg) async { try { if (cfg.kr_config.isNotEmpty) { final Map root = jsonDecode(cfg.kr_config); _siteConfig = KRSiteConfig.fromJson(root); AppConfig.getInstance().device_limit = getDeviceLimit(); notifyListeners(); return true; } } catch (_) {} return false; }, ); } catch (_) { return false; } } /// 打印配置信息 void _printConfigInfo() { if (_siteConfig == null) return; KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('📊 网站配置信息:', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); // 站点信息 KRLogUtil.kr_i('🏠 站点名称: ${_siteConfig!.site.siteName}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('🏠 站点描述: ${_siteConfig!.site.siteDesc}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('🏠 站点域名: ${_siteConfig!.site.host}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('💬 Crisp ID: ${_siteConfig!.site.crispId}', tag: 'KRSiteConfigService'); // 注册相关 KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('📝 注册配置:', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 开放注册: ${isRegisterEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 手机号注册: ${isMobileRegisterEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 邮箱注册: ${isEmailRegisterEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 设备登录: ${isDeviceLoginEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); // 验证相关 KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('🔐 验证配置:', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 邮箱验证: ${isEmailVerificationEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 手机验证: ${isMobileVerificationEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 登录验证: ${isLoginVerificationEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 注册验证: ${isRegisterVerificationEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i( ' ✓ 重置密码验证: ${isResetPasswordVerificationEnabled() ? "是" : "否"}', tag: 'KRSiteConfigService'); // 邀请相关 KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('🎁 邀请配置:', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 强制邀请码: ${isForcedInvite() ? "是" : "否"}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 推荐比例: ${_siteConfig!.invite.referralPercentage}%', tag: 'KRSiteConfigService'); // 货币相关 KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('💰 货币配置:', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 货币单位: ${_siteConfig!.currency.currencyUnit}', tag: 'KRSiteConfigService'); KRLogUtil.kr_i(' ✓ 货币符号: ${_siteConfig!.currency.currencySymbol}', tag: 'KRSiteConfigService'); // OAuth 方法 if (_siteConfig!.oauthMethods.isNotEmpty) { KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('🔑 OAuth 方法: ${_siteConfig!.oauthMethods.join(", ")}', tag: 'KRSiteConfigService'); } KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('✅ 网站配置初始化成功', tag: 'KRSiteConfigService'); KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'KRSiteConfigService'); } /// 是否开启手机号注册 bool isMobileRegisterEnabled() { return _siteConfig?.auth.mobile.enable ?? false; } /// 是否开启邮箱注册 bool isEmailRegisterEnabled() { return _siteConfig?.auth.email.enable ?? false; } /// 是否开放注册(未停止注册) bool isRegisterEnabled() { return !(_siteConfig?.auth.register.stopRegister ?? true); } /// 是否开启邮箱验证 bool isEmailVerificationEnabled() { return _siteConfig?.auth.email.enableVerify ?? false; } /// 是否开启手机验证 bool isMobileVerificationEnabled() { return _siteConfig?.auth.mobile.enable ?? false; } /// 是否开启登录验证 bool isLoginVerificationEnabled() { return _siteConfig?.verify.enableLoginVerify ?? false; } /// 是否开启注册验证 bool isRegisterVerificationEnabled() { return _siteConfig?.verify.enableRegisterVerify ?? false; } /// 是否开启重置密码验证 bool isResetPasswordVerificationEnabled() { return _siteConfig?.verify.enableResetPasswordVerify ?? false; } /// 是否强制邀请码 bool isForcedInvite() { return _siteConfig?.invite.forcedInvite ?? false; } /// 获取验证码间隔时间(秒) int getVerifyCodeInterval() { return _siteConfig?.verifyCode.verifyCodeInterval ?? 60; } /// 获取OAuth方法列表 List getOAuthMethods() { return _siteConfig?.oauthMethods ?? []; } /// 检查是否支持设备模式(匿名游客模式) bool isDeviceModeSupported() { final oauthMethods = getOAuthMethods(); return oauthMethods.contains('device'); } /// 检查是否启用设备登录 bool isDeviceLoginEnabled() { return _siteConfig?.auth.device.enable ?? false; } /// 检查是否需要设备安全加密 bool isDeviceSecurityEnabled() { return _siteConfig?.auth.device.enableSecurity ?? false; } /// 检查是否显示广告 bool isDeviceShowAds() { return _siteConfig?.auth.device.showAds ?? false; } /// 检查是否只允许真实设备 bool isOnlyRealDevice() { return _siteConfig?.auth.device.onlyRealDevice ?? false; } /// 获取站点信息 KRSiteInfo? getSiteInfo() { return _siteConfig?.site; } /// 获取货币配置 KRCurrencyConfig? getCurrencyConfig() { return _siteConfig?.currency; } /// 获取订阅配置 KRSubscribeConfig? getSubscribeConfig() { return _siteConfig?.subscribe; } /// 检查手机号是否在白名单中 bool isMobileInWhitelist(String mobile) { if (!(_siteConfig?.auth.mobile.enableWhitelist ?? false)) { return true; // 如果未开启白名单,则允许所有手机号 } final whitelist = _siteConfig?.auth.mobile.whitelist ?? []; return whitelist.contains(mobile); } /// 检查邮箱域名是否被允许 bool isEmailDomainAllowed(String email) { if (!(_siteConfig?.auth.email.enableDomainSuffix ?? false)) { return true; // 如果未开启域名限制,则允许所有域名 } final domainSuffixList = _siteConfig?.auth.email.domainSuffixList ?? ''; if (domainSuffixList.isEmpty) { return true; } final allowedDomains = domainSuffixList.split(',').map((d) => d.trim()).toList(); final emailDomain = email.split('@').last.toLowerCase(); return allowedDomains .any((domain) => emailDomain.endsWith(domain.toLowerCase())); } /// 获取Crisp客服系统ID String getCrispId() { return _siteConfig?.site.crispId ?? '0'; } /// 获取设备限制 String getDeviceLimit() { return _siteConfig?.site.deviceLimit ?? '0'; } /// 获取当前版本号 /// /// 功能:从站点配置的 customData 中解析并返回 curVersion /// 参数:无 /// 返回:String 当前版本号,如未配置返回空字符串 String getCurVersion() { try { final customData = _siteConfig?.site.customData ?? ''; if (customData.isEmpty) return ''; final Map jsonMap = jsonDecode(customData) as Map; final value = jsonMap['curVersion']; return value == null ? '' : value.toString(); } catch (_) { return ''; } } /// 获取分享地址 /// /// 功能:从站点配置的 customData 中解析并返回 shareUrl /// 参数:无 /// 返回:String 分享地址,如未配置返回空字符串 String getShareUrl() { try { final customData = _siteConfig?.site.customData ?? ''; if (customData.isEmpty) return ''; final Map jsonMap = jsonDecode(customData) as Map; final value = jsonMap['shareUrl']; return value == null ? '' : value.toString(); } catch (_) { return ''; } } /// 重置配置 void reset() { _siteConfig = null; _isInitialized = false; notifyListeners(); } }