@firebase/app-check 0.5.1 → 0.5.2-canary.086df7c7e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/app-check-public.d.ts +10 -0
- package/dist/app-check.d.ts +10 -0
- package/dist/esm/index.esm.js +267 -89
- package/dist/esm/index.esm.js.map +1 -1
- package/dist/esm/index.esm2017.js +217 -47
- package/dist/esm/index.esm2017.js.map +1 -1
- package/dist/esm/src/constants.d.ts +4 -0
- package/dist/esm/src/errors.d.ts +6 -1
- package/dist/esm/src/internal-api.d.ts +1 -0
- package/dist/esm/src/providers.d.ts +10 -0
- package/dist/esm/src/providers.test.d.ts +17 -0
- package/dist/esm/src/state.d.ts +1 -0
- package/dist/esm/src/types.d.ts +5 -0
- package/dist/esm/src/util.d.ts +1 -0
- package/dist/index.cjs.js +266 -88
- package/dist/index.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +4 -0
- package/dist/src/errors.d.ts +6 -1
- package/dist/src/internal-api.d.ts +1 -0
- package/dist/src/providers.d.ts +10 -0
- package/dist/src/providers.test.d.ts +17 -0
- package/dist/src/state.d.ts +1 -0
- package/dist/src/types.d.ts +5 -0
- package/dist/src/util.d.ts +1 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @firebase/app-check
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`6f0049e66`](https://github.com/firebase/firebase-js-sdk/commit/6f0049e66064809ae990a2d9461e28b2d6d08d19) [#5676](https://github.com/firebase/firebase-js-sdk/pull/5676) - Block exchange requests for certain periods of time after certain error codes to prevent overwhelming the endpoint. Start token listener when App Check is initialized to avoid extra wait time on first getToken() call.
|
|
8
|
+
|
|
3
9
|
## 0.5.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -169,6 +169,11 @@ export declare class ReCaptchaEnterpriseProvider implements AppCheckProvider {
|
|
|
169
169
|
private _siteKey;
|
|
170
170
|
private _app?;
|
|
171
171
|
private _platformLoggerProvider?;
|
|
172
|
+
/**
|
|
173
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
174
|
+
* in a short time.
|
|
175
|
+
*/
|
|
176
|
+
private _throttleData;
|
|
172
177
|
/**
|
|
173
178
|
* Create a ReCaptchaEnterpriseProvider instance.
|
|
174
179
|
* @param siteKey - reCAPTCHA Enterprise score-based site key.
|
|
@@ -189,6 +194,11 @@ export declare class ReCaptchaV3Provider implements AppCheckProvider {
|
|
|
189
194
|
private _siteKey;
|
|
190
195
|
private _app?;
|
|
191
196
|
private _platformLoggerProvider?;
|
|
197
|
+
/**
|
|
198
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
199
|
+
* in a short time.
|
|
200
|
+
*/
|
|
201
|
+
private _throttleData;
|
|
192
202
|
/**
|
|
193
203
|
* Create a ReCaptchaV3Provider instance.
|
|
194
204
|
* @param siteKey - ReCAPTCHA V3 siteKey.
|
package/dist/app-check.d.ts
CHANGED
|
@@ -191,6 +191,11 @@ export declare class ReCaptchaEnterpriseProvider implements AppCheckProvider {
|
|
|
191
191
|
private _siteKey;
|
|
192
192
|
private _app?;
|
|
193
193
|
private _platformLoggerProvider?;
|
|
194
|
+
/**
|
|
195
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
196
|
+
* in a short time.
|
|
197
|
+
*/
|
|
198
|
+
private _throttleData;
|
|
194
199
|
/**
|
|
195
200
|
* Create a ReCaptchaEnterpriseProvider instance.
|
|
196
201
|
* @param siteKey - reCAPTCHA Enterprise score-based site key.
|
|
@@ -221,6 +226,11 @@ export declare class ReCaptchaV3Provider implements AppCheckProvider {
|
|
|
221
226
|
private _siteKey;
|
|
222
227
|
private _app?;
|
|
223
228
|
private _platformLoggerProvider?;
|
|
229
|
+
/**
|
|
230
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
231
|
+
* in a short time.
|
|
232
|
+
*/
|
|
233
|
+
private _throttleData;
|
|
224
234
|
/**
|
|
225
235
|
* Create a ReCaptchaV3Provider instance.
|
|
226
236
|
* @param siteKey - ReCAPTCHA V3 siteKey.
|
package/dist/esm/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _getProvider, getApp, _registerComponent, registerVersion } from '@firebase/app';
|
|
2
2
|
import { Component } from '@firebase/component';
|
|
3
3
|
import { __awaiter, __generator, __assign, __spreadArray } from 'tslib';
|
|
4
|
-
import { Deferred, ErrorFactory, isIndexedDBAvailable, getGlobal, base64, issuedAtTime, getModularInstance } from '@firebase/util';
|
|
4
|
+
import { Deferred, ErrorFactory, isIndexedDBAvailable, getGlobal, base64, issuedAtTime, calculateBackoffMillis, getModularInstance } from '@firebase/util';
|
|
5
5
|
import { Logger } from '@firebase/logger';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -74,7 +74,11 @@ var TOKEN_REFRESH_TIME = {
|
|
|
74
74
|
* This is the maximum retrial wait, currently 16 minutes.
|
|
75
75
|
*/
|
|
76
76
|
RETRIAL_MAX_WAIT: 16 * 60 * 1000
|
|
77
|
-
};
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* One day in millis, for certain error code backoffs.
|
|
80
|
+
*/
|
|
81
|
+
var ONE_DAY = 24 * 60 * 60 * 1000;
|
|
78
82
|
|
|
79
83
|
/**
|
|
80
84
|
* @license
|
|
@@ -238,6 +242,7 @@ var ERRORS = (_a = {},
|
|
|
238
242
|
_a["storage-get" /* STORAGE_GET */] = 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
|
|
239
243
|
_a["storage-set" /* STORAGE_WRITE */] = 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
|
|
240
244
|
_a["recaptcha-error" /* RECAPTCHA_ERROR */] = 'ReCAPTCHA error.',
|
|
245
|
+
_a["throttled" /* THROTTLED */] = "Requests throttled due to {$httpStatus} error. Attempts allowed again after {$time}",
|
|
241
246
|
_a);
|
|
242
247
|
var ERROR_FACTORY = new ErrorFactory('appCheck', 'AppCheck', ERRORS);
|
|
243
248
|
|
|
@@ -280,6 +285,28 @@ function uuidv4() {
|
|
|
280
285
|
var r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
281
286
|
return v.toString(16);
|
|
282
287
|
});
|
|
288
|
+
}
|
|
289
|
+
function getDurationString(durationInMillis) {
|
|
290
|
+
var totalSeconds = Math.round(durationInMillis / 1000);
|
|
291
|
+
var days = Math.floor(totalSeconds / (3600 * 24));
|
|
292
|
+
var hours = Math.floor((totalSeconds - days * 3600 * 24) / 3600);
|
|
293
|
+
var minutes = Math.floor((totalSeconds - days * 3600 * 24 - hours * 3600) / 60);
|
|
294
|
+
var seconds = totalSeconds - days * 3600 * 24 - hours * 3600 - minutes * 60;
|
|
295
|
+
var result = '';
|
|
296
|
+
if (days) {
|
|
297
|
+
result += pad(days) + 'd:';
|
|
298
|
+
}
|
|
299
|
+
if (hours) {
|
|
300
|
+
result += pad(hours) + 'h:';
|
|
301
|
+
}
|
|
302
|
+
result += pad(minutes) + 'm:' + pad(seconds) + 's';
|
|
303
|
+
return result;
|
|
304
|
+
}
|
|
305
|
+
function pad(value) {
|
|
306
|
+
if (value === 0) {
|
|
307
|
+
return '00';
|
|
308
|
+
}
|
|
309
|
+
return value >= 10 ? value.toString() : '0' + value;
|
|
283
310
|
}
|
|
284
311
|
|
|
285
312
|
/**
|
|
@@ -740,9 +767,9 @@ function formatDummyToken(tokenErrorData) {
|
|
|
740
767
|
function getToken$2(appCheck, forceRefresh) {
|
|
741
768
|
if (forceRefresh === void 0) { forceRefresh = false; }
|
|
742
769
|
return __awaiter(this, void 0, void 0, function () {
|
|
743
|
-
var app, state, token, error, cachedToken,
|
|
744
|
-
return __generator(this, function (
|
|
745
|
-
switch (
|
|
770
|
+
var app, state, token, error, cachedToken, shouldCallListeners, _a, _b, _c, _d, tokenFromDebugExchange, e_1, interopTokenResult;
|
|
771
|
+
return __generator(this, function (_e) {
|
|
772
|
+
switch (_e.label) {
|
|
746
773
|
case 0:
|
|
747
774
|
app = appCheck.app;
|
|
748
775
|
ensureActivated(app);
|
|
@@ -752,14 +779,11 @@ function getToken$2(appCheck, forceRefresh) {
|
|
|
752
779
|
if (!!token) return [3 /*break*/, 2];
|
|
753
780
|
return [4 /*yield*/, state.cachedTokenPromise];
|
|
754
781
|
case 1:
|
|
755
|
-
cachedToken =
|
|
782
|
+
cachedToken = _e.sent();
|
|
756
783
|
if (cachedToken && isValid(cachedToken)) {
|
|
757
784
|
token = cachedToken;
|
|
758
|
-
setState(app, __assign(__assign({}, state), { token: token }));
|
|
759
|
-
// notify all listeners with the cached token
|
|
760
|
-
notifyTokenListeners(app, { token: token.token });
|
|
761
785
|
}
|
|
762
|
-
|
|
786
|
+
_e.label = 2;
|
|
763
787
|
case 2:
|
|
764
788
|
// Return the cached token (from either memory or indexedDB) if it's valid
|
|
765
789
|
if (!forceRefresh && token && isValid(token)) {
|
|
@@ -767,44 +791,69 @@ function getToken$2(appCheck, forceRefresh) {
|
|
|
767
791
|
token: token.token
|
|
768
792
|
}];
|
|
769
793
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
794
|
+
shouldCallListeners = false;
|
|
795
|
+
if (!isDebugMode()) return [3 /*break*/, 7];
|
|
796
|
+
if (!!state.exchangeTokenPromise) return [3 /*break*/, 4];
|
|
797
|
+
_a = state;
|
|
798
|
+
_b = exchangeToken;
|
|
799
|
+
_c = getExchangeDebugTokenRequest;
|
|
800
|
+
_d = [app];
|
|
774
801
|
return [4 /*yield*/, getDebugToken()];
|
|
775
|
-
case 3:
|
|
776
|
-
|
|
777
|
-
|
|
802
|
+
case 3:
|
|
803
|
+
_a.exchangeTokenPromise = _b.apply(void 0, [_c.apply(void 0, _d.concat([_e.sent()])), appCheck.platformLoggerProvider]).then(function (token) {
|
|
804
|
+
state.exchangeTokenPromise = undefined;
|
|
805
|
+
return token;
|
|
806
|
+
});
|
|
807
|
+
shouldCallListeners = true;
|
|
808
|
+
_e.label = 4;
|
|
809
|
+
case 4: return [4 /*yield*/, state.exchangeTokenPromise];
|
|
810
|
+
case 5:
|
|
811
|
+
tokenFromDebugExchange = _e.sent();
|
|
778
812
|
// Write debug token to indexedDB.
|
|
779
813
|
return [4 /*yield*/, writeTokenToStorage(app, tokenFromDebugExchange)];
|
|
780
|
-
case
|
|
814
|
+
case 6:
|
|
781
815
|
// Write debug token to indexedDB.
|
|
782
|
-
|
|
816
|
+
_e.sent();
|
|
783
817
|
// Write debug token to state.
|
|
784
818
|
setState(app, __assign(__assign({}, state), { token: tokenFromDebugExchange }));
|
|
785
819
|
return [2 /*return*/, { token: tokenFromDebugExchange.token }];
|
|
786
|
-
case 6:
|
|
787
|
-
_d.trys.push([6, 8, , 9]);
|
|
788
|
-
return [4 /*yield*/, state.provider.getToken()];
|
|
789
820
|
case 7:
|
|
790
|
-
|
|
791
|
-
//
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
821
|
+
_e.trys.push([7, 9, , 10]);
|
|
822
|
+
// Avoid making another call to the exchange endpoint if one is in flight.
|
|
823
|
+
if (!state.exchangeTokenPromise) {
|
|
824
|
+
// state.provider is populated in initializeAppCheck()
|
|
825
|
+
// ensureActivated() at the top of this function checks that
|
|
826
|
+
// initializeAppCheck() has been called.
|
|
827
|
+
state.exchangeTokenPromise = state.provider.getToken().then(function (token) {
|
|
828
|
+
state.exchangeTokenPromise = undefined;
|
|
829
|
+
return token;
|
|
830
|
+
});
|
|
831
|
+
shouldCallListeners = true;
|
|
832
|
+
}
|
|
833
|
+
return [4 /*yield*/, state.exchangeTokenPromise];
|
|
795
834
|
case 8:
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
logger.error(e_1);
|
|
799
|
-
error = e_1;
|
|
800
|
-
return [3 /*break*/, 9];
|
|
835
|
+
token = _e.sent();
|
|
836
|
+
return [3 /*break*/, 10];
|
|
801
837
|
case 9:
|
|
802
|
-
|
|
838
|
+
e_1 = _e.sent();
|
|
839
|
+
if (e_1.code === "appCheck/" + "throttled" /* THROTTLED */) {
|
|
840
|
+
// Warn if throttled, but do not treat it as an error.
|
|
841
|
+
logger.warn(e_1.message);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
// `getToken()` should never throw, but logging error text to console will aid debugging.
|
|
845
|
+
logger.error(e_1);
|
|
846
|
+
}
|
|
847
|
+
// Always save error to be added to dummy token.
|
|
848
|
+
error = e_1;
|
|
849
|
+
return [3 /*break*/, 10];
|
|
850
|
+
case 10:
|
|
851
|
+
if (!!token) return [3 /*break*/, 11];
|
|
803
852
|
// if token is undefined, there must be an error.
|
|
804
853
|
// we return a dummy token along with the error
|
|
805
854
|
interopTokenResult = makeDummyTokenResult(error);
|
|
806
|
-
return [3 /*break*/,
|
|
807
|
-
case
|
|
855
|
+
return [3 /*break*/, 13];
|
|
856
|
+
case 11:
|
|
808
857
|
interopTokenResult = {
|
|
809
858
|
token: token.token
|
|
810
859
|
};
|
|
@@ -812,11 +861,13 @@ function getToken$2(appCheck, forceRefresh) {
|
|
|
812
861
|
// Only do it if we got a valid new token
|
|
813
862
|
setState(app, __assign(__assign({}, state), { token: token }));
|
|
814
863
|
return [4 /*yield*/, writeTokenToStorage(app, token)];
|
|
815
|
-
case 11:
|
|
816
|
-
_d.sent();
|
|
817
|
-
_d.label = 12;
|
|
818
864
|
case 12:
|
|
819
|
-
|
|
865
|
+
_e.sent();
|
|
866
|
+
_e.label = 13;
|
|
867
|
+
case 13:
|
|
868
|
+
if (shouldCallListeners) {
|
|
869
|
+
notifyTokenListeners(app, interopTokenResult);
|
|
870
|
+
}
|
|
820
871
|
return [2 /*return*/, interopTokenResult];
|
|
821
872
|
}
|
|
822
873
|
});
|
|
@@ -830,44 +881,31 @@ function addTokenListener(appCheck, type, listener, onError) {
|
|
|
830
881
|
error: onError,
|
|
831
882
|
type: type
|
|
832
883
|
};
|
|
833
|
-
|
|
834
|
-
/**
|
|
835
|
-
* Invoke the listener with the valid token, then start the token refresher
|
|
836
|
-
*/
|
|
837
|
-
if (!newState.tokenRefresher) {
|
|
838
|
-
var tokenRefresher = createTokenRefresher(appCheck);
|
|
839
|
-
newState.tokenRefresher = tokenRefresher;
|
|
840
|
-
}
|
|
841
|
-
// Create the refresher but don't start it if `isTokenAutoRefreshEnabled`
|
|
842
|
-
// is not true.
|
|
843
|
-
if (!newState.tokenRefresher.isRunning() && state.isTokenAutoRefreshEnabled) {
|
|
844
|
-
newState.tokenRefresher.start();
|
|
845
|
-
}
|
|
884
|
+
setState(app, __assign(__assign({}, state), { tokenObservers: __spreadArray(__spreadArray([], state.tokenObservers), [tokenObserver]) }));
|
|
846
885
|
// Invoke the listener async immediately if there is a valid token
|
|
847
886
|
// in memory.
|
|
848
887
|
if (state.token && isValid(state.token)) {
|
|
849
888
|
var validToken_1 = state.token;
|
|
850
889
|
Promise.resolve()
|
|
851
|
-
.then(function () {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
else if (state.token == null) {
|
|
857
|
-
// Only check cache if there was no token. If the token was invalid,
|
|
858
|
-
// skip this and rely on exchange endpoint.
|
|
859
|
-
void state
|
|
860
|
-
.cachedTokenPromise // Storage token promise. Always populated in `activate()`.
|
|
861
|
-
.then(function (cachedToken) {
|
|
862
|
-
if (cachedToken && isValid(cachedToken)) {
|
|
863
|
-
listener({ token: cachedToken.token });
|
|
864
|
-
}
|
|
890
|
+
.then(function () {
|
|
891
|
+
listener({ token: validToken_1.token });
|
|
892
|
+
initTokenRefresher(appCheck);
|
|
865
893
|
})
|
|
866
894
|
.catch(function () {
|
|
867
|
-
|
|
895
|
+
/* we don't care about exceptions thrown in listeners */
|
|
868
896
|
});
|
|
869
897
|
}
|
|
870
|
-
|
|
898
|
+
/**
|
|
899
|
+
* Wait for any cached token promise to resolve before starting the token
|
|
900
|
+
* refresher. The refresher checks to see if there is an existing token
|
|
901
|
+
* in state and calls the exchange endpoint if not. We should first let the
|
|
902
|
+
* IndexedDB check have a chance to populate state if it can.
|
|
903
|
+
*
|
|
904
|
+
* Listener call isn't needed here because cachedTokenPromise will call any
|
|
905
|
+
* listeners that exist when it resolves.
|
|
906
|
+
*/
|
|
907
|
+
// state.cachedTokenPromise is always populated in `activate()`.
|
|
908
|
+
void state.cachedTokenPromise.then(function () { return initTokenRefresher(appCheck); });
|
|
871
909
|
}
|
|
872
910
|
function removeTokenListener(app, listener) {
|
|
873
911
|
var state = getState(app);
|
|
@@ -879,6 +917,23 @@ function removeTokenListener(app, listener) {
|
|
|
879
917
|
}
|
|
880
918
|
setState(app, __assign(__assign({}, state), { tokenObservers: newObservers }));
|
|
881
919
|
}
|
|
920
|
+
/**
|
|
921
|
+
* Logic to create and start refresher as needed.
|
|
922
|
+
*/
|
|
923
|
+
function initTokenRefresher(appCheck) {
|
|
924
|
+
var app = appCheck.app;
|
|
925
|
+
var state = getState(app);
|
|
926
|
+
// Create the refresher but don't start it if `isTokenAutoRefreshEnabled`
|
|
927
|
+
// is not true.
|
|
928
|
+
var refresher = state.tokenRefresher;
|
|
929
|
+
if (!refresher) {
|
|
930
|
+
refresher = createTokenRefresher(appCheck);
|
|
931
|
+
setState(app, __assign(__assign({}, state), { tokenRefresher: refresher }));
|
|
932
|
+
}
|
|
933
|
+
if (!refresher.isRunning() && state.isTokenAutoRefreshEnabled) {
|
|
934
|
+
refresher.start();
|
|
935
|
+
}
|
|
936
|
+
}
|
|
882
937
|
function createTokenRefresher(appCheck) {
|
|
883
938
|
var _this = this;
|
|
884
939
|
var app = appCheck.app;
|
|
@@ -909,7 +964,6 @@ function createTokenRefresher(appCheck) {
|
|
|
909
964
|
}
|
|
910
965
|
});
|
|
911
966
|
}); }, function () {
|
|
912
|
-
// TODO: when should we retry?
|
|
913
967
|
return true;
|
|
914
968
|
}, function () {
|
|
915
969
|
var state = getState(app);
|
|
@@ -1010,7 +1064,7 @@ function internalFactory(appCheck) {
|
|
|
1010
1064
|
}
|
|
1011
1065
|
|
|
1012
1066
|
var name = "@firebase/app-check";
|
|
1013
|
-
var version = "0.5.
|
|
1067
|
+
var version = "0.5.2-canary.086df7c7e";
|
|
1014
1068
|
|
|
1015
1069
|
/**
|
|
1016
1070
|
* @license
|
|
@@ -1177,23 +1231,53 @@ var ReCaptchaV3Provider = /** @class */ (function () {
|
|
|
1177
1231
|
*/
|
|
1178
1232
|
function ReCaptchaV3Provider(_siteKey) {
|
|
1179
1233
|
this._siteKey = _siteKey;
|
|
1234
|
+
/**
|
|
1235
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
1236
|
+
* in a short time.
|
|
1237
|
+
*/
|
|
1238
|
+
this._throttleData = null;
|
|
1180
1239
|
}
|
|
1181
1240
|
/**
|
|
1182
1241
|
* Returns an App Check token.
|
|
1183
1242
|
* @internal
|
|
1184
1243
|
*/
|
|
1185
1244
|
ReCaptchaV3Provider.prototype.getToken = function () {
|
|
1245
|
+
var _a;
|
|
1186
1246
|
return __awaiter(this, void 0, void 0, function () {
|
|
1187
|
-
var attestedClaimsToken;
|
|
1188
|
-
return __generator(this, function (
|
|
1189
|
-
switch (
|
|
1190
|
-
case 0:
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1247
|
+
var attestedClaimsToken, result, e_1;
|
|
1248
|
+
return __generator(this, function (_b) {
|
|
1249
|
+
switch (_b.label) {
|
|
1250
|
+
case 0:
|
|
1251
|
+
throwIfThrottled(this._throttleData);
|
|
1252
|
+
return [4 /*yield*/, getToken$1(this._app).catch(function (_e) {
|
|
1253
|
+
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1254
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* RECAPTCHA_ERROR */);
|
|
1255
|
+
})];
|
|
1194
1256
|
case 1:
|
|
1195
|
-
attestedClaimsToken =
|
|
1196
|
-
|
|
1257
|
+
attestedClaimsToken = _b.sent();
|
|
1258
|
+
_b.label = 2;
|
|
1259
|
+
case 2:
|
|
1260
|
+
_b.trys.push([2, 4, , 5]);
|
|
1261
|
+
return [4 /*yield*/, exchangeToken(getExchangeRecaptchaV3TokenRequest(this._app, attestedClaimsToken), this._platformLoggerProvider)];
|
|
1262
|
+
case 3:
|
|
1263
|
+
result = _b.sent();
|
|
1264
|
+
return [3 /*break*/, 5];
|
|
1265
|
+
case 4:
|
|
1266
|
+
e_1 = _b.sent();
|
|
1267
|
+
if (e_1.code === "fetch-status-error" /* FETCH_STATUS_ERROR */) {
|
|
1268
|
+
this._throttleData = setBackoff(Number((_a = e_1.customData) === null || _a === void 0 ? void 0 : _a.httpStatus), this._throttleData);
|
|
1269
|
+
throw ERROR_FACTORY.create("throttled" /* THROTTLED */, {
|
|
1270
|
+
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1271
|
+
httpStatus: this._throttleData.httpStatus
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
throw e_1;
|
|
1276
|
+
}
|
|
1277
|
+
case 5:
|
|
1278
|
+
// If successful, clear throttle data.
|
|
1279
|
+
this._throttleData = null;
|
|
1280
|
+
return [2 /*return*/, result];
|
|
1197
1281
|
}
|
|
1198
1282
|
});
|
|
1199
1283
|
});
|
|
@@ -1234,23 +1318,53 @@ var ReCaptchaEnterpriseProvider = /** @class */ (function () {
|
|
|
1234
1318
|
*/
|
|
1235
1319
|
function ReCaptchaEnterpriseProvider(_siteKey) {
|
|
1236
1320
|
this._siteKey = _siteKey;
|
|
1321
|
+
/**
|
|
1322
|
+
* Throttle requests on certain error codes to prevent too many retries
|
|
1323
|
+
* in a short time.
|
|
1324
|
+
*/
|
|
1325
|
+
this._throttleData = null;
|
|
1237
1326
|
}
|
|
1238
1327
|
/**
|
|
1239
1328
|
* Returns an App Check token.
|
|
1240
1329
|
* @internal
|
|
1241
1330
|
*/
|
|
1242
1331
|
ReCaptchaEnterpriseProvider.prototype.getToken = function () {
|
|
1332
|
+
var _a;
|
|
1243
1333
|
return __awaiter(this, void 0, void 0, function () {
|
|
1244
|
-
var attestedClaimsToken;
|
|
1245
|
-
return __generator(this, function (
|
|
1246
|
-
switch (
|
|
1247
|
-
case 0:
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1334
|
+
var attestedClaimsToken, result, e_2;
|
|
1335
|
+
return __generator(this, function (_b) {
|
|
1336
|
+
switch (_b.label) {
|
|
1337
|
+
case 0:
|
|
1338
|
+
throwIfThrottled(this._throttleData);
|
|
1339
|
+
return [4 /*yield*/, getToken$1(this._app).catch(function (_e) {
|
|
1340
|
+
// reCaptcha.execute() throws null which is not very descriptive.
|
|
1341
|
+
throw ERROR_FACTORY.create("recaptcha-error" /* RECAPTCHA_ERROR */);
|
|
1342
|
+
})];
|
|
1251
1343
|
case 1:
|
|
1252
|
-
attestedClaimsToken =
|
|
1253
|
-
|
|
1344
|
+
attestedClaimsToken = _b.sent();
|
|
1345
|
+
_b.label = 2;
|
|
1346
|
+
case 2:
|
|
1347
|
+
_b.trys.push([2, 4, , 5]);
|
|
1348
|
+
return [4 /*yield*/, exchangeToken(getExchangeRecaptchaEnterpriseTokenRequest(this._app, attestedClaimsToken), this._platformLoggerProvider)];
|
|
1349
|
+
case 3:
|
|
1350
|
+
result = _b.sent();
|
|
1351
|
+
return [3 /*break*/, 5];
|
|
1352
|
+
case 4:
|
|
1353
|
+
e_2 = _b.sent();
|
|
1354
|
+
if (e_2.code === "fetch-status-error" /* FETCH_STATUS_ERROR */) {
|
|
1355
|
+
this._throttleData = setBackoff(Number((_a = e_2.customData) === null || _a === void 0 ? void 0 : _a.httpStatus), this._throttleData);
|
|
1356
|
+
throw ERROR_FACTORY.create("throttled" /* THROTTLED */, {
|
|
1357
|
+
time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
|
|
1358
|
+
httpStatus: this._throttleData.httpStatus
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
else {
|
|
1362
|
+
throw e_2;
|
|
1363
|
+
}
|
|
1364
|
+
case 5:
|
|
1365
|
+
// If successful, clear throttle data.
|
|
1366
|
+
this._throttleData = null;
|
|
1367
|
+
return [2 /*return*/, result];
|
|
1254
1368
|
}
|
|
1255
1369
|
});
|
|
1256
1370
|
});
|
|
@@ -1327,7 +1441,58 @@ var CustomProvider = /** @class */ (function () {
|
|
|
1327
1441
|
}
|
|
1328
1442
|
};
|
|
1329
1443
|
return CustomProvider;
|
|
1330
|
-
}());
|
|
1444
|
+
}());
|
|
1445
|
+
/**
|
|
1446
|
+
* Set throttle data to block requests until after a certain time
|
|
1447
|
+
* depending on the failed request's status code.
|
|
1448
|
+
* @param httpStatus - Status code of failed request.
|
|
1449
|
+
* @param throttleData - `ThrottleData` object containing previous throttle
|
|
1450
|
+
* data state.
|
|
1451
|
+
* @returns Data about current throttle state and expiration time.
|
|
1452
|
+
*/
|
|
1453
|
+
function setBackoff(httpStatus, throttleData) {
|
|
1454
|
+
/**
|
|
1455
|
+
* Block retries for 1 day for the following error codes:
|
|
1456
|
+
*
|
|
1457
|
+
* 404: Likely malformed URL.
|
|
1458
|
+
*
|
|
1459
|
+
* 403:
|
|
1460
|
+
* - Attestation failed
|
|
1461
|
+
* - Wrong API key
|
|
1462
|
+
* - Project deleted
|
|
1463
|
+
*/
|
|
1464
|
+
if (httpStatus === 404 || httpStatus === 403) {
|
|
1465
|
+
return {
|
|
1466
|
+
backoffCount: 1,
|
|
1467
|
+
allowRequestsAfter: Date.now() + ONE_DAY,
|
|
1468
|
+
httpStatus: httpStatus
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
else {
|
|
1472
|
+
/**
|
|
1473
|
+
* For all other error codes, the time when it is ok to retry again
|
|
1474
|
+
* is based on exponential backoff.
|
|
1475
|
+
*/
|
|
1476
|
+
var backoffCount = throttleData ? throttleData.backoffCount : 0;
|
|
1477
|
+
var backoffMillis = calculateBackoffMillis(backoffCount, 1000, 2);
|
|
1478
|
+
return {
|
|
1479
|
+
backoffCount: backoffCount + 1,
|
|
1480
|
+
allowRequestsAfter: Date.now() + backoffMillis,
|
|
1481
|
+
httpStatus: httpStatus
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
function throwIfThrottled(throttleData) {
|
|
1486
|
+
if (throttleData) {
|
|
1487
|
+
if (Date.now() - throttleData.allowRequestsAfter <= 0) {
|
|
1488
|
+
// If before, throw.
|
|
1489
|
+
throw ERROR_FACTORY.create("throttled" /* THROTTLED */, {
|
|
1490
|
+
time: getDurationString(throttleData.allowRequestsAfter - Date.now()),
|
|
1491
|
+
httpStatus: throttleData.httpStatus
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1331
1496
|
|
|
1332
1497
|
/**
|
|
1333
1498
|
* @license
|
|
@@ -1384,6 +1549,17 @@ function initializeAppCheck(app, options) {
|
|
|
1384
1549
|
}
|
|
1385
1550
|
var appCheck = provider.initialize({ options: options });
|
|
1386
1551
|
_activate(app, options.provider, options.isTokenAutoRefreshEnabled);
|
|
1552
|
+
// If isTokenAutoRefreshEnabled is false, do not send any requests to the
|
|
1553
|
+
// exchange endpoint without an explicit call from the user either directly
|
|
1554
|
+
// or through another Firebase library (storage, functions, etc.)
|
|
1555
|
+
if (getState(app).isTokenAutoRefreshEnabled) {
|
|
1556
|
+
// Adding a listener will start the refresher and fetch a token if needed.
|
|
1557
|
+
// This gets a token ready and prevents a delay when an internal library
|
|
1558
|
+
// requests the token.
|
|
1559
|
+
// Listener function does not need to do anything, its base functionality
|
|
1560
|
+
// of calling getToken() already fetches token and writes it to memory/storage.
|
|
1561
|
+
addTokenListener(appCheck, "INTERNAL" /* INTERNAL */, function () { });
|
|
1562
|
+
}
|
|
1387
1563
|
return appCheck;
|
|
1388
1564
|
}
|
|
1389
1565
|
/**
|
|
@@ -1403,6 +1579,8 @@ function _activate(app, provider, isTokenAutoRefreshEnabled) {
|
|
|
1403
1579
|
newState.cachedTokenPromise = readTokenFromStorage(app).then(function (cachedToken) {
|
|
1404
1580
|
if (cachedToken && isValid(cachedToken)) {
|
|
1405
1581
|
setState(app, __assign(__assign({}, getState(app)), { token: cachedToken }));
|
|
1582
|
+
// notify all listeners with the cached token
|
|
1583
|
+
notifyTokenListeners(app, { token: cachedToken.token });
|
|
1406
1584
|
}
|
|
1407
1585
|
return cachedToken;
|
|
1408
1586
|
});
|