@cloudbase/oauth 0.0.4-alpha.0 → 1.0.0-alpha.1
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/CHANGELOG.md +30 -0
- package/Dockerfile +15 -0
- package/README.md +165 -3
- package/_exmaple/assets/scripts/function/function.ts +99 -0
- package/_exmaple/assets/scripts/index.ts +101 -0
- package/_exmaple/assets/scripts/request.ts +11 -0
- package/_exmaple/index.html +15 -0
- package/_exmaple/package.json +33 -0
- package/_exmaple/tsconfig.json +71 -0
- package/_exmaple/typings.d.ts +0 -0
- package/_exmaple/webpack.config.js +42 -0
- package/dist/auth/apis.d.ts +13 -5
- package/dist/auth/apis.js +118 -40
- package/dist/auth/consts.d.ts +26 -2
- package/dist/auth/consts.js +28 -3
- package/dist/auth/models.d.ts +207 -1
- package/dist/auth/models.js +1 -1
- package/dist/captcha/captcha.js +5 -3
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -166
- package/dist/oauth2client/interface.d.ts +6 -6
- package/dist/oauth2client/interface.js +1 -1
- package/dist/oauth2client/oauth2client.d.ts +1 -0
- package/dist/oauth2client/oauth2client.js +17 -1
- package/package.json +28 -28
- package/publish.sh +2 -0
- package/src/auth/apis.ts +134 -29
- package/src/auth/consts.ts +27 -1
- package/src/auth/models.ts +256 -1
- package/src/captcha/captcha.ts +185 -180
- package/src/index.ts +3 -105
- package/src/oauth2client/interface.ts +6 -6
- package/src/oauth2client/oauth2client.ts +9 -0
- package/wiki/README.md +75 -0
package/src/auth/models.ts
CHANGED
|
@@ -2,10 +2,11 @@ interface BaseRequest {
|
|
|
2
2
|
client_id?: string;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
export type GetCustomSignTicketFn = () => Promise<string>;
|
|
6
|
+
|
|
5
7
|
export interface SignInRequest extends BaseRequest {
|
|
6
8
|
username?: string;
|
|
7
9
|
password?: string;
|
|
8
|
-
verification_code?: string;
|
|
9
10
|
verification_token?: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -124,6 +125,18 @@ export interface UserProfile {
|
|
|
124
125
|
created_from?: string;
|
|
125
126
|
sub?: string
|
|
126
127
|
uid?: string
|
|
128
|
+
address?: {
|
|
129
|
+
formatted?: string,
|
|
130
|
+
street_address?: string,
|
|
131
|
+
locality?: string,
|
|
132
|
+
region?: string,
|
|
133
|
+
postal_code?: string,
|
|
134
|
+
country?: string
|
|
135
|
+
}
|
|
136
|
+
nickName?: string // TODO:
|
|
137
|
+
province?: string // TODO:
|
|
138
|
+
country?: string // TODO:
|
|
139
|
+
city?: string // TODO:
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
export type UserInfo = UserProfile;
|
|
@@ -176,3 +189,245 @@ export type ChangeBindedProviderResponse = BaseRequest
|
|
|
176
189
|
export interface QueryUserProfileReq extends BaseRequest {
|
|
177
190
|
appended_params: string;
|
|
178
191
|
}
|
|
192
|
+
|
|
193
|
+
export interface SignInWithProviderRequest {
|
|
194
|
+
provider_token: string;
|
|
195
|
+
provider_id?: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface SignUpRequest {
|
|
199
|
+
phone_number?: string;
|
|
200
|
+
email?: string;
|
|
201
|
+
|
|
202
|
+
verification_code?: string;
|
|
203
|
+
verification_token?: string;
|
|
204
|
+
provider_token?: string;
|
|
205
|
+
|
|
206
|
+
password?: string;
|
|
207
|
+
name?: string;
|
|
208
|
+
gender?: string;
|
|
209
|
+
picture?: string;
|
|
210
|
+
locale?: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface GetVerificationRequest {
|
|
214
|
+
phone_number?: string;
|
|
215
|
+
email?: string;
|
|
216
|
+
// 可选 ANY,USER,NOT_USER, CUR_USER;
|
|
217
|
+
target?: string | 'ANY';
|
|
218
|
+
usage?: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface GetVerificationResponse {
|
|
222
|
+
verification_id?: string;
|
|
223
|
+
is_user?: boolean | false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface VerifyResponse {
|
|
227
|
+
verification_token?: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface VerifyRequest {
|
|
231
|
+
verification_code: string;
|
|
232
|
+
verification_id?: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface ProviderBindRequest {
|
|
236
|
+
provider_token: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface GrantProviderTokenRequest {
|
|
240
|
+
provider_id: string;
|
|
241
|
+
provider_redirect_uri?: string;
|
|
242
|
+
provider_code?: string;
|
|
243
|
+
provider_access_token?: string;
|
|
244
|
+
provider_id_token?: string;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface GrantProviderTokenResponse {
|
|
248
|
+
provider_token: string;
|
|
249
|
+
expires_in: number;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface PatchProviderTokenRequest {
|
|
253
|
+
provider_token: string;
|
|
254
|
+
provider_params: {
|
|
255
|
+
encryptedData: string;
|
|
256
|
+
iv: string;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export interface PatchProviderTokenResponse {
|
|
261
|
+
provider_token: string;
|
|
262
|
+
expires_in: number;
|
|
263
|
+
provider_profile: ProviderProfile;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface GenProviderRedirectUriRequest {
|
|
267
|
+
provider_id: string;
|
|
268
|
+
provider_redirect_uri: string;
|
|
269
|
+
state: string;
|
|
270
|
+
other_params?: {
|
|
271
|
+
sign_out_uri?: string;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface GenProviderRedirectUriResponse {
|
|
276
|
+
uri: string;
|
|
277
|
+
signout_uri?: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface BindWithProviderRequest {
|
|
281
|
+
provider_token: string;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export interface BindWithProviderRequest {
|
|
285
|
+
provider_token: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface UserProfileProvider {
|
|
289
|
+
id?: string;
|
|
290
|
+
provider_user_id?: string;
|
|
291
|
+
name?: string;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface UserProfile {
|
|
295
|
+
name?: string;
|
|
296
|
+
picture?: string;
|
|
297
|
+
username?: string;
|
|
298
|
+
email?: string;
|
|
299
|
+
email_verified?: boolean;
|
|
300
|
+
phone_number?: string;
|
|
301
|
+
providers?: [UserProfileProvider];
|
|
302
|
+
gender?: string;
|
|
303
|
+
birthdate?: string;
|
|
304
|
+
zoneinfo?: string;
|
|
305
|
+
locale?: string;
|
|
306
|
+
created_from?: string;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export interface ProviderProfile {
|
|
310
|
+
provider_id: string;
|
|
311
|
+
phone_number?: string;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export interface TransByProviderRequest {
|
|
315
|
+
provider_token: string;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export interface GrantTokenRequest {
|
|
319
|
+
client_secret?: string;
|
|
320
|
+
code?: string;
|
|
321
|
+
grant_type?: string;
|
|
322
|
+
redirect_uri?: string;
|
|
323
|
+
nonce?: string;
|
|
324
|
+
refresh_token?: string;
|
|
325
|
+
scope?: string;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface UnbindProviderRequest {
|
|
329
|
+
provider_id: string;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface CheckPasswordrRequest {
|
|
333
|
+
password: string;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface BindPhoneRequest {
|
|
337
|
+
phone_number: string;
|
|
338
|
+
sudo_token: string;
|
|
339
|
+
verification_token: string;
|
|
340
|
+
conflict_resolution: string
|
|
341
|
+
// 1. DEFAULT 0, 默认提示用户手机号已被绑定
|
|
342
|
+
// 2. DELETE_ACCOUNT_TRANSFER 1, 标记原账号已被注销,并将手机换绑给自己
|
|
343
|
+
// 3. TRANSFER 2, 仅换绑手机号,不注销原有账号(换绑后原账号无法登录时,则自动注销原账号)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface BindEmailRequest {
|
|
347
|
+
email: string;
|
|
348
|
+
sudo_token: string;
|
|
349
|
+
verification_token: string;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface SetPasswordRequest {
|
|
353
|
+
new_password: string;
|
|
354
|
+
sudo_token: string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
export interface SetPasswordRequest {
|
|
359
|
+
new_password: string;
|
|
360
|
+
sudo_token: string;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export interface UpdatePasswordRequest {
|
|
364
|
+
old_password: string;
|
|
365
|
+
new_password: string;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// password 和 verification_token 而选一,如果绑定了手机号,则必须使用verification_token 进行sudo
|
|
369
|
+
export interface SudoRequest {
|
|
370
|
+
password?: string;
|
|
371
|
+
verification_token?: string
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export interface SudoResponse {
|
|
375
|
+
sudo_token?: string
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
export interface ChangeBoundProviderRequest {
|
|
380
|
+
trans_token: string;
|
|
381
|
+
provider_id: string;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface ChangeBoundProviderResponse {
|
|
385
|
+
client_id: string;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export interface QueryUserProfileRequest {
|
|
389
|
+
id?: [string];
|
|
390
|
+
username?: string;
|
|
391
|
+
email?: string;
|
|
392
|
+
phone_number?: string;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export interface QueryUserProfileResponse {
|
|
396
|
+
total: string;
|
|
397
|
+
data: SimpleUserProfile[]
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export interface ResetPasswordRequest extends BaseRequest {
|
|
401
|
+
email: string
|
|
402
|
+
phone_number: string
|
|
403
|
+
new_password: string
|
|
404
|
+
verification_token: string
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface DeviceAuthorizeRequest extends BaseRequest {
|
|
408
|
+
scope?: string
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export interface DeviceAuthorizeResponse {
|
|
412
|
+
device_code: string
|
|
413
|
+
user_code: string
|
|
414
|
+
expires_in: number
|
|
415
|
+
interval: number
|
|
416
|
+
verification_url: string
|
|
417
|
+
verification_uri_complete: string
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 简化版用户信息
|
|
421
|
+
export interface SimpleUserProfile {
|
|
422
|
+
sub: string;
|
|
423
|
+
name: string;
|
|
424
|
+
picture?: string;
|
|
425
|
+
gender?: string;
|
|
426
|
+
locale?: string;
|
|
427
|
+
email?: string;
|
|
428
|
+
phone_number?: string;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export interface CheckUsernameRequest {
|
|
432
|
+
username: string
|
|
433
|
+
}
|
package/src/captcha/captcha.ts
CHANGED
|
@@ -1,217 +1,222 @@
|
|
|
1
|
-
import {SimpleStorage, RequestFunction} from '../oauth2client/interface';
|
|
2
|
-
import {AuthClientRequestOptions} from "../oauth2client/models";
|
|
3
|
-
import {defaultStorage} from "../oauth2client/oauth2client";
|
|
1
|
+
import { SimpleStorage, RequestFunction } from '../oauth2client/interface';
|
|
2
|
+
import { AuthClientRequestOptions } from "../oauth2client/models";
|
|
3
|
+
import { defaultStorage } from "../oauth2client/oauth2client";
|
|
4
4
|
|
|
5
5
|
export interface CaptchaOptions {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
clientId: string
|
|
7
|
+
request: RequestFunction;
|
|
8
|
+
storage: SimpleStorage;
|
|
9
|
+
// 打开网页并通过URL回调获取 CaptchaToken,针对不通的平台,该函数可以自定义实现, 默认集成浏览器端认证
|
|
10
|
+
openURIWithCallback?: OpenURIWithCallbackFuction;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
type OpenURIWithCallbackFuction = (url: string) => Promise<CaptchaToken>;
|
|
14
14
|
|
|
15
15
|
export interface CaptchaToken {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
captcha_token: string
|
|
17
|
+
expires_in: number
|
|
18
|
+
expires_at?: Date | null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface CaptchaRequestOptions extends AuthClientRequestOptions {
|
|
22
|
-
|
|
22
|
+
withCaptcha?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface GetCaptchaResponse {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
captcha_token?: string
|
|
27
|
+
expires_in?: number
|
|
28
|
+
url?: string
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const GET_CAPTCHA_URL = '/auth/v1/captcha/init'
|
|
32
32
|
|
|
33
33
|
export class Captcha {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
private _config: CaptchaOptions;
|
|
35
|
+
private _tokenSectionName: string;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
if (!opts.storage) {
|
|
46
|
-
opts.storage = defaultStorage
|
|
47
|
-
}
|
|
48
|
-
this._config = opts
|
|
49
|
-
this._tokenSectionName = 'captcha_' + opts.clientId
|
|
37
|
+
/**
|
|
38
|
+
* constructor
|
|
39
|
+
* @param {CaptchaOptions} opts
|
|
40
|
+
*/
|
|
41
|
+
constructor(opts: CaptchaOptions) {
|
|
42
|
+
if (!opts.openURIWithCallback) {
|
|
43
|
+
opts.openURIWithCallback = this._getDefaultOpenURIWithCallback()
|
|
50
44
|
}
|
|
45
|
+
if (!opts.storage) {
|
|
46
|
+
opts.storage = defaultStorage
|
|
47
|
+
}
|
|
48
|
+
this._config = opts
|
|
49
|
+
this._tokenSectionName = 'captcha_' + opts.clientId
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
try {
|
|
73
|
-
return this._config.request<T>(reqURL, options)
|
|
74
|
-
} catch (err) {
|
|
75
|
-
if (err.error === 'captcha_required' || err.error === 'captcha_invalid') {
|
|
76
|
-
url = await this._appendCaptchaTokenToURL(url, state, err.error === 'captcha_invalid')
|
|
77
|
-
return this._config.request<T>(url, options)
|
|
78
|
-
} else {
|
|
79
|
-
return Promise.reject(err)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
52
|
+
/**
|
|
53
|
+
* request http like simple fetch api, exp:request('/v1/user/me', {withCredentials:true})
|
|
54
|
+
* @param {string} url
|
|
55
|
+
* @param {AuthClientRequestOptions} options
|
|
56
|
+
*/
|
|
57
|
+
public async request<T>(
|
|
58
|
+
url: string,
|
|
59
|
+
options?: CaptchaRequestOptions,
|
|
60
|
+
): Promise<T> {
|
|
61
|
+
if (!options) {
|
|
62
|
+
options = {};
|
|
63
|
+
}
|
|
64
|
+
if (!options.method) {
|
|
65
|
+
options.method = 'GET'
|
|
66
|
+
}
|
|
67
|
+
const state = options.method + ":" + url
|
|
68
|
+
let reqURL = url;
|
|
69
|
+
if (options.withCaptcha) {
|
|
70
|
+
reqURL = await this._appendCaptchaTokenToURL(url, state, false);
|
|
82
71
|
}
|
|
83
72
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
return this._defaultOpenURIWithCallback
|
|
73
|
+
let resp: T;
|
|
74
|
+
try {
|
|
75
|
+
resp = await this._config.request<T>(reqURL, options)
|
|
76
|
+
} catch (err) {
|
|
77
|
+
if (err.error === 'captcha_required' || err.error === 'captcha_invalid') {
|
|
78
|
+
url = await this._appendCaptchaTokenToURL(url, state, err.error === 'captcha_invalid')
|
|
79
|
+
return this._config.request<T>(url, options)
|
|
80
|
+
} else {
|
|
81
|
+
return Promise.reject(err)
|
|
82
|
+
}
|
|
96
83
|
}
|
|
84
|
+
return resp
|
|
85
|
+
}
|
|
97
86
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
private async _defaultOpenURIWithCallback(url: string): Promise<CaptchaToken> {
|
|
102
|
-
const target = document.getElementById('captcha_panel_wrap'),
|
|
103
|
-
iframe = document.createElement('iframe')
|
|
104
|
-
target.innerHTML = '';
|
|
105
|
-
iframe.setAttribute('src', url)
|
|
106
|
-
iframe.setAttribute('id', 'review-panel-iframe')
|
|
107
|
-
iframe.style.cssText = 'min-width:355px;display:block;height:355px;margin:0 auto;background-color: rgb(255, 255, 255);border: none;';
|
|
108
|
-
target.appendChild(iframe);
|
|
109
|
-
target.style.display = 'block';
|
|
110
|
-
return new Promise<CaptchaToken>((resolve, reject) => {
|
|
111
|
-
iframe.onload = function () {
|
|
112
|
-
try {
|
|
113
|
-
var windowLocation = window.location;
|
|
114
|
-
var iframeLocation = iframe.contentWindow.location;
|
|
115
|
-
if (
|
|
116
|
-
iframeLocation.host +
|
|
117
|
-
iframeLocation.pathname ===
|
|
118
|
-
windowLocation.host +
|
|
119
|
-
windowLocation.pathname
|
|
120
|
-
) {
|
|
121
|
-
target.style.display = 'none';
|
|
122
|
-
const iframeUrlParams = new URLSearchParams(iframeLocation.search);
|
|
123
|
-
const captchToken = iframeUrlParams.get('captcha_token');
|
|
124
|
-
if (captchToken) {
|
|
125
|
-
return resolve({
|
|
126
|
-
captcha_token: captchToken,
|
|
127
|
-
expires_in: Number(iframeUrlParams.get('expires_in'))
|
|
128
|
-
})
|
|
129
|
-
}
|
|
130
|
-
return reject({
|
|
131
|
-
error: iframeUrlParams.get('error'),
|
|
132
|
-
error_description: iframeUrlParams.get('error_description')
|
|
133
|
-
})
|
|
134
|
-
} else {
|
|
135
|
-
target.style.display = 'block';
|
|
136
|
-
}
|
|
137
|
-
} catch (error) {
|
|
138
|
-
target.style.display = 'block';
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
})
|
|
87
|
+
private _getDefaultOpenURIWithCallback(): OpenURIWithCallbackFuction {
|
|
88
|
+
if (window.location.search.indexOf('__captcha') > 0) {
|
|
89
|
+
document.body.style.display = 'none';
|
|
142
90
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return captchaToken
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const redirectURL = window.location.origin + window.location.pathname + "?__captcha=on"
|
|
155
|
-
const captchaTokenResp = await this._config.request<GetCaptchaResponse>(GET_CAPTCHA_URL, {
|
|
156
|
-
method: 'POST',
|
|
157
|
-
body: {
|
|
158
|
-
client_id: this._config.clientId,
|
|
159
|
-
redirect_uri: redirectURL,
|
|
160
|
-
state: state
|
|
161
|
-
},
|
|
162
|
-
withCredentials: false,
|
|
163
|
-
})
|
|
164
|
-
if (captchaTokenResp.captcha_token) {
|
|
165
|
-
const captchaToken = {
|
|
166
|
-
captcha_token: captchaTokenResp.captcha_token,
|
|
167
|
-
expires_in: captchaTokenResp.expires_in,
|
|
168
|
-
}
|
|
169
|
-
this._saveCaptchaToken(captchaToken)
|
|
170
|
-
return captchaTokenResp.captcha_token
|
|
171
|
-
}
|
|
172
|
-
const captchaToken = await this._config.openURIWithCallback(captchaTokenResp.url)
|
|
173
|
-
this._saveCaptchaToken(captchaToken)
|
|
174
|
-
return captchaToken.captcha_token
|
|
91
|
+
if (document.getElementById('captcha_panel_wrap') === null) {
|
|
92
|
+
var elementDiv = document.createElement('div');
|
|
93
|
+
elementDiv.style.cssText =
|
|
94
|
+
'background-color: rgba(0, 0, 0, 0.7);position: fixed;left: 0px;right: 0px;top: 0px;bottom: 0px;padding: 9vw 0 0 0;display: none;z-index:100;';
|
|
95
|
+
elementDiv.setAttribute('id', 'captcha_panel_wrap');
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
document.body.appendChild(elementDiv);
|
|
98
|
+
}, 0)
|
|
175
99
|
}
|
|
100
|
+
return this._defaultOpenURIWithCallback
|
|
101
|
+
}
|
|
176
102
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
103
|
+
/**
|
|
104
|
+
* 默认通过浏览器打开网页并获取回调
|
|
105
|
+
*/
|
|
106
|
+
private async _defaultOpenURIWithCallback(url: string): Promise<CaptchaToken> {
|
|
107
|
+
const target = document.getElementById('captcha_panel_wrap'),
|
|
108
|
+
iframe = document.createElement('iframe')
|
|
109
|
+
target.innerHTML = '';
|
|
110
|
+
iframe.setAttribute('src', url)
|
|
111
|
+
iframe.setAttribute('id', 'review-panel-iframe')
|
|
112
|
+
iframe.style.cssText = 'min-width:355px;display:block;height:355px;margin:0 auto;background-color: rgb(255, 255, 255);border: none;';
|
|
113
|
+
target.appendChild(iframe);
|
|
114
|
+
target.style.display = 'block';
|
|
115
|
+
return new Promise<CaptchaToken>((resolve, reject) => {
|
|
116
|
+
iframe.onload = function () {
|
|
117
|
+
try {
|
|
118
|
+
var windowLocation = window.location;
|
|
119
|
+
var iframeLocation = iframe.contentWindow.location;
|
|
120
|
+
if (
|
|
121
|
+
iframeLocation.host +
|
|
122
|
+
iframeLocation.pathname ===
|
|
123
|
+
windowLocation.host +
|
|
124
|
+
windowLocation.pathname
|
|
125
|
+
) {
|
|
126
|
+
target.style.display = 'none';
|
|
127
|
+
const iframeUrlParams = new URLSearchParams(iframeLocation.search);
|
|
128
|
+
const captchToken = iframeUrlParams.get('captcha_token');
|
|
129
|
+
if (captchToken) {
|
|
130
|
+
return resolve({
|
|
131
|
+
captcha_token: captchToken,
|
|
132
|
+
expires_in: Number(iframeUrlParams.get('expires_in'))
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
return reject({
|
|
136
|
+
error: iframeUrlParams.get('error'),
|
|
137
|
+
error_description: iframeUrlParams.get('error_description')
|
|
138
|
+
})
|
|
139
|
+
} else {
|
|
140
|
+
target.style.display = 'block';
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
target.style.display = 'block';
|
|
183
144
|
}
|
|
184
|
-
|
|
145
|
+
};
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* _getCaptchaToken 获取captchaToken
|
|
150
|
+
*/
|
|
151
|
+
private async _getCaptchaToken(forceNewToken: boolean, state: string): Promise<string> {
|
|
152
|
+
if (!forceNewToken) {
|
|
153
|
+
// 如果本地存在,则直接返回
|
|
154
|
+
const captchaToken = await this._findCaptchaToken()
|
|
155
|
+
if (captchaToken) {
|
|
156
|
+
return captchaToken
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const redirectURL = window.location.origin + window.location.pathname + "?__captcha=on"
|
|
160
|
+
const captchaTokenResp = await this._config.request<GetCaptchaResponse>(GET_CAPTCHA_URL, {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
body: {
|
|
163
|
+
client_id: this._config.clientId,
|
|
164
|
+
redirect_uri: redirectURL,
|
|
165
|
+
state: state
|
|
166
|
+
},
|
|
167
|
+
withCredentials: false,
|
|
168
|
+
})
|
|
169
|
+
if (captchaTokenResp.captcha_token) {
|
|
170
|
+
const captchaToken = {
|
|
171
|
+
captcha_token: captchaTokenResp.captcha_token,
|
|
172
|
+
expires_in: captchaTokenResp.expires_in,
|
|
173
|
+
}
|
|
174
|
+
this._saveCaptchaToken(captchaToken)
|
|
175
|
+
return captchaTokenResp.captcha_token
|
|
185
176
|
}
|
|
177
|
+
const captchaToken = await this._config.openURIWithCallback(captchaTokenResp.url)
|
|
178
|
+
this._saveCaptchaToken(captchaToken)
|
|
179
|
+
return captchaToken.captcha_token
|
|
180
|
+
}
|
|
186
181
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
182
|
+
private async _appendCaptchaTokenToURL(url: string, state: string, forceNewToken: boolean): Promise<string> {
|
|
183
|
+
const captchaToken = await this._getCaptchaToken(forceNewToken, state);
|
|
184
|
+
if (url.indexOf("?") > 0) {
|
|
185
|
+
url += "&captcha_token=" + captchaToken
|
|
186
|
+
} else {
|
|
187
|
+
url += "?captcha_token=" + captchaToken
|
|
193
188
|
}
|
|
189
|
+
return url
|
|
190
|
+
}
|
|
194
191
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
192
|
+
private async _saveCaptchaToken(token: CaptchaToken) {
|
|
193
|
+
token.expires_at = new Date(
|
|
194
|
+
Date.now() + (token.expires_in - 10) * 1000,
|
|
195
|
+
);
|
|
196
|
+
const tokenStr: string = JSON.stringify(token);
|
|
197
|
+
await this._config.storage.setItem(this._tokenSectionName, tokenStr);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async _findCaptchaToken(): Promise<string> {
|
|
201
|
+
const tokenStr: string = await this._config.storage.getItem(
|
|
202
|
+
this._tokenSectionName,
|
|
203
|
+
);
|
|
204
|
+
if (tokenStr !== undefined && tokenStr !== null) {
|
|
205
|
+
try {
|
|
206
|
+
const captchaToken = JSON.parse(tokenStr);
|
|
207
|
+
if (captchaToken?.expires_at) {
|
|
208
|
+
captchaToken.expires_at = new Date(captchaToken.expires_at);
|
|
209
|
+
}
|
|
210
|
+
const isExpired = captchaToken.expires_at < new Date();
|
|
211
|
+
if (isExpired) {
|
|
212
|
+
return null
|
|
214
213
|
}
|
|
214
|
+
return captchaToken.captcha_token
|
|
215
|
+
} catch (error) {
|
|
216
|
+
await this._config.storage.removeItem(this._tokenSectionName);
|
|
215
217
|
return null
|
|
218
|
+
}
|
|
216
219
|
}
|
|
220
|
+
return null
|
|
221
|
+
}
|
|
217
222
|
}
|