@firebase/app-check 0.8.9 → 0.8.10

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.
Files changed (61) hide show
  1. package/dist/esm/index.esm2017.js +1632 -1632
  2. package/dist/esm/index.esm2017.js.map +1 -1
  3. package/dist/esm/src/api.d.ts +105 -105
  4. package/dist/esm/src/api.test.d.ts +17 -17
  5. package/dist/esm/src/client.d.ts +30 -30
  6. package/dist/esm/src/client.test.d.ts +17 -17
  7. package/dist/esm/src/constants.d.ts +40 -40
  8. package/dist/esm/src/debug.d.ts +22 -22
  9. package/dist/esm/src/debug.test.d.ts +17 -17
  10. package/dist/esm/src/errors.d.ts +61 -61
  11. package/dist/esm/src/factory.d.ts +31 -31
  12. package/dist/esm/src/index.d.ts +14 -14
  13. package/dist/esm/src/indexeddb.d.ts +22 -22
  14. package/dist/esm/src/internal-api.d.ts +44 -44
  15. package/dist/esm/src/internal-api.test.d.ts +17 -17
  16. package/dist/esm/src/logger.d.ts +18 -18
  17. package/dist/esm/src/proactive-refresh.d.ts +35 -35
  18. package/dist/esm/src/proactive-refresh.test.d.ts +17 -17
  19. package/dist/esm/src/providers.d.ts +108 -108
  20. package/dist/esm/src/providers.test.d.ts +17 -17
  21. package/dist/esm/src/public-types.d.ts +85 -85
  22. package/dist/esm/src/recaptcha.d.ts +43 -43
  23. package/dist/esm/src/recaptcha.test.d.ts +17 -17
  24. package/dist/esm/src/state.d.ts +54 -54
  25. package/dist/esm/src/storage.d.ts +27 -27
  26. package/dist/esm/src/storage.test.d.ts +17 -17
  27. package/dist/esm/src/types.d.ts +66 -66
  28. package/dist/esm/src/util.d.ts +21 -21
  29. package/dist/esm/test/setup.d.ts +17 -17
  30. package/dist/esm/test/util.d.ts +34 -34
  31. package/dist/index.cjs.js +1632 -1632
  32. package/dist/index.cjs.js.map +1 -1
  33. package/dist/src/api.d.ts +105 -105
  34. package/dist/src/api.test.d.ts +17 -17
  35. package/dist/src/client.d.ts +30 -30
  36. package/dist/src/client.test.d.ts +17 -17
  37. package/dist/src/constants.d.ts +40 -40
  38. package/dist/src/debug.d.ts +22 -22
  39. package/dist/src/debug.test.d.ts +17 -17
  40. package/dist/src/errors.d.ts +61 -61
  41. package/dist/src/factory.d.ts +31 -31
  42. package/dist/src/index.d.ts +14 -14
  43. package/dist/src/indexeddb.d.ts +22 -22
  44. package/dist/src/internal-api.d.ts +44 -44
  45. package/dist/src/internal-api.test.d.ts +17 -17
  46. package/dist/src/logger.d.ts +18 -18
  47. package/dist/src/proactive-refresh.d.ts +35 -35
  48. package/dist/src/proactive-refresh.test.d.ts +17 -17
  49. package/dist/src/providers.d.ts +108 -108
  50. package/dist/src/providers.test.d.ts +17 -17
  51. package/dist/src/public-types.d.ts +85 -85
  52. package/dist/src/recaptcha.d.ts +43 -43
  53. package/dist/src/recaptcha.test.d.ts +17 -17
  54. package/dist/src/state.d.ts +54 -54
  55. package/dist/src/storage.d.ts +27 -27
  56. package/dist/src/storage.test.d.ts +17 -17
  57. package/dist/src/types.d.ts +66 -66
  58. package/dist/src/util.d.ts +21 -21
  59. package/dist/test/setup.d.ts +17 -17
  60. package/dist/test/util.d.ts +34 -34
  61. package/package.json +6 -6
package/dist/index.cjs.js CHANGED
@@ -7,1672 +7,1672 @@ var component = require('@firebase/component');
7
7
  var util = require('@firebase/util');
8
8
  var logger$1 = require('@firebase/logger');
9
9
 
