@cloudbase/oauth 2.4.5-beta.0 → 2.5.1-beta.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/.eslintrc.js +15 -0
- package/dist/cjs/auth/apis.d.ts +3 -3
- package/dist/cjs/auth/apis.js +69 -69
- package/dist/cjs/captcha/captcha.d.ts +9 -9
- package/dist/cjs/captcha/captcha.js +43 -46
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +6 -6
- package/dist/cjs/oauth2client/interface.d.ts +1 -1
- package/dist/cjs/oauth2client/interface.js +1 -1
- package/dist/cjs/oauth2client/models.js +1 -1
- package/dist/cjs/oauth2client/oauth2client.d.ts +31 -31
- package/dist/cjs/oauth2client/oauth2client.js +229 -229
- package/dist/cjs/utils/function/single-promise.d.ts +2 -2
- package/dist/cjs/utils/function/single-promise.js +40 -33
- package/dist/cjs/utils/uuid.js +2 -2
- package/dist/esm/auth/apis.d.ts +3 -3
- package/dist/esm/auth/apis.js +69 -69
- package/dist/esm/captcha/captcha.d.ts +9 -9
- package/dist/esm/captcha/captcha.js +44 -47
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +5 -5
- package/dist/esm/oauth2client/interface.d.ts +1 -1
- package/dist/esm/oauth2client/interface.js +1 -1
- package/dist/esm/oauth2client/models.js +1 -1
- package/dist/esm/oauth2client/oauth2client.d.ts +31 -31
- package/dist/esm/oauth2client/oauth2client.js +229 -229
- package/dist/esm/utils/function/single-promise.d.ts +2 -2
- package/dist/esm/utils/function/single-promise.js +40 -33
- package/dist/esm/utils/uuid.js +2 -2
- package/package.json +13 -6
- package/src/auth/apis.ts +135 -158
- package/src/captcha/captcha.ts +71 -78
- package/src/index.ts +13 -14
- package/src/oauth2client/interface.ts +5 -5
- package/src/oauth2client/models.ts +38 -38
- package/src/oauth2client/oauth2client.ts +255 -268
- package/src/utils/function/single-promise.ts +22 -21
- package/src/utils/uuid.ts +4 -4
- package/.eslintrc +0 -26
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ErrorType } from './consts'
|
|
1
|
+
import { ErrorType } from './consts'
|
|
2
2
|
|
|
3
|
-
import { AuthClient, SimpleStorage } from './interface'
|
|
3
|
+
import { AuthClient, SimpleStorage } from './interface'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
Credentials,
|
|
@@ -9,15 +9,15 @@ import {
|
|
|
9
9
|
RequestFunction,
|
|
10
10
|
OAuth2ClientOptions,
|
|
11
11
|
AuthClientRequestOptions,
|
|
12
|
-
} from './models'
|
|
12
|
+
} from './models'
|
|
13
13
|
|
|
14
|
-
import { uuidv4 } from '../utils/uuid'
|
|
14
|
+
import { uuidv4 } from '../utils/uuid'
|
|
15
15
|
|
|
16
|
-
import { SinglePromise } from '../utils/function/single-promise'
|
|
16
|
+
import { SinglePromise } from '../utils/function/single-promise'
|
|
17
17
|
|
|
18
|
-
const RequestIdHeaderName = 'x-request-id'
|
|
19
|
-
const DeviceIdHeaderName = 'x-device-id'
|
|
20
|
-
const DeviceIdSectionName = 'device_id'
|
|
18
|
+
const RequestIdHeaderName = 'x-request-id'
|
|
19
|
+
const DeviceIdHeaderName = 'x-device-id'
|
|
20
|
+
const DeviceIdSectionName = 'device_id'
|
|
21
21
|
|
|
22
22
|
export interface ToResponseErrorOptions {
|
|
23
23
|
error?: ErrorType;
|
|
@@ -26,75 +26,76 @@ export interface ToResponseErrorOptions {
|
|
|
26
26
|
details?: any | null;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
export const defaultRequest: RequestFunction = async function <T>(
|
|
30
31
|
url: string,
|
|
31
|
-
options?: RequestOptions
|
|
32
|
-
): Promise<T>
|
|
33
|
-
let result: T | null = null
|
|
34
|
-
let responseError: ResponseError | null = null
|
|
32
|
+
options?: RequestOptions
|
|
33
|
+
): Promise<T> {
|
|
34
|
+
let result: T | null = null
|
|
35
|
+
let responseError: ResponseError | null = null
|
|
35
36
|
try {
|
|
36
37
|
// Objects must be copied to prevent modification of data such as body.
|
|
37
|
-
const copyOptions = Object.assign({}, options)
|
|
38
|
+
const copyOptions = Object.assign({}, options)
|
|
38
39
|
if (!copyOptions.method) {
|
|
39
|
-
copyOptions.method = 'GET'
|
|
40
|
+
copyOptions.method = 'GET'
|
|
40
41
|
}
|
|
41
42
|
if (copyOptions.body && typeof copyOptions.body !== 'string') {
|
|
42
|
-
copyOptions.body = JSON.stringify(copyOptions.body)
|
|
43
|
+
copyOptions.body = JSON.stringify(copyOptions.body)
|
|
43
44
|
}
|
|
44
|
-
const responseResult: Response = await fetch(url, copyOptions)
|
|
45
|
-
const jsonResponse = await responseResult.json()
|
|
45
|
+
const responseResult: Response = await fetch(url, copyOptions)
|
|
46
|
+
const jsonResponse = await responseResult.json()
|
|
46
47
|
if (jsonResponse?.error) {
|
|
47
|
-
responseError = jsonResponse as ResponseError
|
|
48
|
-
responseError.error_uri = new URL(url).pathname
|
|
48
|
+
responseError = jsonResponse as ResponseError
|
|
49
|
+
responseError.error_uri = new URL(url).pathname
|
|
49
50
|
} else {
|
|
50
|
-
result = jsonResponse as T
|
|
51
|
+
result = jsonResponse as T
|
|
51
52
|
}
|
|
52
53
|
} catch (error) {
|
|
53
54
|
responseError = {
|
|
54
55
|
error: ErrorType.UNREACHABLE,
|
|
55
56
|
error_description: error.message,
|
|
56
57
|
error_uri: new URL(url).pathname,
|
|
57
|
-
}
|
|
58
|
+
}
|
|
58
59
|
}
|
|
59
60
|
if (responseError) {
|
|
60
|
-
throw responseError
|
|
61
|
+
throw responseError
|
|
61
62
|
} else {
|
|
62
|
-
return result
|
|
63
|
+
return result
|
|
63
64
|
}
|
|
64
|
-
}
|
|
65
|
+
}
|
|
65
66
|
|
|
66
67
|
export const toResponseError = (
|
|
67
68
|
error: ResponseError | Error,
|
|
68
69
|
options?: ToResponseErrorOptions,
|
|
69
70
|
): ResponseError => {
|
|
70
|
-
let responseError: ResponseError
|
|
71
|
-
const formatOptions: ToResponseErrorOptions = options || {}
|
|
71
|
+
let responseError: ResponseError
|
|
72
|
+
const formatOptions: ToResponseErrorOptions = options || {}
|
|
72
73
|
if (error instanceof Error) {
|
|
73
74
|
responseError = {
|
|
74
75
|
error: formatOptions.error || ErrorType.LOCAL,
|
|
75
76
|
error_description: formatOptions.error_description || error.message,
|
|
76
77
|
error_uri: formatOptions.error_uri,
|
|
77
78
|
details: formatOptions.details || error.stack,
|
|
78
|
-
}
|
|
79
|
+
}
|
|
79
80
|
} else {
|
|
80
|
-
const formatError: ToResponseErrorOptions = error || {}
|
|
81
|
+
const formatError: ToResponseErrorOptions = error || {}
|
|
81
82
|
responseError = {
|
|
82
83
|
error: formatOptions.error || formatError.error || ErrorType.LOCAL,
|
|
83
84
|
error_description:
|
|
84
85
|
formatOptions.error_description || formatError.error_description,
|
|
85
86
|
error_uri: formatOptions.error_uri || formatError.error_uri,
|
|
86
87
|
details: formatOptions.details || formatError.details,
|
|
87
|
-
}
|
|
88
|
+
}
|
|
88
89
|
}
|
|
89
|
-
return responseError
|
|
90
|
-
}
|
|
90
|
+
return responseError
|
|
91
|
+
}
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
94
|
* Generate request id.
|
|
94
95
|
* @return {string}
|
|
95
96
|
*/
|
|
96
97
|
export function generateRequestId(): string {
|
|
97
|
-
return uuidv4()
|
|
98
|
+
return uuidv4()
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
|
|
@@ -107,7 +108,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
107
108
|
* @param {string} key
|
|
108
109
|
*/
|
|
109
110
|
async getItem(key: string): Promise<string | null> {
|
|
110
|
-
return window.localStorage.getItem(key)
|
|
111
|
+
return window.localStorage.getItem(key)
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
/**
|
|
@@ -115,7 +116,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
115
116
|
* @param {string} key
|
|
116
117
|
*/
|
|
117
118
|
async removeItem(key: string): Promise<void> {
|
|
118
|
-
window.localStorage.removeItem(key)
|
|
119
|
+
window.localStorage.removeItem(key)
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
/**
|
|
@@ -124,7 +125,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
124
125
|
* @param {string} value
|
|
125
126
|
*/
|
|
126
127
|
async setItem(key: string, value: string): Promise<void> {
|
|
127
|
-
window.localStorage.setItem(key, value)
|
|
128
|
+
window.localStorage.setItem(key, value)
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
/**
|
|
@@ -132,7 +133,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
132
133
|
* @param {string} key
|
|
133
134
|
*/
|
|
134
135
|
getItemSync(key: string): string | null {
|
|
135
|
-
return window.localStorage.getItem(key)
|
|
136
|
+
return window.localStorage.getItem(key)
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
/**
|
|
@@ -140,7 +141,7 @@ class DefaultStorage implements SimpleStorage {
|
|
|
140
141
|
* @param {string} key
|
|
141
142
|
*/
|
|
142
143
|
removeItemSync(key: string): void {
|
|
143
|
-
window.localStorage.removeItem(key)
|
|
144
|
+
window.localStorage.removeItem(key)
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
/**
|
|
@@ -149,11 +150,11 @@ class DefaultStorage implements SimpleStorage {
|
|
|
149
150
|
* @param {string} value
|
|
150
151
|
*/
|
|
151
152
|
setItemSync(key: string, value: string): void {
|
|
152
|
-
window.localStorage.setItem(key, value)
|
|
153
|
+
window.localStorage.setItem(key, value)
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
export const defaultStorage = new DefaultStorage()
|
|
157
|
+
export const defaultStorage = new DefaultStorage()
|
|
157
158
|
|
|
158
159
|
interface LocalCredentialsOptions {
|
|
159
160
|
tokenSectionName: string;
|
|
@@ -166,11 +167,11 @@ interface LocalCredentialsOptions {
|
|
|
166
167
|
* @return {boolean}
|
|
167
168
|
*/
|
|
168
169
|
function isCredentialsExpired(credentials: Credentials): boolean {
|
|
169
|
-
let isExpired = true
|
|
170
|
+
let isExpired = true
|
|
170
171
|
if (credentials?.expires_at && credentials?.access_token) {
|
|
171
|
-
isExpired = credentials.expires_at < new Date()
|
|
172
|
+
isExpired = credentials.expires_at < new Date()
|
|
172
173
|
}
|
|
173
|
-
return isExpired
|
|
174
|
+
return isExpired
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
/**
|
|
@@ -179,21 +180,38 @@ function isCredentialsExpired(credentials: Credentials): boolean {
|
|
|
179
180
|
* If the memory cache expires, the storage cache is automatically loaded.
|
|
180
181
|
*/
|
|
181
182
|
export class LocalCredentials {
|
|
182
|
-
private
|
|
183
|
+
private tokenSectionName: string
|
|
183
184
|
|
|
184
|
-
private
|
|
185
|
+
private storage: SimpleStorage
|
|
185
186
|
|
|
186
|
-
private
|
|
187
|
+
private credentials: Credentials | null = null
|
|
187
188
|
|
|
188
|
-
private
|
|
189
|
+
private singlePromise: SinglePromise = new SinglePromise()
|
|
189
190
|
|
|
190
191
|
/**
|
|
191
192
|
* constructor
|
|
192
193
|
* @param {LocalCredentialsOptions} options
|
|
193
194
|
*/
|
|
194
195
|
constructor(options: LocalCredentialsOptions) {
|
|
195
|
-
this.
|
|
196
|
-
this.
|
|
196
|
+
this.tokenSectionName = options.tokenSectionName
|
|
197
|
+
this.storage = options.storage
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public getStorageCredentialsSync(): Credentials | null {
|
|
201
|
+
let credentials: Credentials = null
|
|
202
|
+
const tokenStr: string = this.storage.getItemSync(this.tokenSectionName,)
|
|
203
|
+
if (tokenStr !== undefined && tokenStr !== null) {
|
|
204
|
+
try {
|
|
205
|
+
credentials = JSON.parse(tokenStr)
|
|
206
|
+
if (credentials?.expires_at) {
|
|
207
|
+
credentials.expires_at = new Date(credentials.expires_at)
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
this.storage.removeItem(this.tokenSectionName)
|
|
211
|
+
credentials = null
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return credentials
|
|
197
215
|
}
|
|
198
216
|
|
|
199
217
|
/**
|
|
@@ -202,19 +220,17 @@ export class LocalCredentials {
|
|
|
202
220
|
*/
|
|
203
221
|
public async setCredentials(credentials?: Credentials): Promise<void> {
|
|
204
222
|
if (credentials?.expires_in) {
|
|
205
|
-
credentials.expires_at = new Date(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const tokenStr: string = JSON.stringify(credentials);
|
|
210
|
-
await this._storage.setItem(this._tokenSectionName, tokenStr);
|
|
223
|
+
credentials.expires_at = new Date(Date.now() + (credentials.expires_in - 30) * 1000,)
|
|
224
|
+
if (this.storage) {
|
|
225
|
+
const tokenStr: string = JSON.stringify(credentials)
|
|
226
|
+
await this.storage.setItem(this.tokenSectionName, tokenStr)
|
|
211
227
|
}
|
|
212
|
-
this.
|
|
228
|
+
this.credentials = credentials
|
|
213
229
|
} else {
|
|
214
|
-
if (this.
|
|
215
|
-
await this.
|
|
230
|
+
if (this.storage) {
|
|
231
|
+
await this.storage.removeItem(this.tokenSectionName)
|
|
216
232
|
}
|
|
217
|
-
this.
|
|
233
|
+
this.credentials = null
|
|
218
234
|
}
|
|
219
235
|
}
|
|
220
236
|
|
|
@@ -223,108 +239,85 @@ export class LocalCredentials {
|
|
|
223
239
|
* @return {Promise<Credentials | null>}
|
|
224
240
|
*/
|
|
225
241
|
public async getCredentials(): Promise<Credentials | null> {
|
|
226
|
-
return this.
|
|
227
|
-
if (isCredentialsExpired(this.
|
|
228
|
-
this.
|
|
242
|
+
return this.singlePromise.run('getCredentials', async () => {
|
|
243
|
+
if (isCredentialsExpired(this.credentials)) {
|
|
244
|
+
this.credentials = await this.getStorageCredentials()
|
|
229
245
|
}
|
|
230
|
-
return this.
|
|
231
|
-
})
|
|
246
|
+
return this.credentials
|
|
247
|
+
})
|
|
232
248
|
}
|
|
233
249
|
|
|
234
250
|
/**
|
|
235
251
|
* Get storage credentials.
|
|
236
252
|
*/
|
|
237
|
-
private async
|
|
238
|
-
return this.
|
|
239
|
-
let credentials: Credentials = null
|
|
240
|
-
const tokenStr: string = await this.
|
|
241
|
-
this._tokenSectionName,
|
|
242
|
-
);
|
|
253
|
+
private async getStorageCredentials(): Promise<Credentials | null> {
|
|
254
|
+
return this.singlePromise.run('_getStorageCredentials', async () => {
|
|
255
|
+
let credentials: Credentials = null
|
|
256
|
+
const tokenStr: string = await this.storage.getItem(this.tokenSectionName,)
|
|
243
257
|
if (tokenStr !== undefined && tokenStr !== null) {
|
|
244
258
|
try {
|
|
245
|
-
credentials = JSON.parse(tokenStr)
|
|
259
|
+
credentials = JSON.parse(tokenStr)
|
|
246
260
|
if (credentials?.expires_at) {
|
|
247
|
-
credentials.expires_at = new Date(credentials.expires_at)
|
|
261
|
+
credentials.expires_at = new Date(credentials.expires_at)
|
|
248
262
|
}
|
|
249
263
|
} catch (error) {
|
|
250
|
-
await this.
|
|
251
|
-
credentials = null
|
|
264
|
+
await this.storage.removeItem(this.tokenSectionName)
|
|
265
|
+
credentials = null
|
|
252
266
|
}
|
|
253
267
|
}
|
|
254
|
-
return credentials
|
|
255
|
-
})
|
|
268
|
+
return credentials
|
|
269
|
+
})
|
|
256
270
|
}
|
|
257
|
-
|
|
258
|
-
public _getStorageCredentialsSync(): Credentials | null {
|
|
259
|
-
let credentials: Credentials = null;
|
|
260
|
-
const tokenStr: string = this._storage.getItemSync(
|
|
261
|
-
this._tokenSectionName,
|
|
262
|
-
);
|
|
263
|
-
if (tokenStr !== undefined && tokenStr !== null) {
|
|
264
|
-
try {
|
|
265
|
-
credentials = JSON.parse(tokenStr);
|
|
266
|
-
if (credentials?.expires_at) {
|
|
267
|
-
credentials.expires_at = new Date(credentials.expires_at);
|
|
268
|
-
}
|
|
269
|
-
} catch (error) {
|
|
270
|
-
this._storage.removeItem(this._tokenSectionName);
|
|
271
|
-
credentials = null;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return credentials
|
|
275
|
-
}
|
|
276
|
-
|
|
277
271
|
}
|
|
278
272
|
|
|
279
273
|
/**
|
|
280
274
|
* OAuth2Client
|
|
281
275
|
*/
|
|
282
276
|
export class OAuth2Client implements AuthClient {
|
|
283
|
-
private static
|
|
284
|
-
private static
|
|
285
|
-
private static
|
|
286
|
-
private static
|
|
287
|
-
|
|
288
|
-
private
|
|
289
|
-
private
|
|
290
|
-
private
|
|
291
|
-
private
|
|
292
|
-
private
|
|
277
|
+
private static defaultRetry = 2
|
|
278
|
+
private static minRetry = 0
|
|
279
|
+
private static maxRetry = 5
|
|
280
|
+
private static retryInterval = 1000
|
|
281
|
+
|
|
282
|
+
private apiOrigin: string
|
|
283
|
+
private clientId: string
|
|
284
|
+
private retry: number
|
|
285
|
+
private clientSecret?: string
|
|
286
|
+
private baseRequest: <T>(
|
|
293
287
|
url: string,
|
|
294
288
|
options?: RequestOptions,
|
|
295
|
-
) => Promise<T
|
|
296
|
-
private
|
|
297
|
-
private
|
|
298
|
-
private
|
|
299
|
-
private
|
|
300
|
-
private
|
|
301
|
-
private
|
|
302
|
-
private
|
|
289
|
+
) => Promise<T>
|
|
290
|
+
private localCredentials: LocalCredentials
|
|
291
|
+
private storage: SimpleStorage
|
|
292
|
+
private deviceID?: string
|
|
293
|
+
private tokenInURL?: boolean
|
|
294
|
+
private refreshTokenFunc: (refreshToken?: string) => Promise<Credentials>
|
|
295
|
+
private headers?: { [key: string]: string }
|
|
296
|
+
private singlePromise: SinglePromise = new SinglePromise()
|
|
303
297
|
|
|
304
298
|
/**
|
|
305
299
|
* constructor
|
|
306
300
|
* @param {OAuth2ClientOptions} options
|
|
307
301
|
*/
|
|
308
302
|
constructor(options: OAuth2ClientOptions) {
|
|
309
|
-
this.
|
|
310
|
-
this.
|
|
311
|
-
this.
|
|
312
|
-
if (options.baseRequest
|
|
313
|
-
this.
|
|
303
|
+
this.apiOrigin = options.apiOrigin
|
|
304
|
+
this.clientId = options.clientId
|
|
305
|
+
this.retry = this.formatRetry(options.retry, OAuth2Client.defaultRetry)
|
|
306
|
+
if (options.baseRequest) {
|
|
307
|
+
this.baseRequest = options.baseRequest
|
|
314
308
|
} else {
|
|
315
|
-
this.
|
|
309
|
+
this.baseRequest = defaultRequest
|
|
316
310
|
}
|
|
317
|
-
this.
|
|
318
|
-
this.
|
|
311
|
+
this.tokenInURL = options.tokenInURL
|
|
312
|
+
this.headers = options.headers
|
|
319
313
|
// @ts-ignore
|
|
320
|
-
this.
|
|
321
|
-
this.
|
|
322
|
-
tokenSectionName:
|
|
323
|
-
storage: this.
|
|
324
|
-
})
|
|
325
|
-
this.
|
|
326
|
-
this.
|
|
327
|
-
options.refreshTokenFunc || this._defaultRefreshTokenFunc;
|
|
314
|
+
this.storage = options.storage || defaultStorage
|
|
315
|
+
this.localCredentials = new LocalCredentials({
|
|
316
|
+
tokenSectionName: `credentials_${options.clientId}`,
|
|
317
|
+
storage: this.storage,
|
|
318
|
+
})
|
|
319
|
+
this.clientSecret = options.clientSecret
|
|
320
|
+
this.refreshTokenFunc = options.refreshTokenFunc || this.defaultRefreshTokenFunc
|
|
328
321
|
}
|
|
329
322
|
|
|
330
323
|
/**
|
|
@@ -333,18 +326,19 @@ export class OAuth2Client implements AuthClient {
|
|
|
333
326
|
* @return {Promise<void>}
|
|
334
327
|
*/
|
|
335
328
|
public setCredentials(credentials?: Credentials): Promise<void> {
|
|
336
|
-
return this.
|
|
329
|
+
return this.localCredentials.setCredentials(credentials)
|
|
337
330
|
}
|
|
338
331
|
|
|
339
332
|
/**
|
|
340
333
|
* getAccessToken return a validate access token
|
|
341
334
|
*/
|
|
342
335
|
public async getAccessToken(): Promise<string> {
|
|
343
|
-
const credentials: Credentials = await this.
|
|
336
|
+
const credentials: Credentials = await this.getCredentials()
|
|
344
337
|
if (credentials?.access_token) {
|
|
345
|
-
return Promise.resolve(credentials.access_token)
|
|
338
|
+
return Promise.resolve(credentials.access_token)
|
|
346
339
|
}
|
|
347
|
-
|
|
340
|
+
const respErr: ResponseError = { error: ErrorType.UNAUTHENTICATED }
|
|
341
|
+
return Promise.reject(respErr)
|
|
348
342
|
}
|
|
349
343
|
|
|
350
344
|
/**
|
|
@@ -357,72 +351,112 @@ export class OAuth2Client implements AuthClient {
|
|
|
357
351
|
options?: AuthClientRequestOptions,
|
|
358
352
|
): Promise<T> {
|
|
359
353
|
if (!options) {
|
|
360
|
-
options = {}
|
|
354
|
+
options = {}
|
|
361
355
|
}
|
|
362
|
-
const retry: number = this.
|
|
363
|
-
options.headers = options.headers || {}
|
|
364
|
-
if (this.
|
|
356
|
+
const retry: number = this.formatRetry(options.retry, this.retry)
|
|
357
|
+
options.headers = options.headers || {}
|
|
358
|
+
if (this.headers) {
|
|
365
359
|
options.headers = {
|
|
366
|
-
...this.
|
|
360
|
+
...this.headers,
|
|
367
361
|
...options.headers,
|
|
368
|
-
}
|
|
362
|
+
}
|
|
369
363
|
}
|
|
370
364
|
if (!options.headers[RequestIdHeaderName]) {
|
|
371
|
-
options.headers[RequestIdHeaderName] = generateRequestId()
|
|
365
|
+
options.headers[RequestIdHeaderName] = generateRequestId()
|
|
372
366
|
}
|
|
373
367
|
if (!options.headers[DeviceIdHeaderName]) {
|
|
374
|
-
const deviceId = await this.
|
|
375
|
-
options.headers[DeviceIdHeaderName] = deviceId
|
|
368
|
+
const deviceId = await this.getDeviceId()
|
|
369
|
+
options.headers[DeviceIdHeaderName] = deviceId
|
|
376
370
|
}
|
|
377
371
|
if (options?.withCredentials) {
|
|
378
|
-
const credentials = await this.
|
|
372
|
+
const credentials = await this.getCredentials()
|
|
379
373
|
if (credentials) {
|
|
380
|
-
if (this.
|
|
374
|
+
if (this.tokenInURL) {
|
|
381
375
|
if (url.indexOf('?') < 0) {
|
|
382
|
-
url += '?'
|
|
376
|
+
url += '?'
|
|
383
377
|
}
|
|
384
|
-
url +=
|
|
378
|
+
url += `access_token=${credentials.access_token}`
|
|
385
379
|
} else {
|
|
386
|
-
options.headers
|
|
387
|
-
credentials.token_type + ' ' + credentials.access_token;
|
|
380
|
+
options.headers.Authorization = `${credentials.token_type} ${credentials.access_token}`
|
|
388
381
|
}
|
|
389
382
|
}
|
|
390
383
|
} else {
|
|
391
|
-
if (this.
|
|
392
|
-
url += url.indexOf('?') < 0 ? '?' : '&'
|
|
393
|
-
url +=
|
|
384
|
+
if (this.clientId && url.indexOf('client_id') < 0) {
|
|
385
|
+
url += url.indexOf('?') < 0 ? '?' : '&'
|
|
386
|
+
url += `client_id=${this.clientId}`
|
|
394
387
|
}
|
|
395
388
|
}
|
|
396
389
|
if (url.startsWith('/')) {
|
|
397
|
-
url = this.
|
|
390
|
+
url = this.apiOrigin + url
|
|
398
391
|
}
|
|
399
|
-
let response: T | null = null
|
|
400
|
-
const maxRequestTimes: number = retry + 1
|
|
392
|
+
let response: T | null = null
|
|
393
|
+
const maxRequestTimes: number = retry + 1
|
|
401
394
|
for (
|
|
402
395
|
let requestTime = 0;
|
|
403
396
|
requestTime < maxRequestTimes;
|
|
404
397
|
requestTime++
|
|
405
398
|
) {
|
|
406
399
|
try {
|
|
407
|
-
response = await this.
|
|
408
|
-
break
|
|
400
|
+
response = await this.baseRequest<T>(url, options)
|
|
401
|
+
break
|
|
409
402
|
} catch (responseError) {
|
|
410
403
|
if (options.withCredentials && responseError && responseError.error === ErrorType.UNAUTHENTICATED) {
|
|
411
|
-
await this.setCredentials(null)
|
|
412
|
-
return Promise.reject(responseError)
|
|
404
|
+
await this.setCredentials(null)
|
|
405
|
+
return Promise.reject(responseError)
|
|
413
406
|
}
|
|
414
|
-
|
|
407
|
+
|
|
415
408
|
if (
|
|
416
|
-
requestTime === retry
|
|
417
|
-
!responseError
|
|
418
|
-
responseError.error !== 'unreachable'
|
|
409
|
+
requestTime === retry
|
|
410
|
+
|| !responseError
|
|
411
|
+
|| responseError.error !== 'unreachable'
|
|
419
412
|
) {
|
|
420
|
-
return Promise.reject(responseError)
|
|
413
|
+
return Promise.reject(responseError)
|
|
421
414
|
}
|
|
422
415
|
}
|
|
423
|
-
await this.
|
|
416
|
+
await this.sleep(OAuth2Client.retryInterval)
|
|
417
|
+
}
|
|
418
|
+
return response
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get credentials.
|
|
424
|
+
*/
|
|
425
|
+
public async getCredentials(): Promise<Credentials | null> {
|
|
426
|
+
let credentials: Credentials = await this.localCredentials.getCredentials()
|
|
427
|
+
if (isCredentialsExpired(credentials)) {
|
|
428
|
+
if (credentials && credentials.scope === 'anonymous') {
|
|
429
|
+
credentials = await this.anonymousSignIn(credentials)
|
|
430
|
+
} else {
|
|
431
|
+
credentials = await this.refreshToken(credentials)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return credentials
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
public getCredentialsSync(): Credentials | null {
|
|
438
|
+
const credentials: Credentials = this.localCredentials.getStorageCredentialsSync()
|
|
439
|
+
return credentials
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
public getCredentialsAsync(): Promise<Credentials | null> {
|
|
443
|
+
return this.localCredentials.getCredentials()
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
public async getScope(): Promise<string> {
|
|
447
|
+
const credentials: Credentials = await this.localCredentials.getCredentials()
|
|
448
|
+
if (!credentials) {
|
|
449
|
+
return this.unAuthenticatedError('credentials not found')
|
|
450
|
+
}
|
|
451
|
+
return credentials.scope
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
public async getGroups(): Promise<string[]> {
|
|
455
|
+
const credentials: Credentials = await this.localCredentials.getCredentials()
|
|
456
|
+
if (!credentials) {
|
|
457
|
+
return this.unAuthenticatedError('credentials not found')
|
|
424
458
|
}
|
|
425
|
-
return
|
|
459
|
+
return credentials.groups
|
|
426
460
|
}
|
|
427
461
|
|
|
428
462
|
/**
|
|
@@ -430,22 +464,22 @@ export class OAuth2Client implements AuthClient {
|
|
|
430
464
|
* @param {number} retry
|
|
431
465
|
* @return {number}
|
|
432
466
|
*/
|
|
433
|
-
private
|
|
434
|
-
let responseError: ResponseError | null = null
|
|
467
|
+
private checkRetry(retry: number): number {
|
|
468
|
+
let responseError: ResponseError | null = null
|
|
435
469
|
if (
|
|
436
|
-
typeof retry !== 'number'
|
|
437
|
-
retry < OAuth2Client.
|
|
438
|
-
retry > OAuth2Client.
|
|
470
|
+
typeof retry !== 'number'
|
|
471
|
+
|| retry < OAuth2Client.minRetry
|
|
472
|
+
|| retry > OAuth2Client.maxRetry
|
|
439
473
|
) {
|
|
440
474
|
responseError = {
|
|
441
475
|
error: ErrorType.UNREACHABLE,
|
|
442
476
|
error_description: 'wrong options param: retry',
|
|
443
|
-
}
|
|
477
|
+
}
|
|
444
478
|
}
|
|
445
479
|
if (responseError) {
|
|
446
|
-
throw responseError
|
|
480
|
+
throw responseError
|
|
447
481
|
}
|
|
448
|
-
return retry
|
|
482
|
+
return retry
|
|
449
483
|
}
|
|
450
484
|
|
|
451
485
|
/**
|
|
@@ -454,12 +488,11 @@ export class OAuth2Client implements AuthClient {
|
|
|
454
488
|
* @param {number} defaultVale
|
|
455
489
|
* @return {number}
|
|
456
490
|
*/
|
|
457
|
-
private
|
|
491
|
+
private formatRetry(retry: number, defaultVale: number): number {
|
|
458
492
|
if (typeof retry === 'undefined') {
|
|
459
|
-
return defaultVale
|
|
460
|
-
} else {
|
|
461
|
-
return this._checkRetry(retry);
|
|
493
|
+
return defaultVale
|
|
462
494
|
}
|
|
495
|
+
return this.checkRetry(retry)
|
|
463
496
|
}
|
|
464
497
|
|
|
465
498
|
/**
|
|
@@ -467,12 +500,12 @@ export class OAuth2Client implements AuthClient {
|
|
|
467
500
|
* @param {number} ms
|
|
468
501
|
* @return {Promise<void>}
|
|
469
502
|
*/
|
|
470
|
-
private async
|
|
503
|
+
private async sleep(ms: number): Promise<void> {
|
|
471
504
|
return new Promise<void>((resolve) => {
|
|
472
505
|
setTimeout(() => {
|
|
473
|
-
resolve()
|
|
474
|
-
}, ms)
|
|
475
|
-
})
|
|
506
|
+
resolve()
|
|
507
|
+
}, ms)
|
|
508
|
+
})
|
|
476
509
|
}
|
|
477
510
|
|
|
478
511
|
/**
|
|
@@ -480,25 +513,23 @@ export class OAuth2Client implements AuthClient {
|
|
|
480
513
|
* @param {Credentials} credentials
|
|
481
514
|
* @return {Promise<Credentials>}
|
|
482
515
|
*/
|
|
483
|
-
private async
|
|
484
|
-
return this.
|
|
516
|
+
private async refreshToken(credentials: Credentials): Promise<Credentials> {
|
|
517
|
+
return this.singlePromise.run('_refreshToken', async () => {
|
|
485
518
|
if (!credentials || !credentials.refresh_token) {
|
|
486
|
-
return this.
|
|
519
|
+
return this.unAuthenticatedError('no refresh token found in credentials')
|
|
487
520
|
}
|
|
488
521
|
try {
|
|
489
|
-
const newCredentials: Credentials = await this.
|
|
490
|
-
|
|
491
|
-
);
|
|
492
|
-
await this._localCredentials.setCredentials(newCredentials);
|
|
522
|
+
const newCredentials: Credentials = await this.refreshTokenFunc(credentials.refresh_token,)
|
|
523
|
+
await this.localCredentials.setCredentials(newCredentials)
|
|
493
524
|
return newCredentials
|
|
494
525
|
} catch (error) {
|
|
495
526
|
if (error.error === ErrorType.INVALID_GRANT) {
|
|
496
|
-
await this.
|
|
497
|
-
return this.
|
|
527
|
+
await this.localCredentials.setCredentials(null)
|
|
528
|
+
return this.unAuthenticatedError(error.error_description)
|
|
498
529
|
}
|
|
499
|
-
return Promise.reject(error)
|
|
530
|
+
return Promise.reject(error)
|
|
500
531
|
}
|
|
501
|
-
})
|
|
532
|
+
})
|
|
502
533
|
}
|
|
503
534
|
|
|
504
535
|
/**
|
|
@@ -506,29 +537,29 @@ export class OAuth2Client implements AuthClient {
|
|
|
506
537
|
* @param {Credentials} credentials
|
|
507
538
|
* @return {Promise<Credentials>}
|
|
508
539
|
*/
|
|
509
|
-
private async
|
|
510
|
-
return this.
|
|
540
|
+
private async anonymousSignIn(credentials: Credentials): Promise<Credentials> {
|
|
541
|
+
return this.singlePromise.run('_anonymous', async () => {
|
|
511
542
|
if (!credentials || credentials.scope !== 'anonymous') {
|
|
512
|
-
return this.
|
|
543
|
+
return this.unAuthenticatedError('no anonymous in credentials')
|
|
513
544
|
}
|
|
514
545
|
try {
|
|
515
546
|
const newCredentials: Credentials = await this.request('/auth/v1/signin/anonymously', {
|
|
516
547
|
method: 'POST',
|
|
517
548
|
body: {
|
|
518
|
-
client_id: this.
|
|
519
|
-
client_secret: this.
|
|
549
|
+
client_id: this.clientId,
|
|
550
|
+
client_secret: this.clientSecret,
|
|
520
551
|
},
|
|
521
|
-
})
|
|
522
|
-
await this.
|
|
552
|
+
})
|
|
553
|
+
await this.localCredentials.setCredentials(newCredentials)
|
|
523
554
|
return newCredentials
|
|
524
555
|
} catch (error) {
|
|
525
556
|
if (error.error === ErrorType.INVALID_GRANT) {
|
|
526
|
-
await this.
|
|
527
|
-
return this.
|
|
557
|
+
await this.localCredentials.setCredentials(null)
|
|
558
|
+
return this.unAuthenticatedError(error.error_description)
|
|
528
559
|
}
|
|
529
|
-
return Promise.reject(error)
|
|
560
|
+
return Promise.reject(error)
|
|
530
561
|
}
|
|
531
|
-
})
|
|
562
|
+
})
|
|
532
563
|
}
|
|
533
564
|
|
|
534
565
|
/**
|
|
@@ -536,92 +567,48 @@ export class OAuth2Client implements AuthClient {
|
|
|
536
567
|
* @param {string} refreshToken
|
|
537
568
|
* @return {Promise<Credentials>}
|
|
538
569
|
*/
|
|
539
|
-
private
|
|
540
|
-
refreshToken?: string,
|
|
541
|
-
): Promise<Credentials> {
|
|
570
|
+
private defaultRefreshTokenFunc(refreshToken?: string,): Promise<Credentials> {
|
|
542
571
|
if (refreshToken === undefined || refreshToken === '') {
|
|
543
|
-
return this.
|
|
572
|
+
return this.unAuthenticatedError('refresh token not found')
|
|
544
573
|
}
|
|
545
574
|
return this.request('/auth/v1/token', {
|
|
546
575
|
method: 'POST',
|
|
547
576
|
body: {
|
|
548
|
-
client_id: this.
|
|
549
|
-
client_secret: this.
|
|
577
|
+
client_id: this.clientId,
|
|
578
|
+
client_secret: this.clientSecret,
|
|
550
579
|
grant_type: 'refresh_token',
|
|
551
580
|
refresh_token: refreshToken,
|
|
552
581
|
},
|
|
553
|
-
})
|
|
582
|
+
})
|
|
554
583
|
}
|
|
555
584
|
|
|
556
|
-
/**
|
|
557
|
-
* Get credentials.
|
|
558
|
-
*/
|
|
559
|
-
public async _getCredentials(): Promise<Credentials | null> {
|
|
560
|
-
let credentials: Credentials = await this._localCredentials.getCredentials();
|
|
561
|
-
if (isCredentialsExpired(credentials)) {
|
|
562
|
-
if (credentials && credentials.scope === 'anonymous') {
|
|
563
|
-
credentials = await this._anonymousSignIn(credentials)
|
|
564
|
-
} else {
|
|
565
|
-
credentials = await this._refreshToken(credentials);
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return credentials;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
public getCredentialsSync(): Credentials | null {
|
|
572
|
-
const credentials: Credentials = this._localCredentials._getStorageCredentialsSync();
|
|
573
|
-
return credentials
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
public getCredentialsAsync(): Promise<Credentials | null> {
|
|
577
|
-
return this._localCredentials.getCredentials()
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
public async getScope(): Promise<string> {
|
|
581
|
-
let credentials: Credentials = await this._localCredentials.getCredentials();
|
|
582
|
-
if (credentials == null) {
|
|
583
|
-
return this._unAuthenticatedError("credentials not found")
|
|
584
|
-
}
|
|
585
|
-
return credentials.scope;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
public async getGroups(): Promise<string[]> {
|
|
589
|
-
let credentials: Credentials = await this._localCredentials.getCredentials();
|
|
590
|
-
if (credentials == null) {
|
|
591
|
-
return this._unAuthenticatedError("credentials not found")
|
|
592
|
-
}
|
|
593
|
-
return credentials.groups;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
|
|
597
585
|
/**
|
|
598
586
|
* Get deviceId
|
|
599
587
|
*/
|
|
600
|
-
private async
|
|
601
|
-
if (this.
|
|
602
|
-
return this.
|
|
588
|
+
private async getDeviceId(): Promise<string> {
|
|
589
|
+
if (this.deviceID) {
|
|
590
|
+
return this.deviceID
|
|
603
591
|
}
|
|
604
|
-
let deviceId: string = await this.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
deviceId
|
|
609
|
-
|
|
610
|
-
deviceId = uuidv4();
|
|
611
|
-
await this._storage.setItem(DeviceIdSectionName, deviceId);
|
|
592
|
+
let deviceId: string = await this.storage.getItem(DeviceIdSectionName,)
|
|
593
|
+
if (!(typeof deviceId === 'string'
|
|
594
|
+
&& deviceId.length >= 16
|
|
595
|
+
&& deviceId.length <= 48)) {
|
|
596
|
+
deviceId = uuidv4()
|
|
597
|
+
await this.storage.setItem(DeviceIdSectionName, deviceId)
|
|
612
598
|
}
|
|
613
|
-
this.
|
|
614
|
-
return deviceId
|
|
599
|
+
this.deviceID = deviceId
|
|
600
|
+
return deviceId
|
|
615
601
|
}
|
|
616
602
|
/**
|
|
617
603
|
* Generate unAuthenticated error.
|
|
618
604
|
* @param {string} err
|
|
619
605
|
* @return {Promise<T>}
|
|
620
606
|
*/
|
|
621
|
-
private
|
|
622
|
-
|
|
607
|
+
private unAuthenticatedError<T>(err?: string): Promise<T> {
|
|
608
|
+
const respErr: ResponseError = {
|
|
623
609
|
error: ErrorType.UNAUTHENTICATED,
|
|
624
610
|
error_description: err,
|
|
625
|
-
}
|
|
611
|
+
}
|
|
612
|
+
return Promise.reject(respErr)
|
|
626
613
|
}
|
|
627
614
|
}
|