@cloudbase/oauth 3.0.0 → 3.0.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/dist/cjs/auth/apis.d.ts +22 -4
- package/dist/cjs/auth/apis.js +255 -66
- package/dist/cjs/auth/auth-error.d.ts +6 -0
- package/dist/cjs/auth/auth-error.js +32 -0
- package/dist/cjs/auth/consts.d.ts +22 -0
- package/dist/cjs/auth/consts.js +24 -2
- package/dist/cjs/auth/models.d.ts +13 -4
- package/dist/cjs/auth/models.js +1 -1
- package/dist/cjs/captcha/captcha-dom.d.ts +3 -0
- package/dist/cjs/captcha/captcha-dom.js +223 -0
- package/dist/cjs/captcha/captcha.d.ts +3 -1
- package/dist/cjs/captcha/captcha.js +11 -102
- package/dist/cjs/index.d.ts +12 -2
- package/dist/cjs/index.js +27 -4
- package/dist/cjs/oauth2client/interface.d.ts +1 -1
- package/dist/cjs/oauth2client/interface.js +1 -1
- package/dist/cjs/oauth2client/models.d.ts +15 -1
- package/dist/cjs/oauth2client/models.js +1 -1
- package/dist/cjs/oauth2client/oauth2client.d.ts +62 -3
- package/dist/cjs/oauth2client/oauth2client.js +426 -131
- package/dist/cjs/utils/base64.d.ts +5 -0
- package/dist/cjs/utils/base64.js +15 -2
- package/dist/cjs/utils/encryptlong/index.js +22 -16
- package/dist/cjs/utils/index.js +1 -1
- package/dist/cjs/utils/mp.js +4 -4
- package/dist/cjs/utils/urlSearchParams.js +1 -1
- package/dist/esm/auth/apis.d.ts +22 -4
- package/dist/esm/auth/apis.js +130 -10
- package/dist/esm/auth/auth-error.d.ts +6 -0
- package/dist/esm/auth/auth-error.js +9 -0
- package/dist/esm/auth/consts.d.ts +22 -0
- package/dist/esm/auth/consts.js +22 -0
- package/dist/esm/auth/models.d.ts +13 -4
- package/dist/esm/captcha/captcha-dom.d.ts +3 -0
- package/dist/esm/captcha/captcha-dom.js +129 -0
- package/dist/esm/captcha/captcha.d.ts +3 -1
- package/dist/esm/captcha/captcha.js +14 -97
- package/dist/esm/index.d.ts +12 -2
- package/dist/esm/index.js +20 -3
- package/dist/esm/oauth2client/interface.d.ts +1 -1
- package/dist/esm/oauth2client/models.d.ts +15 -1
- package/dist/esm/oauth2client/oauth2client.d.ts +62 -3
- package/dist/esm/oauth2client/oauth2client.js +200 -55
- package/dist/esm/utils/base64.d.ts +5 -0
- package/dist/esm/utils/base64.js +12 -0
- package/dist/esm/utils/encryptlong/index.js +21 -15
- package/dist/esm/utils/mp.js +3 -3
- package/dist/miniprogram/index.js +1 -1
- package/package.json +10 -4
- package/src/auth/apis.ts +222 -17
- package/src/auth/auth-error.ts +21 -0
- package/src/auth/consts.ts +28 -0
- package/src/auth/models.ts +13 -4
- package/src/captcha/captcha-dom.ts +178 -0
- package/src/captcha/captcha.ts +25 -114
- package/src/index.ts +54 -4
- package/src/oauth2client/interface.ts +1 -1
- package/src/oauth2client/models.ts +29 -1
- package/src/oauth2client/oauth2client.ts +308 -55
- package/src/utils/base64.ts +12 -0
- package/src/utils/encryptlong/index.js +20 -14
- package/src/utils/index.ts +1 -0
- package/src/utils/mp.ts +3 -3
- package/src/utils/urlSearchParams.ts +2 -0
- package/tsconfig.json +1 -0
- package/dist/cjs/utils/cloudbase-adapter-wx_mp.d.ts +0 -1
- package/dist/cjs/utils/cloudbase-adapter-wx_mp.js +0 -40
- package/dist/esm/utils/cloudbase-adapter-wx_mp.d.ts +0 -1
- package/dist/esm/utils/cloudbase-adapter-wx_mp.js +0 -35
- package/src/utils/cloudbase-adapter-wx_mp.ts +0 -42
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ErrorType } from './consts'
|
|
2
|
-
import { ApiUrls, ApiUrlsV2, AUTH_API_PREFIX } from '../auth/consts'
|
|
2
|
+
import { ApiUrls, ApiUrlsV2, AUTH_API_PREFIX, AUTH_STATE_CHANGED_TYPE, EVENTS } from '../auth/consts'
|
|
3
3
|
|
|
4
4
|
import { AuthClient, SimpleStorage } from './interface'
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ import { getPathName } from '../utils/index'
|
|
|
17
17
|
|
|
18
18
|
import { SinglePromise } from '../utils/function/single-promise'
|
|
19
19
|
import { weBtoa } from '../utils/base64'
|
|
20
|
-
import {
|
|
20
|
+
import { isMp } from '../utils/mp'
|
|
21
21
|
import { AuthOptions } from '../auth/apis'
|
|
22
22
|
import { ICloudbaseConfig } from '@cloudbase/types'
|
|
23
23
|
import { langEvent } from '@cloudbase/utilities'
|
|
@@ -106,6 +106,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
106
106
|
/**
|
|
107
107
|
* 缓存key统一使用后缀区分
|
|
108
108
|
*/
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
109
110
|
private readonly _env: string
|
|
110
111
|
|
|
111
112
|
constructor(opts?: { env: string }) {
|
|
@@ -197,6 +198,8 @@ class LocalCredentials {
|
|
|
197
198
|
private clientId: string
|
|
198
199
|
|
|
199
200
|
private credentials: Credentials | null = null
|
|
201
|
+
// 来自accessKey的身份,不持久化
|
|
202
|
+
private accessKeyCredentials: Credentials | null = null
|
|
200
203
|
|
|
201
204
|
private singlePromise: SinglePromise = null
|
|
202
205
|
|
|
@@ -210,9 +213,6 @@ class LocalCredentials {
|
|
|
210
213
|
this.clientId = options.clientId
|
|
211
214
|
this.singlePromise = new SinglePromise({ clientId: this.clientId })
|
|
212
215
|
this.credentials = options.credentials || null
|
|
213
|
-
if (this.credentials) {
|
|
214
|
-
this.setCredentials(this.credentials)
|
|
215
|
-
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
public getStorageCredentialsSync(): Credentials | null {
|
|
@@ -254,6 +254,14 @@ class LocalCredentials {
|
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/**
|
|
258
|
+
* set credentials from accessKey
|
|
259
|
+
* @param {Credentials} credentials
|
|
260
|
+
*/
|
|
261
|
+
public setAccessKeyCredentials(credentials?: Credentials) {
|
|
262
|
+
this.accessKeyCredentials = credentials
|
|
263
|
+
}
|
|
264
|
+
|
|
257
265
|
/**
|
|
258
266
|
* Get credentials.
|
|
259
267
|
* @return {Promise<Credentials | null>}
|
|
@@ -261,7 +269,11 @@ class LocalCredentials {
|
|
|
261
269
|
public async getCredentials(): Promise<Credentials | null> {
|
|
262
270
|
return this.singlePromise.run('getCredentials', async () => {
|
|
263
271
|
if (isCredentialsExpired(this.credentials)) {
|
|
264
|
-
|
|
272
|
+
const { credentials, isAccessKeyCredentials } = await this.getStorageCredentials()
|
|
273
|
+
if (isAccessKeyCredentials) {
|
|
274
|
+
return credentials
|
|
275
|
+
}
|
|
276
|
+
this.credentials = credentials
|
|
265
277
|
}
|
|
266
278
|
return this.credentials
|
|
267
279
|
})
|
|
@@ -270,11 +282,12 @@ class LocalCredentials {
|
|
|
270
282
|
/**
|
|
271
283
|
* Get storage credentials.
|
|
272
284
|
*/
|
|
273
|
-
private async getStorageCredentials(): Promise<Credentials | null> {
|
|
285
|
+
private async getStorageCredentials(): Promise<{ credentials: Credentials | null; isAccessKeyCredentials: boolean }> {
|
|
274
286
|
return this.singlePromise.run('_getStorageCredentials', async () => {
|
|
275
287
|
let credentials: Credentials = null
|
|
288
|
+
let isAccessKeyCredentials = false
|
|
276
289
|
const tokenStr: string = await this.storage.getItem(this.tokenSectionName)
|
|
277
|
-
if (tokenStr
|
|
290
|
+
if (!!tokenStr) {
|
|
278
291
|
try {
|
|
279
292
|
credentials = JSON.parse(tokenStr)
|
|
280
293
|
if (credentials?.expires_at) {
|
|
@@ -284,8 +297,11 @@ class LocalCredentials {
|
|
|
284
297
|
await this.storage.removeItem(this.tokenSectionName)
|
|
285
298
|
credentials = null
|
|
286
299
|
}
|
|
300
|
+
} else {
|
|
301
|
+
credentials = this.accessKeyCredentials || null
|
|
302
|
+
isAccessKeyCredentials = true
|
|
287
303
|
}
|
|
288
|
-
return credentials
|
|
304
|
+
return { credentials, isAccessKeyCredentials }
|
|
289
305
|
})
|
|
290
306
|
}
|
|
291
307
|
}
|
|
@@ -299,6 +315,20 @@ export class OAuth2Client implements AuthClient {
|
|
|
299
315
|
private static maxRetry = 5
|
|
300
316
|
private static retryInterval = 1000
|
|
301
317
|
|
|
318
|
+
public localCredentials: LocalCredentials
|
|
319
|
+
/**
|
|
320
|
+
* Keeps track of the async client initialization.
|
|
321
|
+
* When null or not yet resolved the auth state is `unknown`
|
|
322
|
+
* Once resolved the auth state is known and it's safe to call any further client methods.
|
|
323
|
+
*/
|
|
324
|
+
public initializePromise: Promise<{ error: Error | null }> | null = null
|
|
325
|
+
protected lockAcquired = false
|
|
326
|
+
protected pendingInLock: Promise<any>[] = []
|
|
327
|
+
protected logDebugMessages: boolean
|
|
328
|
+
protected getInitialSession?: () => Promise<{
|
|
329
|
+
data: { session: Credentials; user?: any } | null
|
|
330
|
+
error: Error | null
|
|
331
|
+
}>
|
|
302
332
|
private apiOrigin: string
|
|
303
333
|
private apiPath: string
|
|
304
334
|
private clientId: string
|
|
@@ -306,7 +336,6 @@ export class OAuth2Client implements AuthClient {
|
|
|
306
336
|
private retry: number
|
|
307
337
|
private clientSecret?: string
|
|
308
338
|
private baseRequest: <T>(url: string, options?: RequestOptions) => Promise<T>
|
|
309
|
-
private localCredentials: LocalCredentials
|
|
310
339
|
private storage: SimpleStorage
|
|
311
340
|
private deviceID?: string
|
|
312
341
|
private tokenInURL?: boolean
|
|
@@ -315,9 +344,11 @@ export class OAuth2Client implements AuthClient {
|
|
|
315
344
|
private singlePromise: SinglePromise = null
|
|
316
345
|
private anonymousSignInFunc: (Credentials) => Promise<Credentials | void>
|
|
317
346
|
private wxCloud: any
|
|
347
|
+
private useWxCloud: boolean
|
|
348
|
+
private eventBus: any
|
|
318
349
|
private basicAuth: string
|
|
319
350
|
private onCredentialsError: AuthOptions['onCredentialsError'] | undefined
|
|
320
|
-
private
|
|
351
|
+
private onInitialSessionObtained?: (data: { session: Credentials; user?: any }, error?: any) => void | Promise<void>
|
|
321
352
|
|
|
322
353
|
/**
|
|
323
354
|
* constructor
|
|
@@ -336,7 +367,7 @@ export class OAuth2Client implements AuthClient {
|
|
|
336
367
|
this.apiPath = options.apiPath || AUTH_API_PREFIX
|
|
337
368
|
this.clientId = options.clientId
|
|
338
369
|
this.i18n = options.i18n
|
|
339
|
-
this.
|
|
370
|
+
this.eventBus = options.eventBus
|
|
340
371
|
this.singlePromise = new SinglePromise({ clientId: this.clientId })
|
|
341
372
|
this.retry = this.formatRetry(options.retry, OAuth2Client.defaultRetry)
|
|
342
373
|
if (options.baseRequest) {
|
|
@@ -352,13 +383,6 @@ export class OAuth2Client implements AuthClient {
|
|
|
352
383
|
tokenSectionName: `credentials_${options.clientId}`,
|
|
353
384
|
storage: this.storage,
|
|
354
385
|
clientId: options.clientId,
|
|
355
|
-
credentials: this.publishable_key ? {
|
|
356
|
-
access_token: this.publishable_key,
|
|
357
|
-
token_type: 'Bearer',
|
|
358
|
-
scope: 'publishable_key',
|
|
359
|
-
expires_at: new Date(+new Date() + +new Date()),
|
|
360
|
-
expires_in: +new Date() + +new Date(),
|
|
361
|
-
} : null,
|
|
362
386
|
})
|
|
363
387
|
|
|
364
388
|
this.clientSecret = options.clientSecret
|
|
@@ -367,9 +391,12 @@ export class OAuth2Client implements AuthClient {
|
|
|
367
391
|
}
|
|
368
392
|
this.wxCloud = options.wxCloud
|
|
369
393
|
try {
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
this.wxCloud
|
|
394
|
+
if (isMp()) {
|
|
395
|
+
this.useWxCloud = options.useWxCloud
|
|
396
|
+
if (this.wxCloud === undefined && options.env) {
|
|
397
|
+
wx.cloud.init({ env: options.env })
|
|
398
|
+
this.wxCloud = wx.cloud
|
|
399
|
+
}
|
|
373
400
|
}
|
|
374
401
|
} catch (error) {
|
|
375
402
|
//
|
|
@@ -378,9 +405,61 @@ export class OAuth2Client implements AuthClient {
|
|
|
378
405
|
this.anonymousSignInFunc = options.anonymousSignInFunc
|
|
379
406
|
this.onCredentialsError = options.onCredentialsError
|
|
380
407
|
|
|
381
|
-
|
|
408
|
+
// New options for session detection
|
|
409
|
+
this.getInitialSession = options.getInitialSession
|
|
410
|
+
this.onInitialSessionObtained = options.onInitialSessionObtained
|
|
411
|
+
this.logDebugMessages = options.debug ?? false
|
|
412
|
+
|
|
413
|
+
langEvent.bus.on(langEvent.LANG_CHANGE_EVENT, (params: any) => {
|
|
382
414
|
this.i18n = params.data?.i18n || this.i18n
|
|
383
415
|
})
|
|
416
|
+
|
|
417
|
+
// Note: Auto-initialize is NOT called here to allow CloudbaseOAuth to set getInitialSession first
|
|
418
|
+
// CloudbaseOAuth.constructor will call initialize() after setting up the callback
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Sets the getInitialSession callback.
|
|
423
|
+
* This callback is called during initialize() to get the initial session (e.g., from OAuth callback in URL).
|
|
424
|
+
* @param callback The callback function to get initial session
|
|
425
|
+
*/
|
|
426
|
+
public setGetInitialSession(callback: () => Promise<{
|
|
427
|
+
data: { session: Credentials; user?: any } | null
|
|
428
|
+
error: Error | null
|
|
429
|
+
}>,): void {
|
|
430
|
+
this.getInitialSession = callback
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Sets the onInitialSessionObtained callback.
|
|
435
|
+
* This callback is invoked after initial session is obtained and stored,
|
|
436
|
+
* allowing upper layers to handle user info storage.
|
|
437
|
+
* @param callback The callback function to handle session and user data
|
|
438
|
+
*/
|
|
439
|
+
public setOnInitialSessionObtained(callback: (data: { session: Credentials; user?: any }) => void | Promise<void>,): void {
|
|
440
|
+
this.onInitialSessionObtained = callback
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Initializes the client session either from the url or from storage.
|
|
445
|
+
* This method is automatically called when instantiating the client with detectSessionInUrl=true,
|
|
446
|
+
* but should also be called manually when checking for an error from an auth redirect.
|
|
447
|
+
* @param onInitialSessionObtained Optional callback to set before initialization starts
|
|
448
|
+
*/
|
|
449
|
+
async initialize(func?: Promise<{ error: Error | null }>): Promise<{ error: Error | null }> {
|
|
450
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
451
|
+
if (this.initializePromise) {
|
|
452
|
+
return await this.initializePromise
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (func !== undefined) {
|
|
456
|
+
this.initializePromise = func
|
|
457
|
+
return await this.initializePromise
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
this.initializePromise = (async () => await this._acquireLock(-1, async () => await this._initialize()))()
|
|
461
|
+
|
|
462
|
+
return await this.initializePromise
|
|
384
463
|
}
|
|
385
464
|
|
|
386
465
|
/**
|
|
@@ -388,14 +467,26 @@ export class OAuth2Client implements AuthClient {
|
|
|
388
467
|
* @param {Credentials} credentials
|
|
389
468
|
* @return {Promise<void>}
|
|
390
469
|
*/
|
|
391
|
-
public setCredentials(credentials?: Credentials): Promise<void> {
|
|
392
|
-
|
|
470
|
+
public async setCredentials(credentials?: Credentials): Promise<void> {
|
|
471
|
+
// If initialization is in progress, wait for it first
|
|
472
|
+
await this.initializePromise
|
|
473
|
+
return this._acquireLock(-1, async () => this.localCredentials.setCredentials(credentials))
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* set credentials from accessKey
|
|
478
|
+
* @param {Credentials} credentials
|
|
479
|
+
*/
|
|
480
|
+
public setAccessKeyCredentials(credentials?: Credentials) {
|
|
481
|
+
return this.localCredentials.setAccessKeyCredentials(credentials)
|
|
393
482
|
}
|
|
394
483
|
|
|
395
484
|
/**
|
|
396
485
|
* getAccessToken return a validate access token
|
|
397
486
|
*/
|
|
398
487
|
public async getAccessToken(): Promise<string> {
|
|
488
|
+
// If initialization is in progress, wait for it first
|
|
489
|
+
await this.initializePromise
|
|
399
490
|
const credentials: Credentials = await this.getCredentials()
|
|
400
491
|
if (credentials?.access_token) {
|
|
401
492
|
return Promise.resolve(credentials.access_token)
|
|
@@ -432,7 +523,9 @@ export class OAuth2Client implements AuthClient {
|
|
|
432
523
|
options.headers.Authorization = this.basicAuth
|
|
433
524
|
}
|
|
434
525
|
if (options?.withCredentials) {
|
|
435
|
-
|
|
526
|
+
// Use custom getCredentials function if provided, otherwise use default
|
|
527
|
+
// Custom getCredentials avoids default getCredentials() call which may cause deadlock during initialization
|
|
528
|
+
const credentials = options.getCredentials ? await options.getCredentials() : await this.getCredentials()
|
|
436
529
|
if (credentials) {
|
|
437
530
|
if (this.tokenInURL) {
|
|
438
531
|
if (url.indexOf('?') < 0) {
|
|
@@ -456,11 +549,20 @@ export class OAuth2Client implements AuthClient {
|
|
|
456
549
|
const maxRequestTimes: number = retry + 1
|
|
457
550
|
for (let requestTime = 0; requestTime < maxRequestTimes; requestTime++) {
|
|
458
551
|
try {
|
|
459
|
-
if (options.useWxCloud) {
|
|
552
|
+
if (options.useWxCloud || this.useWxCloud) {
|
|
460
553
|
response = await this.wxCloudCallFunction<T>(url, options)
|
|
461
554
|
} else {
|
|
462
555
|
response = await this.baseRequest<T>(url, options)
|
|
463
556
|
}
|
|
557
|
+
|
|
558
|
+
if (!!(response as any)?.code) {
|
|
559
|
+
throw ({
|
|
560
|
+
error: (response as any).code,
|
|
561
|
+
error_description: (response as any).message,
|
|
562
|
+
error_uri: new URL(url).pathname,
|
|
563
|
+
})
|
|
564
|
+
}
|
|
565
|
+
|
|
464
566
|
break
|
|
465
567
|
} catch (responseError) {
|
|
466
568
|
if (options.withCredentials && responseError && responseError.error === ErrorType.UNAUTHENTICATED) {
|
|
@@ -524,33 +626,10 @@ export class OAuth2Client implements AuthClient {
|
|
|
524
626
|
* Get credentials.
|
|
525
627
|
*/
|
|
526
628
|
public async getCredentials(): Promise<Credentials | null> {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return this.unAuthenticatedError(msg)
|
|
532
|
-
}
|
|
533
|
-
if (isCredentialsExpired(credentials)) {
|
|
534
|
-
if (credentials.refresh_token) {
|
|
535
|
-
try {
|
|
536
|
-
credentials = await this.refreshToken(credentials)
|
|
537
|
-
} catch (error) {
|
|
538
|
-
if (credentials.scope === 'anonymous') {
|
|
539
|
-
credentials = await this.anonymousLogin(credentials)
|
|
540
|
-
} else {
|
|
541
|
-
this.onCredentialsError?.({ msg: error.error_description })
|
|
542
|
-
return Promise.reject(error)
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
} else if (credentials.scope === 'anonymous') {
|
|
546
|
-
credentials = await this.anonymousLogin(credentials)
|
|
547
|
-
} else {
|
|
548
|
-
const msg = 'no refresh token found in credentials'
|
|
549
|
-
this.onCredentialsError?.({ msg })
|
|
550
|
-
return this.unAuthenticatedError(msg)
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
return credentials
|
|
629
|
+
// If initialization is in progress, wait for it first
|
|
630
|
+
await this.initializePromise
|
|
631
|
+
|
|
632
|
+
return this._acquireLock(-1, async () => this._getCredentials())
|
|
554
633
|
}
|
|
555
634
|
|
|
556
635
|
/**
|
|
@@ -590,7 +669,17 @@ export class OAuth2Client implements AuthClient {
|
|
|
590
669
|
* @param {Credentials} credentials
|
|
591
670
|
* @return {Promise<Credentials>}
|
|
592
671
|
*/
|
|
593
|
-
public async refreshToken(credentials: Credentials): Promise<Credentials> {
|
|
672
|
+
public async refreshToken(credentials: Credentials, options?: { throwError?: boolean }): Promise<Credentials> {
|
|
673
|
+
// If initialization is in progress, wait for it first
|
|
674
|
+
await this.initializePromise
|
|
675
|
+
|
|
676
|
+
return this._acquireLock(-1, async () => this._refreshToken(credentials, options))
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Internal refresh token method (called within lock)
|
|
681
|
+
*/
|
|
682
|
+
private async _refreshToken(credentials: Credentials, options?: { throwError?: boolean }): Promise<Credentials> {
|
|
594
683
|
return this.singlePromise.run('_refreshToken', async () => {
|
|
595
684
|
if (!credentials || !credentials.refresh_token) {
|
|
596
685
|
const msg = 'no refresh token found in credentials'
|
|
@@ -600,8 +689,14 @@ export class OAuth2Client implements AuthClient {
|
|
|
600
689
|
try {
|
|
601
690
|
const newCredentials: Credentials = await this.refreshTokenFunc(credentials.refresh_token, credentials)
|
|
602
691
|
await this.localCredentials.setCredentials(newCredentials)
|
|
692
|
+
|
|
693
|
+
this.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.TOKEN_REFRESHED })
|
|
694
|
+
|
|
603
695
|
return newCredentials
|
|
604
696
|
} catch (error) {
|
|
697
|
+
if (options?.throwError) {
|
|
698
|
+
throw error
|
|
699
|
+
}
|
|
605
700
|
if (error.error === ErrorType.INVALID_GRANT) {
|
|
606
701
|
await this.localCredentials.setCredentials(null)
|
|
607
702
|
const msg = error.error_description
|
|
@@ -758,4 +853,162 @@ export class OAuth2Client implements AuthClient {
|
|
|
758
853
|
}
|
|
759
854
|
return Promise.reject(respErr)
|
|
760
855
|
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Debug logging helper
|
|
859
|
+
*/
|
|
860
|
+
private _debug(...args: any[]): void {
|
|
861
|
+
if (this.logDebugMessages) {
|
|
862
|
+
console.log('[OAuth2Client]', ...args)
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* IMPORTANT:
|
|
868
|
+
* 1. Never throw in this method, as it is called from the constructor
|
|
869
|
+
* 2. Never return a session from this method as it would be cached over
|
|
870
|
+
* the whole lifetime of the client
|
|
871
|
+
*/
|
|
872
|
+
private async _initialize(): Promise<{ error: Error | null }> {
|
|
873
|
+
try {
|
|
874
|
+
// If no getInitialSession callback is set, nothing to do
|
|
875
|
+
if (!this.getInitialSession) {
|
|
876
|
+
this._debug('#_initialize()', 'no getInitialSession callback set, skipping')
|
|
877
|
+
return { error: null }
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
this._debug('#_initialize()', 'calling getInitialSession callback')
|
|
881
|
+
|
|
882
|
+
try {
|
|
883
|
+
const { data, error } = await this.getInitialSession()
|
|
884
|
+
|
|
885
|
+
if (data?.session) {
|
|
886
|
+
this._debug('#_initialize()', 'session obtained from getInitialSession', data.session)
|
|
887
|
+
await this.localCredentials.setCredentials(data?.session)
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Invoke callback for upper layer to handle user storage
|
|
891
|
+
// This is called BEFORE lock is released so user storage is atomic with session
|
|
892
|
+
if (this.onInitialSessionObtained) {
|
|
893
|
+
this._debug('#_initialize()', 'calling onInitialSessionObtained callback')
|
|
894
|
+
try {
|
|
895
|
+
await this.onInitialSessionObtained(data, error)
|
|
896
|
+
} catch (callbackError) {
|
|
897
|
+
this._debug('#_initialize()', 'error in onInitialSessionObtained', callbackError)
|
|
898
|
+
// Don't fail initialization if callback fails
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (error) {
|
|
902
|
+
this._debug('#_initialize()', 'error from getInitialSession', error)
|
|
903
|
+
return { error }
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
return { error: null }
|
|
907
|
+
} catch (err) {
|
|
908
|
+
this._debug('#_initialize()', 'exception during getInitialSession', err)
|
|
909
|
+
return { error: err instanceof Error ? err : new Error(String(err)) }
|
|
910
|
+
}
|
|
911
|
+
} catch (error) {
|
|
912
|
+
this._debug('#_initialize()', 'unexpected error', error)
|
|
913
|
+
return { error: error instanceof Error ? error : new Error(String(error)) }
|
|
914
|
+
} finally {
|
|
915
|
+
this._debug('#_initialize()', 'end')
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Acquires a global lock based on the client ID.
|
|
921
|
+
* This ensures that only one operation can modify credentials at a time.
|
|
922
|
+
*/
|
|
923
|
+
private async _acquireLock<R>(acquireTimeout: number, fn: () => Promise<R>): Promise<R> {
|
|
924
|
+
this._debug('#_acquireLock', 'begin', acquireTimeout)
|
|
925
|
+
|
|
926
|
+
try {
|
|
927
|
+
if (this.lockAcquired) {
|
|
928
|
+
// Lock is already acquired, queue the operation
|
|
929
|
+
const last = this.pendingInLock.length ? this.pendingInLock[this.pendingInLock.length - 1] : Promise.resolve()
|
|
930
|
+
|
|
931
|
+
const result = (async () => {
|
|
932
|
+
await last
|
|
933
|
+
return await fn()
|
|
934
|
+
})()
|
|
935
|
+
|
|
936
|
+
this.pendingInLock.push((async () => {
|
|
937
|
+
try {
|
|
938
|
+
await result
|
|
939
|
+
} catch (_e: any) {
|
|
940
|
+
// we just care if it finished
|
|
941
|
+
}
|
|
942
|
+
})(),)
|
|
943
|
+
|
|
944
|
+
return result
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Acquire the lock
|
|
948
|
+
this._debug('#_acquireLock', 'acquiring lock for client', this.clientId)
|
|
949
|
+
|
|
950
|
+
try {
|
|
951
|
+
this.lockAcquired = true
|
|
952
|
+
|
|
953
|
+
const result = fn()
|
|
954
|
+
|
|
955
|
+
this.pendingInLock.push((async () => {
|
|
956
|
+
try {
|
|
957
|
+
await result
|
|
958
|
+
} catch (_e: any) {
|
|
959
|
+
// we just care if it finished
|
|
960
|
+
}
|
|
961
|
+
})(),)
|
|
962
|
+
|
|
963
|
+
await result
|
|
964
|
+
|
|
965
|
+
// keep draining the queue until there's nothing to wait on
|
|
966
|
+
while (this.pendingInLock.length) {
|
|
967
|
+
const waitOn = [...this.pendingInLock]
|
|
968
|
+
await Promise.all(waitOn)
|
|
969
|
+
this.pendingInLock.splice(0, waitOn.length)
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
return await result
|
|
973
|
+
} finally {
|
|
974
|
+
this._debug('#_acquireLock', 'releasing lock for client', this.clientId)
|
|
975
|
+
this.lockAcquired = false
|
|
976
|
+
}
|
|
977
|
+
} finally {
|
|
978
|
+
this._debug('#_acquireLock', 'end')
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Internal method to get credentials (called within lock)
|
|
984
|
+
*/
|
|
985
|
+
private async _getCredentials(): Promise<Credentials | null> {
|
|
986
|
+
let credentials: Credentials = await this.localCredentials.getCredentials()
|
|
987
|
+
if (!credentials) {
|
|
988
|
+
const msg = 'credentials not found'
|
|
989
|
+
this.onCredentialsError?.({ msg })
|
|
990
|
+
return this.unAuthenticatedError(msg)
|
|
991
|
+
}
|
|
992
|
+
if (isCredentialsExpired(credentials)) {
|
|
993
|
+
if (credentials.refresh_token) {
|
|
994
|
+
try {
|
|
995
|
+
credentials = await this._refreshToken(credentials)
|
|
996
|
+
} catch (error) {
|
|
997
|
+
if (credentials.scope === 'anonymous') {
|
|
998
|
+
credentials = await this.anonymousLogin(credentials)
|
|
999
|
+
} else {
|
|
1000
|
+
this.onCredentialsError?.({ msg: error.error_description })
|
|
1001
|
+
return Promise.reject(error)
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
} else if (credentials.scope === 'anonymous') {
|
|
1005
|
+
credentials = await this.anonymousLogin(credentials)
|
|
1006
|
+
} else {
|
|
1007
|
+
const msg = 'no refresh token found in credentials'
|
|
1008
|
+
this.onCredentialsError?.({ msg })
|
|
1009
|
+
return this.unAuthenticatedError(msg)
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return credentials
|
|
1013
|
+
}
|
|
761
1014
|
}
|
package/src/utils/base64.ts
CHANGED
|
@@ -98,3 +98,15 @@ export function weappJwtDecode(token: string, options?: any) {
|
|
|
98
98
|
throw new Error(`Invalid token specified: ${e}` ? (e as any).message : '')
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
export function weAppJwtDecodeAll(token: string) {
|
|
103
|
+
if (typeof token !== 'string') {
|
|
104
|
+
throw new Error('Invalid token specified')
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const parts = token.split('.').map((segment, i) => i === 2 ? segment : JSON.parse(base64_url_decode(segment)))
|
|
108
|
+
return { claims: parts[1], header: parts[0], signature: parts[2]}
|
|
109
|
+
} catch (e) {
|
|
110
|
+
throw new Error(`Invalid token specified: ${e}` ? (e as any).message : '')
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -2697,12 +2697,14 @@ and limitations under the License.
|
|
|
2697
2697
|
rng_pool = []
|
|
2698
2698
|
rng_pptr = 0
|
|
2699
2699
|
var t = void 0
|
|
2700
|
-
if (window
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2700
|
+
if (typeof window !== 'undefined') {
|
|
2701
|
+
if (window?.crypto && window?.crypto.getRandomValues) {
|
|
2702
|
+
// Extract entropy (2048 bits) from RNG if available
|
|
2703
|
+
var z = new Uint32Array(256)
|
|
2704
|
+
window?.crypto.getRandomValues(z)
|
|
2705
|
+
for (t = 0; t < z.length; ++t) {
|
|
2706
|
+
rng_pool[rng_pptr++] = z[t] & 255
|
|
2707
|
+
}
|
|
2706
2708
|
}
|
|
2707
2709
|
}
|
|
2708
2710
|
// Use mouse events for entropy, if we do not have enough entropy by the time
|
|
@@ -2710,10 +2712,12 @@ and limitations under the License.
|
|
|
2710
2712
|
var onMouseMoveListener_1 = function (ev) {
|
|
2711
2713
|
this.count = this.count || 0
|
|
2712
2714
|
if (this.count >= 256 || rng_pptr >= rng_psize) {
|
|
2713
|
-
if (window
|
|
2714
|
-
window?.removeEventListener
|
|
2715
|
-
|
|
2716
|
-
window?.detachEvent
|
|
2715
|
+
if (typeof window !== 'undefined') {
|
|
2716
|
+
if (window?.removeEventListener) {
|
|
2717
|
+
window?.removeEventListener('mousemove', onMouseMoveListener_1, false)
|
|
2718
|
+
} else if (window?.detachEvent) {
|
|
2719
|
+
window?.detachEvent('onmousemove', onMouseMoveListener_1)
|
|
2720
|
+
}
|
|
2717
2721
|
}
|
|
2718
2722
|
return
|
|
2719
2723
|
}
|
|
@@ -2725,10 +2729,12 @@ and limitations under the License.
|
|
|
2725
2729
|
// Sometimes Firefox will deny permission to access event properties for some reason. Ignore.
|
|
2726
2730
|
}
|
|
2727
2731
|
}
|
|
2728
|
-
if (window
|
|
2729
|
-
window?.addEventListener
|
|
2730
|
-
|
|
2731
|
-
window?.attachEvent
|
|
2732
|
+
if (typeof window !== 'undefined') {
|
|
2733
|
+
if (window?.addEventListener) {
|
|
2734
|
+
window?.addEventListener('mousemove', onMouseMoveListener_1, false)
|
|
2735
|
+
} else if (window?.attachEvent) {
|
|
2736
|
+
window?.attachEvent('onmousemove', onMouseMoveListener_1)
|
|
2737
|
+
}
|
|
2732
2738
|
}
|
|
2733
2739
|
}
|
|
2734
2740
|
function rng_get_byte() {
|
package/src/utils/index.ts
CHANGED
package/src/utils/mp.ts
CHANGED
|
@@ -10,7 +10,7 @@ export function isMp() {
|
|
|
10
10
|
if ((globalThis as any).Page === undefined) {
|
|
11
11
|
return false
|
|
12
12
|
}
|
|
13
|
-
if (!wx.
|
|
13
|
+
if (!wx.getDeviceInfo) {
|
|
14
14
|
return false
|
|
15
15
|
}
|
|
16
16
|
if (!wx.getStorageSync) {
|
|
@@ -27,11 +27,11 @@ export function isMp() {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
try {
|
|
30
|
-
if (!wx.
|
|
30
|
+
if (!wx.getDeviceInfo()) {
|
|
31
31
|
return false
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
if (wx.
|
|
34
|
+
if (wx.getDeviceInfo().platform === 'qq') {
|
|
35
35
|
return false
|
|
36
36
|
}
|
|
37
37
|
} catch (e) {
|
|
@@ -9,6 +9,7 @@ class MyURLSearchParams {
|
|
|
9
9
|
if (typeof init === 'string') {
|
|
10
10
|
this.parse(init)
|
|
11
11
|
} else if (init && typeof init === 'object') {
|
|
12
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
12
13
|
for (const key in init) {
|
|
13
14
|
if (Object.prototype.hasOwnProperty.call(init, key)) {
|
|
14
15
|
this.append(key, init[key])
|
|
@@ -63,6 +64,7 @@ class MyURLSearchParams {
|
|
|
63
64
|
// 返回查询字符串
|
|
64
65
|
toString() {
|
|
65
66
|
const items = []
|
|
67
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
66
68
|
for (const key in this.params) {
|
|
67
69
|
if (Object.prototype.hasOwnProperty.call(this.params, key)) {
|
|
68
70
|
this.params[key].forEach((value) => {
|
package/tsconfig.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function isMatch(): boolean;
|