10
- /**
11
- * @license
12
- * Copyright 2020 Google LLC
13
- *
14
- * Licensed under the Apache License, Version 2.0 (the "License");
15
- * you may not use this file except in compliance with the License.
16
- * You may obtain a copy of the License at
17
- *
18
- * http://www.apache.org/licenses/LICENSE-2.0
19
- *
20
- * Unless required by applicable law or agreed to in writing, software
21
- * distributed under the License is distributed on an "AS IS" BASIS,
22
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
- * See the License for the specific language governing permissions and
24
- * limitations under the License.
25
- */
26
- const APP_CHECK_STATES = new Map();
27
- const DEFAULT_STATE = {
28
- activated: false,
29
- tokenObservers: []
30
- };
31
- const DEBUG_STATE = {
32
- initialized: false,
33
- enabled: false
34
- };
35
- /**
36
- * Gets a reference to the state object.
37
- */
38
- function getStateReference(app) {
39
- return APP_CHECK_STATES.get(app) || Object.assign({}, DEFAULT_STATE);
40
- }
41
- /**
42
- * Set once on initialization. The map should hold the same reference to the
43
- * same object until this entry is deleted.
44
- */
45
- function setInitialState(app, state) {
46
- APP_CHECK_STATES.set(app, state);
47
- return APP_CHECK_STATES.get(app);
48
- }
49
- function getDebugState() {
50
- return DEBUG_STATE;
10
+ /**
11
+ * @license
12
+ * Copyright 2020 Google LLC
13
+ *
14
+ * Licensed under the Apache License, Version 2.0 (the "License");
15
+ * you may not use this file except in compliance with the License.
16
+ * You may obtain a copy of the License at
17
+ *
18
+ * http://www.apache.org/licenses/LICENSE-2.0
19
+ *
20
+ * Unless required by applicable law or agreed to in writing, software
21
+ * distributed under the License is distributed on an "AS IS" BASIS,
22
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ * See the License for the specific language governing permissions and
24
+ * limitations under the License.
25
+ */
26
+ const APP_CHECK_STATES = new Map();
27
+ const DEFAULT_STATE = {
28
+ activated: false,
29
+ tokenObservers: []
30
+ };
31
+ const DEBUG_STATE = {
32
+ initialized: false,
33
+ enabled: false
34
+ };
35
+ /**
36
+ * Gets a reference to the state object.
37
+ */
38
+ function getStateReference(app) {
39
+ return APP_CHECK_STATES.get(app) || Object.assign({}, DEFAULT_STATE);
40
+ }
41
+ /**
42
+ * Set once on initialization. The map should hold the same reference to the
43
+ * same object until this entry is deleted.
44
+ */
45
+ function setInitialState(app, state) {
46
+ APP_CHECK_STATES.set(app, state);
47
+ return APP_CHECK_STATES.get(app);
48
+ }
49
+ function getDebugState() {
50
+ return DEBUG_STATE;
51
51
  }
52
52
 
53
- /**
54
- * @license
55
- * Copyright 2020 Google LLC
56
- *
57
- * Licensed under the Apache License, Version 2.0 (the "License");
58
- * you may not use this file except in compliance with the License.
59
- * You may obtain a copy of the License at
60
- *
61
- * http://www.apache.org/licenses/LICENSE-2.0
62
- *
63
- * Unless required by applicable law or agreed to in writing, software
64
- * distributed under the License is distributed on an "AS IS" BASIS,
65
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
66
- * See the License for the specific language governing permissions and
67
- * limitations under the License.
68
- */
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 = {
74
- /**
75
- * The offset time before token natural expiration to run the refresh.
76
- * This is currently 5 minutes.
77
- */
78
- OFFSET_DURATION: 5 * 60 * 1000,
79
- /**
80
- * This is the first retrial wait after an error. This is currently
81
- * 30 seconds.
82
- */
83
- RETRIAL_MIN_WAIT: 30 * 1000,
84
- /**
85
- * This is the maximum retrial wait, currently 16 minutes.
86
- */
87
- RETRIAL_MAX_WAIT: 16 * 60 * 1000
88
- };
89
- /**
90
- * One day in millis, for certain error code backoffs.
91
- */
53
+ /**
54
+ * @license
55
+ * Copyright 2020 Google LLC
56
+ *
57
+ * Licensed under the Apache License, Version 2.0 (the "License");
58
+ * you may not use this file except in compliance with the License.
59
+ * You may obtain a copy of the License at
60
+ *
61
+ * http://www.apache.org/licenses/LICENSE-2.0
62
+ *
63
+ * Unless required by applicable law or agreed to in writing, software
64
+ * distributed under the License is distributed on an "AS IS" BASIS,
65
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
66
+ * See the License for the specific language governing permissions and
67
+ * limitations under the License.
68
+ */
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 = {
74
+ /**
75
+ * The offset time before token natural expiration to run the refresh.
76
+ * This is currently 5 minutes.
77
+ */
78
+ OFFSET_DURATION: 5 * 60 * 1000,
79
+ /**
80
+ * This is the first retrial wait after an error. This is currently
81
+ * 30 seconds.
82
+ */
83
+ RETRIAL_MIN_WAIT: 30 * 1000,
84
+ /**
85
+ * This is the maximum retrial wait, currently 16 minutes.
86
+ */
87
+ RETRIAL_MAX_WAIT: 16 * 60 * 1000
88
+ };
89
+ /**
90
+ * One day in millis, for certain error code backoffs.
91
+ */
92
92
  const ONE_DAY = 24 * 60 * 60 * 1000;
93
93
 
94
- /**
95
- * @license
96
- * Copyright 2020 Google LLC
97
- *
98
- * Licensed under the Apache License, Version 2.0 (the "License");
99
- * you may not use this file except in compliance with the License.
100
- * You may obtain a copy of the License at
101
- *
102
- * http://www.apache.org/licenses/LICENSE-2.0
103
- *
104
- * Unless required by applicable law or agreed to in writing, software
105
- * distributed under the License is distributed on an "AS IS" BASIS,
106
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
107
- * See the License for the specific language governing permissions and
108
- * limitations under the License.
109
- */
110
- /**
111
- * Port from auth proactiverefresh.js
112
- *
113
- */
114
- // TODO: move it to @firebase/util?
115
- // TODO: allow to config whether refresh should happen in the background
116
- class Refresher {
117
- constructor(operation, retryPolicy, getWaitDuration, lowerBound, upperBound) {
118
- this.operation = operation;
119
- this.retryPolicy = retryPolicy;
120
- this.getWaitDuration = getWaitDuration;
121
- this.lowerBound = lowerBound;
122
- this.upperBound = upperBound;
123
- this.pending = null;
124
- this.nextErrorWaitInterval = lowerBound;
125
- if (lowerBound > upperBound) {
126
- throw new Error('Proactive refresh lower bound greater than upper bound!');
127
- }
128
- }
129
- start() {
130
- this.nextErrorWaitInterval = this.lowerBound;
131
- this.process(true).catch(() => {
132
- /* we don't care about the result */
133
- });
134
- }
135
- stop() {
136
- if (this.pending) {
137
- this.pending.reject('cancelled');
138
- this.pending = null;
139
- }
140
- }
141
- isRunning() {
142
- return !!this.pending;
143
- }
144
- async process(hasSucceeded) {
145
- this.stop();
146
- try {
147
- this.pending = new util.Deferred();
148
- this.pending.promise.catch(_e => {
149
- /* ignore */
150
- });
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) {
182
- if (hasSucceeded) {
183
- // If last operation succeeded, reset next error wait interval and return
184
- // the default wait duration.
185
- this.nextErrorWaitInterval = this.lowerBound;
186
- // Return typical wait duration interval after a successful operation.
187
- return this.getWaitDuration();
188
- }
189
- else {
190
- // Get next error wait interval.
191
- const currentErrorWaitInterval = this.nextErrorWaitInterval;
192
- // Double interval for next consecutive error.
193
- this.nextErrorWaitInterval *= 2;
194
- // Make sure next wait interval does not exceed the maximum upper bound.
195
- if (this.nextErrorWaitInterval > this.upperBound) {
196
- this.nextErrorWaitInterval = this.upperBound;
197
- }
198
- return currentErrorWaitInterval;
199
- }
200
- }
201
- }
202
- function sleep(ms) {
203
- return new Promise(resolve => {
204
- setTimeout(resolve, ms);
205
- });
94
+ /**
95
+ * @license
96
+ * Copyright 2020 Google LLC
97
+ *
98
+ * Licensed under the Apache License, Version 2.0 (the "License");
99
+ * you may not use this file except in compliance with the License.
100
+ * You may obtain a copy of the License at
101
+ *
102
+ * http://www.apache.org/licenses/LICENSE-2.0
103
+ *
104
+ * Unless required by applicable law or agreed to in writing, software
105
+ * distributed under the License is distributed on an "AS IS" BASIS,
106
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
107
+ * See the License for the specific language governing permissions and
108
+ * limitations under the License.
109
+ */
110
+ /**
111
+ * Port from auth proactiverefresh.js
112
+ *
113
+ */
114
+ // TODO: move it to @firebase/util?
115
+ // TODO: allow to config whether refresh should happen in the background
116
+ class Refresher {
117
+ constructor(operation, retryPolicy, getWaitDuration, lowerBound, upperBound) {
118
+ this.operation = operation;
119
+ this.retryPolicy = retryPolicy;
120
+ this.getWaitDuration = getWaitDuration;
121
+ this.lowerBound = lowerBound;
122
+ this.upperBound = upperBound;
123
+ this.pending = null;
124
+ this.nextErrorWaitInterval = lowerBound;
125
+ if (lowerBound > upperBound) {
126
+ throw new Error('Proactive refresh lower bound greater than upper bound!');
127
+ }
128
+ }
129
+ start() {
130
+ this.nextErrorWaitInterval = this.lowerBound;
131
+ this.process(true).catch(() => {
132
+ /* we don't care about the result */
133
+ });
134
+ }
135
+ stop() {
136
+ if (this.pending) {
137
+ this.pending.reject('cancelled');
138
+ this.pending = null;
139
+ }
140
+ }
141
+ isRunning() {
142
+ return !!this.pending;
143
+ }
144
+ async process(hasSucceeded) {
145
+ this.stop();
146
+ try {
147
+ this.pending = new util.Deferred();
148
+ this.pending.promise.catch(_e => {
149
+ /* ignore */
150
+ });
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) {
182
+ if (hasSucceeded) {
183
+ // If last operation succeeded, reset next error wait interval and return
184
+ // the default wait duration.
185
+ this.nextErrorWaitInterval = this.lowerBound;
186
+ // Return typical wait duration interval after a successful operation.
187
+ return this.getWaitDuration();
188
+ }
189
+ else {
190
+ // Get next error wait interval.
191
+ const currentErrorWaitInterval = this.nextErrorWaitInterval;
192
+ // Double interval for next consecutive error.
193
+ this.nextErrorWaitInterval *= 2;
194
+ // Make sure next wait interval does not exceed the maximum upper bound.
195
+ if (this.nextErrorWaitInterval > this.upperBound) {
196
+ this.nextErrorWaitInterval = this.upperBound;
197
+ }
198
+ return currentErrorWaitInterval;
199
+ }
200
+ }
201
+ }
202
+ function sleep(ms) {
203
+ return new Promise(resolve => {
204
+ setTimeout(resolve, ms);
205
+ });
206
206
  }
207
207
 
208
- /**
209
- * @license
210
- * Copyright 2020 Google LLC
211
- *
212
- * Licensed under the Apache License, Version 2.0 (the "License");
213
- * you may not use this file except in compliance with the License.
214
- * You may obtain a copy of the License at
215
- *
216
- * http://www.apache.org/licenses/LICENSE-2.0
217
- *
218
- * Unless required by applicable law or agreed to in writing, software
219
- * distributed under the License is distributed on an "AS IS" BASIS,
220
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
221
- * See the License for the specific language governing permissions and
222
- * limitations under the License.
223
- */
224
- const ERRORS = {
225
- ["already-initialized" /* AppCheckError.ALREADY_INITIALIZED */]: 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
226
- 'different options. To avoid this error, call initializeAppCheck() with the ' +
227
- 'same options as when it was originally called. This will return the ' +
228
- 'already initialized instance.',
229
- ["use-before-activation" /* AppCheckError.USE_BEFORE_ACTIVATION */]: 'App Check is being used before initializeAppCheck() is called for FirebaseApp {$appName}. ' +
230
- 'Call initializeAppCheck() before instantiating other Firebase services.',
231
- ["fetch-network-error" /* AppCheckError.FETCH_NETWORK_ERROR */]: 'Fetch failed to connect to a network. Check Internet connection. ' +
232
- 'Original error: {$originalErrorMessage}.',
233
- ["fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */]: 'Fetch client could not parse response.' +
234
- ' Original error: {$originalErrorMessage}.',
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
- };
208
+ /**
209
+ * @license
210
+ * Copyright 2020 Google LLC
211
+ *
212
+ * Licensed under the Apache License, Version 2.0 (the "License");
213
+ * you may not use this file except in compliance with the License.
214
+ * You may obtain a copy of the License at
215
+ *
216
+ * http://www.apache.org/licenses/LICENSE-2.0
217
+ *
218
+ * Unless required by applicable law or agreed to in writing, software
219
+ * distributed under the License is distributed on an "AS IS" BASIS,
220
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
221
+ * See the License for the specific language governing permissions and
222
+ * limitations under the License.
223
+ */
224
+ const ERRORS = {
225
+ ["already-initialized" /* AppCheckError.ALREADY_INITIALIZED */]: 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
226
+ 'different options. To avoid this error, call initializeAppCheck() with the ' +
227
+ 'same options as when it was originally called. This will return the ' +
228
+ 'already initialized instance.',
229
+ ["use-before-activation" /* AppCheckError.USE_BEFORE_ACTIVATION */]: 'App Check is being used before initializeAppCheck() is called for FirebaseApp {$appName}. ' +
230
+ 'Call initializeAppCheck() before instantiating other Firebase services.',
231
+ ["fetch-network-error" /* AppCheckError.FETCH_NETWORK_ERROR */]: 'Fetch failed to connect to a network. Check Internet connection. ' +
232
+ 'Original error: {$originalErrorMessage}.',
233
+ ["fetch-parse-error" /* AppCheckError.FETCH_PARSE_ERROR */]: 'Fetch client could not parse response.' +
234
+ ' Original error: {$originalErrorMessage}.',
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
242
  const ERROR_FACTORY = new util.ErrorFactory('appCheck', 'AppCheck', ERRORS);
243
243
 
244
- /**
245
- * @license
246
- * Copyright 2020 Google LLC
247
- *
248
- * Licensed under the Apache License, Version 2.0 (the "License");
249
- * you may not use this file except in compliance with the License.
250
- * You may obtain a copy of the License at
251
- *
252
- * http://www.apache.org/licenses/LICENSE-2.0
253
- *
254
- * Unless required by applicable law or agreed to in writing, software
255
- * distributed under the License is distributed on an "AS IS" BASIS,
256
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
257
- * See the License for the specific language governing permissions and
258
- * limitations under the License.
259
- */
260
- function getRecaptcha(isEnterprise = false) {
261
- var _a;
262
- if (isEnterprise) {
263
- return (_a = self.grecaptcha) === null || _a === void 0 ? void 0 : _a.enterprise;
264
- }
265
- return self.grecaptcha;
266
- }
267
- function ensureActivated(app) {
268
- if (!getStateReference(app).activated) {
269
- throw ERROR_FACTORY.create("use-before-activation" /* AppCheckError.USE_BEFORE_ACTIVATION */, {
270
- appName: app.name
271
- });
272
- }
273
- }
274
- function getDurationString(durationInMillis) {
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 = '';
281
- if (days) {
282
- result += pad(days) + 'd:';
283
- }
284
- if (hours) {
285
- result += pad(hours) + 'h:';
286
- }
287
- result += pad(minutes) + 'm:' + pad(seconds) + 's';
288
- return result;
289
- }
290
- function pad(value) {
291
- if (value === 0) {
292
- return '00';
293
- }
294
- return value >= 10 ? value.toString() : '0' + value;
244
+ /**
245
+ * @license
246
+ * Copyright 2020 Google LLC
247
+ *
248
+ * Licensed under the Apache License, Version 2.0 (the "License");
249
+ * you may not use this file except in compliance with the License.
250
+ * You may obtain a copy of the License at
251
+ *
252
+ * http://www.apache.org/licenses/LICENSE-2.0
253
+ *
254
+ * Unless required by applicable law or agreed to in writing, software
255
+ * distributed under the License is distributed on an "AS IS" BASIS,
256
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
257
+ * See the License for the specific language governing permissions and
258
+ * limitations under the License.
259
+ */
260
+ function getRecaptcha(isEnterprise = false) {
261
+ var _a;
262
+ if (isEnterprise) {
263
+ return (_a = self.grecaptcha) === null || _a === void 0 ? void 0 : _a.enterprise;
264
+ }
265
+ return self.grecaptcha;
266
+ }
267
+ function ensureActivated(app) {
268
+ if (!getStateReference(app).activated) {
269
+ throw ERROR_FACTORY.create("use-before-activation" /* AppCheckError.USE_BEFORE_ACTIVATION */, {
270
+ appName: app.name
271
+ });
272
+ }
273
+ }
274
+ function getDurationString(durationInMillis) {
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 = '';
281
+ if (days) {
282
+ result += pad(days) + 'd:';
283
+ }
284
+ if (hours) {
285
+ result += pad(hours) + 'h:';
286
+ }
287
+ result += pad(minutes) + 'm:' + pad(seconds) + 's';
288
+ return result;
289
+ }
290
+ function pad(value) {
291
+ if (value === 0) {
292
+ return '00';
293
+ }
294
+ return value >= 10 ? value.toString() : '0' + value;
295
295
  }
296
296
 
297
- /**
298
- * @license
299
- * Copyright 2020 Google LLC
300
- *
301
- * Licensed under the Apache License, Version 2.0 (the "License");
302
- * you may not use this file except in compliance with the License.
303
- * You may obtain a copy of the License at
304
- *
305
- * http://www.apache.org/licenses/LICENSE-2.0
306
- *
307
- * Unless required by applicable law or agreed to in writing, software
308
- * distributed under the License is distributed on an "AS IS" BASIS,
309
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
310
- * See the License for the specific language governing permissions and
311
- * limitations under the License.
312
- */
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
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
- };
372
- }
373
- function getExchangeRecaptchaV3TokenRequest(app, reCAPTCHAToken) {
374
- const { projectId, appId, apiKey } = app.options;
375
- return {
376
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_TOKEN_METHOD}?key=${apiKey}`,
377
- body: {
378
- 'recaptcha_v3_token': reCAPTCHAToken
379
- }
380
- };
381
- }
382
- function getExchangeRecaptchaEnterpriseTokenRequest(app, reCAPTCHAToken) {
383
- const { projectId, appId, apiKey } = app.options;
384
- return {
385
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD}?key=${apiKey}`,
386
- body: {
387
- 'recaptcha_enterprise_token': reCAPTCHAToken
388
- }
389
- };
390
- }
391
- function getExchangeDebugTokenRequest(app, debugToken) {
392
- const { projectId, appId, apiKey } = app.options;
393
- return {
394
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_DEBUG_TOKEN_METHOD}?key=${apiKey}`,
395
- body: {
396
- // eslint-disable-next-line
397
- debug_token: debugToken
398
- }
399
- };
297
+ /**
298
+ * @license
299
+ * Copyright 2020 Google LLC
300
+ *
301
+ * Licensed under the Apache License, Version 2.0 (the "License");
302
+ * you may not use this file except in compliance with the License.
303
+ * You may obtain a copy of the License at
304
+ *
305
+ * http://www.apache.org/licenses/LICENSE-2.0
306
+ *
307
+ * Unless required by applicable law or agreed to in writing, software
308
+ * distributed under the License is distributed on an "AS IS" BASIS,
309
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
310
+ * See the License for the specific language governing permissions and
311
+ * limitations under the License.
312
+ */
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
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
+ };
372
+ }
373
+ function getExchangeRecaptchaV3TokenRequest(app, reCAPTCHAToken) {
374
+ const { projectId, appId, apiKey } = app.options;
375
+ return {
376
+ url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_TOKEN_METHOD}?key=${apiKey}`,
377
+ body: {
378
+ 'recaptcha_v3_token': reCAPTCHAToken
379
+ }
380
+ };
381
+ }
382
+ function getExchangeRecaptchaEnterpriseTokenRequest(app, reCAPTCHAToken) {
383
+ const { projectId, appId, apiKey } = app.options;
384
+ return {
385
+ url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD}?key=${apiKey}`,
386
+ body: {
387
+ 'recaptcha_enterprise_token': reCAPTCHAToken
388
+ }
389
+ };
390
+ }
391
+ function getExchangeDebugTokenRequest(app, debugToken) {
392
+ const { projectId, appId, apiKey } = app.options;
393
+ return {
394
+ url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_DEBUG_TOKEN_METHOD}?key=${apiKey}`,
395
+ body: {
396
+ // eslint-disable-next-line
397
+ debug_token: debugToken
398
+ }
399
+ };
400
400
  }
401
401
 
402
- /**
403
- * @license
404
- * Copyright 2020 Google LLC
405
- *
406
- * Licensed under the Apache License, Version 2.0 (the "License");
407
- * you may not use this file except in compliance with the License.
408
- * You may obtain a copy of the License at
409
- *
410
- * http://www.apache.org/licenses/LICENSE-2.0
411
- *
412
- * Unless required by applicable law or agreed to in writing, software
413
- * distributed under the License is distributed on an "AS IS" BASIS,
414
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
415
- * See the License for the specific language governing permissions and
416
- * limitations under the License.
417
- */
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;
423
- function getDBPromise() {
424
- if (dbPromise) {
425
- return dbPromise;
426
- }
427
- dbPromise = new Promise((resolve, reject) => {
428
- try {
429
- const request = indexedDB.open(DB_NAME, DB_VERSION);
430
- request.onsuccess = event => {
431
- resolve(event.target.result);
432
- };
433
- request.onerror = event => {
434
- var _a;
435
- reject(ERROR_FACTORY.create("storage-open" /* AppCheckError.STORAGE_OPEN */, {
436
- originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
437
- }));
438
- };
439
- request.onupgradeneeded = event => {
440
- const db = event.target.result;
441
- // We don't use 'break' in this switch statement, the fall-through
442
- // behavior is what we want, because if there are multiple versions between
443
- // the old version and the current version, we want ALL the migrations
444
- // that correspond to those versions to run, not only the last one.
445
- // eslint-disable-next-line default-case
446
- switch (event.oldVersion) {
447
- case 0:
448
- db.createObjectStore(STORE_NAME, {
449
- keyPath: 'compositeKey'
450
- });
451
- }
452
- };
453
- }
454
- catch (e) {
455
- reject(ERROR_FACTORY.create("storage-open" /* AppCheckError.STORAGE_OPEN */, {
456
- originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
457
- }));
458
- }
459
- });
460
- return dbPromise;
461
- }
462
- function readTokenFromIndexedDB(app) {
463
- return read(computeKey(app));
464
- }
465
- function writeTokenToIndexedDB(app, token) {
466
- return write(computeKey(app), token);
467
- }
468
- function writeDebugTokenToIndexedDB(token) {
469
- return write(DEBUG_TOKEN_KEY, token);
470
- }
471
- function readDebugTokenFromIndexedDB() {
472
- return read(DEBUG_TOKEN_KEY);
473
- }
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
- };
492
- });
493
- }
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);
504
- }
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
- };
515
- });
516
- }
517
- function computeKey(app) {
518
- return `${app.options.appId}-${app.name}`;
402
+ /**
403
+ * @license
404
+ * Copyright 2020 Google LLC
405
+ *
406
+ * Licensed under the Apache License, Version 2.0 (the "License");
407
+ * you may not use this file except in compliance with the License.
408
+ * You may obtain a copy of the License at
409
+ *
410
+ * http://www.apache.org/licenses/LICENSE-2.0
411
+ *
412
+ * Unless required by applicable law or agreed to in writing, software
413
+ * distributed under the License is distributed on an "AS IS" BASIS,
414
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
415
+ * See the License for the specific language governing permissions and
416
+ * limitations under the License.
417
+ */
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;
423
+ function getDBPromise() {
424
+ if (dbPromise) {
425
+ return dbPromise;
426
+ }
427
+ dbPromise = new Promise((resolve, reject) => {
428
+ try {
429
+ const request = indexedDB.open(DB_NAME, DB_VERSION);
430
+ request.onsuccess = event => {
431
+ resolve(event.target.result);
432
+ };
433
+ request.onerror = event => {
434
+ var _a;
435
+ reject(ERROR_FACTORY.create("storage-open" /* AppCheckError.STORAGE_OPEN */, {
436
+ originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
437
+ }));
438
+ };
439
+ request.onupgradeneeded = event => {
440
+ const db = event.target.result;
441
+ // We don't use 'break' in this switch statement, the fall-through
442
+ // behavior is what we want, because if there are multiple versions between
443
+ // the old version and the current version, we want ALL the migrations
444
+ // that correspond to those versions to run, not only the last one.
445
+ // eslint-disable-next-line default-case
446
+ switch (event.oldVersion) {
447
+ case 0:
448
+ db.createObjectStore(STORE_NAME, {
449
+ keyPath: 'compositeKey'
450
+ });
451
+ }
452
+ };
453
+ }
454
+ catch (e) {
455
+ reject(ERROR_FACTORY.create("storage-open" /* AppCheckError.STORAGE_OPEN */, {
456
+ originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
457
+ }));
458
+ }
459
+ });
460
+ return dbPromise;
461
+ }
462
+ function readTokenFromIndexedDB(app) {
463
+ return read(computeKey(app));
464
+ }
465
+ function writeTokenToIndexedDB(app, token) {
466
+ return write(computeKey(app), token);
467
+ }
468
+ function writeDebugTokenToIndexedDB(token) {
469
+ return write(DEBUG_TOKEN_KEY, token);
470
+ }
471
+ function readDebugTokenFromIndexedDB() {
472
+ return read(DEBUG_TOKEN_KEY);
473
+ }
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
+ };
492
+ });
493
+ }
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);
504
+ }
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
+ };
515
+ });
516
+ }
517
+ function computeKey(app) {
518
+ return `${app.options.appId}-${app.name}`;
519
519
  }
