com.taptap.sdk.login 4.3.12 → 4.4.0
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/Mobile/Editor/TapLoginMobileProcessBuild.cs +1 -1
- package/Runtime/Public/TapTapLogin.cs +1 -1
- package/Standalone/Runtime/Internal2/LoginService.cs +26 -15
- package/Standalone/Runtime/Internal2/TapLoginService.cs +45 -0
- package/Standalone/Runtime/{Internal/Net.cs.meta → Internal2/TapLoginService.cs.meta} +1 -1
- package/Standalone/Runtime/Internal2/TapLoginStandaloneImpl.cs +1 -1
- package/Standalone/Runtime/Internal2/UI/QRCodeController.cs +3 -3
- package/link.xml +4 -0
- package/link.xml.meta +7 -0
- package/package.json +2 -2
- package/Standalone/Runtime/Internal/Net.cs +0 -291
- package/Standalone/Runtime/Internal/QRCodeWindow.cs +0 -776
- package/Standalone/Runtime/Internal/QRCodeWindow.cs.meta +0 -11
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<repositories>
|
|
5
5
|
<repository>https://repo.maven.apache.org/maven2</repository>
|
|
6
6
|
</repositories>
|
|
7
|
-
<androidPackage spec="com.taptap.sdk:tap-login-unity:4.
|
|
7
|
+
<androidPackage spec="com.taptap.sdk:tap-login-unity:4.4.0"/>
|
|
8
8
|
</androidPackages>
|
|
9
9
|
<iosPods>
|
|
10
10
|
<sources>
|
|
11
11
|
<source>https://github.com/CocoaPods/Specs.git</source>
|
|
12
12
|
</sources>
|
|
13
13
|
<iosPod name="Kingfisher" version="~> 6.0" bitcodeEnabled="false" addToAllTargets="false"/>
|
|
14
|
-
<iosPod name="TapTapLoginSDK" version="~> 4.
|
|
14
|
+
<iosPod name="TapTapLoginSDK" version="~> 4.4.0" bitcodeEnabled="false" addToAllTargets="false"/>
|
|
15
15
|
</iosPods>
|
|
16
16
|
</dependencies>
|
|
@@ -6,7 +6,7 @@ namespace TapSDK.Login.Mobile.Editor {
|
|
|
6
6
|
public class TapLoginMobileProcessBuild : SDKLinkProcessBuild {
|
|
7
7
|
public override int callbackOrder => 0;
|
|
8
8
|
|
|
9
|
-
public override string LinkPath => "
|
|
9
|
+
public override string LinkPath => "TapSDK/Login/link.xml";
|
|
10
10
|
|
|
11
11
|
public override LinkedAssembly[] LinkedAssemblies => new LinkedAssembly[] {
|
|
12
12
|
new LinkedAssembly { Fullname = "TapSDK.Login.Runtime" },
|
|
@@ -7,7 +7,7 @@ namespace TapSDK.Login
|
|
|
7
7
|
public class TapTapLogin
|
|
8
8
|
{
|
|
9
9
|
|
|
10
|
-
public static readonly string Version = "4.
|
|
10
|
+
public static readonly string Version = "4.4.0";
|
|
11
11
|
|
|
12
12
|
public const string TAP_LOGIN_SCOPE_BASIC_INFO = "basic_info";
|
|
13
13
|
public const string TAP_LOGIN_SCOPE_PUBLIC_PROFILE = "public_profile";
|
|
@@ -5,14 +5,18 @@ using System.Security.Cryptography;
|
|
|
5
5
|
using System.Text;
|
|
6
6
|
using UnityEngine;
|
|
7
7
|
using TapSDK.Login.Internal.Http;
|
|
8
|
+
using TapSDK.Core.Standalone.Internal.Service;
|
|
8
9
|
|
|
9
|
-
namespace TapSDK.Login.Internal
|
|
10
|
-
|
|
10
|
+
namespace TapSDK.Login.Internal
|
|
11
|
+
{
|
|
12
|
+
public static class LoginService
|
|
13
|
+
{
|
|
11
14
|
private static readonly LoginHttpClient httpClient = new LoginHttpClient();
|
|
12
15
|
|
|
13
16
|
public static LoginHttpClient HttpClient => httpClient;
|
|
14
17
|
|
|
15
|
-
public static async Task<QRCodeData> GetQRCodeUrl(string clientId, string[] scopes)
|
|
18
|
+
public static async Task<QRCodeData> GetQRCodeUrl(string clientId, string[] scopes)
|
|
19
|
+
{
|
|
16
20
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
|
17
21
|
{ "client_id", clientId },
|
|
18
22
|
{ "response_type", "device_code" },
|
|
@@ -21,12 +25,13 @@ namespace TapSDK.Login.Internal {
|
|
|
21
25
|
{ "platform", "unity" },
|
|
22
26
|
{ "info", "{\"device_id\":\"" + SystemInfo.deviceModel + "\"}" }
|
|
23
27
|
};
|
|
24
|
-
QRCodeResponse response = await httpClient.Post<QRCodeResponse>(TapTapSdk.CurrentRegion.CodeUrl(),
|
|
28
|
+
QRCodeResponse response = await httpClient.Post<QRCodeResponse>(TapTapSdk.CurrentRegion.CodeUrl(),
|
|
25
29
|
data: data);
|
|
26
30
|
return response.Data;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
public static async Task<TokenData> Authorize(string clientId, string code)
|
|
33
|
+
public static async Task<TokenData> Authorize(string clientId, string code)
|
|
34
|
+
{
|
|
30
35
|
Dictionary<string, string> data = new Dictionary<string, string> {
|
|
31
36
|
{ "client_id", clientId },
|
|
32
37
|
{ "grant_type", "authorization_code" },
|
|
@@ -35,12 +40,13 @@ namespace TapSDK.Login.Internal {
|
|
|
35
40
|
{ "redirect_uri", WebLoginRequestManager.Instance.GetCurrentRequest().GetRedirectUri() },
|
|
36
41
|
{ "code_verifier", WebLoginRequestManager.Instance.GetCodeVerifier() }
|
|
37
42
|
};
|
|
38
|
-
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
43
|
+
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
39
44
|
data: data);
|
|
40
45
|
return response.Data;
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
public static async Task<TokenData> RequestScanQRCodeResult(string clientId, string deviceCode)
|
|
48
|
+
public static async Task<TokenData> RequestScanQRCodeResult(string clientId, string deviceCode)
|
|
49
|
+
{
|
|
44
50
|
Dictionary<string, string> data = new Dictionary<string, string> {
|
|
45
51
|
{ "grant_type", "device_token" },
|
|
46
52
|
{ "client_id", clientId },
|
|
@@ -50,16 +56,18 @@ namespace TapSDK.Login.Internal {
|
|
|
50
56
|
{ "platform", "unity" },
|
|
51
57
|
{ "info", "{\"device_id\":\"" + SystemInfo.deviceModel + "\"}" }
|
|
52
58
|
};
|
|
53
|
-
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
59
|
+
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
54
60
|
data: data);
|
|
55
61
|
return response.Data;
|
|
56
62
|
}
|
|
57
63
|
|
|
58
|
-
public static async Task<ProfileData> GetProfile(string clientId, AccessToken token, int timestamp = 0)
|
|
64
|
+
public static async Task<ProfileData> GetProfile(string clientId, AccessToken token, int timestamp = 0)
|
|
65
|
+
{
|
|
59
66
|
string url = TapTapSdk.CurrentRegion.ProfileUrl(token.scopeSet.Contains(TapTapLogin.TAP_LOGIN_SCOPE_PUBLIC_PROFILE)) + clientId;
|
|
60
67
|
var uri = new Uri(url);
|
|
61
68
|
var ts = timestamp;
|
|
62
|
-
if (ts == 0)
|
|
69
|
+
if (ts == 0)
|
|
70
|
+
{
|
|
63
71
|
var dt = DateTime.UtcNow - new DateTime(1970, 1, 1);
|
|
64
72
|
ts = (int)dt.TotalSeconds;
|
|
65
73
|
}
|
|
@@ -76,7 +84,7 @@ namespace TapSDK.Login.Internal {
|
|
|
76
84
|
ProfileResponse response = await httpClient.Get<ProfileResponse>(url, headers: headers);
|
|
77
85
|
return response.Data;
|
|
78
86
|
}
|
|
79
|
-
|
|
87
|
+
|
|
80
88
|
public static string GetAuthorizationHeader(string kid,
|
|
81
89
|
string macKey,
|
|
82
90
|
string macAlgorithm,
|
|
@@ -84,13 +92,15 @@ namespace TapSDK.Login.Internal {
|
|
|
84
92
|
string uri,
|
|
85
93
|
string host,
|
|
86
94
|
string port,
|
|
87
|
-
int timestamp)
|
|
95
|
+
int timestamp)
|
|
96
|
+
{
|
|
88
97
|
var nonce = new System.Random().Next().ToString();
|
|
89
98
|
|
|
90
99
|
var normalizedString = $"{timestamp}\n{nonce}\n{method}\n{uri}\n{host}\n{port}\n\n";
|
|
91
100
|
|
|
92
101
|
HashAlgorithm hashGenerator;
|
|
93
|
-
switch (macAlgorithm)
|
|
102
|
+
switch (macAlgorithm)
|
|
103
|
+
{
|
|
94
104
|
case "hmac-sha-256":
|
|
95
105
|
hashGenerator = new HMACSHA256(Encoding.ASCII.GetBytes(macKey));
|
|
96
106
|
break;
|
|
@@ -110,7 +120,8 @@ namespace TapSDK.Login.Internal {
|
|
|
110
120
|
return authorizationHeader.ToString();
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
public static async Task<TokenData> RefreshToken(string clientId, string accessToken)
|
|
123
|
+
public static async Task<TokenData> RefreshToken(string clientId, string accessToken)
|
|
124
|
+
{
|
|
114
125
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
|
115
126
|
{ "client_id", clientId },
|
|
116
127
|
{ "grant_type", "refresh_token" },
|
|
@@ -119,7 +130,7 @@ namespace TapSDK.Login.Internal {
|
|
|
119
130
|
{ "platform", "unity" },
|
|
120
131
|
{ "info", "{\"device_id\":\"" + SystemInfo.deviceModel + "\"}" }
|
|
121
132
|
};
|
|
122
|
-
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
133
|
+
TokenResponse response = await httpClient.Post<TokenResponse>(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
123
134
|
data: data);
|
|
124
135
|
return response.Data;
|
|
125
136
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Threading.Tasks;
|
|
3
|
+
using TapSDK.Core.Internal.Log;
|
|
4
|
+
using TapSDK.Core.Standalone.Internal.Service;
|
|
5
|
+
using TapSDK.Login.Internal;
|
|
6
|
+
|
|
7
|
+
namespace TapSDK.Login.Standalone.Internal
|
|
8
|
+
{
|
|
9
|
+
internal class TapLoginService : ITapLoginService
|
|
10
|
+
{
|
|
11
|
+
public string ObtainAuthorizationAsync(string url, string method)
|
|
12
|
+
{
|
|
13
|
+
TapTapAccount tapAccount = AccountManager.Instance.Account;
|
|
14
|
+
if (tapAccount == null)
|
|
15
|
+
{
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
AccessToken token = tapAccount.accessToken;
|
|
19
|
+
if (token == null)
|
|
20
|
+
{
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
var dt = DateTime.UtcNow - new DateTime(1970, 1, 1);
|
|
24
|
+
var ts = (int)dt.TotalSeconds;
|
|
25
|
+
string port = "443";
|
|
26
|
+
if (url.StartsWith("http://"))
|
|
27
|
+
{
|
|
28
|
+
port = "80";
|
|
29
|
+
}
|
|
30
|
+
UriBuilder uri = new UriBuilder(url);
|
|
31
|
+
string host = uri.Host;
|
|
32
|
+
string pathAndQuery = url.Substring(url.LastIndexOf(host) + host.Length);
|
|
33
|
+
var sign = "MAC " + LoginService.GetAuthorizationHeader(
|
|
34
|
+
token.kid,
|
|
35
|
+
token.macKey,
|
|
36
|
+
token.macAlgorithm,
|
|
37
|
+
method,
|
|
38
|
+
pathAndQuery,
|
|
39
|
+
host,
|
|
40
|
+
port,
|
|
41
|
+
ts);
|
|
42
|
+
return sign;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -18,13 +18,13 @@ namespace TapSDK.Login.Internal {
|
|
|
18
18
|
private readonly static string DEMO_IMAGE_URL_IOS_EN = $"{DEMO_IMAGE_IO_HOST}/scan-guide/ios.png";
|
|
19
19
|
private readonly static string DEMO_IMAGE_URL_ANDROID_EN = $"{DEMO_IMAGE_IO_HOST}/scan-guide/android.png";
|
|
20
20
|
|
|
21
|
-
private readonly static string DEFAULT_IOS_CLIENT = "Sprites/taptap-login-ios-client";
|
|
22
|
-
private readonly static string DEFAULT_ANDROID_CLIENT = "Sprites/taptap-login-android-client";
|
|
21
|
+
// private readonly static string DEFAULT_IOS_CLIENT = "Sprites/taptap-login-ios-client";
|
|
22
|
+
// private readonly static string DEFAULT_ANDROID_CLIENT = "Sprites/taptap-login-android-client";
|
|
23
23
|
|
|
24
24
|
private readonly static string AUTH_PENDING = "authorization_pending";
|
|
25
25
|
private readonly static string AUTH_WAITING = "authorization_waiting";
|
|
26
26
|
private readonly static string AUTH_DENIED = "access_denied";
|
|
27
|
-
private readonly static string AUTH_SUCCESS = "";
|
|
27
|
+
// private readonly static string AUTH_SUCCESS = "";
|
|
28
28
|
|
|
29
29
|
private readonly Action<TokenData, String> onAuth;
|
|
30
30
|
|
package/link.xml
ADDED
package/link.xml.meta
ADDED
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"name": "com.taptap.sdk.login",
|
|
3
3
|
"displayName": "TapTapSDK Login",
|
|
4
4
|
"description": "TapTapSDK Login",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.4.0",
|
|
6
6
|
"unity": "2019.4",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"com.taptap.sdk.core": "4.
|
|
9
|
+
"com.taptap.sdk.core": "4.4.0"
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections;
|
|
3
|
-
using System.Collections.Generic;
|
|
4
|
-
using System.Collections.Specialized;
|
|
5
|
-
using System.Text;
|
|
6
|
-
using System.Text.RegularExpressions;
|
|
7
|
-
using TapSDK.Core;
|
|
8
|
-
using UnityEngine;
|
|
9
|
-
|
|
10
|
-
namespace TapSDK.Login.Internal
|
|
11
|
-
{
|
|
12
|
-
public class Net : MonoBehaviour
|
|
13
|
-
{
|
|
14
|
-
public delegate void Action();
|
|
15
|
-
|
|
16
|
-
// ReSharper disable Unity.PerformanceAnalysis
|
|
17
|
-
public void PostAsync(string url, Dictionary<string, string> queryParams, Dictionary<string, string> formParams, Action<string> methodForResult, Action<int, string> methodForError)
|
|
18
|
-
{
|
|
19
|
-
if (string.IsNullOrEmpty(url))
|
|
20
|
-
{
|
|
21
|
-
methodForError(-1, "empty url");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
StartCoroutine(Post(url, queryParams, formParams, methodForResult, methodForError));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ReSharper disable Unity.PerformanceAnalysis
|
|
28
|
-
public void GetAsync(string url, string authorization, Dictionary<string, string> queryParams, Action<string> methodForResult, Action<int, string> methodForError)
|
|
29
|
-
{
|
|
30
|
-
if (string.IsNullOrEmpty(url))
|
|
31
|
-
{
|
|
32
|
-
methodForError(-1, "empty url");
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
StartCoroutine(Get(url, authorization, queryParams, methodForResult, methodForError));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ReSharper disable Unity.PerformanceAnalysis
|
|
39
|
-
private IEnumerator Get(string url, string authorization, Dictionary<string, string> queryParams, Action<string> methodForResult, Action<int, string> methodForError)
|
|
40
|
-
{
|
|
41
|
-
string baseUrl;
|
|
42
|
-
Dictionary<string, string> finalQueryParams = queryParams ?? new Dictionary<string, string>();
|
|
43
|
-
NameValueCollection collection = new NameValueCollection();
|
|
44
|
-
ParseUrl(url, out baseUrl, out collection);
|
|
45
|
-
foreach (string key in collection.AllKeys)
|
|
46
|
-
{
|
|
47
|
-
foreach (string value in collection.GetValues(key))
|
|
48
|
-
{
|
|
49
|
-
finalQueryParams.Add(key, value);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
string finalUrl;
|
|
53
|
-
if (finalQueryParams.Count == 0)
|
|
54
|
-
{
|
|
55
|
-
finalUrl = baseUrl;
|
|
56
|
-
}
|
|
57
|
-
else
|
|
58
|
-
{
|
|
59
|
-
finalUrl = baseUrl + "?" + DictToQueryString(finalQueryParams);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Dictionary<string, string> headers = new Dictionary<string, string>();
|
|
64
|
-
headers.Add("User-Agent", "TapTapUnitySDK/" + TapTapSdk.Version + " " + "UnityPlayer/" + Application.unityVersion);
|
|
65
|
-
headers.Add("Authorization", authorization);
|
|
66
|
-
WWW w = new WWW(finalUrl, null, headers);
|
|
67
|
-
PrintRequest(w, "GET", null, headers);
|
|
68
|
-
yield return w;
|
|
69
|
-
PrintResponse(w);
|
|
70
|
-
if (!string.IsNullOrEmpty(w.error))
|
|
71
|
-
{
|
|
72
|
-
string data = w.text;
|
|
73
|
-
if (data != null)
|
|
74
|
-
{
|
|
75
|
-
methodForError(GetResponseCode(w), data);
|
|
76
|
-
}
|
|
77
|
-
else
|
|
78
|
-
{
|
|
79
|
-
methodForError(GetResponseCode(w), w.error);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
w.Dispose();
|
|
83
|
-
yield break;
|
|
84
|
-
}
|
|
85
|
-
else
|
|
86
|
-
{
|
|
87
|
-
string data = w.text;
|
|
88
|
-
if (data != null)
|
|
89
|
-
{
|
|
90
|
-
methodForResult(w.text);
|
|
91
|
-
yield break;
|
|
92
|
-
}
|
|
93
|
-
else
|
|
94
|
-
{
|
|
95
|
-
methodForError(GetResponseCode(w), "Empyt response from server : " + url);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ReSharper disable Unity.PerformanceAnalysis
|
|
101
|
-
private IEnumerator Post(string url, Dictionary<string, string> queryParams, Dictionary<string, string> formParams, Action<string> methodForResult, Action<int, string> methodForError)
|
|
102
|
-
{
|
|
103
|
-
string baseUrl;
|
|
104
|
-
Dictionary<string, string> finalQueryParams = queryParams ?? new Dictionary<string, string>();
|
|
105
|
-
NameValueCollection collection = new NameValueCollection();
|
|
106
|
-
ParseUrl(url, out baseUrl, out collection);
|
|
107
|
-
foreach (string key in collection.AllKeys)
|
|
108
|
-
{
|
|
109
|
-
foreach (string value in collection.GetValues(key))
|
|
110
|
-
{
|
|
111
|
-
finalQueryParams.Add(key, value);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
string finalUrl;
|
|
115
|
-
if(finalQueryParams.Count == 0)
|
|
116
|
-
{
|
|
117
|
-
finalUrl = baseUrl;
|
|
118
|
-
} else
|
|
119
|
-
{
|
|
120
|
-
finalUrl = baseUrl + "?" + DictToQueryString(finalQueryParams);
|
|
121
|
-
}
|
|
122
|
-
WWWForm wwwForm = new WWWForm();
|
|
123
|
-
Dictionary<string, string> finalFormParams = formParams ?? new Dictionary<string, string>();
|
|
124
|
-
foreach (KeyValuePair<string, string> kv in finalFormParams)
|
|
125
|
-
{
|
|
126
|
-
// Debug.Log($"kv.key:{kv.Key} value:{kv.Value}");
|
|
127
|
-
wwwForm.AddField(kv.Key, kv.Value);
|
|
128
|
-
; }
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Dictionary<string, string> headers = new Dictionary<string, string>();
|
|
132
|
-
headers.Add("User-Agent", "TapTapUnitySDK/1.0 " + "UnityPlayer/" + Application.unityVersion);
|
|
133
|
-
WWW w = new WWW(finalUrl, wwwForm.data, headers);
|
|
134
|
-
PrintRequest(w, "POST", wwwForm, headers);
|
|
135
|
-
yield return w;
|
|
136
|
-
PrintResponse(w);
|
|
137
|
-
if (!string.IsNullOrEmpty(w.error))
|
|
138
|
-
{
|
|
139
|
-
string data = w.text;
|
|
140
|
-
if (data != null)
|
|
141
|
-
{
|
|
142
|
-
methodForError(GetResponseCode(w), data);
|
|
143
|
-
}
|
|
144
|
-
else
|
|
145
|
-
{
|
|
146
|
-
methodForError(GetResponseCode(w), w.error);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
w.Dispose();
|
|
150
|
-
yield break;
|
|
151
|
-
}
|
|
152
|
-
else
|
|
153
|
-
{
|
|
154
|
-
string data = w.text;
|
|
155
|
-
if (data != null)
|
|
156
|
-
{
|
|
157
|
-
methodForResult(w.text);
|
|
158
|
-
yield break;
|
|
159
|
-
}
|
|
160
|
-
else
|
|
161
|
-
{
|
|
162
|
-
methodForError(GetResponseCode(w), "Empyt response from server : " + url);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
public static void PrintRequest(WWW request, string method, WWWForm wwwFrom, Dictionary<string, string> headers) {
|
|
167
|
-
if (TapLogger.LogDelegate == null) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (request == null) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
StringBuilder sb = new StringBuilder();
|
|
174
|
-
sb.AppendLine("=== HTTP Request Start ===");
|
|
175
|
-
sb.AppendLine($"URL: {request.url}");
|
|
176
|
-
sb.AppendLine($"Method: {method}");
|
|
177
|
-
|
|
178
|
-
sb.AppendLine($"Headers: \t");
|
|
179
|
-
if (wwwFrom?.headers != null)
|
|
180
|
-
{
|
|
181
|
-
foreach (var header in wwwFrom.headers) {
|
|
182
|
-
sb.AppendLine($"{header.Key}: {header.Value}");
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (headers != null)
|
|
187
|
-
{
|
|
188
|
-
foreach (var header in headers) {
|
|
189
|
-
sb.AppendLine($"{header.Key}: {header.Value}");
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
sb.AppendLine("=== HTTP Request End ===");
|
|
193
|
-
TapLogger.Debug(sb.ToString());
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private static void PrintResponse(WWW response) {
|
|
197
|
-
if (TapLogger.LogDelegate == null) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
StringBuilder sb = new StringBuilder();
|
|
201
|
-
sb.AppendLine("=== HTTP Response Start ===");
|
|
202
|
-
sb.AppendLine($"URL: {response.url}");
|
|
203
|
-
sb.AppendLine($"Status Code: {GetResponseCode(response)}");
|
|
204
|
-
sb.AppendLine($"error: {response.error}");
|
|
205
|
-
if (!string.IsNullOrEmpty(response.text)) {
|
|
206
|
-
sb.AppendLine($"Content: {response.text}");
|
|
207
|
-
}
|
|
208
|
-
sb.AppendLine("=== HTTP Response End ===");
|
|
209
|
-
TapLogger.Debug(sb.ToString());
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
public static int GetResponseCode(WWW request)
|
|
213
|
-
{
|
|
214
|
-
int ret = 0;
|
|
215
|
-
if (request.responseHeaders == null)
|
|
216
|
-
{
|
|
217
|
-
Debug.LogError("no response headers.");
|
|
218
|
-
}
|
|
219
|
-
else
|
|
220
|
-
{
|
|
221
|
-
if (!request.responseHeaders.ContainsKey("STATUS"))
|
|
222
|
-
{
|
|
223
|
-
Debug.LogError("response headers has no STATUS.");
|
|
224
|
-
}
|
|
225
|
-
else
|
|
226
|
-
{
|
|
227
|
-
ret = ParseResponseCode(request.responseHeaders["STATUS"]);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return ret;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
public static int ParseResponseCode(string statusLine)
|
|
235
|
-
{
|
|
236
|
-
int ret = 0;
|
|
237
|
-
|
|
238
|
-
string[] components = statusLine.Split(' ');
|
|
239
|
-
if (components.Length < 3)
|
|
240
|
-
{
|
|
241
|
-
Debug.LogError("invalid response status: " + statusLine);
|
|
242
|
-
}
|
|
243
|
-
else
|
|
244
|
-
{
|
|
245
|
-
if (!int.TryParse(components[1], out ret))
|
|
246
|
-
{
|
|
247
|
-
Debug.LogError("invalid response code: " + components[1]);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return ret;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
public static string DictToQueryString(IDictionary<string, string> dict)
|
|
255
|
-
{
|
|
256
|
-
List<string> list = new List<string>();
|
|
257
|
-
foreach (var item in dict)
|
|
258
|
-
{
|
|
259
|
-
list.Add(item.Key + "=" + item.Value);
|
|
260
|
-
}
|
|
261
|
-
return string.Join("&", list.ToArray());
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
public static void ParseUrl(string url, out string baseUrl, out NameValueCollection nvc)
|
|
265
|
-
{
|
|
266
|
-
if (url == null)
|
|
267
|
-
throw new ArgumentNullException("url");
|
|
268
|
-
nvc = new NameValueCollection();
|
|
269
|
-
baseUrl = "";
|
|
270
|
-
if (url == "")
|
|
271
|
-
return;
|
|
272
|
-
int questionMarkIndex = url.IndexOf('?');
|
|
273
|
-
if (questionMarkIndex == -1)
|
|
274
|
-
{
|
|
275
|
-
baseUrl = url;
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
baseUrl = url.Substring(0, questionMarkIndex);
|
|
279
|
-
if (questionMarkIndex == url.Length - 1)
|
|
280
|
-
return;
|
|
281
|
-
string ps = url.Substring(questionMarkIndex + 1);
|
|
282
|
-
Regex re = new Regex(@"(^|&)?(\w+)=([^&]+)(&|$)?", RegexOptions.None);
|
|
283
|
-
MatchCollection mc = re.Matches(ps);
|
|
284
|
-
foreach (Match m in mc)
|
|
285
|
-
{
|
|
286
|
-
nvc.Add(m.Result("$2").ToLower(), m.Result("$3"));
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
}
|
|
@@ -1,776 +0,0 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections;
|
|
3
|
-
using System.Collections.Generic;
|
|
4
|
-
using System.Diagnostics;
|
|
5
|
-
using System.Linq;
|
|
6
|
-
using System.Net;
|
|
7
|
-
using System.Security.Cryptography;
|
|
8
|
-
using System.Text;
|
|
9
|
-
using System.Threading.Tasks;
|
|
10
|
-
using TapSDK.Core;
|
|
11
|
-
using UnityEngine;
|
|
12
|
-
using UnityEngine.UI;
|
|
13
|
-
using ZXing;
|
|
14
|
-
using ZXing.Common;
|
|
15
|
-
using ZXing.QrCode.Internal;
|
|
16
|
-
using Debug = UnityEngine.Debug;
|
|
17
|
-
using Random = System.Random;
|
|
18
|
-
|
|
19
|
-
namespace TapSDK.Login.Internal
|
|
20
|
-
{
|
|
21
|
-
internal class QRCodeWindow : UIElement
|
|
22
|
-
{
|
|
23
|
-
// // \ue90f\ue91c\ue911\ue91a\ue901\ue902\ue903\ue90c 您已取消此次登录
|
|
24
|
-
// private static readonly string TEXT_CANCEL_LOGIN = "";
|
|
25
|
-
//
|
|
26
|
-
// // \ue910\ue91f\ue91b\ue914\ue90d 请重新扫码
|
|
27
|
-
// private static readonly string TEXT_PLEASE_RESCRAN = "";
|
|
28
|
-
//
|
|
29
|
-
// // \ue914\ue90d\ue900\ue907 扫码成功
|
|
30
|
-
// private static readonly string TEXT_SCAN_SUCCESS = "";
|
|
31
|
-
//
|
|
32
|
-
// // \ue910\ue91e\ue917\ue90a\ue915\ue912\ue913 请在手机上确认
|
|
33
|
-
// private static readonly string TEXT_CONFIRM_ON_PHONE = "";
|
|
34
|
-
|
|
35
|
-
public RawImage QRCodeRawImage;
|
|
36
|
-
public Text StatusText;
|
|
37
|
-
public Text SubStatusText;
|
|
38
|
-
public Image RefreshImage;
|
|
39
|
-
public Button RefreshButton;
|
|
40
|
-
public Button CloseButton;
|
|
41
|
-
|
|
42
|
-
public Button WebLoginButton;
|
|
43
|
-
|
|
44
|
-
private string clientId;
|
|
45
|
-
private string[] scopes;
|
|
46
|
-
private bool isLogin;
|
|
47
|
-
|
|
48
|
-
private string deviceCode;
|
|
49
|
-
private long expireAt = 0;
|
|
50
|
-
private long lastCheckAt = 0;
|
|
51
|
-
private long interval = 5;
|
|
52
|
-
|
|
53
|
-
private Net net;
|
|
54
|
-
private HttpListener _httpListener;
|
|
55
|
-
|
|
56
|
-
private long lastWebRequestTime = 0;
|
|
57
|
-
private string webRequestMode = "";
|
|
58
|
-
|
|
59
|
-
private void SetObjectText(string parentName, string objectName, string text)
|
|
60
|
-
{
|
|
61
|
-
try
|
|
62
|
-
{
|
|
63
|
-
var targetTransform = transform;
|
|
64
|
-
if (!string.IsNullOrEmpty(parentName))
|
|
65
|
-
{
|
|
66
|
-
targetTransform = transform.Find(parentName).gameObject.transform;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
var targetObject = targetTransform.Find(objectName).gameObject;
|
|
70
|
-
var gameText = targetObject.GetComponent<Text>();
|
|
71
|
-
gameText.text = text;
|
|
72
|
-
}
|
|
73
|
-
catch (Exception e)
|
|
74
|
-
{
|
|
75
|
-
Debug.Log("SetObjectText fail" + parentName + " " + objectName);
|
|
76
|
-
Debug.Log("SetObjectText fail\n" + e);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
void Awake()
|
|
81
|
-
{
|
|
82
|
-
var qrImageObject = transform.Find("QRImage").gameObject;
|
|
83
|
-
QRCodeRawImage = qrImageObject.GetComponent<RawImage>();
|
|
84
|
-
var statusObject = transform.Find("Status").gameObject;
|
|
85
|
-
StatusText = statusObject.GetComponent<Text>();
|
|
86
|
-
var subStatusObject = transform.Find("SubStatus").gameObject;
|
|
87
|
-
SubStatusText = subStatusObject.GetComponent<Text>();
|
|
88
|
-
var refreshObject = transform.Find("Refresh").gameObject;
|
|
89
|
-
RefreshImage = refreshObject.GetComponent<Image>();
|
|
90
|
-
var refreshButtonObject = refreshObject.transform.Find("RefreshButton").gameObject;
|
|
91
|
-
RefreshButton = refreshButtonObject.GetComponent<Button>();
|
|
92
|
-
var closeObject = transform.Find("Close").gameObject;
|
|
93
|
-
CloseButton = closeObject.GetComponent<Button>();
|
|
94
|
-
|
|
95
|
-
var webLoginButtonObject = transform.Find("WebLoginButton").gameObject;
|
|
96
|
-
WebLoginButton = webLoginButtonObject.GetComponent<Button>();
|
|
97
|
-
|
|
98
|
-
WebLoginButton.onClick.AddListener(() =>
|
|
99
|
-
{
|
|
100
|
-
var now = GetCurrentTime();
|
|
101
|
-
if (now - lastWebRequestTime > 1)
|
|
102
|
-
{
|
|
103
|
-
StartWebLogin();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
lastWebRequestTime = now;
|
|
107
|
-
});
|
|
108
|
-
RefreshImage.gameObject.SetActive(false);
|
|
109
|
-
RefreshButton.onClick.AddListener(RefreshCode);
|
|
110
|
-
SubStatusText.gameObject.SetActive(false);
|
|
111
|
-
StatusText.gameObject.SetActive(false);
|
|
112
|
-
CloseButton.onClick.AddListener(Close);
|
|
113
|
-
|
|
114
|
-
// SetObjectText("TitleContent", "TitleUse", LoginLanguage.GetCurrentLang().TitleUse());
|
|
115
|
-
SetObjectText("TitleContent", "TitleAccount", LoginLanguage.GetCurrentLang().TitleLogin());
|
|
116
|
-
SetObjectText("", "ScanLogin", LoginLanguage.GetCurrentLang().QrTitleLogin());
|
|
117
|
-
SetObjectText("", "ScanLogin", LoginLanguage.GetCurrentLang().QrTitleLogin());
|
|
118
|
-
SetObjectText("Notice", "Notice1", LoginLanguage.GetCurrentLang().QrNoticeUse());
|
|
119
|
-
SetObjectText("Notice", "Notice2", LoginLanguage.GetCurrentLang().QrNoticeClient());
|
|
120
|
-
SetObjectText("", "Notice3", LoginLanguage.GetCurrentLang().QrNoticeScanToLogin());
|
|
121
|
-
SetObjectText("", "WebLogin", LoginLanguage.GetCurrentLang().WebLogin());
|
|
122
|
-
SetObjectText("", "WebDescription", LoginLanguage.GetCurrentLang().WebNotice());
|
|
123
|
-
SetObjectText("WebLoginButton", "Text", LoginLanguage.GetCurrentLang().WebButtonJumpToWeb());
|
|
124
|
-
|
|
125
|
-
refreshButtonObject.transform.Find("Text").gameObject.GetComponent<Text>().text =
|
|
126
|
-
LoginLanguage.GetCurrentLang().QrRefresh();
|
|
127
|
-
|
|
128
|
-
if (string.IsNullOrEmpty(LoginLanguage.GetCurrentLang().QrNoticeUse()) &&
|
|
129
|
-
string.IsNullOrEmpty(LoginLanguage.GetCurrentLang().QrNoticeClient())) {
|
|
130
|
-
GameObject logoGO = transform.Find("Notice/Logo").gameObject;
|
|
131
|
-
logoGO.SetActive(false);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
public override void OnEnter()
|
|
136
|
-
{
|
|
137
|
-
base.OnEnter();
|
|
138
|
-
gameObject.AddComponent<Net>();
|
|
139
|
-
net = gameObject.GetComponent<Net>();
|
|
140
|
-
GetCode();
|
|
141
|
-
WebLoginRequestManager.Instance.CreateNewLoginRequest(scopes);
|
|
142
|
-
StartHttpServer();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
public override void OnExit()
|
|
146
|
-
{
|
|
147
|
-
base.OnExit();
|
|
148
|
-
Destroy(net.gameObject);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private void Close()
|
|
152
|
-
{
|
|
153
|
-
if (_httpListener != null)
|
|
154
|
-
{
|
|
155
|
-
try
|
|
156
|
-
{
|
|
157
|
-
_httpListener.Stop();
|
|
158
|
-
}
|
|
159
|
-
catch (Exception)
|
|
160
|
-
{
|
|
161
|
-
// ignored
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
OnCallback(UIManager.RESULT_CLOSE, "Close button clicked.");
|
|
166
|
-
GetUIManager().Pop();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private void StartHttpServer()
|
|
170
|
-
{
|
|
171
|
-
if (_httpListener == null)
|
|
172
|
-
{
|
|
173
|
-
_httpListener = new HttpListener();
|
|
174
|
-
_httpListener.Prefixes.Add(WebLoginRequestManager.Instance.GetCurrentRequest().GetRedirectHost());
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
try
|
|
178
|
-
{
|
|
179
|
-
_httpListener.Start();
|
|
180
|
-
}
|
|
181
|
-
catch (Exception)
|
|
182
|
-
{
|
|
183
|
-
Debug.Log("Http listener start fail, maybe is already started");
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private void StartWebLogin()
|
|
188
|
-
{
|
|
189
|
-
ShowStatus("", "");
|
|
190
|
-
|
|
191
|
-
Application.OpenURL(WebLoginRequestManager.Instance.GetCurrentRequest().GetWebLoginUrl());
|
|
192
|
-
// Waits for the OAuth authorization response.
|
|
193
|
-
|
|
194
|
-
_ = StartWaitForRequest();
|
|
195
|
-
|
|
196
|
-
// _httpListener.BeginGetContext(HandleHttpRequest, _httpListener);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private async Task StartWaitForRequest()
|
|
200
|
-
{
|
|
201
|
-
HttpListenerContext context = await _httpListener.GetContextAsync();
|
|
202
|
-
|
|
203
|
-
Debug.Log(context.Request.RawUrl);
|
|
204
|
-
|
|
205
|
-
if (context.Request.HttpMethod == "OPTIONS") {
|
|
206
|
-
// 跨域请求
|
|
207
|
-
context.Response.StatusCode = 200;
|
|
208
|
-
context.Response.Close();
|
|
209
|
-
} else {
|
|
210
|
-
webRequestMode = "";
|
|
211
|
-
// NOTE@luran:这里负责监听 authorization code 的回调
|
|
212
|
-
TapLogger.Debug($"[TapLogin] Get Authorization Code Response: {context.Request.RawUrl}");
|
|
213
|
-
var resultCode = UrlCheck(context.Request.RawUrl);
|
|
214
|
-
|
|
215
|
-
CodeToTokenFromWeb(resultCode);
|
|
216
|
-
|
|
217
|
-
var response = context.Response;
|
|
218
|
-
var buffer = Array.Empty<byte>();
|
|
219
|
-
if (!string.IsNullOrEmpty(resultCode)) {
|
|
220
|
-
switch (webRequestMode) {
|
|
221
|
-
case "gif": {
|
|
222
|
-
response.StatusCode = 200;
|
|
223
|
-
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
|
224
|
-
response.ContentType = "image/gif";
|
|
225
|
-
const string gif = "R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
226
|
-
try {
|
|
227
|
-
buffer = Convert.FromBase64String(gif);
|
|
228
|
-
} catch (Exception) {
|
|
229
|
-
buffer = Encoding.UTF8.GetBytes("ok");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
break;
|
|
233
|
-
}
|
|
234
|
-
case "redirect":
|
|
235
|
-
response.Redirect(CodeUtil.GetTapTapOAuthRedirectUri());
|
|
236
|
-
break;
|
|
237
|
-
default:
|
|
238
|
-
response.StatusCode = 200;
|
|
239
|
-
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
|
240
|
-
response.ContentType = "text/plain";
|
|
241
|
-
buffer = Encoding.UTF8.GetBytes("ok");
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
} else {
|
|
245
|
-
response.StatusCode = 404;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
response.ContentLength64 = buffer.Length;
|
|
249
|
-
var responseOutput = response.OutputStream;
|
|
250
|
-
await responseOutput.WriteAsync(buffer, 0, buffer.Length)
|
|
251
|
-
.ContinueWith((task) => { responseOutput.Close(); });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
_ = StartWaitForRequest();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
private string UrlCheck(string url)
|
|
258
|
-
{
|
|
259
|
-
// check url
|
|
260
|
-
if (string.IsNullOrEmpty(url) || !url.Contains(CodeUtil.GetTapTapOAuthPrefix()))
|
|
261
|
-
{
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
var urlParams = url.Split('?');
|
|
266
|
-
if (urlParams.Length <= 1)
|
|
267
|
-
{
|
|
268
|
-
return null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
var args = urlParams[1].Split('&');
|
|
272
|
-
var dic = args.Select(arg => arg.Split('=')).ToDictionary(kv => kv[0], kv => kv[1]);
|
|
273
|
-
|
|
274
|
-
var code = dic.ContainsKey("code") ? dic["code"] : "";
|
|
275
|
-
var state = dic.ContainsKey("state") ? dic["state"] : "";
|
|
276
|
-
webRequestMode = dic.ContainsKey("mode") ? dic["mode"] : "";
|
|
277
|
-
if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(state))
|
|
278
|
-
{
|
|
279
|
-
return null;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
var content = new StringBuilder();
|
|
283
|
-
foreach (var VARIABLE in dic) {
|
|
284
|
-
content.AppendLine($"key: {VARIABLE.Key}, value: {VARIABLE.Value}");
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
TapLogger.Debug($"[TapLogin] Get Authorization Code Response Content:\n {content.ToString()}");
|
|
288
|
-
|
|
289
|
-
return !state.Equals(WebLoginRequestManager.Instance.GetCurrentRequest().GetState()) ? null : code;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
private void CodeToTokenFromWeb(string code)
|
|
293
|
-
{
|
|
294
|
-
if (string.IsNullOrEmpty(code)) return;
|
|
295
|
-
ShowStatus(LoginLanguage.GetCurrentLang().WebNoticeLogin(), "");
|
|
296
|
-
// url is ok, go to get token
|
|
297
|
-
var formParams = new Dictionary<string, string>
|
|
298
|
-
{
|
|
299
|
-
{ "client_id", clientId },
|
|
300
|
-
{ "grant_type", "authorization_code" },
|
|
301
|
-
{ "secret_type", "hmac-sha-1" },
|
|
302
|
-
{ "code", code },
|
|
303
|
-
{ "redirect_uri", WebLoginRequestManager.Instance.GetCurrentRequest().GetRedirectUri() },
|
|
304
|
-
{ "code_verifier", WebLoginRequestManager.Instance.GetCodeVerifier() }
|
|
305
|
-
};
|
|
306
|
-
net.PostAsync(TapTapSdk.CurrentRegion.TokenUrl(), null, formParams, (result =>
|
|
307
|
-
{
|
|
308
|
-
TapLogger.Debug($"[TapLogin] Get Access Token Origin Result: {result}");
|
|
309
|
-
if (Json.Deserialize(result) is Dictionary<string, object> resultDict &&
|
|
310
|
-
resultDict.ContainsKey("success") && (bool)resultDict["success"])
|
|
311
|
-
{
|
|
312
|
-
if (resultDict["data"] is Dictionary<string, object> dataDict) {
|
|
313
|
-
// convert dataDict content to a format string for debug
|
|
314
|
-
#if UNITY_EDITOR
|
|
315
|
-
var c = new StringBuilder();
|
|
316
|
-
foreach (var kv in dataDict) {
|
|
317
|
-
c.AppendLine($"key: {kv.Key}, valuue: {kv.Value.ToString()}");
|
|
318
|
-
}
|
|
319
|
-
TapLogger.Debug($"[TapLogin] Get Access Token data:\n {c.ToString()}");
|
|
320
|
-
#endif
|
|
321
|
-
var token = new AccessToken
|
|
322
|
-
{
|
|
323
|
-
kid = dataDict["kid"] as string,
|
|
324
|
-
macKey = dataDict["mac_key"] as string,
|
|
325
|
-
tokenType = dataDict["token_type"] as string,
|
|
326
|
-
macAlgorithm = dataDict["mac_algorithm"] as string,
|
|
327
|
-
scopeSet = new HashSet<string>((dataDict["scope"] as string)?.Split(' '))
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
// stop http server when success get token
|
|
331
|
-
_httpListener.Stop();
|
|
332
|
-
Debug.Log("HTTP server stopped.");
|
|
333
|
-
GetProfile(token);
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
ShowStatus(LoginLanguage.GetCurrentLang().WebNoticeFail(),
|
|
339
|
-
LoginLanguage.GetCurrentLang().WebNoticeFail2());
|
|
340
|
-
Debug.Log("CodeToTokenFromWeb success with fail data \n" + result);
|
|
341
|
-
}), ((error, msg) =>
|
|
342
|
-
{
|
|
343
|
-
Debug.Log("CodeToTokenFromWeb fail \n" + msg);
|
|
344
|
-
if (Json.Deserialize(msg) is Dictionary<string, object> resultDict &&
|
|
345
|
-
resultDict.ContainsKey("data"))
|
|
346
|
-
{
|
|
347
|
-
if (resultDict["data"] is Dictionary<string, object> dataDict &&
|
|
348
|
-
dataDict.ContainsKey("error"))
|
|
349
|
-
{
|
|
350
|
-
var errorMsg = dataDict["error"] as string;
|
|
351
|
-
var errorDesc = dataDict["error_description"] as string;
|
|
352
|
-
ShowStatus(LoginLanguage.GetCurrentLang().WebNoticeFail(),
|
|
353
|
-
LoginLanguage.GetCurrentLang().WebNoticeFail2());
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
ShowStatus(LoginLanguage.GetCurrentLang().WebNoticeFail(),
|
|
359
|
-
LoginLanguage.GetCurrentLang().WebNoticeFail2());
|
|
360
|
-
}));
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
private void RefreshCode()
|
|
364
|
-
{
|
|
365
|
-
StatusText.gameObject.SetActive(false);
|
|
366
|
-
SubStatusText.gameObject.SetActive(false);
|
|
367
|
-
GetCode();
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
private void GetCode() {
|
|
371
|
-
RefreshImage.gameObject.SetActive(false);
|
|
372
|
-
|
|
373
|
-
var formParams = new Dictionary<string, string>
|
|
374
|
-
{
|
|
375
|
-
{ "client_id", clientId },
|
|
376
|
-
{ "response_type", "device_code" },
|
|
377
|
-
{ "scope", string.Join(",", scopes) },
|
|
378
|
-
{ "version", TapTapSdk.Version },
|
|
379
|
-
{ "platform", "unity" },
|
|
380
|
-
{ "info", "{\"device_id\":\"" + SystemInfo.deviceModel + "\"}" }
|
|
381
|
-
};
|
|
382
|
-
net.PostAsync(TapTapSdk.CurrentRegion.CodeUrl(),
|
|
383
|
-
null,
|
|
384
|
-
formParams,
|
|
385
|
-
(result) =>
|
|
386
|
-
{
|
|
387
|
-
if (Json.Deserialize(result) is Dictionary<string, object> resultDict &&
|
|
388
|
-
resultDict.ContainsKey("success") && (bool)resultDict["success"])
|
|
389
|
-
{
|
|
390
|
-
if (resultDict["data"] is Dictionary<string, object> dataDict &&
|
|
391
|
-
dataDict.ContainsKey("qrcode_url"))
|
|
392
|
-
{
|
|
393
|
-
var qrCodeUrl = dataDict["qrcode_url"] as string;
|
|
394
|
-
EncodeQrImage(qrCodeUrl, 309, 309);
|
|
395
|
-
if (dataDict.ContainsKey("device_code"))
|
|
396
|
-
{
|
|
397
|
-
deviceCode = dataDict["device_code"] as string;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (dataDict.ContainsKey("expires_in"))
|
|
401
|
-
{
|
|
402
|
-
var expireIn = (long)dataDict["expires_in"];
|
|
403
|
-
var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
404
|
-
expireAt = Convert.ToInt64(ts.TotalSeconds) + expireIn;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
if (dataDict.ContainsKey("interval"))
|
|
408
|
-
{
|
|
409
|
-
interval = (long)dataDict["interval"];
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
StartCheck();
|
|
413
|
-
Debug.Log("QRCODE Get");
|
|
414
|
-
}
|
|
415
|
-
else
|
|
416
|
-
{
|
|
417
|
-
//StatusText.text = "获取二维码失败";
|
|
418
|
-
ShowQrRefresh();
|
|
419
|
-
Debug.Log("QRCODE Get Fail 1");
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
else
|
|
423
|
-
{
|
|
424
|
-
//StatusText.text = "获取二维码失败";
|
|
425
|
-
ShowQrRefresh();
|
|
426
|
-
Debug.Log("QRCODE Get Fail 2");
|
|
427
|
-
}
|
|
428
|
-
},
|
|
429
|
-
(error, msg) =>
|
|
430
|
-
{
|
|
431
|
-
//StatusText.text = "获取二维码失败";
|
|
432
|
-
ShowQrRefresh();
|
|
433
|
-
Debug.Log("QRCODE Get Fail 3");
|
|
434
|
-
}
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
private void EncodeQrImage(string content, int width, int height)
|
|
439
|
-
{
|
|
440
|
-
var writer = new MultiFormatWriter();
|
|
441
|
-
var hints = new Dictionary<EncodeHintType, object>
|
|
442
|
-
{
|
|
443
|
-
{ EncodeHintType.CHARACTER_SET, "UTF-8" },
|
|
444
|
-
//hints.Add(EncodeHintType.MARGIN, 0);
|
|
445
|
-
{ EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M }
|
|
446
|
-
};
|
|
447
|
-
var bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
|
|
448
|
-
bitMatrix = DeleteWhite(bitMatrix);
|
|
449
|
-
var w = bitMatrix.Width;
|
|
450
|
-
var h = bitMatrix.Height;
|
|
451
|
-
var texture = new Texture2D(w, h);
|
|
452
|
-
for (var x = 0; x < h; x++)
|
|
453
|
-
{
|
|
454
|
-
for (var y = 0; y < w; y++)
|
|
455
|
-
{
|
|
456
|
-
texture.SetPixel(y, x, bitMatrix[x, y] ? Color.black : Color.white);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
texture.Apply();
|
|
461
|
-
texture.filterMode = FilterMode.Point;
|
|
462
|
-
QRCodeRawImage.texture = texture;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
private static BitMatrix DeleteWhite(BitMatrix matrix)
|
|
466
|
-
{
|
|
467
|
-
var rec = matrix.getEnclosingRectangle();
|
|
468
|
-
var resWidth = rec[2];
|
|
469
|
-
var resHeight = rec[3];
|
|
470
|
-
|
|
471
|
-
var resMatrix = new BitMatrix(resWidth, resHeight);
|
|
472
|
-
resMatrix.clear();
|
|
473
|
-
for (var i = 0; i < resWidth; i++)
|
|
474
|
-
{
|
|
475
|
-
for (var j = 0; j < resHeight; j++)
|
|
476
|
-
{
|
|
477
|
-
if (matrix[i + rec[0], j + rec[1]])
|
|
478
|
-
{
|
|
479
|
-
resMatrix.flip(i, j);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return resMatrix;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
private void StartCheck()
|
|
488
|
-
{
|
|
489
|
-
StartCoroutine(nameof(AutoCheck));
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
private void StopCheck()
|
|
493
|
-
{
|
|
494
|
-
StopCoroutine(nameof(AutoCheck));
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
private IEnumerator AutoCheck()
|
|
498
|
-
{
|
|
499
|
-
while (true)
|
|
500
|
-
{
|
|
501
|
-
yield return new WaitForSeconds(0.5f);
|
|
502
|
-
var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
503
|
-
var now = Convert.ToInt64(ts.TotalSeconds);
|
|
504
|
-
//Debug.Log("Now: " + now + " ExpireAt: " + expireAt + " Remain: " + (expireAt - now));
|
|
505
|
-
if (now > expireAt)
|
|
506
|
-
{
|
|
507
|
-
ShowQrRefresh();
|
|
508
|
-
StopCheck();
|
|
509
|
-
break;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
if (now <= lastCheckAt + interval) continue;
|
|
513
|
-
var wait = true;
|
|
514
|
-
var stop = false;
|
|
515
|
-
var formParams = new Dictionary<string, string>
|
|
516
|
-
{
|
|
517
|
-
{ "grant_type", "device_token" },
|
|
518
|
-
{ "client_id", clientId },
|
|
519
|
-
{ "secret_type", "hmac-sha-1" },
|
|
520
|
-
{ "code", deviceCode },
|
|
521
|
-
{ "version", "1.0" },
|
|
522
|
-
{ "platform", "unity" },
|
|
523
|
-
{ "info", "{\"device_id\":\"" + SystemInfo.deviceModel + "\"}" }
|
|
524
|
-
};
|
|
525
|
-
net.PostAsync(TapTapSdk.CurrentRegion.TokenUrl(),
|
|
526
|
-
null,
|
|
527
|
-
formParams,
|
|
528
|
-
(result) =>
|
|
529
|
-
{
|
|
530
|
-
//StatusText.text = "";
|
|
531
|
-
TapLogger.Debug(string.Format("qr code login result: {0}", result));
|
|
532
|
-
if (Json.Deserialize(result) is Dictionary<string, object> resultDict &&
|
|
533
|
-
resultDict.ContainsKey("success") && (bool)resultDict["success"])
|
|
534
|
-
{
|
|
535
|
-
//StatusText.text = "扫码成功";
|
|
536
|
-
//SubStatusText.gameObject.SetActive(false);
|
|
537
|
-
if (resultDict["data"] is Dictionary<string, object> dataDict)
|
|
538
|
-
{
|
|
539
|
-
var token = new AccessToken
|
|
540
|
-
{
|
|
541
|
-
kid = dataDict["kid"] as string,
|
|
542
|
-
macKey = dataDict["mac_key"] as string,
|
|
543
|
-
tokenType = dataDict["token_type"] as string,
|
|
544
|
-
macAlgorithm = dataDict["mac_algorithm"] as string,
|
|
545
|
-
scopeSet = new HashSet<string>((dataDict["scope"] as string)?.Split(' '))
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
GetProfile(token);
|
|
549
|
-
}
|
|
550
|
-
else
|
|
551
|
-
{
|
|
552
|
-
ShowQrRefresh();
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
else
|
|
556
|
-
{
|
|
557
|
-
//StatusText.text = "扫描二维码失败";
|
|
558
|
-
ShowQrRefresh();
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
wait = false;
|
|
562
|
-
stop = true;
|
|
563
|
-
StopCheck();
|
|
564
|
-
},
|
|
565
|
-
(error, msg) =>
|
|
566
|
-
{
|
|
567
|
-
wait = false;
|
|
568
|
-
|
|
569
|
-
if (Json.Deserialize(msg) is Dictionary<string, object> resultDict &&
|
|
570
|
-
resultDict.ContainsKey("data"))
|
|
571
|
-
{
|
|
572
|
-
if (resultDict["data"] is Dictionary<string, object> dataDict &&
|
|
573
|
-
dataDict.ContainsKey("error"))
|
|
574
|
-
{
|
|
575
|
-
var errorMsg = dataDict["error"] as string;
|
|
576
|
-
|
|
577
|
-
// Debug.Log("QRCODE FAIL " + errorMsg);
|
|
578
|
-
switch (errorMsg)
|
|
579
|
-
{
|
|
580
|
-
case "authorization_pending":
|
|
581
|
-
//StatusText.text = "扫码二维码登录";
|
|
582
|
-
break;
|
|
583
|
-
case "authorization_waiting":
|
|
584
|
-
ShowStatus(LoginLanguage.GetCurrentLang().QrnNoticeSuccess(),
|
|
585
|
-
LoginLanguage.GetCurrentLang().QrnNoticeSuccess2());
|
|
586
|
-
break;
|
|
587
|
-
case "access_denied":
|
|
588
|
-
ShowStatus(LoginLanguage.GetCurrentLang().QrNoticeCancel(),
|
|
589
|
-
LoginLanguage.GetCurrentLang().QrNoticeCancel2());
|
|
590
|
-
stop = true;
|
|
591
|
-
StopCheck();
|
|
592
|
-
GetCode();
|
|
593
|
-
break;
|
|
594
|
-
case "invalid_grant":
|
|
595
|
-
ShowQrRefresh();
|
|
596
|
-
stop = true;
|
|
597
|
-
StopCheck();
|
|
598
|
-
break;
|
|
599
|
-
case "slow_down":
|
|
600
|
-
break;
|
|
601
|
-
default:
|
|
602
|
-
ShowQrRefresh();
|
|
603
|
-
stop = true;
|
|
604
|
-
StopCheck();
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
return;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// if false then refresh
|
|
613
|
-
ShowQrRefresh();
|
|
614
|
-
stop = true;
|
|
615
|
-
StopCheck();
|
|
616
|
-
}
|
|
617
|
-
);
|
|
618
|
-
while (wait)
|
|
619
|
-
{
|
|
620
|
-
yield return new WaitForSeconds(0.5f);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
624
|
-
lastCheckAt = Convert.ToInt64(ts.TotalSeconds);
|
|
625
|
-
if (stop) break;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
private void GetProfile(AccessToken accessToken, int timestamp = 0) {
|
|
630
|
-
var havePublicProfile = accessToken.scopeSet != null && accessToken.scopeSet.Contains("public_profile");
|
|
631
|
-
var url = TapTapSdk.CurrentRegion.ProfileUrl(havePublicProfile) + clientId;
|
|
632
|
-
var ts = timestamp;
|
|
633
|
-
if (ts == 0)
|
|
634
|
-
{
|
|
635
|
-
var dt = DateTime.UtcNow - new DateTime(1970, 1, 1);
|
|
636
|
-
ts = (int)dt.TotalSeconds;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
var uri = new Uri(url);
|
|
640
|
-
var sign = "MAC " + GetAuthorizationHeader(accessToken.kid,
|
|
641
|
-
accessToken.macKey,
|
|
642
|
-
accessToken.macAlgorithm,
|
|
643
|
-
"GET",
|
|
644
|
-
uri.PathAndQuery,
|
|
645
|
-
uri.Host,
|
|
646
|
-
"443", ts);
|
|
647
|
-
|
|
648
|
-
net.GetAsync(url,
|
|
649
|
-
sign,
|
|
650
|
-
null,
|
|
651
|
-
(result) =>
|
|
652
|
-
{
|
|
653
|
-
try
|
|
654
|
-
{
|
|
655
|
-
var tokenDict = new Dictionary<string, string>
|
|
656
|
-
{
|
|
657
|
-
{ "kid", accessToken.kid },
|
|
658
|
-
{ "mac_key", accessToken.macKey },
|
|
659
|
-
{ "token_type", accessToken.tokenType },
|
|
660
|
-
{ "mac_algorithm", accessToken.macAlgorithm },
|
|
661
|
-
{ "scope", string.Join(" ", accessToken.scopeSet) },
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
if (Json.Deserialize(result) is Dictionary<string, object> resultDict &&
|
|
665
|
-
resultDict.ContainsKey("success") && (bool)resultDict["success"])
|
|
666
|
-
{
|
|
667
|
-
var dataDict = resultDict["data"] as Dictionary<string, object>;
|
|
668
|
-
var profileStr = Json.Serialize(dataDict);
|
|
669
|
-
Profile p = new Profile(profileStr);
|
|
670
|
-
if (isLogin) {
|
|
671
|
-
DataStorage.SaveString("taptapsdk_accesstoken", Json.Serialize(tokenDict));
|
|
672
|
-
DataStorage.SaveString("taptapsdk_profile", profileStr);
|
|
673
|
-
}
|
|
674
|
-
OnCallback(UIManager.RESULT_SUCCESS, new Tuple<AccessToken, Profile>(accessToken, p));
|
|
675
|
-
GetUIManager().Pop();
|
|
676
|
-
}
|
|
677
|
-
else
|
|
678
|
-
{
|
|
679
|
-
OnCallback(UIManager.RESULT_FAILED, "Get profile error");
|
|
680
|
-
GetUIManager().Pop();
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
catch (Exception)
|
|
684
|
-
{
|
|
685
|
-
OnCallback(UIManager.RESULT_FAILED, "Get profile error");
|
|
686
|
-
GetUIManager().Pop();
|
|
687
|
-
}
|
|
688
|
-
},
|
|
689
|
-
(error, msg) =>
|
|
690
|
-
{
|
|
691
|
-
if (timestamp == 0 && !string.IsNullOrEmpty(msg) && msg.Contains("invalid_time") &&
|
|
692
|
-
msg.Contains("now"))
|
|
693
|
-
{
|
|
694
|
-
try
|
|
695
|
-
{
|
|
696
|
-
if (!(Json.Deserialize(msg) is Dictionary<string, object> json)) return;
|
|
697
|
-
var now = (int)(long)json["now"];
|
|
698
|
-
GetProfile(accessToken, now);
|
|
699
|
-
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
702
|
-
catch (Exception)
|
|
703
|
-
{
|
|
704
|
-
// ignored
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
OnCallback(UIManager.RESULT_FAILED, msg);
|
|
709
|
-
GetUIManager().Pop();
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
private static string GetAuthorizationHeader(string kid,
|
|
714
|
-
string macKey,
|
|
715
|
-
string macAlgorithm,
|
|
716
|
-
string method,
|
|
717
|
-
string uri,
|
|
718
|
-
string host,
|
|
719
|
-
string port,
|
|
720
|
-
int timestamp)
|
|
721
|
-
{
|
|
722
|
-
var nonce = new Random().Next().ToString();
|
|
723
|
-
|
|
724
|
-
var normalizedString = $"{timestamp}\n{nonce}\n{method}\n{uri}\n{host}\n{port}\n\n";
|
|
725
|
-
|
|
726
|
-
HashAlgorithm hashGenerator;
|
|
727
|
-
switch (macAlgorithm)
|
|
728
|
-
{
|
|
729
|
-
case "hmac-sha-256":
|
|
730
|
-
hashGenerator = new HMACSHA256(Encoding.ASCII.GetBytes(macKey));
|
|
731
|
-
break;
|
|
732
|
-
case "hmac-sha-1":
|
|
733
|
-
hashGenerator = new HMACSHA1(Encoding.ASCII.GetBytes(macKey));
|
|
734
|
-
break;
|
|
735
|
-
default:
|
|
736
|
-
throw new InvalidOperationException("Unsupported MAC algorithm");
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
var hash = Convert.ToBase64String(hashGenerator.ComputeHash(Encoding.ASCII.GetBytes(normalizedString)));
|
|
740
|
-
|
|
741
|
-
var authorizationHeader = new StringBuilder();
|
|
742
|
-
authorizationHeader.AppendFormat(@"id=""{0}"",ts=""{1}"",nonce=""{2}"",mac=""{3}""",
|
|
743
|
-
kid, timestamp, nonce, hash);
|
|
744
|
-
|
|
745
|
-
return authorizationHeader.ToString();
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
private void ShowQrRefresh()
|
|
749
|
-
{
|
|
750
|
-
RefreshImage.gameObject.SetActive(true);
|
|
751
|
-
SubStatusText.gameObject.SetActive(false);
|
|
752
|
-
StatusText.gameObject.SetActive(false);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
private void ShowStatus(string statusText, string subStatusText)
|
|
756
|
-
{
|
|
757
|
-
StatusText.text = statusText;
|
|
758
|
-
SubStatusText.text = subStatusText;
|
|
759
|
-
if (!string.IsNullOrEmpty(statusText))
|
|
760
|
-
{
|
|
761
|
-
StatusText.gameObject.SetActive(true);
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if (!string.IsNullOrEmpty(subStatusText))
|
|
765
|
-
{
|
|
766
|
-
SubStatusText.gameObject.SetActive(true);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
private static long GetCurrentTime()
|
|
771
|
-
{
|
|
772
|
-
var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
773
|
-
return Convert.ToInt64(ts.TotalSeconds);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
}
|