com.taptap.sdk.compliance 4.5.2 → 4.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Mobile/Editor/NativeDependencies.xml +2 -2
- package/Runtime/Public/TapTapCompliance.cs +2 -1
- package/Standalone/Runtime/ComplianceWorker.cs +14 -3
- package/Standalone/Runtime/Internal/Http/ComplianceHttpClient.cs +47 -142
- package/Standalone/Runtime/Internal/Network.cs +78 -123
- package/Standalone/Runtime/Internal/Worker/BaseComplianceWorker.cs +25 -0
- package/link.xml +5 -0
- package/link.xml.meta +7 -0
- package/package.json +3 -3
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
<repositories>
|
|
5
5
|
<repository>https://repo.maven.apache.org/maven2</repository>
|
|
6
6
|
</repositories>
|
|
7
|
-
<androidPackage spec="com.taptap.sdk:tap-compliance:4.5.
|
|
7
|
+
<androidPackage spec="com.taptap.sdk:tap-compliance:4.5.3"/>
|
|
8
8
|
</androidPackages>
|
|
9
9
|
<iosPods>
|
|
10
10
|
<sources>
|
|
11
11
|
<source>https://github.com/CocoaPods/Specs.git</source>
|
|
12
12
|
</sources>
|
|
13
|
-
<iosPod name="TapTapComplianceSDK" version="~> 4.5.
|
|
13
|
+
<iosPod name="TapTapComplianceSDK" version="~> 4.5.3" bitcodeEnabled="false" addToAllTargets="false"/>
|
|
14
14
|
</iosPods>
|
|
15
15
|
</dependencies>
|
|
@@ -10,7 +10,7 @@ namespace TapSDK.Compliance
|
|
|
10
10
|
public static class TapTapCompliance
|
|
11
11
|
{
|
|
12
12
|
|
|
13
|
-
public static readonly string Version = "4.5.
|
|
13
|
+
public static readonly string Version = "4.5.3";
|
|
14
14
|
|
|
15
15
|
public static void RegisterComplianceCallback(Action<int, string> callback)
|
|
16
16
|
{
|
|
@@ -109,6 +109,7 @@ namespace TapSDK.Compliance
|
|
|
109
109
|
/// 设置测试环境,需要在 startup 接口调用前设置
|
|
110
110
|
/// </summary>
|
|
111
111
|
/// <param name="enable">测试环境是否可用</param>
|
|
112
|
+
[Obsolete("该方法已失效,不需要再额外调用")]
|
|
112
113
|
public static void SetTestEnvironment(bool enable) {
|
|
113
114
|
ComplianceJobManager.Job?.SetTestEnvironment(enable);
|
|
114
115
|
}
|
|
@@ -16,6 +16,7 @@ using TapSDK.Core.Internal;
|
|
|
16
16
|
using UnityEngine;
|
|
17
17
|
using System.Linq;
|
|
18
18
|
using TapSDK.Compliance.Standalone.Internal;
|
|
19
|
+
using TapSDK.Core.Standalone.Internal.Http;
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
namespace TapSDK.Compliance
|
|
@@ -107,7 +108,8 @@ namespace TapSDK.Compliance
|
|
|
107
108
|
|
|
108
109
|
// 计算时间
|
|
109
110
|
DateTimeOffset gameEndTime = Config.StrictEndTime;
|
|
110
|
-
|
|
111
|
+
DateTimeOffset now = DateTimeOffset.FromUnixTimeSeconds(GetCurrentTime()).ToOffset(DateTimeOffset.Now.Offset);
|
|
112
|
+
TimeSpan remain = gameEndTime - now;
|
|
111
113
|
|
|
112
114
|
return new PlayableResult
|
|
113
115
|
{
|
|
@@ -221,7 +223,8 @@ namespace TapSDK.Compliance
|
|
|
221
223
|
/// </summary>
|
|
222
224
|
private bool IsGameTime()
|
|
223
225
|
{
|
|
224
|
-
|
|
226
|
+
DateTimeOffset now = DateTimeOffset.FromUnixTimeSeconds(GetCurrentTime()).ToOffset(DateTimeOffset.Now.Offset);
|
|
227
|
+
string currentDate = now.ToString( "yyyy-MM-dd" );
|
|
225
228
|
List<string> holidays = TapTapComplianceManager.CurrentUserAntiResult.localConfig.timeRangeConfig.holidays;
|
|
226
229
|
TapLogger.Debug("current date = " + currentDate + " holidays = " + holidays.ToArray());
|
|
227
230
|
if(holidays.Contains(currentDate)){
|
|
@@ -229,7 +232,6 @@ namespace TapSDK.Compliance
|
|
|
229
232
|
DateTimeOffset strictEnd = Config.StrictEndTime;
|
|
230
233
|
|
|
231
234
|
bool playable;
|
|
232
|
-
DateTimeOffset now = DateTimeOffset.Now;
|
|
233
235
|
TapLogger.Debug(" now = " + now + " ,start = " + strictStart + ", end = " + strictEnd);
|
|
234
236
|
playable = now >= strictStart && now < strictEnd;
|
|
235
237
|
return playable;
|
|
@@ -237,6 +239,15 @@ namespace TapSDK.Compliance
|
|
|
237
239
|
return false;
|
|
238
240
|
}
|
|
239
241
|
|
|
242
|
+
private long GetCurrentTime(){
|
|
243
|
+
long serverTime = TapHttpTime.GetCurrentServerTime();
|
|
244
|
+
TapLogger.Debug("current serverTime = " + serverTime + " localTime = " + GetCurrentLocalTime());
|
|
245
|
+
if ( serverTime > 0){
|
|
246
|
+
return serverTime;
|
|
247
|
+
}
|
|
248
|
+
return GetCurrentLocalTime();
|
|
249
|
+
}
|
|
250
|
+
|
|
240
251
|
/// <summary>
|
|
241
252
|
/// 打开中国实名制窗口
|
|
242
253
|
/// </summary>
|
|
@@ -1,44 +1,29 @@
|
|
|
1
1
|
using System;
|
|
2
|
-
using System.Text;
|
|
3
|
-
using System.Linq;
|
|
4
2
|
using System.Collections.Generic;
|
|
5
3
|
using System.Net;
|
|
6
4
|
using System.Net.Http;
|
|
7
|
-
using System.
|
|
5
|
+
using System.Text;
|
|
8
6
|
using System.Threading.Tasks;
|
|
9
|
-
using
|
|
10
|
-
using TapSDK.Core;
|
|
11
|
-
using TapSDK.Core.Internal.Json;
|
|
12
|
-
using TapSDK.Core.Internal.Http;
|
|
13
|
-
using TapSDK.Compliance.Model;
|
|
7
|
+
using TapSDK.Core.Standalone.Internal.Http;
|
|
14
8
|
|
|
15
9
|
namespace TapSDK.Compliance.Internal.Http {
|
|
16
10
|
public class ComplianceHttpClient {
|
|
11
|
+
|
|
17
12
|
static readonly int INTERNAL_SERVER_ERROR_LIMIT = 3;
|
|
18
13
|
|
|
19
14
|
internal readonly string serverUrl;
|
|
20
15
|
|
|
21
|
-
private readonly
|
|
16
|
+
private static readonly TapHttp tapHttp = TapHttp
|
|
17
|
+
.NewBuilder("TapCompliance", TapTapCompliance.Version)
|
|
18
|
+
.Build();
|
|
22
19
|
|
|
23
|
-
private readonly Dictionary<string, Func<Task<string>>> runtimeHeaderTasks = new Dictionary<string, Func<Task<string>>>();
|
|
24
20
|
|
|
25
21
|
private readonly Dictionary<string, string> additionalHeaders = new Dictionary<string, string>();
|
|
26
22
|
|
|
27
23
|
public ComplianceHttpClient(string serverUrl) {
|
|
28
24
|
this.serverUrl = serverUrl;
|
|
29
|
-
client = new HttpClient();
|
|
30
|
-
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
31
25
|
}
|
|
32
26
|
|
|
33
|
-
public void AddRuntimeHeaderTask(string key, Func<Task<string>> task) {
|
|
34
|
-
if (string.IsNullOrEmpty(key)) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (task == null) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
runtimeHeaderTasks[key] = task;
|
|
41
|
-
}
|
|
42
27
|
|
|
43
28
|
public void ChangeAddtionalHeader(string key, string value) {
|
|
44
29
|
if (string.IsNullOrEmpty(key)) {
|
|
@@ -69,19 +54,6 @@ namespace TapSDK.Compliance.Internal.Http {
|
|
|
69
54
|
return Request<T>(path, HttpMethod.Post, headers, data, queryParams);
|
|
70
55
|
}
|
|
71
56
|
|
|
72
|
-
public Task<T> Put<T>(string path,
|
|
73
|
-
Dictionary<string, object> headers = null,
|
|
74
|
-
object data = null,
|
|
75
|
-
Dictionary<string, object> queryParams = null) {
|
|
76
|
-
return Request<T>(path, HttpMethod.Put, headers, data, queryParams);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public Task Delete(string path,
|
|
80
|
-
Dictionary<string, object> headers = null,
|
|
81
|
-
object data = null,
|
|
82
|
-
Dictionary<string, object> queryParams = null) {
|
|
83
|
-
return Request<Dictionary<string, object>>(path, HttpMethod.Delete, headers, data, queryParams);
|
|
84
|
-
}
|
|
85
57
|
|
|
86
58
|
async Task<T> Request<T>(string path,
|
|
87
59
|
HttpMethod method,
|
|
@@ -89,123 +61,56 @@ namespace TapSDK.Compliance.Internal.Http {
|
|
|
89
61
|
object data = null,
|
|
90
62
|
Dictionary<string, object> queryParams = null) {
|
|
91
63
|
|
|
92
|
-
int retryTimes = INTERNAL_SERVER_ERROR_LIMIT;
|
|
93
|
-
HttpStatusCode serverErrorStatusCode = HttpStatusCode.InternalServerError;
|
|
94
|
-
string serverErrorString = "";
|
|
95
|
-
while(retryTimes > 0){
|
|
96
|
-
string url = BuildUrl(path, queryParams);
|
|
97
|
-
HttpRequestMessage request = new HttpRequestMessage {
|
|
98
|
-
RequestUri = new Uri(url),
|
|
99
|
-
Method = method,
|
|
100
|
-
};
|
|
101
|
-
await FillHeaders(request.Headers, headers);
|
|
102
|
-
|
|
103
|
-
string content = null;
|
|
104
|
-
if (data != null) {
|
|
105
|
-
content = JsonConvert.SerializeObject(data);
|
|
106
|
-
StringContent requestContent = new StringContent(content);
|
|
107
|
-
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
|
108
|
-
request.Content = requestContent;
|
|
109
|
-
}
|
|
110
|
-
TapHttpUtils.PrintRequest(client, request, content);
|
|
111
|
-
|
|
112
|
-
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
|
113
|
-
request.Dispose();
|
|
114
|
-
|
|
115
|
-
string resultString = await response.Content.ReadAsStringAsync();
|
|
116
|
-
response.Dispose();
|
|
117
|
-
TapHttpUtils.PrintResponse(response, resultString);
|
|
118
|
-
|
|
119
|
-
if (response.IsSuccessStatusCode)
|
|
120
|
-
{
|
|
121
|
-
T ret = JsonConvert.DeserializeObject<T>(resultString,
|
|
122
|
-
TapJsonConverter.Default);
|
|
123
|
-
if (ret is BaseResponse baseResponse && !baseResponse.Success)
|
|
124
|
-
{
|
|
125
|
-
throw HandleErrorResponse(response.StatusCode, resultString);
|
|
126
|
-
}
|
|
127
|
-
return ret;
|
|
128
|
-
}
|
|
129
|
-
TapLogger.Debug("http log response code = " + response.StatusCode + " result = " + resultString);
|
|
130
|
-
if(response.StatusCode >= HttpStatusCode.InternalServerError){
|
|
131
|
-
retryTimes--;
|
|
132
|
-
serverErrorStatusCode = response.StatusCode;
|
|
133
|
-
serverErrorString = resultString;
|
|
134
|
-
}else{
|
|
135
|
-
throw HandleErrorResponse(response.StatusCode, resultString);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
throw HandleErrorResponse(serverErrorStatusCode, serverErrorString);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
Exception HandleErrorResponse(HttpStatusCode statusCode, string responseContent)
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
if (statusCode >= HttpStatusCode.InternalServerError) {
|
|
145
|
-
return new ComplianceException((int)statusCode, responseContent);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
int code = (int)statusCode;
|
|
149
|
-
string message = responseContent;
|
|
150
|
-
string err = null;
|
|
151
|
-
string desc = null;
|
|
152
|
-
long timestamp = 0;
|
|
153
|
-
long errorCode = -1;
|
|
154
|
-
try {
|
|
155
|
-
// 尝试获取 LeanCloud 返回错误信息
|
|
156
|
-
ErrorResponse error = JsonConvert.DeserializeObject<ErrorResponse>(responseContent,
|
|
157
|
-
TapJsonConverter.Default);
|
|
158
|
-
message = error.Result.Message;
|
|
159
|
-
err = error.Result.Error;
|
|
160
|
-
desc = error.Result.Description;
|
|
161
|
-
timestamp = error.Now;
|
|
162
|
-
errorCode = error.Result.ErrorCode;
|
|
163
|
-
} catch (Exception e) {
|
|
164
|
-
TapLogger.Error(e);
|
|
165
|
-
}
|
|
166
|
-
return new ComplianceException(code, message) {
|
|
167
|
-
Error = err,
|
|
168
|
-
Description = desc,
|
|
169
|
-
Now = timestamp,
|
|
170
|
-
ErrorCode = errorCode
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
string BuildUrl(string path, Dictionary<string, object> queryParams) {
|
|
175
64
|
string apiServer = serverUrl;
|
|
176
65
|
StringBuilder urlSB = new StringBuilder(apiServer.TrimEnd('/'));
|
|
177
66
|
urlSB.Append($"/{path}");
|
|
178
67
|
string url = urlSB.ToString();
|
|
179
|
-
if (queryParams != null) {
|
|
180
|
-
IEnumerable<string> queryPairs = queryParams.Select(kv => $"{kv.Key}={Uri.EscapeDataString(kv.Value.ToString())}");
|
|
181
|
-
string queries = string.Join("&", queryPairs);
|
|
182
|
-
url = $"{url}?{queries}";
|
|
183
|
-
}
|
|
184
|
-
return url;
|
|
185
|
-
}
|
|
186
68
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
69
|
+
Dictionary<string, string> newHeaders = null;
|
|
70
|
+
if(headers != null){
|
|
71
|
+
newHeaders = new Dictionary<string, string>();
|
|
72
|
+
foreach (KeyValuePair<string, object> kv in headers) {
|
|
73
|
+
newHeaders.Add(kv.Key, kv.Value.ToString());
|
|
192
74
|
}
|
|
193
75
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
76
|
+
|
|
77
|
+
Dictionary<string, string> newQueryParams = null;
|
|
78
|
+
if(queryParams != null){
|
|
79
|
+
newQueryParams = new Dictionary<string, string>();
|
|
80
|
+
foreach (KeyValuePair<string, object> kv in queryParams) {
|
|
81
|
+
newQueryParams.Add(kv.Key, kv.Value.ToString());
|
|
197
82
|
}
|
|
198
83
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
84
|
+
|
|
85
|
+
TapHttpResult<T> result;
|
|
86
|
+
if(method == HttpMethod.Get)
|
|
87
|
+
{
|
|
88
|
+
result = await tapHttp.GetAsync<T>(url:url, headers:newHeaders, queryParams: newQueryParams);
|
|
89
|
+
} else {
|
|
90
|
+
result = await tapHttp.PostJsonAsync<T>(path:url, headers: newHeaders, queryParams:newQueryParams,
|
|
91
|
+
json: data, retryStrategy: TapHttpRetryStrategy.CreateDefault(TapHttpBackoffStrategy.CreateFixed(INTERNAL_SERVER_ERROR_LIMIT)));
|
|
92
|
+
}
|
|
93
|
+
if (result.IsSuccess){
|
|
94
|
+
return result.Data;
|
|
95
|
+
}else{
|
|
96
|
+
AbsTapHttpException exception = result.HttpException;
|
|
97
|
+
if(exception is TapHttpServerException serverException) {
|
|
98
|
+
ComplianceException complianceException;
|
|
99
|
+
if(serverException.StatusCode >= HttpStatusCode.InternalServerError){
|
|
100
|
+
complianceException = new ComplianceException((int)serverException.StatusCode, serverException.Message);
|
|
101
|
+
}else {
|
|
102
|
+
complianceException = new ComplianceException((int)serverException.StatusCode, serverException.Message) {
|
|
103
|
+
Error = serverException.ErrorData.Error,
|
|
104
|
+
Description = serverException.ErrorData.ErrorDescription,
|
|
105
|
+
Now = serverException.TapHttpResponse.Now,
|
|
106
|
+
ErrorCode = serverException.ErrorData.Code
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
throw complianceException;
|
|
110
|
+
}else {
|
|
111
|
+
throw exception;
|
|
112
|
+
}
|
|
113
|
+
|
|
209
114
|
}
|
|
210
115
|
}
|
|
211
116
|
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections.Generic;
|
|
3
|
-
using System.Globalization;
|
|
4
|
-
using System.Net.Http.Headers;
|
|
5
3
|
using System.Reflection;
|
|
6
4
|
using System.Threading.Tasks;
|
|
7
|
-
using Newtonsoft.Json;
|
|
8
5
|
using TapSDK.Compliance.Internal.Http;
|
|
9
6
|
using TapSDK.Compliance.Model;
|
|
10
7
|
using TapSDK.Core;
|
|
11
8
|
using TapSDK.Login;
|
|
12
9
|
using TapSDK.Login.Internal;
|
|
13
|
-
using TapSDK.Login.Standalone;
|
|
14
|
-
using UnityEngine;
|
|
15
|
-
using System.Security.Cryptography;
|
|
16
|
-
using System.Text;
|
|
17
|
-
using System.Linq;
|
|
18
|
-
using TapSDK.Core.Standalone.Internal;
|
|
19
|
-
using TapSDK.Core.Standalone;
|
|
20
10
|
using System.Net;
|
|
21
11
|
|
|
22
12
|
|
|
@@ -32,13 +22,10 @@ namespace TapSDK.Compliance.Internal
|
|
|
32
22
|
|
|
33
23
|
private static string clientToken;
|
|
34
24
|
|
|
35
|
-
private static bool enableTestMode;
|
|
36
|
-
|
|
37
25
|
internal static void SetGameInfo(string gameId, string clientToken)
|
|
38
26
|
{
|
|
39
27
|
Network.gameId = gameId;
|
|
40
28
|
Network.clientToken = clientToken;
|
|
41
|
-
HttpClient.ChangeAddtionalHeader("X-LC-Id", gameId);
|
|
42
29
|
}
|
|
43
30
|
|
|
44
31
|
internal static void InitSetting()
|
|
@@ -59,10 +46,14 @@ namespace TapSDK.Compliance.Internal
|
|
|
59
46
|
/// </summary>
|
|
60
47
|
/// <returns></returns>
|
|
61
48
|
internal static async Task<RealNameConfigResult> FetchConfig(string userId) {
|
|
62
|
-
string path = $"real-name/v1/get-global-config
|
|
63
|
-
var headers = GetAuthHeaders(
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
string path = $"real-name/v1/get-global-config";
|
|
50
|
+
var headers = GetAuthHeaders();
|
|
51
|
+
var queryParams = new Dictionary<string, object>{
|
|
52
|
+
["client_id"] = gameId,
|
|
53
|
+
["user_identifier"] = userId
|
|
54
|
+
};
|
|
55
|
+
RealNameConfigResult response = await HttpClient.Get<RealNameConfigResult>(path, headers, queryParams);
|
|
56
|
+
return response;
|
|
66
57
|
}
|
|
67
58
|
|
|
68
59
|
/// <summary>
|
|
@@ -71,30 +62,38 @@ namespace TapSDK.Compliance.Internal
|
|
|
71
62
|
/// <returns></returns>
|
|
72
63
|
internal static async Task<VerificationResult> FetchVerification(string userId)
|
|
73
64
|
{
|
|
74
|
-
string path = $"real-name/v1/anti-addiction-token
|
|
75
|
-
var headers = GetAuthHeaders(
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
string path = $"real-name/v1/anti-addiction-token";
|
|
66
|
+
var headers = GetAuthHeaders();
|
|
67
|
+
var queryParams = new Dictionary<string, object>{
|
|
68
|
+
["client_id"] = gameId,
|
|
69
|
+
["user_identifier"] = userId
|
|
70
|
+
};
|
|
71
|
+
VerificationResult response = await HttpClient.Get<VerificationResult>(path, headers, queryParams);
|
|
72
|
+
return response;
|
|
78
73
|
}
|
|
79
74
|
|
|
80
75
|
/// <summary>
|
|
81
76
|
/// V1 升级 v2 token
|
|
82
77
|
internal static async Task<VerificationResult> UpgradeToken(string userId, string oldToken)
|
|
83
78
|
{
|
|
84
|
-
string path = $"real-name/v1/anti-addiction-token-upgrade
|
|
79
|
+
string path = $"real-name/v1/anti-addiction-token-upgrade";
|
|
85
80
|
var param = new Dictionary<string, object> {
|
|
86
81
|
["anti_addiction_token_v1"] = oldToken,
|
|
87
82
|
["user_identifier"] = userId
|
|
88
83
|
};
|
|
89
|
-
var
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
var queryParams = new Dictionary<string, object>{
|
|
85
|
+
["client_id"] = gameId
|
|
86
|
+
};
|
|
87
|
+
var headers = GetAuthHeaders();
|
|
88
|
+
VerificationResult response = await HttpClient.Post<VerificationResult>(path, headers, data:param, queryParams);
|
|
89
|
+
return response;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
/// </summary>
|
|
95
93
|
/// 使用 TapToken 获取实名 token
|
|
96
94
|
/// <returns></returns>
|
|
97
95
|
public static async Task<VerificationResult> FetchVerificationByTapToken(string userId, AccessToken token, long timestamp = 0) {
|
|
96
|
+
// 这里手动拼 query 是为了进行 Tap 的签算
|
|
98
97
|
string path = $"real-name/v1/anti-addiction-token-taptap?client_id={gameId}&user_identifier={WebUtility.UrlEncode(userId)}";
|
|
99
98
|
var httpClientType = typeof(ComplianceHttpClient);
|
|
100
99
|
var hostFieldInfo = httpClientType.GetField("serverUrl", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
@@ -102,10 +101,15 @@ namespace TapSDK.Compliance.Internal
|
|
|
102
101
|
var uri = new Uri(host + "/" + path);
|
|
103
102
|
|
|
104
103
|
var sign = GetMacToken(token, uri, timestamp);
|
|
105
|
-
var headers = GetAuthHeaders(
|
|
104
|
+
var headers = GetAuthHeaders();
|
|
106
105
|
headers.Add("Authorization", sign);
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
|
|
107
|
+
var queryParams = new Dictionary<string, object>{
|
|
108
|
+
["client_id"] = gameId,
|
|
109
|
+
["user_identifier"] = userId
|
|
110
|
+
};
|
|
111
|
+
VerificationResult response = await HttpClient.Get<VerificationResult>(path, headers:headers, queryParams);
|
|
112
|
+
return response;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
private static string GetMacToken(AccessToken token, Uri uri, long timestamp = 0) {
|
|
@@ -136,16 +140,19 @@ namespace TapSDK.Compliance.Internal
|
|
|
136
140
|
internal static async Task<VerificationResult> FetchVerificationManual(string userName, string idCard)
|
|
137
141
|
{
|
|
138
142
|
var tcs = new TaskCompletionSource<VerificationResult>();
|
|
139
|
-
string path = $"real-name/v1/anti-addiction-token-manual
|
|
143
|
+
string path = $"real-name/v1/anti-addiction-token-manual";
|
|
140
144
|
Dictionary<string, object> data = new Dictionary<string, object>
|
|
141
145
|
{
|
|
142
146
|
["name"] = userName,
|
|
143
147
|
["idcard"] = idCard,
|
|
144
148
|
["user_identifier"] = TapTapComplianceManager.UserId
|
|
145
149
|
};
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
var headers = GetAuthHeaders();
|
|
151
|
+
var queryParams = new Dictionary<string, object>{
|
|
152
|
+
["client_id"] = gameId
|
|
153
|
+
};
|
|
154
|
+
VerificationResult response = await HttpClient.Post<VerificationResult>(path, headers, data, queryParams);
|
|
155
|
+
tcs.TrySetResult(response);
|
|
149
156
|
|
|
150
157
|
return await tcs.Task;
|
|
151
158
|
}
|
|
@@ -156,18 +163,18 @@ namespace TapSDK.Compliance.Internal
|
|
|
156
163
|
/// <returns></returns>
|
|
157
164
|
internal static async Task<UserComplianceConfigResult> CheckUserConfig()
|
|
158
165
|
{
|
|
159
|
-
string path;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
string path = $"anti-addiction/v1/get-config-by-token";
|
|
167
|
+
Dictionary<string, object> headers = GetAuthHeaders();
|
|
168
|
+
var queryParams = new Dictionary<string, object>{
|
|
169
|
+
["client_id"] = gameId,
|
|
170
|
+
["user_identifier"] = TapTapComplianceManager.UserId,
|
|
171
|
+
["platform"] = "pc"
|
|
172
|
+
};
|
|
173
|
+
UserComplianceConfigResult response = await HttpClient.Get<UserComplianceConfigResult>(path, headers, queryParams);
|
|
167
174
|
#if UNITY_EDITOR
|
|
168
|
-
TapLogger.Debug($"检查用户状态: ageLimit: {response.
|
|
175
|
+
TapLogger.Debug($"检查用户状态: ageLimit: {response.userState.ageLimit} ageCheck: {response.ageCheckResult.allow} IsAdult: {response.userState.isAdult} ");
|
|
169
176
|
#endif
|
|
170
|
-
return response
|
|
177
|
+
return response;
|
|
171
178
|
}
|
|
172
179
|
/// <summary>
|
|
173
180
|
/// 检测是否可玩
|
|
@@ -175,23 +182,21 @@ namespace TapSDK.Compliance.Internal
|
|
|
175
182
|
/// <returns></returns>
|
|
176
183
|
internal static async Task<PlayableResult> CheckPlayable()
|
|
177
184
|
{
|
|
178
|
-
string
|
|
179
|
-
|
|
180
|
-
path = $"anti-addiction/v1/heartbeat?client_id={gameId}";
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
path = $"anti-addiction/v1/heartbeat?client_id={gameId}&test_mode=1";
|
|
184
|
-
}
|
|
185
|
+
string path = $"anti-addiction/v1/heartbeat";
|
|
186
|
+
|
|
185
187
|
Dictionary<string,object> data = new Dictionary<string,object>{
|
|
186
188
|
["session_id"] = TapTapComplianceManager.CurrentSession,
|
|
187
189
|
["user_identifier"] = TapTapComplianceManager.UserId
|
|
188
190
|
};
|
|
189
|
-
Dictionary<string, object> headers = GetAuthHeaders(
|
|
190
|
-
|
|
191
|
+
Dictionary<string, object> headers = GetAuthHeaders();
|
|
192
|
+
var queryParams = new Dictionary<string, object>{
|
|
193
|
+
["client_id"] = gameId
|
|
194
|
+
};
|
|
195
|
+
PlayableResult response = await HttpClient.Post<PlayableResult>(path, headers, data, queryParams);
|
|
191
196
|
#if UNITY_EDITOR
|
|
192
|
-
TapLogger.Debug($"检查是否可玩结果: remainTime: {response.
|
|
197
|
+
TapLogger.Debug($"检查是否可玩结果: remainTime: {response.RemainTime} Content: {response.Content}");
|
|
193
198
|
#endif
|
|
194
|
-
return response
|
|
199
|
+
return response;
|
|
195
200
|
}
|
|
196
201
|
|
|
197
202
|
/// <summary>
|
|
@@ -201,16 +206,15 @@ namespace TapSDK.Compliance.Internal
|
|
|
201
206
|
/// <returns></returns>
|
|
202
207
|
internal static async Task<PayableResult> CheckPayable(long amount)
|
|
203
208
|
{
|
|
204
|
-
string path = "";
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return response.Result;
|
|
209
|
+
string path = $"anti-addiction/v1/payable";
|
|
210
|
+
Dictionary<string, object> headers = GetAuthHeaders();
|
|
211
|
+
var queryParams = new Dictionary<string, object>{
|
|
212
|
+
["client_id"] = gameId,
|
|
213
|
+
["user_identifier"] = TapTapComplianceManager.UserId,
|
|
214
|
+
["amount"] = amount
|
|
215
|
+
};
|
|
216
|
+
PayableResult response = await HttpClient.Get<PayableResult>(path, headers, queryParams);
|
|
217
|
+
return response;
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
/// <summary>
|
|
@@ -220,86 +224,37 @@ namespace TapSDK.Compliance.Internal
|
|
|
220
224
|
/// <returns></returns>
|
|
221
225
|
internal static async Task SubmitPayment(long amount)
|
|
222
226
|
{
|
|
223
|
-
string path = "";
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
path = $"anti-addiction/v1/payment-submit?client_id={gameId}&test_mode=1";
|
|
229
|
-
}
|
|
230
|
-
Dictionary<string, object> data = new Dictionary<string, object>
|
|
227
|
+
string path = $"anti-addiction/v1/payment-submit";
|
|
228
|
+
|
|
229
|
+
Dictionary<string, object> data = new Dictionary<string, object>
|
|
231
230
|
{
|
|
232
231
|
{ "amount", amount },
|
|
233
232
|
{"user_identifier", TapTapComplianceManager.UserId}
|
|
234
233
|
};
|
|
235
|
-
Dictionary<string, object> headers = GetAuthHeaders(
|
|
234
|
+
Dictionary<string, object> headers = GetAuthHeaders();
|
|
235
|
+
var queryParams = new Dictionary<string, object>{
|
|
236
|
+
["client_id"] = gameId
|
|
237
|
+
};
|
|
236
238
|
|
|
237
|
-
await HttpClient.Post<SubmitPaymentResponse>(path, headers
|
|
239
|
+
await HttpClient.Post<SubmitPaymentResponse>(path, headers, data, queryParams);
|
|
238
240
|
}
|
|
239
241
|
// internal static Dictionary<string, object> GetAuthHeaders(){
|
|
240
242
|
// return new Dictionary<string,object>{};
|
|
241
243
|
// }
|
|
242
244
|
|
|
243
|
-
internal static Dictionary<string, object> GetAuthHeaders(
|
|
245
|
+
internal static Dictionary<string, object> GetAuthHeaders()
|
|
244
246
|
{
|
|
245
|
-
var
|
|
246
|
-
var hostFieldInfo = httpClientType.GetField("serverUrl", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
247
|
-
string host = hostFieldInfo?.GetValue(HttpClient) as string;
|
|
248
|
-
var uri = "/" + path;
|
|
249
|
-
int ts = timestamp;
|
|
250
|
-
if (ts == 0) {
|
|
251
|
-
var dt = DateTime.UtcNow - new DateTime(1970, 1, 1);
|
|
252
|
-
ts = (int)dt.TotalSeconds;
|
|
253
|
-
}
|
|
254
|
-
var nonce = new System.Random().Next().ToString();
|
|
255
|
-
var headers = new Dictionary<string, object>
|
|
256
|
-
{
|
|
257
|
-
{ "X-Tap-PN", "TapSDK" },
|
|
258
|
-
{ "X-Tap-Lang", Tracker.getServerLanguage() },
|
|
259
|
-
{ "X-Tap-Device-Id", SystemInfo.deviceUniqueIdentifier},
|
|
260
|
-
{ "X-Tap-Platform", "PC"},
|
|
261
|
-
{ "X-Tap-SDK-Module","TapCompliance"},
|
|
262
|
-
{ "X-Tap-SDK-Module-Version", TapTapSDK.Version},
|
|
263
|
-
{ "X-Tap-SDK-Artifact", "Unity"},
|
|
264
|
-
{ "User-Agent","TapSDK-Unity/" + TapTapSDK.Version},
|
|
265
|
-
{ "X-Tap-Nonce", nonce},
|
|
266
|
-
{ "X-Tap-Ts",ts}
|
|
267
|
-
};
|
|
247
|
+
var headers = new Dictionary<string, object>();
|
|
268
248
|
string token = Verification.GetCurrentToken();
|
|
269
249
|
if (!string.IsNullOrEmpty(token))
|
|
270
250
|
{
|
|
271
251
|
headers.Add("X-Tap-Anti-Addiction-Token", token);
|
|
272
252
|
}
|
|
273
|
-
|
|
274
|
-
string currentDBUserId = TapCoreStandalone.GetCurrentUserId();
|
|
275
|
-
if(currentDBUserId != null && currentDBUserId.Length > 0) {
|
|
276
|
-
headers.Add("X-Tap-SDK-Game-User-Id", currentDBUserId);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
headers = headers.OrderBy(x => x.Key).ToDictionary(x => x.Key, y=>y.Value);
|
|
280
|
-
List<string> headerList = new List<string>();
|
|
281
|
-
foreach(KeyValuePair<string,object> kv in headers){
|
|
282
|
-
if(kv.Key.ToLower().StartsWith("x-tap-")){
|
|
283
|
-
headerList.Add(kv.Key.ToLower()+":"+kv.Value);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
string headerString = string.Join("\n",headerList);
|
|
287
|
-
var normalizedString = $"{httpMethod}\n{uri}\n{headerString}\n";
|
|
288
|
-
if(body != null){
|
|
289
|
-
normalizedString += $"{JsonConvert.SerializeObject(body)}\n";
|
|
290
|
-
}else{
|
|
291
|
-
normalizedString += "\n";
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
HashAlgorithm hashGenerator= new HMACSHA256(Encoding.UTF8.GetBytes(clientToken));
|
|
295
|
-
|
|
296
|
-
var hash = Convert.ToBase64String(hashGenerator.ComputeHash(Encoding.UTF8.GetBytes(normalizedString)));
|
|
297
|
-
headers.Add("X-Tap-Sign",hash);
|
|
298
253
|
return headers;
|
|
299
254
|
}
|
|
300
255
|
|
|
301
256
|
internal static void SetTestEnvironment(bool enable) {
|
|
302
|
-
|
|
257
|
+
|
|
303
258
|
}
|
|
304
259
|
}
|
|
305
260
|
}
|
|
@@ -22,6 +22,11 @@ namespace TapSDK.Compliance
|
|
|
22
22
|
#region Abstract
|
|
23
23
|
|
|
24
24
|
static readonly string USER_ANTI_FILENAME = "user_anti_config";
|
|
25
|
+
|
|
26
|
+
// 本地基准时间戳
|
|
27
|
+
private long BaseLocalTime = 0;
|
|
28
|
+
//获取本地时间戳时,应用运行的时间
|
|
29
|
+
private long BaseLocalStartUpTime = 0;
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
/// <summary>
|
|
@@ -145,6 +150,7 @@ namespace TapSDK.Compliance
|
|
|
145
150
|
throw;
|
|
146
151
|
}else{
|
|
147
152
|
if(result != null){
|
|
153
|
+
ResetBaseLocalTime();
|
|
148
154
|
TapTapComplianceManager.CurrentSession = GenerateSession();
|
|
149
155
|
return result;
|
|
150
156
|
}else{
|
|
@@ -158,6 +164,7 @@ namespace TapSDK.Compliance
|
|
|
158
164
|
if(result == null){
|
|
159
165
|
throw;
|
|
160
166
|
}else{
|
|
167
|
+
ResetBaseLocalTime();
|
|
161
168
|
TapTapComplianceManager.CurrentSession = GenerateSession();
|
|
162
169
|
return result;
|
|
163
170
|
}
|
|
@@ -165,6 +172,24 @@ namespace TapSDK.Compliance
|
|
|
165
172
|
|
|
166
173
|
}
|
|
167
174
|
|
|
175
|
+
private void ResetBaseLocalTime(){
|
|
176
|
+
if(BaseLocalTime > 0){
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
BaseLocalTime = DateTimeOffset.Now.ToUnixTimeSeconds();
|
|
180
|
+
BaseLocalStartUpTime = (long)Time.realtimeSinceStartup;
|
|
181
|
+
TapLogger.Debug(" current local time " + DateTimeOffset.Now);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// <summary>
|
|
185
|
+
/// 获取基于本地时间的当前时间戳,用于离线心跳计算
|
|
186
|
+
/// </summary>
|
|
187
|
+
/// <returns></returns>
|
|
188
|
+
protected long GetCurrentLocalTime(){
|
|
189
|
+
long currentStartUpTime = (long) Time.realtimeSinceStartup;
|
|
190
|
+
return BaseLocalTime + currentStartUpTime - BaseLocalStartUpTime;
|
|
191
|
+
}
|
|
192
|
+
|
|
168
193
|
private string GenerateSession()
|
|
169
194
|
{
|
|
170
195
|
const string baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
package/link.xml
ADDED
package/link.xml.meta
ADDED
package/package.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"name": "com.taptap.sdk.compliance",
|
|
3
3
|
"displayName": "TapTapSDK Compliance",
|
|
4
4
|
"description": "TapTapSDK Compliance",
|
|
5
|
-
"version": "4.5.
|
|
5
|
+
"version": "4.5.3",
|
|
6
6
|
"unity": "2019.4",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"com.taptap.sdk.core": "4.5.
|
|
10
|
-
"com.taptap.sdk.login": "4.5.
|
|
9
|
+
"com.taptap.sdk.core": "4.5.3",
|
|
10
|
+
"com.taptap.sdk.login": "4.5.3"
|
|
11
11
|
}
|
|
12
12
|
}
|