520
520
 
521
- /**
522
- * @license
523
- * Copyright 2020 Google LLC
524
- *
525
- * Licensed under the Apache License, Version 2.0 (the "License");
526
- * you may not use this file except in compliance with the License.
527
- * You may obtain a copy of the License at
528
- *
529
- * http://www.apache.org/licenses/LICENSE-2.0
530
- *
531
- * Unless required by applicable law or agreed to in writing, software
532
- * distributed under the License is distributed on an "AS IS" BASIS,
533
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
534
- * See the License for the specific language governing permissions and
535
- * limitations under the License.
536
- */
521
+ /**
522
+ * @license
523
+ * Copyright 2020 Google LLC
524
+ *
525
+ * Licensed under the Apache License, Version 2.0 (the "License");
526
+ * you may not use this file except in compliance with the License.
527
+ * You may obtain a copy of the License at
528
+ *
529
+ * http://www.apache.org/licenses/LICENSE-2.0
530
+ *
531
+ * Unless required by applicable law or agreed to in writing, software
532
+ * distributed under the License is distributed on an "AS IS" BASIS,
533
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
534
+ * See the License for the specific language governing permissions and
535
+ * limitations under the License.
536
+ */
537
537
  const logger = new logger$1.Logger('@firebase/app-check');
538
538
 
539
- /**
540
- * @license
541
- * Copyright 2020 Google LLC
542
- *
543
- * Licensed under the Apache License, Version 2.0 (the "License");
544
- * you may not use this file except in compliance with the License.
545
- * You may obtain a copy of the License at
546
- *
547
- * http://www.apache.org/licenses/LICENSE-2.0
548
- *
549
- * Unless required by applicable law or agreed to in writing, software
550
- * distributed under the License is distributed on an "AS IS" BASIS,
551
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
552
- * See the License for the specific language governing permissions and
553
- * limitations under the License.
554
- */
555
- /**
556
- * Always resolves. In case of an error reading from indexeddb, resolve with undefined
557
- */
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;
571
- }
572
- /**
573
- * Always resolves. In case of an error writing to indexeddb, print a warning and resolve the promise
574
- */
575
- function writeTokenToStorage(app, token) {
576
- if (util.isIndexedDBAvailable()) {
577
- return writeTokenToIndexedDB(app, token).catch(e => {
578
- // swallow the error and resolve the promise
579
- logger.warn(`Failed to write token to IndexedDB. Error: ${e}`);
580
- });
581
- }
582
- return Promise.resolve();
583
- }
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
- }
539
+ /**
540
+ * @license
541
+ * Copyright 2020 Google LLC
542
+ *
543
+ * Licensed under the Apache License, Version 2.0 (the "License");
544
+ * you may not use this file except in compliance with the License.
545
+ * You may obtain a copy of the License at
546
+ *
547
+ * http://www.apache.org/licenses/LICENSE-2.0
548
+ *
549
+ * Unless required by applicable law or agreed to in writing, software
550
+ * distributed under the License is distributed on an "AS IS" BASIS,
551
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
552
+ * See the License for the specific language governing permissions and
553
+ * limitations under the License.
554
+ */
555
+ /**
556
+ * Always resolves. In case of an error reading from indexeddb, resolve with undefined
557
+ */
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;
571
+ }
572
+ /**
573
+ * Always resolves. In case of an error writing to indexeddb, print a warning and resolve the promise
574
+ */
575
+ function writeTokenToStorage(app, token) {
576
+ if (util.isIndexedDBAvailable()) {
577
+ return writeTokenToIndexedDB(app, token).catch(e => {
578
+ // swallow the error and resolve the promise
579
+ logger.warn(`Failed to write token to IndexedDB. Error: ${e}`);
580
+ });
581
+ }
582
+ return Promise.resolve();
583
+ }
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
+ }
610
610
  }
611
611
 
