using System; using System.IO; using System.Threading.Tasks; using UnityEngine; using TapSDK.Compliance.Model; using TapSDK.Core; using TapSDK.Login; using TapSDK.Core.Internal.Log; namespace TapSDK.Compliance.Internal { public static class Verification { internal const int AGE_LIMIT_UNKNOWN = -1; internal const int AGE_LIMIT_CHILD = 0; internal const int AGE_LIMIT_TEEN = 8; internal const int AGE_LIMIT_YOUNG = 16; internal const int AGE_LIMIT_ADULT = 18; // 已实名,但未同意年龄段信息授权且未成年 internal const int UNKNOWN_AGE = 100; // 已实名,但未同意年龄段信息授权且成年 internal const int UNKNOWN_AGE_ADULT = 110; static readonly string VERIFICATION_FILENAME = "verification"; static readonly string VERIFICATION_V2_FILENAME = "verification_v2"; static readonly bool DEFAULT_VERIFIED = false; static readonly bool DEFAULT_VERIFING = false; static readonly bool DEFAULT_ADULT = false; static LocalVerification current; public static LocalVerification Current => current; static Persistence persistence; static Persistence persistenceV2; /// /// 快速获取身份信息 /// /// public static async Task Fetch(string userId) { if (current != null && !current.UserId.Equals(userId)) { Logout(false); } string filename = Tool.EncryptString(userId); // 存储 v2 token 数据 if (persistenceV2 == null) { persistenceV2 = new Persistence(Path.Combine( VERIFICATION_V2_FILENAME, filename)); } VerificationResult result; try { LocalVerification localVerification; TapLog.Log("start check v2 token in local"); //先检查本地是否有 v2 缓存 localVerification = await persistenceV2.Load(); if (localVerification != null && localVerification.ComplianceToken != null && localVerification.ComplianceToken.Length > 0) { current = localVerification; return; } TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount(); AccessToken accessToken = tapAccount?.accessToken; if (HasComplianceAuthInTapToken(accessToken)) { await FetchByTapToken(userId); } else { TapLog.Log("try get v2 token with userId"); result = await Network.FetchVerification(userId); await Save(userId, result); } } catch (Exception e) { //首次异常报错 TapLog.Log("try get v2 token failed error: " + e.Message); TapLog.Error(e.ToString()); throw; } } internal static async Task FetchByTapToken(string userId, AccessToken accessToken = null) { TapLog.Log("start check tapToken in local"); long timestamp = 0; int retryTimes = 1; VerificationResult result; while (true) { if (accessToken == null) { ///判断本地是否有包含 compliance 的 token TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount(); accessToken = tapAccount?.accessToken; } try { if (HasComplianceAuthInTapToken(accessToken)) { TapLog.Log("try use tapToken to get v2 token"); result = await Network.FetchVerificationByTapToken(userId, accessToken, timestamp); await Save(userId, result); return; } } catch (Exception e) { //时间戳异常 if (e is ComplianceException aee && aee.Error != null && aee.Error.Equals(ComplianceConst.SERVER_ERROR_TYPE_INVALID_TIME) && retryTimes > 0) { timestamp = aee.Now; retryTimes--; continue; } else { throw e; } } throw new Exception(); } } internal static bool HasComplianceAuthInTapToken(AccessToken accessToken) { if (accessToken == null) { return false; } bool useAgeRange = TapTapComplianceManager.config.useAgeRange; if (useAgeRange) { return accessToken.scopeSet != null && accessToken.scopeSet.Contains(ComplianceWorker.SCOPE_COMPLIANCE); } else { return accessToken.scopeSet != null && (accessToken.scopeSet.Contains(ComplianceWorker.SCOPE_COMPLIANCE) || accessToken.scopeSet.Contains(ComplianceWorker.SCOPE_COMPLIANCE_BASIC)); } } /// /// 手动输入身份信息 /// /// /// 身份证姓名 /// 身份证号 /// internal static async Task FetchVerificationManual(string userId, string userName, string idCard) { var tcs = new TaskCompletionSource(); try { VerificationResult result = await Network.FetchVerificationManual(userName, idCard); tcs.SetResult(result); await Save(userId, result); } catch (Exception e) { tcs.SetException(e); TapLog.Error(e.ToString()); throw; } return await tcs.Task; } /// /// TapToken 获取实名 /// /// /// TapToken /// public static async Task FetchVerificationByTapToken(string userId, AccessToken token) { var tcs = new TaskCompletionSource(); try { await FetchByTapToken(userId, token); if (persistenceV2 == null) { var filename = Tool.EncryptString(userId); persistenceV2 = new Persistence(Path.Combine( VERIFICATION_V2_FILENAME, filename)); } VerificationResult result = await persistenceV2.Load(); tcs.SetResult(result); } catch (Exception e) { tcs.SetException(e); TapLog.Error(e.ToString()); throw; } return await tcs.Task; } public static async Task Save(string userId, VerificationResult verification) { current = new LocalVerification(verification) { UserId = userId }; TapLog.Log("try save v2 token to local"); if (persistenceV2 == null) { var filename = Tool.EncryptString(userId); persistenceV2 = new Persistence(Path.Combine( VERIFICATION_V2_FILENAME, filename)); } await persistenceV2.Save(current); } public static async Task setAgeState(int ageLimit, bool isAdult) { if (current != null) { current.AgeLimit = ageLimit < 0 ? (isAdult ? UNKNOWN_AGE_ADULT : UNKNOWN_AGE) : ageLimit; current.IsAdult = isAdult; if (persistenceV2 == null) { var filename = Tool.EncryptString(current.UserId); persistenceV2 = new Persistence(Path.Combine( VERIFICATION_V2_FILENAME, filename)); } await persistenceV2.Save(current); } } public static void ClearCacheVerfiction() { persistence?.Delete(); persistenceV2?.Delete(); } internal static void Logout(bool needClearCache = true) { // if (IsVerified && !IsAdult) // { // #pragma warning disable CS4014 // Network.CheckPlayable(); // #pragma warning restore CS4014 // } if (needClearCache) { ClearCacheVerfiction(); } persistence = null; persistenceV2 = null; current = null; } internal static string GetCurrentToken() { return current?.ComplianceToken; } /// /// 是否已认证 /// public static bool IsVerified => current?.IsVerified ?? DEFAULT_VERIFIED; /// /// 是否在认证中 /// public static bool IsVerifing => current?.IsVerifing ?? DEFAULT_VERIFING; /// /// 是否认证失败 /// public static bool IsVerifyFailed => current?.IsVerifyFailed ?? DEFAULT_VERIFING; /// /// 是否是成年人 /// internal static bool IsAdult => current?.IsAdult ?? DEFAULT_ADULT; /// /// 年龄级别 /// internal static int AgeLimit => current?.AgeLimit ?? AGE_LIMIT_CHILD; } }