@firebase/app-check 0.8.8 → 0.8.9
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/esm/index.esm2017.js +1 -1
- package/dist/index.cjs.js +639 -809
- package/dist/index.cjs.js.map +1 -1
- package/package.json +8 -7
- package/dist/esm/index.esm.js +0 -1845
- package/dist/esm/index.esm.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var app = require('@firebase/app');
|
|
6
6
|
var component = require('@firebase/component');
|
|
7
|
-
var tslib = require('tslib');
|
|
8
7
|
var util = require('@firebase/util');
|
|
9
8
|
var logger$1 = require('@firebase/logger');
|
|
10
9
|
|
|
@@ -24,12 +23,12 @@ var logger$1 = require('@firebase/logger');
|
|
|
24
23
|
* See the License for the specific language governing permissions and
|
|
25
24
|
* limitations under the License.
|
|
26
25
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const APP_CHECK_STATES = new Map();
|
|
27
|
+
const DEFAULT_STATE = {
|
|
29
28
|
activated: false,
|
|
30
29
|
tokenObservers: []
|
|
31
30
|
};
|
|
32
|
-
|
|
31
|
+
const DEBUG_STATE = {
|
|
33
32
|
initialized: false,
|
|
34
33
|
enabled: false
|
|
35
34
|
};
|
|
@@ -37,7 +36,7 @@ var DEBUG_STATE = {
|
|
|
37
36
|
* Gets a reference to the state object.
|
|
38
37
|
*/
|
|
39
38
|
function getStateReference(app) {
|
|
40
|
-
return APP_CHECK_STATES.get(app) ||
|
|
39
|
+
return APP_CHECK_STATES.get(app) || Object.assign({}, DEFAULT_STATE);
|
|
41
40
|
}
|
|
42
41
|
/**
|
|
43
42
|
* Set once on initialization. The map should hold the same reference to the
|
|
@@ -67,11 +66,11 @@ function getDebugState() {
|
|
|
67
66
|
* See the License for the specific language governing permissions and
|
|
68
67
|
* limitations under the License.
|
|
69
68
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
const BASE_ENDPOINT = 'https://content-firebaseappcheck.googleapis.com/v1';
|
|
70
|
+
const EXCHANGE_RECAPTCHA_TOKEN_METHOD = 'exchangeRecaptchaV3Token';
|
|
71
|
+
const EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD = 'exchangeRecaptchaEnterpriseToken';
|
|
72
|
+
const EXCHANGE_DEBUG_TOKEN_METHOD = 'exchangeDebugToken';
|
|
73
|
+
const TOKEN_REFRESH_TIME = {
|
|
75
74
|
/**
|
|
76
75
|
* The offset time before token natural expiration to run the refresh.
|
|
77
76
|
* This is currently 5 minutes.
|
|
@@ -90,7 +89,7 @@ var TOKEN_REFRESH_TIME = {
|
|
|
90
89
|
/**
|
|
91
90
|
* One day in millis, for certain error code backoffs.
|
|
92
91
|
*/
|
|
93
|
-
|
|
92
|
+
const ONE_DAY = 24 * 60 * 60 * 1000;
|
|
94
93
|
|
|
95
94
|
/**
|
|
96
95
|
* @license
|
|
@@ -114,8 +113,8 @@ var ONE_DAY = 24 * 60 * 60 * 1000;
|
|
|
114
113
|
*/
|
|
115
114
|
// TODO: move it to @firebase/util?
|
|
116
115
|
// TODO: allow to config whether refresh should happen in the background
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
class Refresher {
|
|
117
|
+
constructor(operation, retryPolicy, getWaitDuration, lowerBound, upperBound) {
|
|
119
118
|
this.operation = operation;
|
|
120
119
|
this.retryPolicy = retryPolicy;
|
|
121
120
|
this.getWaitDuration = getWaitDuration;
|
|
@@ -127,79 +126,59 @@ var Refresher = /** @class */ (function () {
|
|
|
127
126
|
throw new Error('Proactive refresh lower bound greater than upper bound!');
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
|
-
|
|
129
|
+
start() {
|
|
131
130
|
this.nextErrorWaitInterval = this.lowerBound;
|
|
132
|
-
this.process(true).catch(
|
|
131
|
+
this.process(true).catch(() => {
|
|
133
132
|
/* we don't care about the result */
|
|
134
133
|
});
|
|
135
|
-
}
|
|
136
|
-
|
|
134
|
+
}
|
|
135
|
+
stop() {
|
|
137
136
|
if (this.pending) {
|
|
138
137
|
this.pending.reject('cancelled');
|
|
139
138
|
this.pending = null;
|
|
140
139
|
}
|
|
141
|
-
}
|
|
142
|
-
|
|
140
|
+
}
|
|
141
|
+
isRunning() {
|
|
143
142
|
return !!this.pending;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
this.stop();
|
|
152
|
-
_a.label = 1;
|
|
153
|
-
case 1:
|
|
154
|
-
_a.trys.push([1, 6, , 7]);
|
|
155
|
-
this.pending = new util.Deferred();
|
|
156
|
-
this.pending.promise.catch(function (_e) {
|
|
157
|
-
/* ignore */
|
|
158
|
-
});
|
|
159
|
-
return [4 /*yield*/, sleep(this.getNextRun(hasSucceeded))];
|
|
160
|
-
case 2:
|
|
161
|
-
_a.sent();
|
|
162
|
-
// Why do we resolve a promise, then immediate wait for it?
|
|
163
|
-
// We do it to make the promise chain cancellable.
|
|
164
|
-
// We can call stop() which rejects the promise before the following line execute, which makes
|
|
165
|
-
// the code jump to the catch block.
|
|
166
|
-
// TODO: unit test this
|
|
167
|
-
this.pending.resolve();
|
|
168
|
-
return [4 /*yield*/, this.pending.promise];
|
|
169
|
-
case 3:
|
|
170
|
-
_a.sent();
|
|
171
|
-
this.pending = new util.Deferred();
|
|
172
|
-
this.pending.promise.catch(function (_e) {
|
|
173
|
-
/* ignore */
|
|
174
|
-
});
|
|
175
|
-
return [4 /*yield*/, this.operation()];
|
|
176
|
-
case 4:
|
|
177
|
-
_a.sent();
|
|
178
|
-
this.pending.resolve();
|
|
179
|
-
return [4 /*yield*/, this.pending.promise];
|
|
180
|
-
case 5:
|
|
181
|
-
_a.sent();
|
|
182
|
-
this.process(true).catch(function () {
|
|
183
|
-
/* we don't care about the result */
|
|
184
|
-
});
|
|
185
|
-
return [3 /*break*/, 7];
|
|
186
|
-
case 6:
|
|
187
|
-
error_1 = _a.sent();
|
|
188
|
-
if (this.retryPolicy(error_1)) {
|
|
189
|
-
this.process(false).catch(function () {
|
|
190
|
-
/* we don't care about the result */
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
this.stop();
|
|
195
|
-
}
|
|
196
|
-
return [3 /*break*/, 7];
|
|
197
|
-
case 7: return [2 /*return*/];
|
|
198
|
-
}
|
|
143
|
+
}
|
|
144
|
+
async process(hasSucceeded) {
|
|
145
|
+
this.stop();
|
|
146
|
+
try {
|
|
147
|
+
this.pending = new util.Deferred();
|
|
148
|
+
this.pending.promise.catch(_e => {
|
|
149
|
+
/* ignore */
|
|
199
150
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
151
|
+
await sleep(this.getNextRun(hasSucceeded));
|
|
152
|
+
// Why do we resolve a promise, then immediate wait for it?
|
|
153
|
+
// We do it to make the promise chain cancellable.
|
|
154
|
+
// We can call stop() which rejects the promise before the following line execute, which makes
|
|
155
|
+
// the code jump to the catch block.
|
|
156
|
+
// TODO: unit test this
|
|
157
|
+
this.pending.resolve();
|
|
158
|
+
await this.pending.promise;
|
|
159
|
+
this.pending = new util.Deferred();
|
|
160
|
+
this.pending.promise.catch(_e => {
|
|
161
|
+
/* ignore */
|
|
162
|
+
});
|
|
163
|
+
await this.operation();
|
|
164
|
+
this.pending.resolve();
|
|
165
|
+
await this.pending.promise;
|
|
166
|
+
this.process(true).catch(() => {
|
|
167
|
+
/* we don't care about the result */
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
if (this.retryPolicy(error)) {
|
|
172
|
+
this.process(false).catch(() => {
|
|
173
|
+
/* we don't care about the result */
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
this.stop();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
getNextRun(hasSucceeded) {
|
|
203
182
|
if (hasSucceeded) {
|
|
204
183
|
// If last operation succeeded, reset next error wait interval and return
|
|
205
184
|
// the default wait duration.
|
|
@@ -209,7 +188,7 @@ var Refresher = /** @class */ (function () {
|
|
|
209
188
|
}
|
|
210
189
|
else {
|
|
211
190
|
// Get next error wait interval.
|
|
212
|
-
|
|
191
|
+
const currentErrorWaitInterval = this.nextErrorWaitInterval;
|
|
213
192
|
// Double interval for next consecutive error.
|
|
214
193
|
this.nextErrorWaitInterval *= 2;
|
|
215
194
|
// Make sure next wait interval does not exceed the maximum upper bound.
|
|
@@ -218,11 +197,10 @@ var Refresher = /** @class */ (function () {
|
|
|
218
197
|
}
|
|
219
198
|
return currentErrorWaitInterval;
|
|
220
199
|
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
}());
|
|
200
|
+
}
|
|
201
|
+
}
|
|
224
202
|
function sleep(ms) {
|
|
225
|
-
return new Promise(
|
|
203
|
+
return new Promise(resolve => {
|
|
226
204
|
setTimeout(resolve, ms);
|
|
227
205
|
});
|
|
228
206
|
}
|
|
@@ -243,26 +221,25 @@ function sleep(ms) {
|
|
|
243
221
|
* See the License for the specific language governing permissions and
|
|
244
222
|
* limitations under the License.
|
|
245
223
|
*/
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
_a["already-initialized" /* AppCheckError.ALREADY_INITIALIZED */] = 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
|
|
224
|
+
const ERRORS = {
|
|
225
|
+
["already-initialized" /* AppCheckError.ALREADY_INITIALIZED */]: 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
|
|
249
226
|
'different options. To avoid this error, call initializeAppCheck() with the ' +
|
|
250
227
|
'same options as when it was originally called. This will return the ' +
|
|
251
228
|
'already initialized instance.',
|
|
252
|
-
|
|
229
|
+
["use-before-activation" /* AppCheckError.USE_BEFORE_ACTIVATION */]: 'App Check is being used before initializeAppCheck() is called for FirebaseApp {$appName}. ' +
|
|
253
230
|
'Call initializeAppCheck() before instantiating other Firebase services.',
|
|
254
|
-
|
|
231
|
+
["fetch-network-error" /* AppCheckError.FETCH_NETWORK_ERROR */]: 'Fetch failed to connect to a network. Check Internet connection. ' +
|
|
255
232
|
'Original error: {$originalErrorMessage}.',
|
|
256
|
-
|
|
233
|
+
["fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */]: 'Fetch client could not parse response.' +
|
|
257
234
|
' Original error: {$originalErrorMessage}.',
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
235
|
+
["fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */]: 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.',
|
|
236
|
+
["storage-open" /* AppCheckError.STORAGE_OPEN */]: 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
|
|
237
|
+
["storage-get" /* AppCheckError.STORAGE_GET */]: 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
|
|
238
|
+
["storage-set" /* AppCheckError.STORAGE_WRITE */]: 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
|
|
239
|
+
["recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */]: 'ReCAPTCHA error.',
|
|
240
|
+
["throttled" /* AppCheckError.THROTTLED */]: `Requests throttled due to {$httpStatus} error. Attempts allowed again after {$time}`
|
|
241
|
+
};
|
|
242
|
+
const ERROR_FACTORY = new util.ErrorFactory('appCheck', 'AppCheck', ERRORS);
|
|
266
243
|
|
|
267
244
|
/**
|
|
268
245
|
* @license
|
|
@@ -280,9 +257,8 @@ var ERROR_FACTORY = new util.ErrorFactory('appCheck', 'AppCheck', ERRORS);
|
|
|
280
257
|
* See the License for the specific language governing permissions and
|
|
281
258
|
* limitations under the License.
|
|
282
259
|
*/
|
|
283
|
-
function getRecaptcha(isEnterprise) {
|
|
260
|
+
function getRecaptcha(isEnterprise = false) {
|
|
284
261
|
var _a;
|
|
285
|
-
if (isEnterprise === void 0) { isEnterprise = false; }
|
|
286
262
|
if (isEnterprise) {
|
|
287
263
|
return (_a = self.grecaptcha) === null || _a === void 0 ? void 0 : _a.enterprise;
|
|
288
264
|
}
|
|
@@ -296,12 +272,12 @@ function ensureActivated(app) {
|
|
|
296
272
|
}
|
|
297
273
|
}
|
|
298
274
|
function getDurationString(durationInMillis) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
275
|
+
const totalSeconds = Math.round(durationInMillis / 1000);
|
|
276
|
+
const days = Math.floor(totalSeconds / (3600 * 24));
|
|
277
|
+
const hours = Math.floor((totalSeconds - days * 3600 * 24) / 3600);
|
|
278
|
+
const minutes = Math.floor((totalSeconds - days * 3600 * 24 - hours * 3600) / 60);
|
|
279
|
+
const seconds = totalSeconds - days * 3600 * 24 - hours * 3600 - minutes * 60;
|
|
280
|
+
let result = '';
|
|
305
281
|
if (days) {
|
|
306
282
|
result += pad(days) + 'd:';
|
|
307
283
|
}
|
|
@@ -334,105 +310,88 @@ function pad(value) {
|
|
|
334
310
|
* See the License for the specific language governing permissions and
|
|
335
311
|
* limitations under the License.
|
|
336
312
|
*/
|
|
337
|
-
function exchangeToken(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
headers = {
|
|
345
|
-
'Content-Type': 'application/json'
|
|
346
|
-
};
|
|
347
|
-
heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
348
|
-
optional: true
|
|
349
|
-
});
|
|
350
|
-
if (!heartbeatService) return [3 /*break*/, 2];
|
|
351
|
-
return [4 /*yield*/, heartbeatService.getHeartbeatsHeader()];
|
|
352
|
-
case 1:
|
|
353
|
-
heartbeatsHeader = _b.sent();
|
|
354
|
-
if (heartbeatsHeader) {
|
|
355
|
-
headers['X-Firebase-Client'] = heartbeatsHeader;
|
|
356
|
-
}
|
|
357
|
-
_b.label = 2;
|
|
358
|
-
case 2:
|
|
359
|
-
options = {
|
|
360
|
-
method: 'POST',
|
|
361
|
-
body: JSON.stringify(body),
|
|
362
|
-
headers: headers
|
|
363
|
-
};
|
|
364
|
-
_b.label = 3;
|
|
365
|
-
case 3:
|
|
366
|
-
_b.trys.push([3, 5, , 6]);
|
|
367
|
-
return [4 /*yield*/, fetch(url, options)];
|
|
368
|
-
case 4:
|
|
369
|
-
response = _b.sent();
|
|
370
|
-
return [3 /*break*/, 6];
|
|
371
|
-
case 5:
|
|
372
|
-
originalError_1 = _b.sent();
|
|
373
|
-
throw ERROR_FACTORY.create("fetch-network-error" /* AppCheckError.FETCH_NETWORK_ERROR */, {
|
|
374
|
-
originalErrorMessage: originalError_1 === null || originalError_1 === void 0 ? void 0 : originalError_1.message
|
|
375
|
-
});
|
|
376
|
-
case 6:
|
|
377
|
-
if (response.status !== 200) {
|
|
378
|
-
throw ERROR_FACTORY.create("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */, {
|
|
379
|
-
httpStatus: response.status
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
_b.label = 7;
|
|
383
|
-
case 7:
|
|
384
|
-
_b.trys.push([7, 9, , 10]);
|
|
385
|
-
return [4 /*yield*/, response.json()];
|
|
386
|
-
case 8:
|
|
387
|
-
// JSON parsing throws SyntaxError if the response body isn't a JSON string.
|
|
388
|
-
responseBody = _b.sent();
|
|
389
|
-
return [3 /*break*/, 10];
|
|
390
|
-
case 9:
|
|
391
|
-
originalError_2 = _b.sent();
|
|
392
|
-
throw ERROR_FACTORY.create("fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */, {
|
|
393
|
-
originalErrorMessage: originalError_2 === null || originalError_2 === void 0 ? void 0 : originalError_2.message
|
|
394
|
-
});
|
|
395
|
-
case 10:
|
|
396
|
-
match = responseBody.ttl.match(/^([\d.]+)(s)$/);
|
|
397
|
-
if (!match || !match[2] || isNaN(Number(match[1]))) {
|
|
398
|
-
throw ERROR_FACTORY.create("fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */, {
|
|
399
|
-
originalErrorMessage: "ttl field (timeToLive) is not in standard Protobuf Duration " +
|
|
400
|
-
"format: ".concat(responseBody.ttl)
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
timeToLiveAsNumber = Number(match[1]) * 1000;
|
|
404
|
-
now = Date.now();
|
|
405
|
-
return [2 /*return*/, {
|
|
406
|
-
token: responseBody.token,
|
|
407
|
-
expireTimeMillis: now + timeToLiveAsNumber,
|
|
408
|
-
issuedAtTimeMillis: now
|
|
409
|
-
}];
|
|
410
|
-
}
|
|
411
|
-
});
|
|
313
|
+
async function exchangeToken({ url, body }, heartbeatServiceProvider) {
|
|
314
|
+
const headers = {
|
|
315
|
+
'Content-Type': 'application/json'
|
|
316
|
+
};
|
|
317
|
+
// If heartbeat service exists, add heartbeat header string to the header.
|
|
318
|
+
const heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
319
|
+
optional: true
|
|
412
320
|
});
|
|
321
|
+
if (heartbeatService) {
|
|
322
|
+
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
|
|
323
|
+
if (heartbeatsHeader) {
|
|
324
|
+
headers['X-Firebase-Client'] = heartbeatsHeader;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const options = {
|
|
328
|
+
method: 'POST',
|
|
329
|
+
body: JSON.stringify(body),
|
|
330
|
+
headers
|
|
331
|
+
};
|
|
332
|
+
let response;
|
|
333
|
+
try {
|
|
334
|
+
response = await fetch(url, options);
|
|
335
|
+
}
|
|
336
|
+
catch (originalError) {
|
|
337
|
+
throw ERROR_FACTORY.create("fetch-network-error" /* AppCheckError.FETCH_NETWORK_ERROR */, {
|
|
338
|
+
originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (response.status !== 200) {
|
|
342
|
+
throw ERROR_FACTORY.create("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */, {
|
|
343
|
+
httpStatus: response.status
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
let responseBody;
|
|
347
|
+
try {
|
|
348
|
+
// JSON parsing throws SyntaxError if the response body isn't a JSON string.
|
|
349
|
+
responseBody = await response.json();
|
|
350
|
+
}
|
|
351
|
+
catch (originalError) {
|
|
352
|
+
throw ERROR_FACTORY.create("fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */, {
|
|
353
|
+
originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
// Protobuf duration format.
|
|
357
|
+
// https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Duration
|
|
358
|
+
const match = responseBody.ttl.match(/^([\d.]+)(s)$/);
|
|
359
|
+
if (!match || !match[2] || isNaN(Number(match[1]))) {
|
|
360
|
+
throw ERROR_FACTORY.create("fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */, {
|
|
361
|
+
originalErrorMessage: `ttl field (timeToLive) is not in standard Protobuf Duration ` +
|
|
362
|
+
`format: ${responseBody.ttl}`
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
const timeToLiveAsNumber = Number(match[1]) * 1000;
|
|
366
|
+
const now = Date.now();
|
|
367
|
+
return {
|
|
368
|
+
token: responseBody.token,
|
|
369
|
+
expireTimeMillis: now + timeToLiveAsNumber,
|
|
370
|
+
issuedAtTimeMillis: now
|
|
371
|
+
};
|
|
413
372
|
}
|
|
414
373
|
function getExchangeRecaptchaV3TokenRequest(app, reCAPTCHAToken) {
|
|
415
|
-
|
|
374
|
+
const { projectId, appId, apiKey } = app.options;
|
|
416
375
|
return {
|
|
417
|
-
url:
|
|
376
|
+
url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_TOKEN_METHOD}?key=${apiKey}`,
|
|
418
377
|
body: {
|
|
419
378
|
'recaptcha_v3_token': reCAPTCHAToken
|
|
420
379
|
}
|
|
421
380
|
};
|
|
422
381
|
}
|
|
423
382
|
function getExchangeRecaptchaEnterpriseTokenRequest(app, reCAPTCHAToken) {
|
|
424
|
-
|
|
383
|
+
const { projectId, appId, apiKey } = app.options;
|
|
425
384
|
return {
|
|
426
|
-
url:
|
|
385
|
+
url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD}?key=${apiKey}`,
|
|
427
386
|
body: {
|
|
428
387
|
'recaptcha_enterprise_token': reCAPTCHAToken
|
|
429
388
|
}
|
|
430
389
|
};
|
|
431
390
|
}
|
|
432
391
|
function getExchangeDebugTokenRequest(app, debugToken) {
|
|
433
|
-
|
|
392
|
+
const { projectId, appId, apiKey } = app.options;
|
|
434
393
|
return {
|
|
435
|
-
url:
|
|
394
|
+
url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_DEBUG_TOKEN_METHOD}?key=${apiKey}`,
|
|
436
395
|
body: {
|
|
437
396
|
// eslint-disable-next-line
|
|
438
397
|
debug_token: debugToken
|
|
@@ -456,29 +415,29 @@ function getExchangeDebugTokenRequest(app, debugToken) {
|
|
|
456
415
|
* See the License for the specific language governing permissions and
|
|
457
416
|
* limitations under the License.
|
|
458
417
|
*/
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
418
|
+
const DB_NAME = 'firebase-app-check-database';
|
|
419
|
+
const DB_VERSION = 1;
|
|
420
|
+
const STORE_NAME = 'firebase-app-check-store';
|
|
421
|
+
const DEBUG_TOKEN_KEY = 'debug-token';
|
|
422
|
+
let dbPromise = null;
|
|
464
423
|
function getDBPromise() {
|
|
465
424
|
if (dbPromise) {
|
|
466
425
|
return dbPromise;
|
|
467
426
|
}
|
|
468
|
-
dbPromise = new Promise(
|
|
427
|
+
dbPromise = new Promise((resolve, reject) => {
|
|
469
428
|
try {
|
|
470
|
-
|
|
471
|
-
request.onsuccess =
|
|
429
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
430
|
+
request.onsuccess = event => {
|
|
472
431
|
resolve(event.target.result);
|
|
473
432
|
};
|
|
474
|
-
request.onerror =
|
|
433
|
+
request.onerror = event => {
|
|
475
434
|
var _a;
|
|
476
435
|
reject(ERROR_FACTORY.create("storage-open" /* AppCheckError.STORAGE_OPEN */, {
|
|
477
436
|
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
|
|
478
437
|
}));
|
|
479
438
|
};
|
|
480
|
-
request.onupgradeneeded =
|
|
481
|
-
|
|
439
|
+
request.onupgradeneeded = event => {
|
|
440
|
+
const db = event.target.result;
|
|
482
441
|
// We don't use 'break' in this switch statement, the fall-through
|
|
483
442
|
// behavior is what we want, because if there are multiple versions between
|
|
484
443
|
// the old version and the current version, we want ALL the migrations
|
|
@@ -512,69 +471,51 @@ function writeDebugTokenToIndexedDB(token) {
|
|
|
512
471
|
function readDebugTokenFromIndexedDB() {
|
|
513
472
|
return read(DEBUG_TOKEN_KEY);
|
|
514
473
|
}
|
|
515
|
-
function write(key, value) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
transaction.onerror = function (event) {
|
|
534
|
-
var _a;
|
|
535
|
-
reject(ERROR_FACTORY.create("storage-set" /* AppCheckError.STORAGE_WRITE */, {
|
|
536
|
-
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
|
|
537
|
-
}));
|
|
538
|
-
};
|
|
539
|
-
})];
|
|
540
|
-
}
|
|
541
|
-
});
|
|
474
|
+
async function write(key, value) {
|
|
475
|
+
const db = await getDBPromise();
|
|
476
|
+
const transaction = db.transaction(STORE_NAME, 'readwrite');
|
|
477
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
478
|
+
const request = store.put({
|
|
479
|
+
compositeKey: key,
|
|
480
|
+
value
|
|
481
|
+
});
|
|
482
|
+
return new Promise((resolve, reject) => {
|
|
483
|
+
request.onsuccess = _event => {
|
|
484
|
+
resolve();
|
|
485
|
+
};
|
|
486
|
+
transaction.onerror = event => {
|
|
487
|
+
var _a;
|
|
488
|
+
reject(ERROR_FACTORY.create("storage-set" /* AppCheckError.STORAGE_WRITE */, {
|
|
489
|
+
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
|
|
490
|
+
}));
|
|
491
|
+
};
|
|
542
492
|
});
|
|
543
493
|
}
|
|
544
|
-
function read(key) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
request = store.get(key);
|
|
555
|
-
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
556
|
-
request.onsuccess = function (event) {
|
|
557
|
-
var result = event.target.result;
|
|
558
|
-
if (result) {
|
|
559
|
-
resolve(result.value);
|
|
560
|
-
}
|
|
561
|
-
else {
|
|
562
|
-
resolve(undefined);
|
|
563
|
-
}
|
|
564
|
-
};
|
|
565
|
-
transaction.onerror = function (event) {
|
|
566
|
-
var _a;
|
|
567
|
-
reject(ERROR_FACTORY.create("storage-get" /* AppCheckError.STORAGE_GET */, {
|
|
568
|
-
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
|
|
569
|
-
}));
|
|
570
|
-
};
|
|
571
|
-
})];
|
|
494
|
+
async function read(key) {
|
|
495
|
+
const db = await getDBPromise();
|
|
496
|
+
const transaction = db.transaction(STORE_NAME, 'readonly');
|
|
497
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
498
|
+
const request = store.get(key);
|
|
499
|
+
return new Promise((resolve, reject) => {
|
|
500
|
+
request.onsuccess = event => {
|
|
501
|
+
const result = event.target.result;
|
|
502
|
+
if (result) {
|
|
503
|
+
resolve(result.value);
|
|
572
504
|
}
|
|
573
|
-
|
|
505
|
+
else {
|
|
506
|
+
resolve(undefined);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
transaction.onerror = event => {
|
|
510
|
+
var _a;
|
|
511
|
+
reject(ERROR_FACTORY.create("storage-get" /* AppCheckError.STORAGE_GET */, {
|
|
512
|
+
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
|
|
513
|
+
}));
|
|
514
|
+
};
|
|
574
515
|
});
|
|
575
516
|
}
|
|
576
517
|
function computeKey(app) {
|
|
577
|
-
return
|
|
518
|
+
return `${app.options.appId}-${app.name}`;
|
|
578
519
|
}
|
|
579
520
|
|
|
580
521
|
/**
|
|
@@ -593,7 +534,7 @@ function computeKey(app) {
|
|
|
593
534
|
* See the License for the specific language governing permissions and
|
|
594
535
|
* limitations under the License.
|
|
595
536
|
*/
|
|
596
|
-
|
|
537
|
+
const logger = new logger$1.Logger('@firebase/app-check');
|
|
597
538
|
|
|
598
539
|
/**
|
|
599
540
|
* @license
|
|
@@ -614,80 +555,58 @@ var logger = new logger$1.Logger('@firebase/app-check');
|
|
|
614
555
|
/**
|
|
615
556
|
* Always resolves. In case of an error reading from indexeddb, resolve with undefined
|
|
616
557
|
*/
|
|
617
|
-
function readTokenFromStorage(app) {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
token = _a.sent();
|
|
631
|
-
return [3 /*break*/, 4];
|
|
632
|
-
case 3:
|
|
633
|
-
e_1 = _a.sent();
|
|
634
|
-
// swallow the error and return undefined
|
|
635
|
-
logger.warn("Failed to read token from IndexedDB. Error: ".concat(e_1));
|
|
636
|
-
return [3 /*break*/, 4];
|
|
637
|
-
case 4: return [2 /*return*/, token];
|
|
638
|
-
case 5: return [2 /*return*/, undefined];
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
});
|
|
558
|
+
async function readTokenFromStorage(app) {
|
|
559
|
+
if (util.isIndexedDBAvailable()) {
|
|
560
|
+
let token = undefined;
|
|
561
|
+
try {
|
|
562
|
+
token = await readTokenFromIndexedDB(app);
|
|
563
|
+
}
|
|
564
|
+
catch (e) {
|
|
565
|
+
// swallow the error and return undefined
|
|
566
|
+
logger.warn(`Failed to read token from IndexedDB. Error: ${e}`);
|
|
567
|
+
}
|
|
568
|
+
return token;
|
|
569
|
+
}
|
|
570
|
+
return undefined;
|
|
642
571
|
}
|
|
643
572
|
/**
|
|
644
573
|
* Always resolves. In case of an error writing to indexeddb, print a warning and resolve the promise
|
|
645
574
|
*/
|
|
646
575
|
function writeTokenToStorage(app, token) {
|
|
647
576
|
if (util.isIndexedDBAvailable()) {
|
|
648
|
-
return writeTokenToIndexedDB(app, token).catch(
|
|
577
|
+
return writeTokenToIndexedDB(app, token).catch(e => {
|
|
649
578
|
// swallow the error and resolve the promise
|
|
650
|
-
logger.warn(
|
|
579
|
+
logger.warn(`Failed to write token to IndexedDB. Error: ${e}`);
|
|
651
580
|
});
|
|
652
581
|
}
|
|
653
582
|
return Promise.resolve();
|
|
654
583
|
}
|
|
655
|
-
function readOrCreateDebugTokenFromStorage() {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
return logger.warn("Failed to persist debug token to IndexedDB. Error: ".concat(e));
|
|
682
|
-
});
|
|
683
|
-
return [2 /*return*/, newToken];
|
|
684
|
-
}
|
|
685
|
-
else {
|
|
686
|
-
return [2 /*return*/, existingDebugToken];
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
});
|
|
690
|
-
});
|
|
584
|
+
async function readOrCreateDebugTokenFromStorage() {
|
|
585
|
+
/**
|
|
586
|
+
* Theoretically race condition can happen if we read, then write in 2 separate transactions.
|
|
587
|
+
* But it won't happen here, because this function will be called exactly once.
|
|
588
|
+
*/
|
|
589
|
+
let existingDebugToken = undefined;
|
|
590
|
+
try {
|
|
591
|
+
existingDebugToken = await readDebugTokenFromIndexedDB();
|
|
592
|
+
}
|
|
593
|
+
catch (_e) {
|
|
594
|
+
// failed to read from indexeddb. We assume there is no existing debug token, and generate a new one.
|
|
595
|
+
}
|
|
596
|
+
if (!existingDebugToken) {
|
|
597
|
+
// create a new debug token
|
|
598
|
+
const newToken = util.uuidv4();
|
|
599
|
+
// We don't need to block on writing to indexeddb
|
|
600
|
+
// In case persistence failed, a new debug token will be generated every time the page is refreshed.
|
|
601
|
+
// It renders the debug token useless because you have to manually register(whitelist) the new token in the firebase console again and again.
|
|
602
|
+
// If you see this error trying to use debug token, it probably means you are using a browser that doesn't support indexeddb.
|
|
603
|
+
// You should switch to a different browser that supports indexeddb
|
|
604
|
+
writeDebugTokenToIndexedDB(newToken).catch(e => logger.warn(`Failed to persist debug token to IndexedDB. Error: ${e}`));
|
|
605
|
+
return newToken;
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
return existingDebugToken;
|
|
609
|
+
}
|
|
691
610
|
}
|
|
692
611
|
|
|
693
612
|
/**
|
|
@@ -707,27 +626,24 @@ function readOrCreateDebugTokenFromStorage() {
|
|
|
707
626
|
* limitations under the License.
|
|
708
627
|
*/
|
|
709
628
|
function isDebugMode() {
|
|
710
|
-
|
|
629
|
+
const debugState = getDebugState();
|
|
711
630
|
return debugState.enabled;
|
|
712
631
|
}
|
|
713
|
-
function getDebugToken() {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
return
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
});
|
|
726
|
-
});
|
|
632
|
+
async function getDebugToken() {
|
|
633
|
+
const state = getDebugState();
|
|
634
|
+
if (state.enabled && state.token) {
|
|
635
|
+
return state.token.promise;
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
// should not happen!
|
|
639
|
+
throw Error(`
|
|
640
|
+
Can't get debug token in production mode.
|
|
641
|
+
`);
|
|
642
|
+
}
|
|
727
643
|
}
|
|
728
644
|
function initializeDebugMode() {
|
|
729
|
-
|
|
730
|
-
|
|
645
|
+
const globals = util.getGlobal();
|
|
646
|
+
const debugState = getDebugState();
|
|
731
647
|
// Set to true if this function has been called, whether or not
|
|
732
648
|
// it enabled debug mode.
|
|
733
649
|
debugState.initialized = true;
|
|
@@ -736,7 +652,7 @@ function initializeDebugMode() {
|
|
|
736
652
|
return;
|
|
737
653
|
}
|
|
738
654
|
debugState.enabled = true;
|
|
739
|
-
|
|
655
|
+
const deferredToken = new util.Deferred();
|
|
740
656
|
debugState.token = deferredToken;
|
|
741
657
|
if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN === 'string') {
|
|
742
658
|
deferredToken.resolve(globals.FIREBASE_APPCHECK_DEBUG_TOKEN);
|
|
@@ -764,7 +680,7 @@ function initializeDebugMode() {
|
|
|
764
680
|
*/
|
|
765
681
|
// Initial hardcoded value agreed upon across platforms for initial launch.
|
|
766
682
|
// Format left open for possible dynamic error values and other fields in the future.
|
|
767
|
-
|
|
683
|
+
const defaultTokenErrorData = { error: 'UNKNOWN_ERROR' };
|
|
768
684
|
/**
|
|
769
685
|
* Stringify and base64 encode token error data.
|
|
770
686
|
*
|
|
@@ -779,200 +695,179 @@ function formatDummyToken(tokenErrorData) {
|
|
|
779
695
|
* The result will contain an error field if there is any error.
|
|
780
696
|
* In case there is an error, the token field in the result will be populated with a dummy value
|
|
781
697
|
*/
|
|
782
|
-
function getToken$2(appCheck, forceRefresh) {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
case 2:
|
|
698
|
+
async function getToken$2(appCheck, forceRefresh = false) {
|
|
699
|
+
const app = appCheck.app;
|
|
700
|
+
ensureActivated(app);
|
|
701
|
+
const state = getStateReference(app);
|
|
702
|
+
/**
|
|
703
|
+
* First check if there is a token in memory from a previous `getToken()` call.
|
|
704
|
+
*/
|
|
705
|
+
let token = state.token;
|
|
706
|
+
let error = undefined;
|
|
707
|
+
/**
|
|
708
|
+
* If an invalid token was found in memory, clear token from
|
|
709
|
+
* memory and unset the local variable `token`.
|
|
710
|
+
*/
|
|
711
|
+
if (token && !isValid(token)) {
|
|
712
|
+
state.token = undefined;
|
|
713
|
+
token = undefined;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* If there is no valid token in memory, try to load token from indexedDB.
|
|
717
|
+
*/
|
|
718
|
+
if (!token) {
|
|
719
|
+
// cachedTokenPromise contains the token found in IndexedDB or undefined if not found.
|
|
720
|
+
const cachedToken = await state.cachedTokenPromise;
|
|
721
|
+
if (cachedToken) {
|
|
722
|
+
if (isValid(cachedToken)) {
|
|
723
|
+
token = cachedToken;
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
811
726
|
// If there was an invalid token in the indexedDB cache, clear it.
|
|
812
|
-
|
|
813
|
-
case 3:
|
|
814
|
-
// If there was an invalid token in the indexedDB cache, clear it.
|
|
815
|
-
_e.sent();
|
|
816
|
-
_e.label = 4;
|
|
817
|
-
case 4:
|
|
818
|
-
// Return the cached token (from either memory or indexedDB) if it's valid
|
|
819
|
-
if (!forceRefresh && token && isValid(token)) {
|
|
820
|
-
return [2 /*return*/, {
|
|
821
|
-
token: token.token
|
|
822
|
-
}];
|
|
823
|
-
}
|
|
824
|
-
shouldCallListeners = false;
|
|
825
|
-
if (!isDebugMode()) return [3 /*break*/, 9];
|
|
826
|
-
if (!!state.exchangeTokenPromise) return [3 /*break*/, 6];
|
|
827
|
-
_a = state;
|
|
828
|
-
_b = exchangeToken;
|
|
829
|
-
_c = getExchangeDebugTokenRequest;
|
|
830
|
-
_d = [app];
|
|
831
|
-
return [4 /*yield*/, getDebugToken()];
|
|
832
|
-
case 5:
|
|
833
|
-
_a.exchangeTokenPromise = _b.apply(void 0, [_c.apply(void 0, _d.concat([_e.sent()])),
|
|
834
|
-
appCheck.heartbeatServiceProvider]).finally(function () {
|
|
835
|
-
// Clear promise when settled - either resolved or rejected.
|
|
836
|
-
state.exchangeTokenPromise = undefined;
|
|
837
|
-
});
|
|
838
|
-
shouldCallListeners = true;
|
|
839
|
-
_e.label = 6;
|
|
840
|
-
case 6: return [4 /*yield*/, state.exchangeTokenPromise];
|
|
841
|
-
case 7:
|
|
842
|
-
tokenFromDebugExchange = _e.sent();
|
|
843
|
-
// Write debug token to indexedDB.
|
|
844
|
-
return [4 /*yield*/, writeTokenToStorage(app, tokenFromDebugExchange)];
|
|
845
|
-
case 8:
|
|
846
|
-
// Write debug token to indexedDB.
|
|
847
|
-
_e.sent();
|
|
848
|
-
// Write debug token to state.
|
|
849
|
-
state.token = tokenFromDebugExchange;
|
|
850
|
-
return [2 /*return*/, { token: tokenFromDebugExchange.token }];
|
|
851
|
-
case 9:
|
|
852
|
-
_e.trys.push([9, 11, , 12]);
|
|
853
|
-
// Avoid making another call to the exchange endpoint if one is in flight.
|
|
854
|
-
if (!state.exchangeTokenPromise) {
|
|
855
|
-
// state.provider is populated in initializeAppCheck()
|
|
856
|
-
// ensureActivated() at the top of this function checks that
|
|
857
|
-
// initializeAppCheck() has been called.
|
|
858
|
-
state.exchangeTokenPromise = state.provider.getToken().finally(function () {
|
|
859
|
-
// Clear promise when settled - either resolved or rejected.
|
|
860
|
-
state.exchangeTokenPromise = undefined;
|
|
861
|
-
});
|
|
862
|
-
shouldCallListeners = true;
|
|
863
|
-
}
|
|
864
|
-
return [4 /*yield*/, getStateReference(app).exchangeTokenPromise];
|
|
865
|
-
case 10:
|
|
866
|
-
token = _e.sent();
|
|
867
|
-
return [3 /*break*/, 12];
|
|
868
|
-
case 11:
|
|
869
|
-
e_1 = _e.sent();
|
|
870
|
-
if (e_1.code === "appCheck/".concat("throttled" /* AppCheckError.THROTTLED */)) {
|
|
871
|
-
// Warn if throttled, but do not treat it as an error.
|
|
872
|
-
logger.warn(e_1.message);
|
|
873
|
-
}
|
|
874
|
-
else {
|
|
875
|
-
// `getToken()` should never throw, but logging error text to console will aid debugging.
|
|
876
|
-
logger.error(e_1);
|
|
877
|
-
}
|
|
878
|
-
// Always save error to be added to dummy token.
|
|
879
|
-
error = e_1;
|
|
880
|
-
return [3 /*break*/, 12];
|
|
881
|
-
case 12:
|
|
882
|
-
if (!!token) return [3 /*break*/, 13];
|
|
883
|
-
// If token is undefined, there must be an error.
|
|
884
|
-
// Return a dummy token along with the error.
|
|
885
|
-
interopTokenResult = makeDummyTokenResult(error);
|
|
886
|
-
return [3 /*break*/, 16];
|
|
887
|
-
case 13:
|
|
888
|
-
if (!error) return [3 /*break*/, 14];
|
|
889
|
-
if (isValid(token)) {
|
|
890
|
-
// It's also possible a valid token exists, but there's also an error.
|
|
891
|
-
// (Such as if the token is almost expired, tries to refresh, and
|
|
892
|
-
// the exchange request fails.)
|
|
893
|
-
// We add a special error property here so that the refresher will
|
|
894
|
-
// count this as a failed attempt and use the backoff instead of
|
|
895
|
-
// retrying repeatedly with no delay, but any 3P listeners will not
|
|
896
|
-
// be hindered in getting the still-valid token.
|
|
897
|
-
interopTokenResult = {
|
|
898
|
-
token: token.token,
|
|
899
|
-
internalError: error
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
else {
|
|
903
|
-
// No invalid tokens should make it to this step. Memory and cached tokens
|
|
904
|
-
// are checked. Other tokens are from fresh exchanges. But just in case.
|
|
905
|
-
interopTokenResult = makeDummyTokenResult(error);
|
|
906
|
-
}
|
|
907
|
-
return [3 /*break*/, 16];
|
|
908
|
-
case 14:
|
|
909
|
-
interopTokenResult = {
|
|
910
|
-
token: token.token
|
|
911
|
-
};
|
|
912
|
-
// write the new token to the memory state as well as the persistent storage.
|
|
913
|
-
// Only do it if we got a valid new token
|
|
914
|
-
state.token = token;
|
|
915
|
-
return [4 /*yield*/, writeTokenToStorage(app, token)];
|
|
916
|
-
case 15:
|
|
917
|
-
_e.sent();
|
|
918
|
-
_e.label = 16;
|
|
919
|
-
case 16:
|
|
920
|
-
if (shouldCallListeners) {
|
|
921
|
-
notifyTokenListeners(app, interopTokenResult);
|
|
922
|
-
}
|
|
923
|
-
return [2 /*return*/, interopTokenResult];
|
|
727
|
+
await writeTokenToStorage(app, undefined);
|
|
924
728
|
}
|
|
925
|
-
}
|
|
926
|
-
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
// Return the cached token (from either memory or indexedDB) if it's valid
|
|
732
|
+
if (!forceRefresh && token && isValid(token)) {
|
|
733
|
+
return {
|
|
734
|
+
token: token.token
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
// Only set to true if this `getToken()` call is making the actual
|
|
738
|
+
// REST call to the exchange endpoint, versus waiting for an already
|
|
739
|
+
// in-flight call (see debug and regular exchange endpoint paths below)
|
|
740
|
+
let shouldCallListeners = false;
|
|
741
|
+
/**
|
|
742
|
+
* DEBUG MODE
|
|
743
|
+
* If debug mode is set, and there is no cached token, fetch a new App
|
|
744
|
+
* Check token using the debug token, and return it directly.
|
|
745
|
+
*/
|
|
746
|
+
if (isDebugMode()) {
|
|
747
|
+
// Avoid making another call to the exchange endpoint if one is in flight.
|
|
748
|
+
if (!state.exchangeTokenPromise) {
|
|
749
|
+
state.exchangeTokenPromise = exchangeToken(getExchangeDebugTokenRequest(app, await getDebugToken()), appCheck.heartbeatServiceProvider).finally(() => {
|
|
750
|
+
// Clear promise when settled - either resolved or rejected.
|
|
751
|
+
state.exchangeTokenPromise = undefined;
|
|
752
|
+
});
|
|
753
|
+
shouldCallListeners = true;
|
|
754
|
+
}
|
|
755
|
+
const tokenFromDebugExchange = await state.exchangeTokenPromise;
|
|
756
|
+
// Write debug token to indexedDB.
|
|
757
|
+
await writeTokenToStorage(app, tokenFromDebugExchange);
|
|
758
|
+
// Write debug token to state.
|
|
759
|
+
state.token = tokenFromDebugExchange;
|
|
760
|
+
return { token: tokenFromDebugExchange.token };
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* There are no valid tokens in memory or indexedDB and we are not in
|
|
764
|
+
* debug mode.
|
|
765
|
+
* Request a new token from the exchange endpoint.
|
|
766
|
+
*/
|
|
767
|
+
try {
|
|
768
|
+
// Avoid making another call to the exchange endpoint if one is in flight.
|
|
769
|
+
if (!state.exchangeTokenPromise) {
|
|
770
|
+
// state.provider is populated in initializeAppCheck()
|
|
771
|
+
// ensureActivated() at the top of this function checks that
|
|
772
|
+
// initializeAppCheck() has been called.
|
|
773
|
+
state.exchangeTokenPromise = state.provider.getToken().finally(() => {
|
|
774
|
+
// Clear promise when settled - either resolved or rejected.
|
|
775
|
+
state.exchangeTokenPromise = undefined;
|
|
776
|
+
});
|
|
777
|
+
shouldCallListeners = true;
|
|
778
|
+
}
|
|
779
|
+
token = await getStateReference(app).exchangeTokenPromise;
|
|
780
|
+
}
|
|
781
|
+
catch (e) {
|
|
782
|
+
if (e.code === `appCheck/${"throttled" /* AppCheckError.THROTTLED */}`) {
|
|
783
|
+
// Warn if throttled, but do not treat it as an error.
|
|
784
|
+
logger.warn(e.message);
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
// `getToken()` should never throw, but logging error text to console will aid debugging.
|
|
788
|
+
logger.error(e);
|
|
789
|
+
}
|
|
790
|
+
// Always save error to be added to dummy token.
|
|
791
|
+
error = e;
|
|
792
|
+
}
|
|
793
|
+
let interopTokenResult;
|
|
794
|
+
if (!token) {
|
|
795
|
+
// If token is undefined, there must be an error.
|
|
796
|
+
// Return a dummy token along with the error.
|
|
797
|
+
interopTokenResult = makeDummyTokenResult(error);
|
|
798
|
+
}
|
|
799
|
+
else if (error) {
|
|
800
|
+
if (isValid(token)) {
|
|
801
|
+
// It's also possible a valid token exists, but there's also an error.
|
|
802
|
+
// (Such as if the token is almost expired, tries to refresh, and
|
|
803
|
+
// the exchange request fails.)
|
|
804
|
+
// We add a special error property here so that the refresher will
|
|
805
|
+
// count this as a failed attempt and use the backoff instead of
|
|
806
|
+
// retrying repeatedly with no delay, but any 3P listeners will not
|
|
807
|
+
// be hindered in getting the still-valid token.
|
|
808
|
+
interopTokenResult = {
|
|
809
|
+
token: token.token,
|
|
810
|
+
internalError: error
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
// No invalid tokens should make it to this step. Memory and cached tokens
|
|
815
|
+
// are checked. Other tokens are from fresh exchanges. But just in case.
|
|
816
|
+
interopTokenResult = makeDummyTokenResult(error);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
interopTokenResult = {
|
|
821
|
+
token: token.token
|
|
822
|
+
};
|
|
823
|
+
// write the new token to the memory state as well as the persistent storage.
|
|
824
|
+
// Only do it if we got a valid new token
|
|
825
|
+
state.token = token;
|
|
826
|
+
await writeTokenToStorage(app, token);
|
|
827
|
+
}
|
|
828
|
+
if (shouldCallListeners) {
|
|
829
|
+
notifyTokenListeners(app, interopTokenResult);
|
|
830
|
+
}
|
|
831
|
+
return interopTokenResult;
|
|
927
832
|
}
|
|
928
833
|
/**
|
|
929
834
|
* Internal API for limited use tokens. Skips all FAC state and simply calls
|
|
930
835
|
* the underlying provider.
|
|
931
836
|
*/
|
|
932
|
-
function getLimitedUseToken$1(appCheck) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
case 2:
|
|
947
|
-
token = (_a.sent()).token;
|
|
948
|
-
return [2 /*return*/, { token: token }];
|
|
949
|
-
case 3: return [4 /*yield*/, provider.getToken()];
|
|
950
|
-
case 4:
|
|
951
|
-
token = (_a.sent()).token;
|
|
952
|
-
return [2 /*return*/, { token: token }];
|
|
953
|
-
}
|
|
954
|
-
});
|
|
955
|
-
});
|
|
837
|
+
async function getLimitedUseToken$1(appCheck) {
|
|
838
|
+
const app = appCheck.app;
|
|
839
|
+
ensureActivated(app);
|
|
840
|
+
const { provider } = getStateReference(app);
|
|
841
|
+
if (isDebugMode()) {
|
|
842
|
+
const debugToken = await getDebugToken();
|
|
843
|
+
const { token } = await exchangeToken(getExchangeDebugTokenRequest(app, debugToken), appCheck.heartbeatServiceProvider);
|
|
844
|
+
return { token };
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
// provider is definitely valid since we ensure AppCheck was activated
|
|
848
|
+
const { token } = await provider.getToken();
|
|
849
|
+
return { token };
|
|
850
|
+
}
|
|
956
851
|
}
|
|
957
852
|
function addTokenListener(appCheck, type, listener, onError) {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
853
|
+
const { app } = appCheck;
|
|
854
|
+
const state = getStateReference(app);
|
|
855
|
+
const tokenObserver = {
|
|
961
856
|
next: listener,
|
|
962
857
|
error: onError,
|
|
963
|
-
type
|
|
858
|
+
type
|
|
964
859
|
};
|
|
965
|
-
state.tokenObservers =
|
|
860
|
+
state.tokenObservers = [...state.tokenObservers, tokenObserver];
|
|
966
861
|
// Invoke the listener async immediately if there is a valid token
|
|
967
862
|
// in memory.
|
|
968
863
|
if (state.token && isValid(state.token)) {
|
|
969
|
-
|
|
864
|
+
const validToken = state.token;
|
|
970
865
|
Promise.resolve()
|
|
971
|
-
.then(
|
|
972
|
-
listener({ token:
|
|
866
|
+
.then(() => {
|
|
867
|
+
listener({ token: validToken.token });
|
|
973
868
|
initTokenRefresher(appCheck);
|
|
974
869
|
})
|
|
975
|
-
.catch(
|
|
870
|
+
.catch(() => {
|
|
976
871
|
/* we don't care about exceptions thrown in listeners */
|
|
977
872
|
});
|
|
978
873
|
}
|
|
@@ -986,11 +881,11 @@ function addTokenListener(appCheck, type, listener, onError) {
|
|
|
986
881
|
* listeners that exist when it resolves.
|
|
987
882
|
*/
|
|
988
883
|
// state.cachedTokenPromise is always populated in `activate()`.
|
|
989
|
-
void state.cachedTokenPromise.then(
|
|
884
|
+
void state.cachedTokenPromise.then(() => initTokenRefresher(appCheck));
|
|
990
885
|
}
|
|
991
886
|
function removeTokenListener(app, listener) {
|
|
992
|
-
|
|
993
|
-
|
|
887
|
+
const state = getStateReference(app);
|
|
888
|
+
const newObservers = state.tokenObservers.filter(tokenObserver => tokenObserver.next !== listener);
|
|
994
889
|
if (newObservers.length === 0 &&
|
|
995
890
|
state.tokenRefresher &&
|
|
996
891
|
state.tokenRefresher.isRunning()) {
|
|
@@ -1002,11 +897,11 @@ function removeTokenListener(app, listener) {
|
|
|
1002
897
|
* Logic to create and start refresher as needed.
|
|
1003
898
|
*/
|
|
1004
899
|
function initTokenRefresher(appCheck) {
|
|
1005
|
-
|
|
1006
|
-
|
|
900
|
+
const { app } = appCheck;
|
|
901
|
+
const state = getStateReference(app);
|
|
1007
902
|
// Create the refresher but don't start it if `isTokenAutoRefreshEnabled`
|
|
1008
903
|
// is not true.
|
|
1009
|
-
|
|
904
|
+
let refresher = state.tokenRefresher;
|
|
1010
905
|
if (!refresher) {
|
|
1011
906
|
refresher = createTokenRefresher(appCheck);
|
|
1012
907
|
state.tokenRefresher = refresher;
|
|
@@ -1016,60 +911,51 @@ function initTokenRefresher(appCheck) {
|
|
|
1016
911
|
}
|
|
1017
912
|
}
|
|
1018
913
|
function createTokenRefresher(appCheck) {
|
|
1019
|
-
|
|
1020
|
-
var app = appCheck.app;
|
|
914
|
+
const { app } = appCheck;
|
|
1021
915
|
return new Refresher(
|
|
1022
916
|
// Keep in mind when this fails for any reason other than the ones
|
|
1023
917
|
// for which we should retry, it will effectively stop the proactive refresh.
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
*/
|
|
1055
|
-
if (result.internalError) {
|
|
1056
|
-
throw result.internalError;
|
|
1057
|
-
}
|
|
1058
|
-
return [2 /*return*/];
|
|
1059
|
-
}
|
|
1060
|
-
});
|
|
1061
|
-
}); }, function () {
|
|
918
|
+
async () => {
|
|
919
|
+
const state = getStateReference(app);
|
|
920
|
+
// If there is no token, we will try to load it from storage and use it
|
|
921
|
+
// If there is a token, we force refresh it because we know it's going to expire soon
|
|
922
|
+
let result;
|
|
923
|
+
if (!state.token) {
|
|
924
|
+
result = await getToken$2(appCheck);
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
result = await getToken$2(appCheck, true);
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* getToken() always resolves. In case the result has an error field defined, it means
|
|
931
|
+
* the operation failed, and we should retry.
|
|
932
|
+
*/
|
|
933
|
+
if (result.error) {
|
|
934
|
+
throw result.error;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* A special `internalError` field reflects that there was an error
|
|
938
|
+
* getting a new token from the exchange endpoint, but there's still a
|
|
939
|
+
* previous token that's valid for now and this should be passed to 2P/3P
|
|
940
|
+
* requests for a token. But we want this callback (`this.operation` in
|
|
941
|
+
* `Refresher`) to throw in order to kick off the Refresher's retry
|
|
942
|
+
* backoff. (Setting `hasSucceeded` to false.)
|
|
943
|
+
*/
|
|
944
|
+
if (result.internalError) {
|
|
945
|
+
throw result.internalError;
|
|
946
|
+
}
|
|
947
|
+
}, () => {
|
|
1062
948
|
return true;
|
|
1063
|
-
},
|
|
1064
|
-
|
|
949
|
+
}, () => {
|
|
950
|
+
const state = getStateReference(app);
|
|
1065
951
|
if (state.token) {
|
|
1066
952
|
// issuedAtTime + (50% * total TTL) + 5 minutes
|
|
1067
|
-
|
|
953
|
+
let nextRefreshTimeMillis = state.token.issuedAtTimeMillis +
|
|
1068
954
|
(state.token.expireTimeMillis - state.token.issuedAtTimeMillis) *
|
|
1069
955
|
0.5 +
|
|
1070
956
|
5 * 60 * 1000;
|
|
1071
957
|
// Do not allow refresh time to be past (expireTime - 5 minutes)
|
|
1072
|
-
|
|
958
|
+
const latestAllowableRefresh = state.token.expireTimeMillis - 5 * 60 * 1000;
|
|
1073
959
|
nextRefreshTimeMillis = Math.min(nextRefreshTimeMillis, latestAllowableRefresh);
|
|
1074
960
|
return Math.max(0, nextRefreshTimeMillis - Date.now());
|
|
1075
961
|
}
|
|
@@ -1079,9 +965,8 @@ function createTokenRefresher(appCheck) {
|
|
|
1079
965
|
}, TOKEN_REFRESH_TIME.RETRIAL_MIN_WAIT, TOKEN_REFRESH_TIME.RETRIAL_MAX_WAIT);
|
|
1080
966
|
}
|
|
1081
967
|
function notifyTokenListeners(app, token) {
|
|
1082
|
-
|
|
1083
|
-
for (
|
|
1084
|
-
var observer = observers_1[_i];
|
|
968
|
+
const observers = getStateReference(app).tokenObservers;
|
|
969
|
+
for (const observer of observers) {
|
|
1085
970
|
try {
|
|
1086
971
|
if (observer.type === "EXTERNAL" /* ListenerType.EXTERNAL */ && token.error != null) {
|
|
1087
972
|
// If this listener was added by a 3P call, send any token error to
|
|
@@ -1107,7 +992,7 @@ function isValid(token) {
|
|
|
1107
992
|
function makeDummyTokenResult(error) {
|
|
1108
993
|
return {
|
|
1109
994
|
token: formatDummyToken(defaultTokenErrorData),
|
|
1110
|
-
error
|
|
995
|
+
error
|
|
1111
996
|
};
|
|
1112
997
|
}
|
|
1113
998
|
|
|
@@ -1130,37 +1015,33 @@ function makeDummyTokenResult(error) {
|
|
|
1130
1015
|
/**
|
|
1131
1016
|
* AppCheck Service class.
|
|
1132
1017
|
*/
|
|
1133
|
-
|
|
1134
|
-
|
|
1018
|
+
class AppCheckService {
|
|
1019
|
+
constructor(app, heartbeatServiceProvider) {
|
|
1135
1020
|
this.app = app;
|
|
1136
1021
|
this.heartbeatServiceProvider = heartbeatServiceProvider;
|
|
1137
1022
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
for (
|
|
1141
|
-
var tokenObserver = tokenObservers_1[_i];
|
|
1023
|
+
_delete() {
|
|
1024
|
+
const { tokenObservers } = getStateReference(this.app);
|
|
1025
|
+
for (const tokenObserver of tokenObservers) {
|
|
1142
1026
|
removeTokenListener(this.app, tokenObserver.next);
|
|
1143
1027
|
}
|
|
1144
1028
|
return Promise.resolve();
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
}());
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1148
1031
|
function factory(app, heartbeatServiceProvider) {
|
|
1149
1032
|
return new AppCheckService(app, heartbeatServiceProvider);
|
|
1150
1033
|
}
|
|
1151
1034
|
function internalFactory(appCheck) {
|
|
1152
1035
|
return {
|
|
1153
|
-
getToken:
|
|
1154
|
-
getLimitedUseToken:
|
|
1155
|
-
addTokenListener:
|
|
1156
|
-
|
|
1157
|
-
},
|
|
1158
|
-
removeTokenListener: function (listener) { return removeTokenListener(appCheck.app, listener); }
|
|
1036
|
+
getToken: forceRefresh => getToken$2(appCheck, forceRefresh),
|
|
1037
|
+
getLimitedUseToken: () => getLimitedUseToken$1(appCheck),
|
|
1038
|
+
addTokenListener: listener => addTokenListener(appCheck, "INTERNAL" /* ListenerType.INTERNAL */, listener),
|
|
1039
|
+
removeTokenListener: listener => removeTokenListener(appCheck.app, listener)
|
|
1159
1040
|
};
|
|
1160
1041
|
}
|
|
1161
1042
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1043
|
+
const name = "@firebase/app-check";
|
|
1044
|
+
const version = "0.8.9";
|
|
1164
1045
|
|
|
1165
1046
|
/**
|
|
1166
1047
|
* @license
|
|
@@ -1178,17 +1059,17 @@ var version = "0.8.8";
|
|
|
1178
1059
|
* See the License for the specific language governing permissions and
|
|
1179
1060
|
* limitations under the License.
|
|
1180
1061
|
*/
|
|
1181
|
-
|
|
1182
|
-
|
|
1062
|
+
const RECAPTCHA_URL = 'https://www.google.com/recaptcha/api.js';
|
|
1063
|
+
const RECAPTCHA_ENTERPRISE_URL = 'https://www.google.com/recaptcha/enterprise.js';
|
|
1183
1064
|
function initializeV3(app, siteKey) {
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
state.reCAPTCHAState = { initialized
|
|
1187
|
-
|
|
1188
|
-
|
|
1065
|
+
const initialized = new util.Deferred();
|
|
1066
|
+
const state = getStateReference(app);
|
|
1067
|
+
state.reCAPTCHAState = { initialized };
|
|
1068
|
+
const divId = makeDiv(app);
|
|
1069
|
+
const grecaptcha = getRecaptcha(false);
|
|
1189
1070
|
if (!grecaptcha) {
|
|
1190
|
-
loadReCAPTCHAV3Script(
|
|
1191
|
-
|
|
1071
|
+
loadReCAPTCHAV3Script(() => {
|
|
1072
|
+
const grecaptcha = getRecaptcha(false);
|
|
1192
1073
|
if (!grecaptcha) {
|
|
1193
1074
|
// it shouldn't happen.
|
|
1194
1075
|
throw new Error('no recaptcha');
|
|
@@ -1202,14 +1083,14 @@ function initializeV3(app, siteKey) {
|
|
|
1202
1083
|
return initialized.promise;
|
|
1203
1084
|
}
|
|
1204
1085
|
function initializeEnterprise(app, siteKey) {
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
state.reCAPTCHAState = { initialized
|
|
1208
|
-
|
|
1209
|
-
|
|
1086
|
+
const initialized = new util.Deferred();
|
|
1087
|
+
const state = getStateReference(app);
|
|
1088
|
+
state.reCAPTCHAState = { initialized };
|
|
1089
|
+
const divId = makeDiv(app);
|
|
1090
|
+
const grecaptcha = getRecaptcha(true);
|
|
1210
1091
|
if (!grecaptcha) {
|
|
1211
|
-
loadReCAPTCHAEnterpriseScript(
|
|
1212
|
-
|
|
1092
|
+
loadReCAPTCHAEnterpriseScript(() => {
|
|
1093
|
+
const grecaptcha = getRecaptcha(true);
|
|
1213
1094
|
if (!grecaptcha) {
|
|
1214
1095
|
// it shouldn't happen.
|
|
1215
1096
|
throw new Error('no recaptcha');
|
|
@@ -1227,7 +1108,7 @@ function initializeEnterprise(app, siteKey) {
|
|
|
1227
1108
|
* the grecaptcha.ready() event fires.
|
|
1228
1109
|
*/
|
|
1229
1110
|
function queueWidgetRender(app, siteKey, grecaptcha, container, initialized) {
|
|
1230
|
-
grecaptcha.ready(
|
|
1111
|
+
grecaptcha.ready(() => {
|
|
1231
1112
|
// Invisible widgets allow us to set a different siteKey for each widget,
|
|
1232
1113
|
// so we use them to support multiple apps
|
|
1233
1114
|
renderInvisibleWidget(app, siteKey, grecaptcha, container);
|
|
@@ -1238,36 +1119,27 @@ function queueWidgetRender(app, siteKey, grecaptcha, container, initialized) {
|
|
|
1238
1119
|
* Add invisible div to page.
|
|
1239
1120
|
*/
|
|
1240
1121
|
function makeDiv(app) {
|
|
1241
|
-
|
|
1242
|
-
|
|
1122
|
+
const divId = `fire_app_check_${app.name}`;
|
|
1123
|
+
const invisibleDiv = document.createElement('div');
|
|
1243
1124
|
invisibleDiv.id = divId;
|
|
1244
1125
|
invisibleDiv.style.display = 'none';
|
|
1245
1126
|
document.body.appendChild(invisibleDiv);
|
|
1246
1127
|
return divId;
|
|
1247
1128
|
}
|
|
1248
|
-
function getToken$1(app) {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
recaptcha.ready(function () {
|
|
1263
|
-
resolve(
|
|
1264
|
-
// widgetId is guaranteed to be available if reCAPTCHAState.initialized.promise resolved.
|
|
1265
|
-
recaptcha.execute(reCAPTCHAState.widgetId, {
|
|
1266
|
-
action: 'fire_app_check'
|
|
1267
|
-
}));
|
|
1268
|
-
});
|
|
1269
|
-
})];
|
|
1270
|
-
}
|
|
1129
|
+
async function getToken$1(app) {
|
|
1130
|
+
ensureActivated(app);
|
|
1131
|
+
// ensureActivated() guarantees that reCAPTCHAState is set
|
|
1132
|
+
const reCAPTCHAState = getStateReference(app).reCAPTCHAState;
|
|
1133
|
+
const recaptcha = await reCAPTCHAState.initialized.promise;
|
|
1134
|
+
return new Promise((resolve, _reject) => {
|
|
1135
|
+
// Updated after initialization is complete.
|
|
1136
|
+
const reCAPTCHAState = getStateReference(app).reCAPTCHAState;
|
|
1137
|
+
recaptcha.ready(() => {
|
|
1138
|
+
resolve(
|
|
1139
|
+
// widgetId is guaranteed to be available if reCAPTCHAState.initialized.promise resolved.
|
|
1140
|
+
recaptcha.execute(reCAPTCHAState.widgetId, {
|
|
1141
|
+
action: 'fire_app_check'
|
|
1142
|
+
}));
|
|
1271
1143
|
});
|
|
1272
1144
|
});
|
|
1273
1145
|
}
|
|
@@ -1277,30 +1149,30 @@ function getToken$1(app) {
|
|
|
1277
1149
|
* @param container - Id of a HTML element.
|
|
1278
1150
|
*/
|
|
1279
1151
|
function renderInvisibleWidget(app, siteKey, grecaptcha, container) {
|
|
1280
|
-
|
|
1152
|
+
const widgetId = grecaptcha.render(container, {
|
|
1281
1153
|
sitekey: siteKey,
|
|
1282
1154
|
size: 'invisible',
|
|
1283
1155
|
// Success callback - set state
|
|
1284
|
-
callback:
|
|
1156
|
+
callback: () => {
|
|
1285
1157
|
getStateReference(app).reCAPTCHAState.succeeded = true;
|
|
1286
1158
|
},
|
|
1287
1159
|
// Failure callback - set state
|
|
1288
|
-
'error-callback':
|
|
1160
|
+
'error-callback': () => {
|
|
1289
1161
|
getStateReference(app).reCAPTCHAState.succeeded = false;
|
|
1290
1162
|
}
|
|
1291
1163
|
});
|
|
1292
|
-
|
|
1293
|
-
state.reCAPTCHAState =
|
|
1294
|
-
widgetId
|
|
1164
|
+
const state = getStateReference(app);
|
|
1165
|
+
state.reCAPTCHAState = Object.assign(Object.assign({}, state.reCAPTCHAState), { // state.reCAPTCHAState is set in the initialize()
|
|
1166
|
+
widgetId });
|
|
1295
1167
|
}
|
|
1296
1168
|
function loadReCAPTCHAV3Script(onload) {
|
|
1297
|
-
|
|
1169
|
+
const script = document.createElement('script');
|
|
1298
1170
|
script.src = RECAPTCHA_URL;
|
|
1299
1171
|
script.onload = onload;
|
|
1300
1172
|
document.head.appendChild(script);
|
|
1301
1173
|
}
|
|
1302
1174
|
function loadReCAPTCHAEnterpriseScript(onload) {
|
|
1303
|
-
|
|
1175
|
+
const script = document.createElement('script');
|
|
1304
1176
|
script.src = RECAPTCHA_ENTERPRISE_URL;
|
|
1305
1177
|
script.onload = onload;
|
|
1306
1178
|
document.head.appendChild(script);
|
|
@@ -1328,12 +1200,12 @@ function loadReCAPTCHAEnterpriseScript(onload) {
|
|
|
1328
1200
|
*
|
|
1329
1201
|
* @public
|
|
1330
1202
|
*/
|
|
1331
|
-
|
|
1203
|
+
class ReCaptchaV3Provider {
|
|
1332
1204
|
/**
|
|
1333
1205
|
* Create a ReCaptchaV3Provider instance.
|
|
1334
1206
|
* @param siteKey - ReCAPTCHA V3 siteKey.
|
|
1335
1207
|
*/
|
|
1336
|
-
|
|
1208
|
+
constructor(_siteKey) {
|
|
1337
1209
|
this._siteKey = _siteKey;
|
|
1338
1210
|
/**
|
|
1339
1211
|
* Throttle requests on certain error codes to prevent too many retries
|
|
@@ -1345,86 +1217,73 @@ var ReCaptchaV3Provider = /** @class */ (function () {
|
|
|
1345
1217
|
* Returns an App Check token.
|
|
1346
1218
|
* @internal
|
|
1347
1219
|
*/
|
|
1348
|
-
|
|
1220
|
+
async getToken() {
|
|
1349
1221
|
var _a, _b, _c;
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
return [4 /*yield*/, getToken$1(this._app).catch(function (_e) {
|
|
1357
|
-
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1358
|
-
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1359
|
-
})];
|
|
1360
|
-
case 1:
|
|
1361
|
-
attestedClaimsToken = _d.sent();
|
|
1362
|
-
// Check if a failure state was set by the recaptcha "error-callback".
|
|
1363
|
-
if (!((_a = getStateReference(this._app).reCAPTCHAState) === null || _a === void 0 ? void 0 : _a.succeeded)) {
|
|
1364
|
-
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1365
|
-
}
|
|
1366
|
-
_d.label = 2;
|
|
1367
|
-
case 2:
|
|
1368
|
-
_d.trys.push([2, 4, , 5]);
|
|
1369
|
-
return [4 /*yield*/, exchangeToken(getExchangeRecaptchaV3TokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider)];
|
|
1370
|
-
case 3:
|
|
1371
|
-
result = _d.sent();
|
|
1372
|
-
return [3 /*break*/, 5];
|
|
1373
|
-
case 4:
|
|
1374
|
-
e_1 = _d.sent();
|
|
1375
|
-
if ((_b = e_1.code) === null || _b === void 0 ? void 0 : _b.includes("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */)) {
|
|
1376
|
-
this._throttleData = setBackoff(Number((_c = e_1.customData) === null || _c === void 0 ? void 0 : _c.httpStatus), this._throttleData);
|
|
1377
|
-
throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
|
|
1378
|
-
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1379
|
-
httpStatus: this._throttleData.httpStatus
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
else {
|
|
1383
|
-
throw e_1;
|
|
1384
|
-
}
|
|
1385
|
-
case 5:
|
|
1386
|
-
// If successful, clear throttle data.
|
|
1387
|
-
this._throttleData = null;
|
|
1388
|
-
return [2 /*return*/, result];
|
|
1389
|
-
}
|
|
1390
|
-
});
|
|
1222
|
+
throwIfThrottled(this._throttleData);
|
|
1223
|
+
// Top-level `getToken()` has already checked that App Check is initialized
|
|
1224
|
+
// and therefore this._app and this._heartbeatServiceProvider are available.
|
|
1225
|
+
const attestedClaimsToken = await getToken$1(this._app).catch(_e => {
|
|
1226
|
+
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1227
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1391
1228
|
});
|
|
1392
|
-
|
|
1229
|
+
// Check if a failure state was set by the recaptcha "error-callback".
|
|
1230
|
+
if (!((_a = getStateReference(this._app).reCAPTCHAState) === null || _a === void 0 ? void 0 : _a.succeeded)) {
|
|
1231
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1232
|
+
}
|
|
1233
|
+
let result;
|
|
1234
|
+
try {
|
|
1235
|
+
result = await exchangeToken(getExchangeRecaptchaV3TokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider);
|
|
1236
|
+
}
|
|
1237
|
+
catch (e) {
|
|
1238
|
+
if ((_b = e.code) === null || _b === void 0 ? void 0 : _b.includes("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */)) {
|
|
1239
|
+
this._throttleData = setBackoff(Number((_c = e.customData) === null || _c === void 0 ? void 0 : _c.httpStatus), this._throttleData);
|
|
1240
|
+
throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
|
|
1241
|
+
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1242
|
+
httpStatus: this._throttleData.httpStatus
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
throw e;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
// If successful, clear throttle data.
|
|
1250
|
+
this._throttleData = null;
|
|
1251
|
+
return result;
|
|
1252
|
+
}
|
|
1393
1253
|
/**
|
|
1394
1254
|
* @internal
|
|
1395
1255
|
*/
|
|
1396
|
-
|
|
1256
|
+
initialize(app$1) {
|
|
1397
1257
|
this._app = app$1;
|
|
1398
1258
|
this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
|
|
1399
|
-
initializeV3(app$1, this._siteKey).catch(
|
|
1259
|
+
initializeV3(app$1, this._siteKey).catch(() => {
|
|
1400
1260
|
/* we don't care about the initialization result */
|
|
1401
1261
|
});
|
|
1402
|
-
}
|
|
1262
|
+
}
|
|
1403
1263
|
/**
|
|
1404
1264
|
* @internal
|
|
1405
1265
|
*/
|
|
1406
|
-
|
|
1266
|
+
isEqual(otherProvider) {
|
|
1407
1267
|
if (otherProvider instanceof ReCaptchaV3Provider) {
|
|
1408
1268
|
return this._siteKey === otherProvider._siteKey;
|
|
1409
1269
|
}
|
|
1410
1270
|
else {
|
|
1411
1271
|
return false;
|
|
1412
1272
|
}
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
}());
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1416
1275
|
/**
|
|
1417
1276
|
* App Check provider that can obtain a reCAPTCHA Enterprise token and exchange it
|
|
1418
1277
|
* for an App Check token.
|
|
1419
1278
|
*
|
|
1420
1279
|
* @public
|
|
1421
1280
|
*/
|
|
1422
|
-
|
|
1281
|
+
class ReCaptchaEnterpriseProvider {
|
|
1423
1282
|
/**
|
|
1424
1283
|
* Create a ReCaptchaEnterpriseProvider instance.
|
|
1425
1284
|
* @param siteKey - reCAPTCHA Enterprise score-based site key.
|
|
1426
1285
|
*/
|
|
1427
|
-
|
|
1286
|
+
constructor(_siteKey) {
|
|
1428
1287
|
this._siteKey = _siteKey;
|
|
1429
1288
|
/**
|
|
1430
1289
|
* Throttle requests on certain error codes to prevent too many retries
|
|
@@ -1436,114 +1295,97 @@ var ReCaptchaEnterpriseProvider = /** @class */ (function () {
|
|
|
1436
1295
|
* Returns an App Check token.
|
|
1437
1296
|
* @internal
|
|
1438
1297
|
*/
|
|
1439
|
-
|
|
1298
|
+
async getToken() {
|
|
1440
1299
|
var _a, _b, _c;
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
return [4 /*yield*/, getToken$1(this._app).catch(function (_e) {
|
|
1448
|
-
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1449
|
-
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1450
|
-
})];
|
|
1451
|
-
case 1:
|
|
1452
|
-
attestedClaimsToken = _d.sent();
|
|
1453
|
-
// Check if a failure state was set by the recaptcha "error-callback".
|
|
1454
|
-
if (!((_a = getStateReference(this._app).reCAPTCHAState) === null || _a === void 0 ? void 0 : _a.succeeded)) {
|
|
1455
|
-
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1456
|
-
}
|
|
1457
|
-
_d.label = 2;
|
|
1458
|
-
case 2:
|
|
1459
|
-
_d.trys.push([2, 4, , 5]);
|
|
1460
|
-
return [4 /*yield*/, exchangeToken(getExchangeRecaptchaEnterpriseTokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider)];
|
|
1461
|
-
case 3:
|
|
1462
|
-
result = _d.sent();
|
|
1463
|
-
return [3 /*break*/, 5];
|
|
1464
|
-
case 4:
|
|
1465
|
-
e_2 = _d.sent();
|
|
1466
|
-
if ((_b = e_2.code) === null || _b === void 0 ? void 0 : _b.includes("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */)) {
|
|
1467
|
-
this._throttleData = setBackoff(Number((_c = e_2.customData) === null || _c === void 0 ? void 0 : _c.httpStatus), this._throttleData);
|
|
1468
|
-
throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
|
|
1469
|
-
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1470
|
-
httpStatus: this._throttleData.httpStatus
|
|
1471
|
-
});
|
|
1472
|
-
}
|
|
1473
|
-
else {
|
|
1474
|
-
throw e_2;
|
|
1475
|
-
}
|
|
1476
|
-
case 5:
|
|
1477
|
-
// If successful, clear throttle data.
|
|
1478
|
-
this._throttleData = null;
|
|
1479
|
-
return [2 /*return*/, result];
|
|
1480
|
-
}
|
|
1481
|
-
});
|
|
1300
|
+
throwIfThrottled(this._throttleData);
|
|
1301
|
+
// Top-level `getToken()` has already checked that App Check is initialized
|
|
1302
|
+
// and therefore this._app and this._heartbeatServiceProvider are available.
|
|
1303
|
+
const attestedClaimsToken = await getToken$1(this._app).catch(_e => {
|
|
1304
|
+
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1305
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1482
1306
|
});
|
|
1483
|
-
|
|
1307
|
+
// Check if a failure state was set by the recaptcha "error-callback".
|
|
1308
|
+
if (!((_a = getStateReference(this._app).reCAPTCHAState) === null || _a === void 0 ? void 0 : _a.succeeded)) {
|
|
1309
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* AppCheckError.RECAPTCHA_ERROR */);
|
|
1310
|
+
}
|
|
1311
|
+
let result;
|
|
1312
|
+
try {
|
|
1313
|
+
result = await exchangeToken(getExchangeRecaptchaEnterpriseTokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider);
|
|
1314
|
+
}
|
|
1315
|
+
catch (e) {
|
|
1316
|
+
if ((_b = e.code) === null || _b === void 0 ? void 0 : _b.includes("fetch-status-error" /* AppCheckError.FETCH_STATUS_ERROR */)) {
|
|
1317
|
+
this._throttleData = setBackoff(Number((_c = e.customData) === null || _c === void 0 ? void 0 : _c.httpStatus), this._throttleData);
|
|
1318
|
+
throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
|
|
1319
|
+
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1320
|
+
httpStatus: this._throttleData.httpStatus
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
else {
|
|
1324
|
+
throw e;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
// If successful, clear throttle data.
|
|
1328
|
+
this._throttleData = null;
|
|
1329
|
+
return result;
|
|
1330
|
+
}
|
|
1484
1331
|
/**
|
|
1485
1332
|
* @internal
|
|
1486
1333
|
*/
|
|
1487
|
-
|
|
1334
|
+
initialize(app$1) {
|
|
1488
1335
|
this._app = app$1;
|
|
1489
1336
|
this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
|
|
1490
|
-
initializeEnterprise(app$1, this._siteKey).catch(
|
|
1337
|
+
initializeEnterprise(app$1, this._siteKey).catch(() => {
|
|
1491
1338
|
/* we don't care about the initialization result */
|
|
1492
1339
|
});
|
|
1493
|
-
}
|
|
1340
|
+
}
|
|
1494
1341
|
/**
|
|
1495
1342
|
* @internal
|
|
1496
1343
|
*/
|
|
1497
|
-
|
|
1344
|
+
isEqual(otherProvider) {
|
|
1498
1345
|
if (otherProvider instanceof ReCaptchaEnterpriseProvider) {
|
|
1499
1346
|
return this._siteKey === otherProvider._siteKey;
|
|
1500
1347
|
}
|
|
1501
1348
|
else {
|
|
1502
1349
|
return false;
|
|
1503
1350
|
}
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
}());
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1507
1353
|
/**
|
|
1508
1354
|
* Custom provider class.
|
|
1509
1355
|
* @public
|
|
1510
1356
|
*/
|
|
1511
|
-
|
|
1512
|
-
|
|
1357
|
+
class CustomProvider {
|
|
1358
|
+
constructor(_customProviderOptions) {
|
|
1513
1359
|
this._customProviderOptions = _customProviderOptions;
|
|
1514
1360
|
}
|
|
1515
1361
|
/**
|
|
1516
1362
|
* @internal
|
|
1517
1363
|
*/
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
}
|
|
1534
|
-
});
|
|
1535
|
-
});
|
|
1536
|
-
};
|
|
1364
|
+
async getToken() {
|
|
1365
|
+
// custom provider
|
|
1366
|
+
const customToken = await this._customProviderOptions.getToken();
|
|
1367
|
+
// Try to extract IAT from custom token, in case this token is not
|
|
1368
|
+
// being newly issued. JWT timestamps are in seconds since epoch.
|
|
1369
|
+
const issuedAtTimeSeconds = util.issuedAtTime(customToken.token);
|
|
1370
|
+
// Very basic validation, use current timestamp as IAT if JWT
|
|
1371
|
+
// has no `iat` field or value is out of bounds.
|
|
1372
|
+
const issuedAtTimeMillis = issuedAtTimeSeconds !== null &&
|
|
1373
|
+
issuedAtTimeSeconds < Date.now() &&
|
|
1374
|
+
issuedAtTimeSeconds > 0
|
|
1375
|
+
? issuedAtTimeSeconds * 1000
|
|
1376
|
+
: Date.now();
|
|
1377
|
+
return Object.assign(Object.assign({}, customToken), { issuedAtTimeMillis });
|
|
1378
|
+
}
|
|
1537
1379
|
/**
|
|
1538
1380
|
* @internal
|
|
1539
1381
|
*/
|
|
1540
|
-
|
|
1382
|
+
initialize(app) {
|
|
1541
1383
|
this._app = app;
|
|
1542
|
-
}
|
|
1384
|
+
}
|
|
1543
1385
|
/**
|
|
1544
1386
|
* @internal
|
|
1545
1387
|
*/
|
|
1546
|
-
|
|
1388
|
+
isEqual(otherProvider) {
|
|
1547
1389
|
if (otherProvider instanceof CustomProvider) {
|
|
1548
1390
|
return (this._customProviderOptions.getToken.toString() ===
|
|
1549
1391
|
otherProvider._customProviderOptions.getToken.toString());
|
|
@@ -1551,9 +1393,8 @@ var CustomProvider = /** @class */ (function () {
|
|
|
1551
1393
|
else {
|
|
1552
1394
|
return false;
|
|
1553
1395
|
}
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
}());
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1557
1398
|
/**
|
|
1558
1399
|
* Set throttle data to block requests until after a certain time
|
|
1559
1400
|
* depending on the failed request's status code.
|
|
@@ -1577,7 +1418,7 @@ function setBackoff(httpStatus, throttleData) {
|
|
|
1577
1418
|
return {
|
|
1578
1419
|
backoffCount: 1,
|
|
1579
1420
|
allowRequestsAfter: Date.now() + ONE_DAY,
|
|
1580
|
-
httpStatus
|
|
1421
|
+
httpStatus
|
|
1581
1422
|
};
|
|
1582
1423
|
}
|
|
1583
1424
|
else {
|
|
@@ -1585,12 +1426,12 @@ function setBackoff(httpStatus, throttleData) {
|
|
|
1585
1426
|
* For all other error codes, the time when it is ok to retry again
|
|
1586
1427
|
* is based on exponential backoff.
|
|
1587
1428
|
*/
|
|
1588
|
-
|
|
1589
|
-
|
|
1429
|
+
const backoffCount = throttleData ? throttleData.backoffCount : 0;
|
|
1430
|
+
const backoffMillis = util.calculateBackoffMillis(backoffCount, 1000, 2);
|
|
1590
1431
|
return {
|
|
1591
1432
|
backoffCount: backoffCount + 1,
|
|
1592
1433
|
allowRequestsAfter: Date.now() + backoffMillis,
|
|
1593
|
-
httpStatus
|
|
1434
|
+
httpStatus
|
|
1594
1435
|
};
|
|
1595
1436
|
}
|
|
1596
1437
|
}
|
|
@@ -1628,10 +1469,9 @@ function throwIfThrottled(throttleData) {
|
|
|
1628
1469
|
* @param options - App Check initialization options
|
|
1629
1470
|
* @public
|
|
1630
1471
|
*/
|
|
1631
|
-
function initializeAppCheck(app$1, options) {
|
|
1632
|
-
if (app$1 === void 0) { app$1 = app.getApp(); }
|
|
1472
|
+
function initializeAppCheck(app$1 = app.getApp(), options) {
|
|
1633
1473
|
app$1 = util.getModularInstance(app$1);
|
|
1634
|
-
|
|
1474
|
+
const provider = app._getProvider(app$1, 'app-check');
|
|
1635
1475
|
// Ensure initializeDebugMode() is only called once.
|
|
1636
1476
|
if (!getDebugState().initialized) {
|
|
1637
1477
|
initializeDebugMode();
|
|
@@ -1640,14 +1480,13 @@ function initializeAppCheck(app$1, options) {
|
|
|
1640
1480
|
// is called in debug mode.
|
|
1641
1481
|
if (isDebugMode()) {
|
|
1642
1482
|
// Do not block initialization to get the token for the message.
|
|
1643
|
-
void getDebugToken().then(
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
});
|
|
1483
|
+
void getDebugToken().then(token =>
|
|
1484
|
+
// Not using logger because I don't think we ever want this accidentally hidden.
|
|
1485
|
+
console.log(`App Check debug token: ${token}. You will need to add it to your app's App Check settings in the Firebase console for it to work.`));
|
|
1647
1486
|
}
|
|
1648
1487
|
if (provider.isInitialized()) {
|
|
1649
|
-
|
|
1650
|
-
|
|
1488
|
+
const existingInstance = provider.getImmediate();
|
|
1489
|
+
const initialOptions = provider.getOptions();
|
|
1651
1490
|
if (initialOptions.isTokenAutoRefreshEnabled ===
|
|
1652
1491
|
options.isTokenAutoRefreshEnabled &&
|
|
1653
1492
|
initialOptions.provider.isEqual(options.provider)) {
|
|
@@ -1659,7 +1498,7 @@ function initializeAppCheck(app$1, options) {
|
|
|
1659
1498
|
});
|
|
1660
1499
|
}
|
|
1661
1500
|
}
|
|
1662
|
-
|
|
1501
|
+
const appCheck = provider.initialize({ options });
|
|
1663
1502
|
_activate(app$1, options.provider, options.isTokenAutoRefreshEnabled);
|
|
1664
1503
|
// If isTokenAutoRefreshEnabled is false, do not send any requests to the
|
|
1665
1504
|
// exchange endpoint without an explicit call from the user either directly
|
|
@@ -1670,7 +1509,7 @@ function initializeAppCheck(app$1, options) {
|
|
|
1670
1509
|
// requests the token.
|
|
1671
1510
|
// Listener function does not need to do anything, its base functionality
|
|
1672
1511
|
// of calling getToken() already fetches token and writes it to memory/storage.
|
|
1673
|
-
addTokenListener(appCheck, "INTERNAL" /* ListenerType.INTERNAL */,
|
|
1512
|
+
addTokenListener(appCheck, "INTERNAL" /* ListenerType.INTERNAL */, () => { });
|
|
1674
1513
|
}
|
|
1675
1514
|
return appCheck;
|
|
1676
1515
|
}
|
|
@@ -1687,10 +1526,10 @@ function initializeAppCheck(app$1, options) {
|
|
|
1687
1526
|
function _activate(app, provider, isTokenAutoRefreshEnabled) {
|
|
1688
1527
|
// Create an entry in the APP_CHECK_STATES map. Further changes should
|
|
1689
1528
|
// directly mutate this object.
|
|
1690
|
-
|
|
1529
|
+
const state = setInitialState(app, Object.assign({}, DEFAULT_STATE));
|
|
1691
1530
|
state.activated = true;
|
|
1692
1531
|
state.provider = provider; // Read cached token from storage if it exists and store it in memory.
|
|
1693
|
-
state.cachedTokenPromise = readTokenFromStorage(app).then(
|
|
1532
|
+
state.cachedTokenPromise = readTokenFromStorage(app).then(cachedToken => {
|
|
1694
1533
|
if (cachedToken && isValid(cachedToken)) {
|
|
1695
1534
|
state.token = cachedToken;
|
|
1696
1535
|
// notify all listeners with the cached token
|
|
@@ -1717,8 +1556,8 @@ function _activate(app, provider, isTokenAutoRefreshEnabled) {
|
|
|
1717
1556
|
* @public
|
|
1718
1557
|
*/
|
|
1719
1558
|
function setTokenAutoRefreshEnabled(appCheckInstance, isTokenAutoRefreshEnabled) {
|
|
1720
|
-
|
|
1721
|
-
|
|
1559
|
+
const app = appCheckInstance.app;
|
|
1560
|
+
const state = getStateReference(app);
|
|
1722
1561
|
// This will exist if any product libraries have called
|
|
1723
1562
|
// `addTokenListener()`
|
|
1724
1563
|
if (state.tokenRefresher) {
|
|
@@ -1743,21 +1582,12 @@ function setTokenAutoRefreshEnabled(appCheckInstance, isTokenAutoRefreshEnabled)
|
|
|
1743
1582
|
* If false, will use a cached token if found in storage.
|
|
1744
1583
|
* @public
|
|
1745
1584
|
*/
|
|
1746
|
-
function getToken(appCheckInstance, forceRefresh) {
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
case 1:
|
|
1753
|
-
result = _a.sent();
|
|
1754
|
-
if (result.error) {
|
|
1755
|
-
throw result.error;
|
|
1756
|
-
}
|
|
1757
|
-
return [2 /*return*/, { token: result.token }];
|
|
1758
|
-
}
|
|
1759
|
-
});
|
|
1760
|
-
});
|
|
1585
|
+
async function getToken(appCheckInstance, forceRefresh) {
|
|
1586
|
+
const result = await getToken$2(appCheckInstance, forceRefresh);
|
|
1587
|
+
if (result.error) {
|
|
1588
|
+
throw result.error;
|
|
1589
|
+
}
|
|
1590
|
+
return { token: result.token };
|
|
1761
1591
|
}
|
|
1762
1592
|
/**
|
|
1763
1593
|
* Requests a Firebase App Check token. This method should be used
|
|
@@ -1790,8 +1620,8 @@ function onTokenChanged(appCheckInstance, onNextOrObserver, onError,
|
|
|
1790
1620
|
*/
|
|
1791
1621
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1792
1622
|
onCompletion) {
|
|
1793
|
-
|
|
1794
|
-
|
|
1623
|
+
let nextFn = () => { };
|
|
1624
|
+
let errorFn = () => { };
|
|
1795
1625
|
if (onNextOrObserver.next != null) {
|
|
1796
1626
|
nextFn = onNextOrObserver.next.bind(onNextOrObserver);
|
|
1797
1627
|
}
|
|
@@ -1805,7 +1635,7 @@ onCompletion) {
|
|
|
1805
1635
|
errorFn = onError;
|
|
1806
1636
|
}
|
|
1807
1637
|
addTokenListener(appCheckInstance, "EXTERNAL" /* ListenerType.EXTERNAL */, nextFn, errorFn);
|
|
1808
|
-
return
|
|
1638
|
+
return () => removeTokenListener(appCheckInstance.app, nextFn);
|
|
1809
1639
|
}
|
|
1810
1640
|
|
|
1811
1641
|
/**
|
|
@@ -1818,14 +1648,14 @@ onCompletion) {
|
|
|
1818
1648
|
*
|
|
1819
1649
|
* @packageDocumentation
|
|
1820
1650
|
*/
|
|
1821
|
-
|
|
1822
|
-
|
|
1651
|
+
const APP_CHECK_NAME = 'app-check';
|
|
1652
|
+
const APP_CHECK_NAME_INTERNAL = 'app-check-internal';
|
|
1823
1653
|
function registerAppCheck() {
|
|
1824
1654
|
// The public interface
|
|
1825
|
-
app._registerComponent(new component.Component(APP_CHECK_NAME,
|
|
1655
|
+
app._registerComponent(new component.Component(APP_CHECK_NAME, container => {
|
|
1826
1656
|
// getImmediate for FirebaseApp will always succeed
|
|
1827
|
-
|
|
1828
|
-
|
|
1657
|
+
const app = container.getProvider('app').getImmediate();
|
|
1658
|
+
const heartbeatServiceProvider = container.getProvider('heartbeat');
|
|
1829
1659
|
return factory(app, heartbeatServiceProvider);
|
|
1830
1660
|
}, "PUBLIC" /* ComponentType.PUBLIC */)
|
|
1831
1661
|
.setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */)
|
|
@@ -1833,12 +1663,12 @@ function registerAppCheck() {
|
|
|
1833
1663
|
* Initialize app-check-internal after app-check is initialized to make AppCheck available to
|
|
1834
1664
|
* other Firebase SDKs
|
|
1835
1665
|
*/
|
|
1836
|
-
.setInstanceCreatedCallback(
|
|
1666
|
+
.setInstanceCreatedCallback((container, _identifier, _appcheckService) => {
|
|
1837
1667
|
container.getProvider(APP_CHECK_NAME_INTERNAL).initialize();
|
|
1838
1668
|
}));
|
|
1839
1669
|
// The internal interface used by other Firebase products
|
|
1840
|
-
app._registerComponent(new component.Component(APP_CHECK_NAME_INTERNAL,
|
|
1841
|
-
|
|
1670
|
+
app._registerComponent(new component.Component(APP_CHECK_NAME_INTERNAL, container => {
|
|
1671
|
+
const appCheck = container.getProvider('app-check').getImmediate();
|
|
1842
1672
|
return internalFactory(appCheck);
|
|
1843
1673
|
}, "PUBLIC" /* ComponentType.PUBLIC */).setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */));
|
|
1844
1674
|
app.registerVersion(name, version);
|