612
- /**
613
- * @license
614
- * Copyright 2020 Google LLC
615
- *
616
- * Licensed under the Apache License, Version 2.0 (the "License");
617
- * you may not use this file except in compliance with the License.
618
- * You may obtain a copy of the License at
619
- *
620
- * http://www.apache.org/licenses/LICENSE-2.0
621
- *
622
- * Unless required by applicable law or agreed to in writing, software
623
- * distributed under the License is distributed on an "AS IS" BASIS,
624
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
625
- * See the License for the specific language governing permissions and
626
- * limitations under the License.
627
- */
628
- function isDebugMode() {
629
- const debugState = getDebugState();
630
- return debugState.enabled;
631
- }
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!
612
+ /**
613
+ * @license
614
+ * Copyright 2020 Google LLC
615
+ *
616
+ * Licensed under the Apache License, Version 2.0 (the "License");
617
+ * you may not use this file except in compliance with the License.
618
+ * You may obtain a copy of the License at
619
+ *
620
+ * http://www.apache.org/licenses/LICENSE-2.0
621
+ *
622
+ * Unless required by applicable law or agreed to in writing, software
623
+ * distributed under the License is distributed on an "AS IS" BASIS,
624
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
625
+ * See the License for the specific language governing permissions and
626
+ * limitations under the License.
627
+ */
628
+ function isDebugMode() {
629
+ const debugState = getDebugState();
630
+ return debugState.enabled;
631
+ }
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
639
  throw Error(`
640
640
  Can't get debug token in production mode.
641
- `);
642
- }
643
- }
644
- function initializeDebugMode() {
645
- const globals = util.getGlobal();
646
- const debugState = getDebugState();
647
- // Set to true if this function has been called, whether or not
648
- // it enabled debug mode.
649
- debugState.initialized = true;
650
- if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== 'string' &&
651
- globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== true) {
652
- return;
653
- }
654
- debugState.enabled = true;
655
- const deferredToken = new util.Deferred();
656
- debugState.token = deferredToken;
657
- if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN === 'string') {
658
- deferredToken.resolve(globals.FIREBASE_APPCHECK_DEBUG_TOKEN);
659
- }
660
- else {
661
- deferredToken.resolve(readOrCreateDebugTokenFromStorage());
662
- }
641
+ `);
642
+ }
643
+ }
644
+ function initializeDebugMode() {
645
+ const globals = util.getGlobal();
646
+ const debugState = getDebugState();
647
+ // Set to true if this function has been called, whether or not
648
+ // it enabled debug mode.
649
+ debugState.initialized = true;
650
+ if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== 'string' &&
651
+ globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== true) {
652
+ return;
653
+ }
654
+ debugState.enabled = true;
655
+ const deferredToken = new util.Deferred();
656
+ debugState.token = deferredToken;
657
+ if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN === 'string') {
658
+ deferredToken.resolve(globals.FIREBASE_APPCHECK_DEBUG_TOKEN);
659
+ }
660
+ else {
661
+ deferredToken.resolve(readOrCreateDebugTokenFromStorage());
662
+ }
663
663
  }
664
664
 
665
- /**
666
- * @license
667
- * Copyright 2020 Google LLC
668
- *
669
- * Licensed under the Apache License, Version 2.0 (the "License");
670
- * you may not use this file except in compliance with the License.
671
- * You may obtain a copy of the License at
672
- *
673
- * http://www.apache.org/licenses/LICENSE-2.0
674
- *
675
- * Unless required by applicable law or agreed to in writing, software
676
- * distributed under the License is distributed on an "AS IS" BASIS,
677
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
678
- * See the License for the specific language governing permissions and
679
- * limitations under the License.
680
- */
681
- // Initial hardcoded value agreed upon across platforms for initial launch.
682
- // Format left open for possible dynamic error values and other fields in the future.
683
- const defaultTokenErrorData = { error: 'UNKNOWN_ERROR' };
684
- /**
685
- * Stringify and base64 encode token error data.
686
- *
687
- * @param tokenError Error data, currently hardcoded.
688
- */
689
- function formatDummyToken(tokenErrorData) {
690
- return util.base64.encodeString(JSON.stringify(tokenErrorData),
691
- /* webSafe= */ false);
692
- }
693
- /**
694
- * This function always resolves.
695
- * The result will contain an error field if there is any error.
696
- * In case there is an error, the token field in the result will be populated with a dummy value
697
- */
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 {
726
- // If there was an invalid token in the indexedDB cache, clear it.
727
- await writeTokenToStorage(app, undefined);
728
- }
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;
832
- }
833
- /**
834
- * Internal API for limited use tokens. Skips all FAC state and simply calls
835
- * the underlying provider.
836
- */
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
- }
851
- }
852
- function addTokenListener(appCheck, type, listener, onError) {
853
- const { app } = appCheck;
854
- const state = getStateReference(app);
855
- const tokenObserver = {
856
- next: listener,
857
- error: onError,
858
- type
859
- };
860
- state.tokenObservers = [...state.tokenObservers, tokenObserver];
861
- // Invoke the listener async immediately if there is a valid token
862
- // in memory.
863
- if (state.token && isValid(state.token)) {
864
- const validToken = state.token;
865
- Promise.resolve()
866
- .then(() => {
867
- listener({ token: validToken.token });
868
- initTokenRefresher(appCheck);
869
- })
870
- .catch(() => {
871
- /* we don't care about exceptions thrown in listeners */
872
- });
873
- }
874
- /**
875
- * Wait for any cached token promise to resolve before starting the token
876
- * refresher. The refresher checks to see if there is an existing token
877
- * in state and calls the exchange endpoint if not. We should first let the
878
- * IndexedDB check have a chance to populate state if it can.
879
- *
880
- * Listener call isn't needed here because cachedTokenPromise will call any
881
- * listeners that exist when it resolves.
882
- */
883
- // state.cachedTokenPromise is always populated in `activate()`.
884
- void state.cachedTokenPromise.then(() => initTokenRefresher(appCheck));
885
- }
886
- function removeTokenListener(app, listener) {
887
- const state = getStateReference(app);
888
- const newObservers = state.tokenObservers.filter(tokenObserver => tokenObserver.next !== listener);
889
- if (newObservers.length === 0 &&
890
- state.tokenRefresher &&
891
- state.tokenRefresher.isRunning()) {
892
- state.tokenRefresher.stop();
893
- }
894
- state.tokenObservers = newObservers;
895
- }
896
- /**
897
- * Logic to create and start refresher as needed.
898
- */
899
- function initTokenRefresher(appCheck) {
900
- const { app } = appCheck;
901
- const state = getStateReference(app);
902
- // Create the refresher but don't start it if `isTokenAutoRefreshEnabled`
903
- // is not true.
904
- let refresher = state.tokenRefresher;
905
- if (!refresher) {
906
- refresher = createTokenRefresher(appCheck);
907
- state.tokenRefresher = refresher;
908
- }
909
- if (!refresher.isRunning() && state.isTokenAutoRefreshEnabled) {
910
- refresher.start();
911
- }
912
- }
913
- function createTokenRefresher(appCheck) {
914
- const { app } = appCheck;
915
- return new Refresher(
916
- // Keep in mind when this fails for any reason other than the ones
917
- // for which we should retry, it will effectively stop the proactive refresh.
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
- }, () => {
948
- return true;
949
- }, () => {
950
- const state = getStateReference(app);
951
- if (state.token) {
952
- // issuedAtTime + (50% * total TTL) + 5 minutes
953
- let nextRefreshTimeMillis = state.token.issuedAtTimeMillis +
954
- (state.token.expireTimeMillis - state.token.issuedAtTimeMillis) *
955
- 0.5 +
956
- 5 * 60 * 1000;
957
- // Do not allow refresh time to be past (expireTime - 5 minutes)
958
- const latestAllowableRefresh = state.token.expireTimeMillis - 5 * 60 * 1000;
959
- nextRefreshTimeMillis = Math.min(nextRefreshTimeMillis, latestAllowableRefresh);
960
- return Math.max(0, nextRefreshTimeMillis - Date.now());
961
- }
962
- else {
963
- return 0;
964
- }
965
- }, TOKEN_REFRESH_TIME.RETRIAL_MIN_WAIT, TOKEN_REFRESH_TIME.RETRIAL_MAX_WAIT);
966
- }
967
- function notifyTokenListeners(app, token) {
968
- const observers = getStateReference(app).tokenObservers;
969
- for (const observer of observers) {
970
- try {
971
- if (observer.type === "EXTERNAL" /* ListenerType.EXTERNAL */ && token.error != null) {
972
- // If this listener was added by a 3P call, send any token error to
973
- // the supplied error handler. A 3P observer always has an error
974
- // handler.
975
- observer.error(token.error);
976
- }
977
- else {
978
- // If the token has no error field, always return the token.
979
- // If this is a 2P listener, return the token, whether or not it
980
- // has an error field.
981
- observer.next(token);
982
- }
983
- }
984
- catch (e) {
985
- // Errors in the listener function itself are always ignored.
986
- }
987
- }
988
- }
989
- function isValid(token) {
990
- return token.expireTimeMillis - Date.now() > 0;
991
- }
992
- function makeDummyTokenResult(error) {
993
- return {
994
- token: formatDummyToken(defaultTokenErrorData),
995
- error
996
- };
665
+ /**
666
+ * @license
667
+ * Copyright 2020 Google LLC
668
+ *
669
+ * Licensed under the Apache License, Version 2.0 (the "License");
670
+ * you may not use this file except in compliance with the License.
671
+ * You may obtain a copy of the License at
672
+ *
673
+ * http://www.apache.org/licenses/LICENSE-2.0
674
+ *
675
+ * Unless required by applicable law or agreed to in writing, software
676
+ * distributed under the License is distributed on an "AS IS" BASIS,
677
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
678
+ * See the License for the specific language governing permissions and
679
+ * limitations under the License.
680
+ */
681
+ // Initial hardcoded value agreed upon across platforms for initial launch.
682
+ // Format left open for possible dynamic error values and other fields in the future.
683
+ const defaultTokenErrorData = { error: 'UNKNOWN_ERROR' };
684
+ /**
685
+ * Stringify and base64 encode token error data.
686
+ *
687
+ * @param tokenError Error data, currently hardcoded.
688
+ */
689
+ function formatDummyToken(tokenErrorData) {
690
+ return util.base64.encodeString(JSON.stringify(tokenErrorData),
691
+ /* webSafe= */ false);
692
+ }
693
+ /**
694
+ * This function always resolves.
695
+ * The result will contain an error field if there is any error.
696
+ * In case there is an error, the token field in the result will be populated with a dummy value
697
+ */
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 {
726
+ // If there was an invalid token in the indexedDB cache, clear it.
727
+ await writeTokenToStorage(app, undefined);
728
+ }
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;
832
+ }
833
+ /**
834
+ * Internal API for limited use tokens. Skips all FAC state and simply calls
835
+ * the underlying provider.
836
+ */
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
+ }
851
+ }
852
+ function addTokenListener(appCheck, type, listener, onError) {
853
+ const { app } = appCheck;
854
+ const state = getStateReference(app);
855
+ const tokenObserver = {
856
+ next: listener,
857
+ error: onError,
858
+ type
859
+ };
860
+ state.tokenObservers = [...state.tokenObservers, tokenObserver];
861
+ // Invoke the listener async immediately if there is a valid token
862
+ // in memory.
863
+ if (state.token && isValid(state.token)) {
864
+ const validToken = state.token;
865
+ Promise.resolve()
866
+ .then(() => {
867
+ listener({ token: validToken.token });
868
+ initTokenRefresher(appCheck);
869
+ })
870
+ .catch(() => {
871
+ /* we don't care about exceptions thrown in listeners */
872
+ });
873
+ }
874
+ /**
875
+ * Wait for any cached token promise to resolve before starting the token
876
+ * refresher. The refresher checks to see if there is an existing token
877
+ * in state and calls the exchange endpoint if not. We should first let the
878
+ * IndexedDB check have a chance to populate state if it can.
879
+ *
880
+ * Listener call isn't needed here because cachedTokenPromise will call any
881
+ * listeners that exist when it resolves.
882
+ */
883
+ // state.cachedTokenPromise is always populated in `activate()`.
884
+ void state.cachedTokenPromise.then(() => initTokenRefresher(appCheck));
885
+ }
886
+ function removeTokenListener(app, listener) {
887
+ const state = getStateReference(app);
888
+ const newObservers = state.tokenObservers.filter(tokenObserver => tokenObserver.next !== listener);
889
+ if (newObservers.length === 0 &&
890
+ state.tokenRefresher &&
891
+ state.tokenRefresher.isRunning()) {
892
+ state.tokenRefresher.stop();
893
+ }
894
+ state.tokenObservers = newObservers;
895
+ }
896
+ /**
897
+ * Logic to create and start refresher as needed.
898
+ */
899
+ function initTokenRefresher(appCheck) {
900
+ const { app } = appCheck;
901
+ const state = getStateReference(app);
902
+ // Create the refresher but don't start it if `isTokenAutoRefreshEnabled`
903
+ // is not true.
904
+ let refresher = state.tokenRefresher;
905
+ if (!refresher) {
906
+ refresher = createTokenRefresher(appCheck);
907
+ state.tokenRefresher = refresher;
908
+ }
909
+ if (!refresher.isRunning() && state.isTokenAutoRefreshEnabled) {
910
+ refresher.start();
911
+ }
912
+ }
913
+ function createTokenRefresher(appCheck) {
914
+ const { app } = appCheck;
915
+ return new Refresher(
916
+ // Keep in mind when this fails for any reason other than the ones
917
+ // for which we should retry, it will effectively stop the proactive refresh.
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
+ }, () => {
948
+ return true;
949
+ }, () => {
950
+ const state = getStateReference(app);
951
+ if (state.token) {
952
+ // issuedAtTime + (50% * total TTL) + 5 minutes
953
+ let nextRefreshTimeMillis = state.token.issuedAtTimeMillis +
954
+ (state.token.expireTimeMillis - state.token.issuedAtTimeMillis) *
955
+ 0.5 +
956
+ 5 * 60 * 1000;
957
+ // Do not allow refresh time to be past (expireTime - 5 minutes)
958
+ const latestAllowableRefresh = state.token.expireTimeMillis - 5 * 60 * 1000;
959
+ nextRefreshTimeMillis = Math.min(nextRefreshTimeMillis, latestAllowableRefresh);
960
+ return Math.max(0, nextRefreshTimeMillis - Date.now());
961
+ }
962
+ else {
963
+ return 0;
964
+ }
965
+ }, TOKEN_REFRESH_TIME.RETRIAL_MIN_WAIT, TOKEN_REFRESH_TIME.RETRIAL_MAX_WAIT);
966
+ }
967
+ function notifyTokenListeners(app, token) {
968
+ const observers = getStateReference(app).tokenObservers;
969
+ for (const observer of observers) {
970
+ try {
971
+ if (observer.type === "EXTERNAL" /* ListenerType.EXTERNAL */ && token.error != null) {
972
+ // If this listener was added by a 3P call, send any token error to
973
+ // the supplied error handler. A 3P observer always has an error
974
+ // handler.
975
+ observer.error(token.error);
976
+ }
977
+ else {
978
+ // If the token has no error field, always return the token.
979
+ // If this is a 2P listener, return the token, whether or not it
980
+ // has an error field.
981
+ observer.next(token);
982
+ }
983
+ }
984
+ catch (e) {
985
+ // Errors in the listener function itself are always ignored.
986
+ }
987
+ }
988
+ }
989
+ function isValid(token) {
990
+ return token.expireTimeMillis - Date.now() > 0;
991
+ }
992
+ function makeDummyTokenResult(error) {
993
+ return {
994
+ token: formatDummyToken(defaultTokenErrorData),
995
+ error
996
+ };
997
997
  }
998
998
 
999
- /**
1000
- * @license
1001
- * Copyright 2020 Google LLC
1002
- *
1003
- * Licensed under the Apache License, Version 2.0 (the "License");
1004
- * you may not use this file except in compliance with the License.
1005
- * You may obtain a copy of the License at
1006
- *
1007
- * http://www.apache.org/licenses/LICENSE-2.0
1008
- *
1009
- * Unless required by applicable law or agreed to in writing, software
1010
- * distributed under the License is distributed on an "AS IS" BASIS,
1011
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1012
- * See the License for the specific language governing permissions and
1013
- * limitations under the License.
1014
- */
1015
- /**
1016
- * AppCheck Service class.
1017
- */
1018
- class AppCheckService {
1019
- constructor(app, heartbeatServiceProvider) {
1020
- this.app = app;
1021
- this.heartbeatServiceProvider = heartbeatServiceProvider;
1022
- }
1023
- _delete() {
1024
- const { tokenObservers } = getStateReference(this.app);
1025
- for (const tokenObserver of tokenObservers) {
1026
- removeTokenListener(this.app, tokenObserver.next);
1027
- }
1028
- return Promise.resolve();
1029
- }
1030
- }
1031
- function factory(app, heartbeatServiceProvider) {
1032
- return new AppCheckService(app, heartbeatServiceProvider);
1033
- }
1034
- function internalFactory(appCheck) {
1035
- return {
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)
1040
- };
999
+ /**
1000
+ * @license
1001
+ * Copyright 2020 Google LLC
1002
+ *
1003
+ * Licensed under the Apache License, Version 2.0 (the "License");
1004
+ * you may not use this file except in compliance with the License.
1005
+ * You may obtain a copy of the License at
1006
+ *
1007
+ * http://www.apache.org/licenses/LICENSE-2.0
1008
+ *
1009
+ * Unless required by applicable law or agreed to in writing, software
1010
+ * distributed under the License is distributed on an "AS IS" BASIS,
1011
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1012
+ * See the License for the specific language governing permissions and
1013
+ * limitations under the License.
1014
+ */
1015
+ /**
1016
+ * AppCheck Service class.
1017
+ */
1018
+ class AppCheckService {
1019
+ constructor(app, heartbeatServiceProvider) {
1020
+ this.app = app;
1021
+ this.heartbeatServiceProvider = heartbeatServiceProvider;
1022
+ }
1023
+ _delete() {
1024
+ const { tokenObservers } = getStateReference(this.app);
1025
+ for (const tokenObserver of tokenObservers) {
1026
+ removeTokenListener(this.app, tokenObserver.next);
1027
+ }
1028
+ return Promise.resolve();
1029
+ }
1030
+ }
1031
+ function factory(app, heartbeatServiceProvider) {
1032
+ return new AppCheckService(app, heartbeatServiceProvider);
1033
+ }
1034
+ function internalFactory(appCheck) {
1035
+ return {
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)
1040
+ };
1041
1041
  }
1042
1042
 
1043
1043
  const name = "@firebase/app-check";
1044
- const version = "0.8.9";
1044
+ const version = "0.8.10";
1045
1045
 
1046
- /**
1047
- * @license
1048
- * Copyright 2020 Google LLC
1049
- *
1050
- * Licensed under the Apache License, Version 2.0 (the "License");
1051
- * you may not use this file except in compliance with the License.
1052
- * You may obtain a copy of the License at
1053
- *
1054
- * http://www.apache.org/licenses/LICENSE-2.0
1055
- *
1056
- * Unless required by applicable law or agreed to in writing, software
1057
- * distributed under the License is distributed on an "AS IS" BASIS,
1058
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1059
- * See the License for the specific language governing permissions and
1060
- * limitations under the License.
1061
- */
1062
- const RECAPTCHA_URL = 'https://www.google.com/recaptcha/api.js';
1063
- const RECAPTCHA_ENTERPRISE_URL = 'https://www.google.com/recaptcha/enterprise.js';
1064
- function initializeV3(app, siteKey) {
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);
1070
- if (!grecaptcha) {
1071
- loadReCAPTCHAV3Script(() => {
1072
- const grecaptcha = getRecaptcha(false);
1073
- if (!grecaptcha) {
1074
- // it shouldn't happen.
1075
- throw new Error('no recaptcha');
1076
- }
1077
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1078
- });
1079
- }
1080
- else {
1081
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1082
- }
1083
- return initialized.promise;
1084
- }
1085
- function initializeEnterprise(app, siteKey) {
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);
1091
- if (!grecaptcha) {
1092
- loadReCAPTCHAEnterpriseScript(() => {
1093
- const grecaptcha = getRecaptcha(true);
1094
- if (!grecaptcha) {
1095
- // it shouldn't happen.
1096
- throw new Error('no recaptcha');
1097
- }
1098
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1099
- });
1100
- }
1101
- else {
1102
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1103
- }
1104
- return initialized.promise;
1105
- }
1106
- /**
1107
- * Add listener to render the widget and resolve the promise when
1108
- * the grecaptcha.ready() event fires.
1109
- */
1110
- function queueWidgetRender(app, siteKey, grecaptcha, container, initialized) {
1111
- grecaptcha.ready(() => {
1112
- // Invisible widgets allow us to set a different siteKey for each widget,
1113
- // so we use them to support multiple apps
1114
- renderInvisibleWidget(app, siteKey, grecaptcha, container);
1115
- initialized.resolve(grecaptcha);
1116
- });
1117
- }
1118
- /**
1119
- * Add invisible div to page.
1120
- */
1121
- function makeDiv(app) {
1122
- const divId = `fire_app_check_${app.name}`;
1123
- const invisibleDiv = document.createElement('div');
1124
- invisibleDiv.id = divId;
1125
- invisibleDiv.style.display = 'none';
1126
- document.body.appendChild(invisibleDiv);
1127
- return divId;
1128
- }
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
- }));
1143
- });
1144
- });
1145
- }
1146
- /**
1147
- *
1148
- * @param app
1149
- * @param container - Id of a HTML element.
1150
- */
1151
- function renderInvisibleWidget(app, siteKey, grecaptcha, container) {
1152
- const widgetId = grecaptcha.render(container, {
1153
- sitekey: siteKey,
1154
- size: 'invisible',
1155
- // Success callback - set state
1156
- callback: () => {
1157
- getStateReference(app).reCAPTCHAState.succeeded = true;
1158
- },
1159
- // Failure callback - set state
1160
- 'error-callback': () => {
1161
- getStateReference(app).reCAPTCHAState.succeeded = false;
1162
- }
1163
- });
1164
- const state = getStateReference(app);
1165
- state.reCAPTCHAState = Object.assign(Object.assign({}, state.reCAPTCHAState), { // state.reCAPTCHAState is set in the initialize()
1166
- widgetId });
1167
- }
1168
- function loadReCAPTCHAV3Script(onload) {
1169
- const script = document.createElement('script');
1170
- script.src = RECAPTCHA_URL;
1171
- script.onload = onload;
1172
- document.head.appendChild(script);
1173
- }
1174
- function loadReCAPTCHAEnterpriseScript(onload) {
1175
- const script = document.createElement('script');
1176
- script.src = RECAPTCHA_ENTERPRISE_URL;
1177
- script.onload = onload;
1178
- document.head.appendChild(script);
1046
+ /**
1047
+ * @license
1048
+ * Copyright 2020 Google LLC
1049
+ *
1050
+ * Licensed under the Apache License, Version 2.0 (the "License");
1051
+ * you may not use this file except in compliance with the License.
1052
+ * You may obtain a copy of the License at
1053
+ *
1054
+ * http://www.apache.org/licenses/LICENSE-2.0
1055
+ *
1056
+ * Unless required by applicable law or agreed to in writing, software
1057
+ * distributed under the License is distributed on an "AS IS" BASIS,
1058
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1059
+ * See the License for the specific language governing permissions and
1060
+ * limitations under the License.
1061
+ */
1062
+ const RECAPTCHA_URL = 'https://www.google.com/recaptcha/api.js';
1063
+ const RECAPTCHA_ENTERPRISE_URL = 'https://www.google.com/recaptcha/enterprise.js';
1064
+ function initializeV3(app, siteKey) {
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);
1070
+ if (!grecaptcha) {
1071
+ loadReCAPTCHAV3Script(() => {
1072
+ const grecaptcha = getRecaptcha(false);
1073
+ if (!grecaptcha) {
1074
+ // it shouldn't happen.
1075
+ throw new Error('no recaptcha');
1076
+ }
1077
+ queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1078
+ });
1079
+ }
1080
+ else {
1081
+ queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1082
+ }
1083
+ return initialized.promise;
1084
+ }
1085
+ function initializeEnterprise(app, siteKey) {
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);
1091
+ if (!grecaptcha) {
1092
+ loadReCAPTCHAEnterpriseScript(() => {
1093
+ const grecaptcha = getRecaptcha(true);
1094
+ if (!grecaptcha) {
1095
+ // it shouldn't happen.
1096
+ throw new Error('no recaptcha');
1097
+ }
1098
+ queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1099
+ });
1100
+ }
1101
+ else {
1102
+ queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
1103
+ }
1104
+ return initialized.promise;
1105
+ }
1106
+ /**
1107
+ * Add listener to render the widget and resolve the promise when
1108
+ * the grecaptcha.ready() event fires.
1109
+ */
1110
+ function queueWidgetRender(app, siteKey, grecaptcha, container, initialized) {
1111
+ grecaptcha.ready(() => {
1112
+ // Invisible widgets allow us to set a different siteKey for each widget,
1113
+ // so we use them to support multiple apps
1114
+ renderInvisibleWidget(app, siteKey, grecaptcha, container);
1115
+ initialized.resolve(grecaptcha);
1116
+ });
1117
+ }
1118
+ /**
1119
+ * Add invisible div to page.
1120
+ */
1121
+ function makeDiv(app) {
1122
+ const divId = `fire_app_check_${app.name}`;
1123
+ const invisibleDiv = document.createElement('div');
1124
+ invisibleDiv.id = divId;
1125
+ invisibleDiv.style.display = 'none';
1126
+ document.body.appendChild(invisibleDiv);
1127
+ return divId;
1128
+ }
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
+ }));
1143
+ });
1144
+ });
1145
+ }
1146
+ /**
1147
+ *
1148
+ * @param app
1149
+ * @param container - Id of a HTML element.
1150
+ */
1151
+ function renderInvisibleWidget(app, siteKey, grecaptcha, container) {
1152
+ const widgetId = grecaptcha.render(container, {
1153
+ sitekey: siteKey,
1154
+ size: 'invisible',
1155
+ // Success callback - set state
1156
+ callback: () => {
1157
+ getStateReference(app).reCAPTCHAState.succeeded = true;
1158
+ },
1159
+ // Failure callback - set state
1160
+ 'error-callback': () => {
1161
+ getStateReference(app).reCAPTCHAState.succeeded = false;
1162
+ }
1163
+ });
1164
+ const state = getStateReference(app);
1165
+ state.reCAPTCHAState = Object.assign(Object.assign({}, state.reCAPTCHAState), { // state.reCAPTCHAState is set in the initialize()
1166
+ widgetId });
1167
+ }
1168
+ function loadReCAPTCHAV3Script(onload) {
1169
+ const script = document.createElement('script');
1170
+ script.src = RECAPTCHA_URL;
1171
+ script.onload = onload;
1172
+ document.head.appendChild(script);
1173
+ }
1174
+ function loadReCAPTCHAEnterpriseScript(onload) {
1175
+ const script = document.createElement('script');
1176
+ script.src = RECAPTCHA_ENTERPRISE_URL;
1177
+ script.onload = onload;
1178
+ document.head.appendChild(script);
1179
1179
  }
1180
1180
 
1181
- /**
1182
- * @license
1183
- * Copyright 2021 Google LLC
1184
- *
1185
- * Licensed under the Apache License, Version 2.0 (the "License");
1186
- * you may not use this file except in compliance with the License.
1187
- * You may obtain a copy of the License at
1188
- *
1189
- * http://www.apache.org/licenses/LICENSE-2.0
1190
- *
1191
- * Unless required by applicable law or agreed to in writing, software
1192
- * distributed under the License is distributed on an "AS IS" BASIS,
1193
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1194
- * See the License for the specific language governing permissions and
1195
- * limitations under the License.
1196
- */
1197
- /**
1198
- * App Check provider that can obtain a reCAPTCHA V3 token and exchange it
1199
- * for an App Check token.
1200
- *
1201
- * @public
1202
- */
1203
- class ReCaptchaV3Provider {
1204
- /**
1205
- * Create a ReCaptchaV3Provider instance.
1206
- * @param siteKey - ReCAPTCHA V3 siteKey.
1207
- */
1208
- constructor(_siteKey) {
1209
- this._siteKey = _siteKey;
1210
- /**
1211
- * Throttle requests on certain error codes to prevent too many retries
1212
- * in a short time.
1213
- */
1214
- this._throttleData = null;
1215
- }
1216
- /**
1217
- * Returns an App Check token.
1218
- * @internal
1219
- */
1220
- async getToken() {
1221
- var _a, _b, _c;
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 */);
1228
- });
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
- }
1253
- /**
1254
- * @internal
1255
- */
1256
- initialize(app$1) {
1257
- this._app = app$1;
1258
- this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
1259
- initializeV3(app$1, this._siteKey).catch(() => {
1260
- /* we don't care about the initialization result */
1261
- });
1262
- }
1263
- /**
1264
- * @internal
1265
- */
1266
- isEqual(otherProvider) {
1267
- if (otherProvider instanceof ReCaptchaV3Provider) {
1268
- return this._siteKey === otherProvider._siteKey;
1269
- }
1270
- else {
1271
- return false;
1272
- }
1273
- }
1274
- }
1275
- /**
1276
- * App Check provider that can obtain a reCAPTCHA Enterprise token and exchange it
1277
- * for an App Check token.
1278
- *
1279
- * @public
1280
- */
1281
- class ReCaptchaEnterpriseProvider {
1282
- /**
1283
- * Create a ReCaptchaEnterpriseProvider instance.
1284
- * @param siteKey - reCAPTCHA Enterprise score-based site key.
1285
- */
1286
- constructor(_siteKey) {
1287
- this._siteKey = _siteKey;
1288
- /**
1289
- * Throttle requests on certain error codes to prevent too many retries
1290
- * in a short time.
1291
- */
1292
- this._throttleData = null;
1293
- }
1294
- /**
1295
- * Returns an App Check token.
1296
- * @internal
1297
- */
1298
- async getToken() {
1299
- var _a, _b, _c;
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 */);
1306
- });
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
- }
1331
- /**
1332
- * @internal
1333
- */
1334
- initialize(app$1) {
1335
- this._app = app$1;
1336
- this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
1337
- initializeEnterprise(app$1, this._siteKey).catch(() => {
1338
- /* we don't care about the initialization result */
1339
- });
1340
- }
1341
- /**
1342
- * @internal
1343
- */
1344
- isEqual(otherProvider) {
1345
- if (otherProvider instanceof ReCaptchaEnterpriseProvider) {
1346
- return this._siteKey === otherProvider._siteKey;
1347
- }
1348
- else {
1349
- return false;
1350
- }
1351
- }
1352
- }
1353
- /**
1354
- * Custom provider class.
1355
- * @public
1356
- */
1357
- class CustomProvider {
1358
- constructor(_customProviderOptions) {
1359
- this._customProviderOptions = _customProviderOptions;
1360
- }
1361
- /**
1362
- * @internal
1363
- */
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
- }
1379
- /**
1380
- * @internal
1381
- */
1382
- initialize(app) {
1383
- this._app = app;
1384
- }
1385
- /**
1386
- * @internal
1387
- */
1388
- isEqual(otherProvider) {
1389
- if (otherProvider instanceof CustomProvider) {
1390
- return (this._customProviderOptions.getToken.toString() ===
1391
- otherProvider._customProviderOptions.getToken.toString());
1392
- }
1393
- else {
1394
- return false;
1395
- }
1396
- }
1397
- }
1398
- /**
1399
- * Set throttle data to block requests until after a certain time
1400
- * depending on the failed request's status code.
1401
- * @param httpStatus - Status code of failed request.
1402
- * @param throttleData - `ThrottleData` object containing previous throttle
1403
- * data state.
1404
- * @returns Data about current throttle state and expiration time.
1405
- */
1406
- function setBackoff(httpStatus, throttleData) {
1407
- /**
1408
- * Block retries for 1 day for the following error codes:
1409
- *
1410
- * 404: Likely malformed URL.
1411
- *
1412
- * 403:
1413
- * - Attestation failed
1414
- * - Wrong API key
1415
- * - Project deleted
1416
- */
1417
- if (httpStatus === 404 || httpStatus === 403) {
1418
- return {
1419
- backoffCount: 1,
1420
- allowRequestsAfter: Date.now() + ONE_DAY,
1421
- httpStatus
1422
- };
1423
- }
1424
- else {
1425
- /**
1426
- * For all other error codes, the time when it is ok to retry again
1427
- * is based on exponential backoff.
1428
- */
1429
- const backoffCount = throttleData ? throttleData.backoffCount : 0;
1430
- const backoffMillis = util.calculateBackoffMillis(backoffCount, 1000, 2);
1431
- return {
1432
- backoffCount: backoffCount + 1,
1433
- allowRequestsAfter: Date.now() + backoffMillis,
1434
- httpStatus
1435
- };
1436
- }
1437
- }
1438
- function throwIfThrottled(throttleData) {
1439
- if (throttleData) {
1440
- if (Date.now() - throttleData.allowRequestsAfter <= 0) {
1441
- // If before, throw.
1442
- throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
1443
- time: getDurationString(throttleData.allowRequestsAfter - Date.now()),
1444
- httpStatus: throttleData.httpStatus
1445
- });
1446
- }
1447
- }
1181
+ /**
1182
+ * @license
1183
+ * Copyright 2021 Google LLC
1184
+ *
1185
+ * Licensed under the Apache License, Version 2.0 (the "License");
1186
+ * you may not use this file except in compliance with the License.
1187
+ * You may obtain a copy of the License at
1188
+ *
1189
+ * http://www.apache.org/licenses/LICENSE-2.0
1190
+ *
1191
+ * Unless required by applicable law or agreed to in writing, software
1192
+ * distributed under the License is distributed on an "AS IS" BASIS,
1193
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1194
+ * See the License for the specific language governing permissions and
1195
+ * limitations under the License.
1196
+ */
1197
+ /**
1198
+ * App Check provider that can obtain a reCAPTCHA V3 token and exchange it
1199
+ * for an App Check token.
1200
+ *
1201
+ * @public
1202
+ */
1203
+ class ReCaptchaV3Provider {
1204
+ /**
1205
+ * Create a ReCaptchaV3Provider instance.
1206
+ * @param siteKey - ReCAPTCHA V3 siteKey.
1207
+ */
1208
+ constructor(_siteKey) {
1209
+ this._siteKey = _siteKey;
1210
+ /**
1211
+ * Throttle requests on certain error codes to prevent too many retries
1212
+ * in a short time.
1213
+ */
1214
+ this._throttleData = null;
1215
+ }
1216
+ /**
1217
+ * Returns an App Check token.
1218
+ * @internal
1219
+ */
1220
+ async getToken() {
1221
+ var _a, _b, _c;
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 */);
1228
+ });
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
+ }
1253
+ /**
1254
+ * @internal
1255
+ */
1256
+ initialize(app$1) {
1257
+ this._app = app$1;
1258
+ this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
1259
+ initializeV3(app$1, this._siteKey).catch(() => {
1260
+ /* we don't care about the initialization result */
1261
+ });
1262
+ }
1263
+ /**
1264
+ * @internal
1265
+ */
1266
+ isEqual(otherProvider) {
1267
+ if (otherProvider instanceof ReCaptchaV3Provider) {
1268
+ return this._siteKey === otherProvider._siteKey;
1269
+ }
1270
+ else {
1271
+ return false;
1272
+ }
1273
+ }
1274
+ }
1275
+ /**
1276
+ * App Check provider that can obtain a reCAPTCHA Enterprise token and exchange it
1277
+ * for an App Check token.
1278
+ *
1279
+ * @public
1280
+ */
1281
+ class ReCaptchaEnterpriseProvider {
1282
+ /**
1283
+ * Create a ReCaptchaEnterpriseProvider instance.
1284
+ * @param siteKey - reCAPTCHA Enterprise score-based site key.
1285
+ */
1286
+ constructor(_siteKey) {
1287
+ this._siteKey = _siteKey;
1288
+ /**
1289
+ * Throttle requests on certain error codes to prevent too many retries
1290
+ * in a short time.
1291
+ */
1292
+ this._throttleData = null;
1293
+ }
1294
+ /**
1295
+ * Returns an App Check token.
1296
+ * @internal
1297
+ */
1298
+ async getToken() {
1299
+ var _a, _b, _c;
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 */);
1306
+ });
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
+ }
1331
+ /**
1332
+ * @internal
1333
+ */
1334
+ initialize(app$1) {
1335
+ this._app = app$1;
1336
+ this._heartbeatServiceProvider = app._getProvider(app$1, 'heartbeat');
1337
+ initializeEnterprise(app$1, this._siteKey).catch(() => {
1338
+ /* we don't care about the initialization result */
1339
+ });
1340
+ }
1341
+ /**
1342
+ * @internal
1343
+ */
1344
+ isEqual(otherProvider) {
1345
+ if (otherProvider instanceof ReCaptchaEnterpriseProvider) {
1346
+ return this._siteKey === otherProvider._siteKey;
1347
+ }
1348
+ else {
1349
+ return false;
1350
+ }
1351
+ }
1352
+ }
1353
+ /**
1354
+ * Custom provider class.
1355
+ * @public
1356
+ */
1357
+ class CustomProvider {
1358
+ constructor(_customProviderOptions) {
1359
+ this._customProviderOptions = _customProviderOptions;
1360
+ }
1361
+ /**
1362
+ * @internal
1363
+ */
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
+ }
1379
+ /**
1380
+ * @internal
1381
+ */
1382
+ initialize(app) {
1383
+ this._app = app;
1384
+ }
1385
+ /**
1386
+ * @internal
1387
+ */
1388
+ isEqual(otherProvider) {
1389
+ if (otherProvider instanceof CustomProvider) {
1390
+ return (this._customProviderOptions.getToken.toString() ===
1391
+ otherProvider._customProviderOptions.getToken.toString());
1392
+ }
1393
+ else {
1394
+ return false;
1395
+ }
1396
+ }
1397
+ }
1398
+ /**
1399
+ * Set throttle data to block requests until after a certain time
1400
+ * depending on the failed request's status code.
1401
+ * @param httpStatus - Status code of failed request.
1402
+ * @param throttleData - `ThrottleData` object containing previous throttle
1403
+ * data state.
1404
+ * @returns Data about current throttle state and expiration time.
1405
+ */
1406
+ function setBackoff(httpStatus, throttleData) {
1407
+ /**
1408
+ * Block retries for 1 day for the following error codes:
1409
+ *
1410
+ * 404: Likely malformed URL.
1411
+ *
1412
+ * 403:
1413
+ * - Attestation failed
1414
+ * - Wrong API key
1415
+ * - Project deleted
1416
+ */
1417
+ if (httpStatus === 404 || httpStatus === 403) {
1418
+ return {
1419
+ backoffCount: 1,
1420
+ allowRequestsAfter: Date.now() + ONE_DAY,
1421
+ httpStatus
1422
+ };
1423
+ }
1424
+ else {
1425
+ /**
1426
+ * For all other error codes, the time when it is ok to retry again
1427
+ * is based on exponential backoff.
1428
+ */
1429
+ const backoffCount = throttleData ? throttleData.backoffCount : 0;
1430
+ const backoffMillis = util.calculateBackoffMillis(backoffCount, 1000, 2);
1431
+ return {
1432
+ backoffCount: backoffCount + 1,
1433
+ allowRequestsAfter: Date.now() + backoffMillis,
1434
+ httpStatus
1435
+ };
1436
+ }
1437
+ }
1438
+ function throwIfThrottled(throttleData) {
1439
+ if (throttleData) {
1440
+ if (Date.now() - throttleData.allowRequestsAfter <= 0) {
1441
+ // If before, throw.
1442
+ throw ERROR_FACTORY.create("throttled" /* AppCheckError.THROTTLED */, {
1443
+ time: getDurationString(throttleData.allowRequestsAfter - Date.now()),
1444
+ httpStatus: throttleData.httpStatus
1445
+ });
1446
+ }
1447
+ }
1448
1448
  }
1449
1449
 
1450
- /**
1451
- * @license
1452
- * Copyright 2020 Google LLC
1453
- *
1454
- * Licensed under the Apache License, Version 2.0 (the "License");
1455
- * you may not use this file except in compliance with the License.
1456
- * You may obtain a copy of the License at
1457
- *
1458
- * http://www.apache.org/licenses/LICENSE-2.0
1459
- *
1460
- * Unless required by applicable law or agreed to in writing, software
1461
- * distributed under the License is distributed on an "AS IS" BASIS,
1462
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1463
- * See the License for the specific language governing permissions and
1464
- * limitations under the License.
1465
- */
1466
- /**
1467
- * Activate App Check for the given app. Can be called only once per app.
1468
- * @param app - the {@link @firebase/app#FirebaseApp} to activate App Check for
1469
- * @param options - App Check initialization options
1470
- * @public
1471
- */
1472
- function initializeAppCheck(app$1 = app.getApp(), options) {
1473
- app$1 = util.getModularInstance(app$1);
1474
- const provider = app._getProvider(app$1, 'app-check');
1475
- // Ensure initializeDebugMode() is only called once.
1476
- if (!getDebugState().initialized) {
1477
- initializeDebugMode();
1478
- }
1479
- // Log a message containing the debug token when `initializeAppCheck()`
1480
- // is called in debug mode.
1481
- if (isDebugMode()) {
1482
- // Do not block initialization to get the token for the message.
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.`));
1486
- }
1487
- if (provider.isInitialized()) {
1488
- const existingInstance = provider.getImmediate();
1489
- const initialOptions = provider.getOptions();
1490
- if (initialOptions.isTokenAutoRefreshEnabled ===
1491
- options.isTokenAutoRefreshEnabled &&
1492
- initialOptions.provider.isEqual(options.provider)) {
1493
- return existingInstance;
1494
- }
1495
- else {
1496
- throw ERROR_FACTORY.create("already-initialized" /* AppCheckError.ALREADY_INITIALIZED */, {
1497
- appName: app$1.name
1498
- });
1499
- }
1500
- }
1501
- const appCheck = provider.initialize({ options });
1502
- _activate(app$1, options.provider, options.isTokenAutoRefreshEnabled);
1503
- // If isTokenAutoRefreshEnabled is false, do not send any requests to the
1504
- // exchange endpoint without an explicit call from the user either directly
1505
- // or through another Firebase library (storage, functions, etc.)
1506
- if (getStateReference(app$1).isTokenAutoRefreshEnabled) {
1507
- // Adding a listener will start the refresher and fetch a token if needed.
1508
- // This gets a token ready and prevents a delay when an internal library
1509
- // requests the token.
1510
- // Listener function does not need to do anything, its base functionality
1511
- // of calling getToken() already fetches token and writes it to memory/storage.
1512
- addTokenListener(appCheck, "INTERNAL" /* ListenerType.INTERNAL */, () => { });
1513
- }
1514
- return appCheck;
1515
- }
1516
- /**
1517
- * Activate App Check
1518
- * @param app - Firebase app to activate App Check for.
1519
- * @param provider - reCAPTCHA v3 provider or
1520
- * custom token provider.
1521
- * @param isTokenAutoRefreshEnabled - If true, the SDK automatically
1522
- * refreshes App Check tokens as needed. If undefined, defaults to the
1523
- * value of `app.automaticDataCollectionEnabled`, which defaults to
1524
- * false and can be set in the app config.
1525
- */
1526
- function _activate(app, provider, isTokenAutoRefreshEnabled) {
1527
- // Create an entry in the APP_CHECK_STATES map. Further changes should
1528
- // directly mutate this object.
1529
- const state = setInitialState(app, Object.assign({}, DEFAULT_STATE));
1530
- state.activated = true;
1531
- state.provider = provider; // Read cached token from storage if it exists and store it in memory.
1532
- state.cachedTokenPromise = readTokenFromStorage(app).then(cachedToken => {
1533
- if (cachedToken && isValid(cachedToken)) {
1534
- state.token = cachedToken;
1535
- // notify all listeners with the cached token
1536
- notifyTokenListeners(app, { token: cachedToken.token });
1537
- }
1538
- return cachedToken;
1539
- });
1540
- // Use value of global `automaticDataCollectionEnabled` (which
1541
- // itself defaults to false if not specified in config) if
1542
- // `isTokenAutoRefreshEnabled` param was not provided by user.
1543
- state.isTokenAutoRefreshEnabled =
1544
- isTokenAutoRefreshEnabled === undefined
1545
- ? app.automaticDataCollectionEnabled
1546
- : isTokenAutoRefreshEnabled;
1547
- state.provider.initialize(app);
1548
- }
1549
- /**
1550
- * Set whether App Check will automatically refresh tokens as needed.
1551
- *
1552
- * @param appCheckInstance - The App Check service instance.
1553
- * @param isTokenAutoRefreshEnabled - If true, the SDK automatically
1554
- * refreshes App Check tokens as needed. This overrides any value set
1555
- * during `initializeAppCheck()`.
1556
- * @public
1557
- */
1558
- function setTokenAutoRefreshEnabled(appCheckInstance, isTokenAutoRefreshEnabled) {
1559
- const app = appCheckInstance.app;
1560
- const state = getStateReference(app);
1561
- // This will exist if any product libraries have called
1562
- // `addTokenListener()`
1563
- if (state.tokenRefresher) {
1564
- if (isTokenAutoRefreshEnabled === true) {
1565
- state.tokenRefresher.start();
1566
- }
1567
- else {
1568
- state.tokenRefresher.stop();
1569
- }
1570
- }
1571
- state.isTokenAutoRefreshEnabled = isTokenAutoRefreshEnabled;
1572
- }
1573
- /**
1574
- * Get the current App Check token. If `forceRefresh` is false, this function first
1575
- * checks for a valid token in memory, then local persistence (IndexedDB).
1576
- * If not found, or if `forceRefresh` is true, it makes a request to the
1577
- * App Check endpoint for a fresh token. That request attaches
1578
- * to the most recent in-flight request if one is present.
1579
- *
1580
- * @param appCheckInstance - The App Check service instance.
1581
- * @param forceRefresh - If true, will always try to fetch a fresh token.
1582
- * If false, will use a cached token if found in storage.
1583
- * @public
1584
- */
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 };
1591
- }
1592
- /**
1593
- * Requests a Firebase App Check token. This method should be used
1594
- * only if you need to authorize requests to a non-Firebase backend.
1595
- *
1596
- * Returns limited-use tokens that are intended for use with your
1597
- * non-Firebase backend endpoints that are protected with
1598
- * <a href="https://firebase.google.com/docs/app-check/custom-resource-backend#replay-protection">
1599
- * Replay Protection</a>. This method
1600
- * does not affect the token generation behavior of the
1601
- * #getAppCheckToken() method.
1602
- *
1603
- * @param appCheckInstance - The App Check service instance.
1604
- * @returns The limited use token.
1605
- * @public
1606
- */
1607
- function getLimitedUseToken(appCheckInstance) {
1608
- return getLimitedUseToken$1(appCheckInstance);
1609
- }
1610
- /**
1611
- * Wraps `addTokenListener`/`removeTokenListener` methods in an `Observer`
1612
- * pattern for public use.
1613
- */
1614
- function onTokenChanged(appCheckInstance, onNextOrObserver, onError,
1615
- /**
1616
- * NOTE: Although an `onCompletion` callback can be provided, it will
1617
- * never be called because the token stream is never-ending.
1618
- * It is added only for API consistency with the observer pattern, which
1619
- * we follow in JS APIs.
1620
- */
1621
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1622
- onCompletion) {
1623
- let nextFn = () => { };
1624
- let errorFn = () => { };
1625
- if (onNextOrObserver.next != null) {
1626
- nextFn = onNextOrObserver.next.bind(onNextOrObserver);
1627
- }
1628
- else {
1629
- nextFn = onNextOrObserver;
1630
- }
1631
- if (onNextOrObserver.error != null) {
1632
- errorFn = onNextOrObserver.error.bind(onNextOrObserver);
1633
- }
1634
- else if (onError) {
1635
- errorFn = onError;
1636
- }
1637
- addTokenListener(appCheckInstance, "EXTERNAL" /* ListenerType.EXTERNAL */, nextFn, errorFn);
1638
- return () => removeTokenListener(appCheckInstance.app, nextFn);
1450
+ /**
1451
+ * @license
1452
+ * Copyright 2020 Google LLC
1453
+ *
1454
+ * Licensed under the Apache License, Version 2.0 (the "License");
1455
+ * you may not use this file except in compliance with the License.
1456
+ * You may obtain a copy of the License at
1457
+ *
1458
+ * http://www.apache.org/licenses/LICENSE-2.0
1459
+ *
1460
+ * Unless required by applicable law or agreed to in writing, software
1461
+ * distributed under the License is distributed on an "AS IS" BASIS,
1462
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1463
+ * See the License for the specific language governing permissions and
1464
+ * limitations under the License.
1465
+ */
1466
+ /**
1467
+ * Activate App Check for the given app. Can be called only once per app.
1468
+ * @param app - the {@link @firebase/app#FirebaseApp} to activate App Check for
1469
+ * @param options - App Check initialization options
1470
+ * @public
1471
+ */
1472
+ function initializeAppCheck(app$1 = app.getApp(), options) {
1473
+ app$1 = util.getModularInstance(app$1);
1474
+ const provider = app._getProvider(app$1, 'app-check');
1475
+ // Ensure initializeDebugMode() is only called once.
1476
+ if (!getDebugState().initialized) {
1477
+ initializeDebugMode();
1478
+ }
1479
+ // Log a message containing the debug token when `initializeAppCheck()`
1480
+ // is called in debug mode.
1481
+ if (isDebugMode()) {
1482
+ // Do not block initialization to get the token for the message.
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.`));
1486
+ }
1487
+ if (provider.isInitialized()) {
1488
+ const existingInstance = provider.getImmediate();
1489
+ const initialOptions = provider.getOptions();
1490
+ if (initialOptions.isTokenAutoRefreshEnabled ===
1491
+ options.isTokenAutoRefreshEnabled &&
1492
+ initialOptions.provider.isEqual(options.provider)) {
1493
+ return existingInstance;
1494
+ }
1495
+ else {
1496
+ throw ERROR_FACTORY.create("already-initialized" /* AppCheckError.ALREADY_INITIALIZED */, {
1497
+ appName: app$1.name
1498
+ });
1499
+ }
1500
+ }
1501
+ const appCheck = provider.initialize({ options });
1502
+ _activate(app$1, options.provider, options.isTokenAutoRefreshEnabled);
1503
+ // If isTokenAutoRefreshEnabled is false, do not send any requests to the
1504
+ // exchange endpoint without an explicit call from the user either directly
1505
+ // or through another Firebase library (storage, functions, etc.)
1506
+ if (getStateReference(app$1).isTokenAutoRefreshEnabled) {
1507
+ // Adding a listener will start the refresher and fetch a token if needed.
1508
+ // This gets a token ready and prevents a delay when an internal library
1509
+ // requests the token.
1510
+ // Listener function does not need to do anything, its base functionality
1511
+ // of calling getToken() already fetches token and writes it to memory/storage.
1512
+ addTokenListener(appCheck, "INTERNAL" /* ListenerType.INTERNAL */, () => { });
1513
+ }
1514
+ return appCheck;
1515
+ }
1516
+ /**
1517
+ * Activate App Check
1518
+ * @param app - Firebase app to activate App Check for.
1519
+ * @param provider - reCAPTCHA v3 provider or
1520
+ * custom token provider.
1521
+ * @param isTokenAutoRefreshEnabled - If true, the SDK automatically
1522
+ * refreshes App Check tokens as needed. If undefined, defaults to the
1523
+ * value of `app.automaticDataCollectionEnabled`, which defaults to
1524
+ * false and can be set in the app config.
1525
+ */
1526
+ function _activate(app, provider, isTokenAutoRefreshEnabled) {
1527
+ // Create an entry in the APP_CHECK_STATES map. Further changes should
1528
+ // directly mutate this object.
1529
+ const state = setInitialState(app, Object.assign({}, DEFAULT_STATE));
1530
+ state.activated = true;
1531
+ state.provider = provider; // Read cached token from storage if it exists and store it in memory.
1532
+ state.cachedTokenPromise = readTokenFromStorage(app).then(cachedToken => {
1533
+ if (cachedToken && isValid(cachedToken)) {
1534
+ state.token = cachedToken;
1535
+ // notify all listeners with the cached token
1536
+ notifyTokenListeners(app, { token: cachedToken.token });
1537
+ }
1538
+ return cachedToken;
1539
+ });
1540
+ // Use value of global `automaticDataCollectionEnabled` (which
1541
+ // itself defaults to false if not specified in config) if
1542
+ // `isTokenAutoRefreshEnabled` param was not provided by user.
1543
+ state.isTokenAutoRefreshEnabled =
1544
+ isTokenAutoRefreshEnabled === undefined
1545
+ ? app.automaticDataCollectionEnabled
1546
+ : isTokenAutoRefreshEnabled;
1547
+ state.provider.initialize(app);
1548
+ }
1549
+ /**
1550
+ * Set whether App Check will automatically refresh tokens as needed.
1551
+ *
1552
+ * @param appCheckInstance - The App Check service instance.
1553
+ * @param isTokenAutoRefreshEnabled - If true, the SDK automatically
1554
+ * refreshes App Check tokens as needed. This overrides any value set
1555
+ * during `initializeAppCheck()`.
1556
+ * @public
1557
+ */
1558
+ function setTokenAutoRefreshEnabled(appCheckInstance, isTokenAutoRefreshEnabled) {
1559
+ const app = appCheckInstance.app;
1560
+ const state = getStateReference(app);
1561
+ // This will exist if any product libraries have called
1562
+ // `addTokenListener()`
1563
+ if (state.tokenRefresher) {
1564
+ if (isTokenAutoRefreshEnabled === true) {
1565
+ state.tokenRefresher.start();
1566
+ }
1567
+ else {
1568
+ state.tokenRefresher.stop();
1569
+ }
1570
+ }
1571
+ state.isTokenAutoRefreshEnabled = isTokenAutoRefreshEnabled;
1572
+ }
1573
+ /**
1574
+ * Get the current App Check token. If `forceRefresh` is false, this function first
1575
+ * checks for a valid token in memory, then local persistence (IndexedDB).
1576
+ * If not found, or if `forceRefresh` is true, it makes a request to the
1577
+ * App Check endpoint for a fresh token. That request attaches
1578
+ * to the most recent in-flight request if one is present.
1579
+ *
1580
+ * @param appCheckInstance - The App Check service instance.
1581
+ * @param forceRefresh - If true, will always try to fetch a fresh token.
1582
+ * If false, will use a cached token if found in storage.
1583
+ * @public
1584
+ */
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 };
1591
+ }
1592
+ /**
1593
+ * Requests a Firebase App Check token. This method should be used
1594
+ * only if you need to authorize requests to a non-Firebase backend.
1595
+ *
1596
+ * Returns limited-use tokens that are intended for use with your
1597
+ * non-Firebase backend endpoints that are protected with
1598
+ * <a href="https://firebase.google.com/docs/app-check/custom-resource-backend#replay-protection">
1599
+ * Replay Protection</a>. This method
1600
+ * does not affect the token generation behavior of the
1601
+ * #getAppCheckToken() method.
1602
+ *
1603
+ * @param appCheckInstance - The App Check service instance.
1604
+ * @returns The limited use token.
1605
+ * @public
1606
+ */
1607
+ function getLimitedUseToken(appCheckInstance) {
1608
+ return getLimitedUseToken$1(appCheckInstance);
1609
+ }
1610
+ /**
1611
+ * Wraps `addTokenListener`/`removeTokenListener` methods in an `Observer`
1612
+ * pattern for public use.
1613
+ */
1614
+ function onTokenChanged(appCheckInstance, onNextOrObserver, onError,
1615
+ /**
1616
+ * NOTE: Although an `onCompletion` callback can be provided, it will
1617
+ * never be called because the token stream is never-ending.
1618
+ * It is added only for API consistency with the observer pattern, which
1619
+ * we follow in JS APIs.
1620
+ */
1621
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1622
+ onCompletion) {
1623
+ let nextFn = () => { };
1624
+ let errorFn = () => { };
1625
+ if (onNextOrObserver.next != null) {
1626
+ nextFn = onNextOrObserver.next.bind(onNextOrObserver);
1627
+ }
1628
+ else {
1629
+ nextFn = onNextOrObserver;
1630
+ }
1631
+ if (onNextOrObserver.error != null) {
1632
+ errorFn = onNextOrObserver.error.bind(onNextOrObserver);
1633
+ }
1634
+ else if (onError) {
1635
+ errorFn = onError;
1636
+ }
1637
+ addTokenListener(appCheckInstance, "EXTERNAL" /* ListenerType.EXTERNAL */, nextFn, errorFn);
1638
+ return () => removeTokenListener(appCheckInstance.app, nextFn);
1639
1639
  }
1640
1640
 
1641
- /**
1642
- * The Firebase App Check Web SDK.
1643
- *
1644
- * @remarks
1645
- * Firebase App Check does not work in a Node.js environment using `ReCaptchaV3Provider` or
1646
- * `ReCaptchaEnterpriseProvider`, but can be used in Node.js if you use
1647
- * `CustomProvider` and write your own attestation method.
1648
- *
1649
- * @packageDocumentation
1650
- */
1651
- const APP_CHECK_NAME = 'app-check';
1652
- const APP_CHECK_NAME_INTERNAL = 'app-check-internal';
1653
- function registerAppCheck() {
1654
- // The public interface
1655
- app._registerComponent(new component.Component(APP_CHECK_NAME, container => {
1656
- // getImmediate for FirebaseApp will always succeed
1657
- const app = container.getProvider('app').getImmediate();
1658
- const heartbeatServiceProvider = container.getProvider('heartbeat');
1659
- return factory(app, heartbeatServiceProvider);
1660
- }, "PUBLIC" /* ComponentType.PUBLIC */)
1661
- .setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */)
1662
- /**
1663
- * Initialize app-check-internal after app-check is initialized to make AppCheck available to
1664
- * other Firebase SDKs
1665
- */
1666
- .setInstanceCreatedCallback((container, _identifier, _appcheckService) => {
1667
- container.getProvider(APP_CHECK_NAME_INTERNAL).initialize();
1668
- }));
1669
- // The internal interface used by other Firebase products
1670
- app._registerComponent(new component.Component(APP_CHECK_NAME_INTERNAL, container => {
1671
- const appCheck = container.getProvider('app-check').getImmediate();
1672
- return internalFactory(appCheck);
1673
- }, "PUBLIC" /* ComponentType.PUBLIC */).setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */));
1674
- app.registerVersion(name, version);
1675
- }
1641
+ /**
1642
+ * The Firebase App Check Web SDK.
1643
+ *
1644
+ * @remarks
1645
+ * Firebase App Check does not work in a Node.js environment using `ReCaptchaV3Provider` or
1646
+ * `ReCaptchaEnterpriseProvider`, but can be used in Node.js if you use
1647
+ * `CustomProvider` and write your own attestation method.
1648
+ *
1649
+ * @packageDocumentation
1650
+ */
1651
+ const APP_CHECK_NAME = 'app-check';
1652
+ const APP_CHECK_NAME_INTERNAL = 'app-check-internal';
1653
+ function registerAppCheck() {
1654
+ // The public interface
1655
+ app._registerComponent(new component.Component(APP_CHECK_NAME, container => {
1656
+ // getImmediate for FirebaseApp will always succeed
1657
+ const app = container.getProvider('app').getImmediate();
1658
+ const heartbeatServiceProvider = container.getProvider('heartbeat');
1659
+ return factory(app, heartbeatServiceProvider);
1660
+ }, "PUBLIC" /* ComponentType.PUBLIC */)
1661
+ .setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */)
1662
+ /**
1663
+ * Initialize app-check-internal after app-check is initialized to make AppCheck available to
1664
+ * other Firebase SDKs
1665
+ */
1666
+ .setInstanceCreatedCallback((container, _identifier, _appcheckService) => {
1667
+ container.getProvider(APP_CHECK_NAME_INTERNAL).initialize();
1668
+ }));
1669
+ // The internal interface used by other Firebase products
1670
+ app._registerComponent(new component.Component(APP_CHECK_NAME_INTERNAL, container => {
1671
+ const appCheck = container.getProvider('app-check').getImmediate();
1672
+ return internalFactory(appCheck);
1673
+ }, "PUBLIC" /* ComponentType.PUBLIC */).setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */));
1674
+ app.registerVersion(name, version);
1675
+ }
1676
1676
  registerAppCheck();
1677
1677
 
1678
1678
  exports.CustomProvider = CustomProvider;