123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608 |
- import { _getProvider, getApp, _registerComponent, registerVersion } from '@firebase/app';
- import { Component } from '@firebase/component';
- import { Deferred, ErrorFactory, isIndexedDBAvailable, uuidv4, getGlobal, base64, issuedAtTime, calculateBackoffMillis, getModularInstance } from '@firebase/util';
- import { Logger } from '@firebase/logger';
-
-
- const APP_CHECK_STATES = new Map();
- const DEFAULT_STATE = {
- activated: false,
- tokenObservers: []
- };
- const DEBUG_STATE = {
- initialized: false,
- enabled: false
- };
-
- function getStateReference(app) {
- return APP_CHECK_STATES.get(app) || Object.assign({}, DEFAULT_STATE);
- }
-
- function setInitialState(app, state) {
- APP_CHECK_STATES.set(app, state);
- return APP_CHECK_STATES.get(app);
- }
- function getDebugState() {
- return DEBUG_STATE;
- }
-
-
- const BASE_ENDPOINT = 'https://content-firebaseappcheck.googleapis.com/v1';
- const EXCHANGE_RECAPTCHA_TOKEN_METHOD = 'exchangeRecaptchaV3Token';
- const EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD = 'exchangeRecaptchaEnterpriseToken';
- const EXCHANGE_DEBUG_TOKEN_METHOD = 'exchangeDebugToken';
- const TOKEN_REFRESH_TIME = {
-
-
- OFFSET_DURATION: 5 * 60 * 1000,
-
-
- RETRIAL_MIN_WAIT: 30 * 1000,
-
-
- RETRIAL_MAX_WAIT: 16 * 60 * 1000
- };
-
- const ONE_DAY = 24 * 60 * 60 * 1000;
-
-
-
-
-
- class Refresher {
- constructor(operation, retryPolicy, getWaitDuration, lowerBound, upperBound) {
- this.operation = operation;
- this.retryPolicy = retryPolicy;
- this.getWaitDuration = getWaitDuration;
- this.lowerBound = lowerBound;
- this.upperBound = upperBound;
- this.pending = null;
- this.nextErrorWaitInterval = lowerBound;
- if (lowerBound > upperBound) {
- throw new Error('Proactive refresh lower bound greater than upper bound!');
- }
- }
- start() {
- this.nextErrorWaitInterval = this.lowerBound;
- this.process(true).catch(() => {
-
- });
- }
- stop() {
- if (this.pending) {
- this.pending.reject('cancelled');
- this.pending = null;
- }
- }
- isRunning() {
- return !!this.pending;
- }
- async process(hasSucceeded) {
- this.stop();
- try {
- this.pending = new Deferred();
- await sleep(this.getNextRun(hasSucceeded));
-
-
-
-
-
- this.pending.resolve();
- await this.pending.promise;
- this.pending = new Deferred();
- await this.operation();
- this.pending.resolve();
- await this.pending.promise;
- this.process(true).catch(() => {
-
- });
- }
- catch (error) {
- if (this.retryPolicy(error)) {
- this.process(false).catch(() => {
-
- });
- }
- else {
- this.stop();
- }
- }
- }
- getNextRun(hasSucceeded) {
- if (hasSucceeded) {
-
-
- this.nextErrorWaitInterval = this.lowerBound;
-
- return this.getWaitDuration();
- }
- else {
-
- const currentErrorWaitInterval = this.nextErrorWaitInterval;
-
- this.nextErrorWaitInterval *= 2;
-
- if (this.nextErrorWaitInterval > this.upperBound) {
- this.nextErrorWaitInterval = this.upperBound;
- }
- return currentErrorWaitInterval;
- }
- }
- }
- function sleep(ms) {
- return new Promise(resolve => {
- setTimeout(resolve, ms);
- });
- }
-
-
- const ERRORS = {
- ["already-initialized" ]: 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
- 'different options. To avoid this error, call initializeAppCheck() with the ' +
- 'same options as when it was originally called. This will return the ' +
- 'already initialized instance.',
- ["use-before-activation" ]: 'App Check is being used before initializeAppCheck() is called for FirebaseApp {$appName}. ' +
- 'Call initializeAppCheck() before instantiating other Firebase services.',
- ["fetch-network-error" ]: 'Fetch failed to connect to a network. Check Internet connection. ' +
- 'Original error: {$originalErrorMessage}.',
- ["fetch-parse-error" ]: 'Fetch client could not parse response.' +
- ' Original error: {$originalErrorMessage}.',
- ["fetch-status-error" ]: 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.',
- ["storage-open" ]: 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
- ["storage-get" ]: 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
- ["storage-set" ]: 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
- ["recaptcha-error" ]: 'ReCAPTCHA error.',
- ["throttled" ]: `Requests throttled due to {$httpStatus} error. Attempts allowed again after {$time}`
- };
- const ERROR_FACTORY = new ErrorFactory('appCheck', 'AppCheck', ERRORS);
-
-
- function getRecaptcha(isEnterprise = false) {
- var _a;
- if (isEnterprise) {
- return (_a = self.grecaptcha) === null || _a === void 0 ? void 0 : _a.enterprise;
- }
- return self.grecaptcha;
- }
- function ensureActivated(app) {
- if (!getStateReference(app).activated) {
- throw ERROR_FACTORY.create("use-before-activation" , {
- appName: app.name
- });
- }
- }
- function getDurationString(durationInMillis) {
- const totalSeconds = Math.round(durationInMillis / 1000);
- const days = Math.floor(totalSeconds / (3600 * 24));
- const hours = Math.floor((totalSeconds - days * 3600 * 24) / 3600);
- const minutes = Math.floor((totalSeconds - days * 3600 * 24 - hours * 3600) / 60);
- const seconds = totalSeconds - days * 3600 * 24 - hours * 3600 - minutes * 60;
- let result = '';
- if (days) {
- result += pad(days) + 'd:';
- }
- if (hours) {
- result += pad(hours) + 'h:';
- }
- result += pad(minutes) + 'm:' + pad(seconds) + 's';
- return result;
- }
- function pad(value) {
- if (value === 0) {
- return '00';
- }
- return value >= 10 ? value.toString() : '0' + value;
- }
-
-
- async function exchangeToken({ url, body }, heartbeatServiceProvider) {
- const headers = {
- 'Content-Type': 'application/json'
- };
-
- const heartbeatService = heartbeatServiceProvider.getImmediate({
- optional: true
- });
- if (heartbeatService) {
- const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
- if (heartbeatsHeader) {
- headers['X-Firebase-Client'] = heartbeatsHeader;
- }
- }
- const options = {
- method: 'POST',
- body: JSON.stringify(body),
- headers
- };
- let response;
- try {
- response = await fetch(url, options);
- }
- catch (originalError) {
- throw ERROR_FACTORY.create("fetch-network-error" , {
- originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message
- });
- }
- if (response.status !== 200) {
- throw ERROR_FACTORY.create("fetch-status-error" , {
- httpStatus: response.status
- });
- }
- let responseBody;
- try {
-
- responseBody = await response.json();
- }
- catch (originalError) {
- throw ERROR_FACTORY.create("fetch-parse-error" , {
- originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message
- });
- }
-
-
- const match = responseBody.ttl.match(/^([\d.]+)(s)$/);
- if (!match || !match[2] || isNaN(Number(match[1]))) {
- throw ERROR_FACTORY.create("fetch-parse-error" , {
- originalErrorMessage: `ttl field (timeToLive) is not in standard Protobuf Duration ` +
- `format: ${responseBody.ttl}`
- });
- }
- const timeToLiveAsNumber = Number(match[1]) * 1000;
- const now = Date.now();
- return {
- token: responseBody.token,
- expireTimeMillis: now + timeToLiveAsNumber,
- issuedAtTimeMillis: now
- };
- }
- function getExchangeRecaptchaV3TokenRequest(app, reCAPTCHAToken) {
- const { projectId, appId, apiKey } = app.options;
- return {
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_TOKEN_METHOD}?key=${apiKey}`,
- body: {
- 'recaptcha_v3_token': reCAPTCHAToken
- }
- };
- }
- function getExchangeRecaptchaEnterpriseTokenRequest(app, reCAPTCHAToken) {
- const { projectId, appId, apiKey } = app.options;
- return {
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_ENTERPRISE_TOKEN_METHOD}?key=${apiKey}`,
- body: {
- 'recaptcha_enterprise_token': reCAPTCHAToken
- }
- };
- }
- function getExchangeDebugTokenRequest(app, debugToken) {
- const { projectId, appId, apiKey } = app.options;
- return {
- url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_DEBUG_TOKEN_METHOD}?key=${apiKey}`,
- body: {
-
- debug_token: debugToken
- }
- };
- }
-
-
- const DB_NAME = 'firebase-app-check-database';
- const DB_VERSION = 1;
- const STORE_NAME = 'firebase-app-check-store';
- const DEBUG_TOKEN_KEY = 'debug-token';
- let dbPromise = null;
- function getDBPromise() {
- if (dbPromise) {
- return dbPromise;
- }
- dbPromise = new Promise((resolve, reject) => {
- try {
- const request = indexedDB.open(DB_NAME, DB_VERSION);
- request.onsuccess = event => {
- resolve(event.target.result);
- };
- request.onerror = event => {
- var _a;
- reject(ERROR_FACTORY.create("storage-open" , {
- originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
- }));
- };
- request.onupgradeneeded = event => {
- const db = event.target.result;
-
-
-
-
-
- switch (event.oldVersion) {
- case 0:
- db.createObjectStore(STORE_NAME, {
- keyPath: 'compositeKey'
- });
- }
- };
- }
- catch (e) {
- reject(ERROR_FACTORY.create("storage-open" , {
- originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
- }));
- }
- });
- return dbPromise;
- }
- function readTokenFromIndexedDB(app) {
- return read(computeKey(app));
- }
- function writeTokenToIndexedDB(app, token) {
- return write(computeKey(app), token);
- }
- function writeDebugTokenToIndexedDB(token) {
- return write(DEBUG_TOKEN_KEY, token);
- }
- function readDebugTokenFromIndexedDB() {
- return read(DEBUG_TOKEN_KEY);
- }
- async function write(key, value) {
- const db = await getDBPromise();
- const transaction = db.transaction(STORE_NAME, 'readwrite');
- const store = transaction.objectStore(STORE_NAME);
- const request = store.put({
- compositeKey: key,
- value
- });
- return new Promise((resolve, reject) => {
- request.onsuccess = _event => {
- resolve();
- };
- transaction.onerror = event => {
- var _a;
- reject(ERROR_FACTORY.create("storage-set" , {
- originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
- }));
- };
- });
- }
- async function read(key) {
- const db = await getDBPromise();
- const transaction = db.transaction(STORE_NAME, 'readonly');
- const store = transaction.objectStore(STORE_NAME);
- const request = store.get(key);
- return new Promise((resolve, reject) => {
- request.onsuccess = event => {
- const result = event.target.result;
- if (result) {
- resolve(result.value);
- }
- else {
- resolve(undefined);
- }
- };
- transaction.onerror = event => {
- var _a;
- reject(ERROR_FACTORY.create("storage-get" , {
- originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
- }));
- };
- });
- }
- function computeKey(app) {
- return `${app.options.appId}-${app.name}`;
- }
-
-
- const logger = new Logger('@firebase/app-check');
-
-
-
- async function readTokenFromStorage(app) {
- if (isIndexedDBAvailable()) {
- let token = undefined;
- try {
- token = await readTokenFromIndexedDB(app);
- }
- catch (e) {
-
- logger.warn(`Failed to read token from IndexedDB. Error: ${e}`);
- }
- return token;
- }
- return undefined;
- }
-
- function writeTokenToStorage(app, token) {
- if (isIndexedDBAvailable()) {
- return writeTokenToIndexedDB(app, token).catch(e => {
-
- logger.warn(`Failed to write token to IndexedDB. Error: ${e}`);
- });
- }
- return Promise.resolve();
- }
- async function readOrCreateDebugTokenFromStorage() {
-
-
- let existingDebugToken = undefined;
- try {
- existingDebugToken = await readDebugTokenFromIndexedDB();
- }
- catch (_e) {
-
- }
- if (!existingDebugToken) {
-
- const newToken = uuidv4();
-
-
-
-
-
- writeDebugTokenToIndexedDB(newToken).catch(e => logger.warn(`Failed to persist debug token to IndexedDB. Error: ${e}`));
- return newToken;
- }
- else {
- return existingDebugToken;
- }
- }
-
-
- function isDebugMode() {
- const debugState = getDebugState();
- return debugState.enabled;
- }
- async function getDebugToken() {
- const state = getDebugState();
- if (state.enabled && state.token) {
- return state.token.promise;
- }
- else {
-
- throw Error(`
- Can't get debug token in production mode.
- `);
- }
- }
- function initializeDebugMode() {
- const globals = getGlobal();
- const debugState = getDebugState();
-
-
- debugState.initialized = true;
- if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== 'string' &&
- globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== true) {
- return;
- }
- debugState.enabled = true;
- const deferredToken = new Deferred();
- debugState.token = deferredToken;
- if (typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN === 'string') {
- deferredToken.resolve(globals.FIREBASE_APPCHECK_DEBUG_TOKEN);
- }
- else {
- deferredToken.resolve(readOrCreateDebugTokenFromStorage());
- }
- }
-
-
-
-
- const defaultTokenErrorData = { error: 'UNKNOWN_ERROR' };
-
- function formatDummyToken(tokenErrorData) {
- return base64.encodeString(JSON.stringify(tokenErrorData),
- false);
- }
-
- async function getToken$2(appCheck, forceRefresh = false) {
- const app = appCheck.app;
- ensureActivated(app);
- const state = getStateReference(app);
-
-
- let token = state.token;
- let error = undefined;
-
-
- if (token && !isValid(token)) {
- state.token = undefined;
- token = undefined;
- }
-
-
- if (!token) {
-
- const cachedToken = await state.cachedTokenPromise;
- if (cachedToken) {
- if (isValid(cachedToken)) {
- token = cachedToken;
- }
- else {
-
- await writeTokenToStorage(app, undefined);
- }
- }
- }
-
- if (!forceRefresh && token && isValid(token)) {
- return {
- token: token.token
- };
- }
-
-
-
- let shouldCallListeners = false;
-
-
- if (isDebugMode()) {
-
- if (!state.exchangeTokenPromise) {
- state.exchangeTokenPromise = exchangeToken(getExchangeDebugTokenRequest(app, await getDebugToken()), appCheck.heartbeatServiceProvider).finally(() => {
-
- state.exchangeTokenPromise = undefined;
- });
- shouldCallListeners = true;
- }
- const tokenFromDebugExchange = await state.exchangeTokenPromise;
-
- await writeTokenToStorage(app, tokenFromDebugExchange);
-
- state.token = tokenFromDebugExchange;
- return { token: tokenFromDebugExchange.token };
- }
-
-
- try {
-
- if (!state.exchangeTokenPromise) {
-
-
-
- state.exchangeTokenPromise = state.provider.getToken().finally(() => {
-
- state.exchangeTokenPromise = undefined;
- });
- shouldCallListeners = true;
- }
- token = await getStateReference(app).exchangeTokenPromise;
- }
- catch (e) {
- if (e.code === `appCheck/${"throttled" /* AppCheckError.THROTTLED */}`) {
-
- logger.warn(e.message);
- }
- else {
-
- logger.error(e);
- }
-
- error = e;
- }
- let interopTokenResult;
- if (!token) {
-
-
- interopTokenResult = makeDummyTokenResult(error);
- }
- else if (error) {
- if (isValid(token)) {
-
-
-
-
-
-
-
- interopTokenResult = {
- token: token.token,
- internalError: error
- };
- }
- else {
-
-
- interopTokenResult = makeDummyTokenResult(error);
- }
- }
- else {
- interopTokenResult = {
- token: token.token
- };
-
-
- state.token = token;
- await writeTokenToStorage(app, token);
- }
- if (shouldCallListeners) {
- notifyTokenListeners(app, interopTokenResult);
- }
- return interopTokenResult;
- }
- function addTokenListener(appCheck, type, listener, onError) {
- const { app } = appCheck;
- const state = getStateReference(app);
- const tokenObserver = {
- next: listener,
- error: onError,
- type
- };
- state.tokenObservers = [...state.tokenObservers, tokenObserver];
-
-
- if (state.token && isValid(state.token)) {
- const validToken = state.token;
- Promise.resolve()
- .then(() => {
- listener({ token: validToken.token });
- initTokenRefresher(appCheck);
- })
- .catch(() => {
-
- });
- }
-
-
-
- void state.cachedTokenPromise.then(() => initTokenRefresher(appCheck));
- }
- function removeTokenListener(app, listener) {
- const state = getStateReference(app);
- const newObservers = state.tokenObservers.filter(tokenObserver => tokenObserver.next !== listener);
- if (newObservers.length === 0 &&
- state.tokenRefresher &&
- state.tokenRefresher.isRunning()) {
- state.tokenRefresher.stop();
- }
- state.tokenObservers = newObservers;
- }
-
- function initTokenRefresher(appCheck) {
- const { app } = appCheck;
- const state = getStateReference(app);
-
-
- let refresher = state.tokenRefresher;
- if (!refresher) {
- refresher = createTokenRefresher(appCheck);
- state.tokenRefresher = refresher;
- }
- if (!refresher.isRunning() && state.isTokenAutoRefreshEnabled) {
- refresher.start();
- }
- }
- function createTokenRefresher(appCheck) {
- const { app } = appCheck;
- return new Refresher(
-
-
- async () => {
- const state = getStateReference(app);
-
-
- let result;
- if (!state.token) {
- result = await getToken$2(appCheck);
- }
- else {
- result = await getToken$2(appCheck, true);
- }
-
-
- if (result.error) {
- throw result.error;
- }
-
-
- if (result.internalError) {
- throw result.internalError;
- }
- }, () => {
- return true;
- }, () => {
- const state = getStateReference(app);
- if (state.token) {
-
- let nextRefreshTimeMillis = state.token.issuedAtTimeMillis +
- (state.token.expireTimeMillis - state.token.issuedAtTimeMillis) *
- 0.5 +
- 5 * 60 * 1000;
-
- const latestAllowableRefresh = state.token.expireTimeMillis - 5 * 60 * 1000;
- nextRefreshTimeMillis = Math.min(nextRefreshTimeMillis, latestAllowableRefresh);
- return Math.max(0, nextRefreshTimeMillis - Date.now());
- }
- else {
- return 0;
- }
- }, TOKEN_REFRESH_TIME.RETRIAL_MIN_WAIT, TOKEN_REFRESH_TIME.RETRIAL_MAX_WAIT);
- }
- function notifyTokenListeners(app, token) {
- const observers = getStateReference(app).tokenObservers;
- for (const observer of observers) {
- try {
- if (observer.type === "EXTERNAL" && token.error != null) {
-
-
-
- observer.error(token.error);
- }
- else {
-
-
-
- observer.next(token);
- }
- }
- catch (e) {
-
- }
- }
- }
- function isValid(token) {
- return token.expireTimeMillis - Date.now() > 0;
- }
- function makeDummyTokenResult(error) {
- return {
- token: formatDummyToken(defaultTokenErrorData),
- error
- };
- }
-
-
-
- class AppCheckService {
- constructor(app, heartbeatServiceProvider) {
- this.app = app;
- this.heartbeatServiceProvider = heartbeatServiceProvider;
- }
- _delete() {
- const { tokenObservers } = getStateReference(this.app);
- for (const tokenObserver of tokenObservers) {
- removeTokenListener(this.app, tokenObserver.next);
- }
- return Promise.resolve();
- }
- }
- function factory(app, heartbeatServiceProvider) {
- return new AppCheckService(app, heartbeatServiceProvider);
- }
- function internalFactory(appCheck) {
- return {
- getToken: forceRefresh => getToken$2(appCheck, forceRefresh),
- addTokenListener: listener => addTokenListener(appCheck, "INTERNAL" , listener),
- removeTokenListener: listener => removeTokenListener(appCheck.app, listener)
- };
- }
-
- const name = "@firebase/app-check";
- const version = "0.6.1";
-
-
- const RECAPTCHA_URL = 'https://www.google.com/recaptcha/api.js';
- const RECAPTCHA_ENTERPRISE_URL = 'https://www.google.com/recaptcha/enterprise.js';
- function initializeV3(app, siteKey) {
- const initialized = new Deferred();
- const state = getStateReference(app);
- state.reCAPTCHAState = { initialized };
- const divId = makeDiv(app);
- const grecaptcha = getRecaptcha(false);
- if (!grecaptcha) {
- loadReCAPTCHAV3Script(() => {
- const grecaptcha = getRecaptcha(false);
- if (!grecaptcha) {
-
- throw new Error('no recaptcha');
- }
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
- });
- }
- else {
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
- }
- return initialized.promise;
- }
- function initializeEnterprise(app, siteKey) {
- const initialized = new Deferred();
- const state = getStateReference(app);
- state.reCAPTCHAState = { initialized };
- const divId = makeDiv(app);
- const grecaptcha = getRecaptcha(true);
- if (!grecaptcha) {
- loadReCAPTCHAEnterpriseScript(() => {
- const grecaptcha = getRecaptcha(true);
- if (!grecaptcha) {
-
- throw new Error('no recaptcha');
- }
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
- });
- }
- else {
- queueWidgetRender(app, siteKey, grecaptcha, divId, initialized);
- }
- return initialized.promise;
- }
-
- function queueWidgetRender(app, siteKey, grecaptcha, container, initialized) {
- grecaptcha.ready(() => {
-
-
- renderInvisibleWidget(app, siteKey, grecaptcha, container);
- initialized.resolve(grecaptcha);
- });
- }
-
- function makeDiv(app) {
- const divId = `fire_app_check_${app.name}`;
- const invisibleDiv = document.createElement('div');
- invisibleDiv.id = divId;
- invisibleDiv.style.display = 'none';
- document.body.appendChild(invisibleDiv);
- return divId;
- }
- async function getToken$1(app) {
- ensureActivated(app);
-
- const reCAPTCHAState = getStateReference(app).reCAPTCHAState;
- const recaptcha = await reCAPTCHAState.initialized.promise;
- return new Promise((resolve, _reject) => {
-
- const reCAPTCHAState = getStateReference(app).reCAPTCHAState;
- recaptcha.ready(() => {
- resolve(
-
- recaptcha.execute(reCAPTCHAState.widgetId, {
- action: 'fire_app_check'
- }));
- });
- });
- }
-
- function renderInvisibleWidget(app, siteKey, grecaptcha, container) {
- const widgetId = grecaptcha.render(container, {
- sitekey: siteKey,
- size: 'invisible'
- });
- const state = getStateReference(app);
- state.reCAPTCHAState = Object.assign(Object.assign({}, state.reCAPTCHAState), {
- widgetId });
- }
- function loadReCAPTCHAV3Script(onload) {
- const script = document.createElement('script');
- script.src = RECAPTCHA_URL;
- script.onload = onload;
- document.head.appendChild(script);
- }
- function loadReCAPTCHAEnterpriseScript(onload) {
- const script = document.createElement('script');
- script.src = RECAPTCHA_ENTERPRISE_URL;
- script.onload = onload;
- document.head.appendChild(script);
- }
-
-
-
- class ReCaptchaV3Provider {
-
-
- constructor(_siteKey) {
- this._siteKey = _siteKey;
-
-
- this._throttleData = null;
- }
-
-
- async getToken() {
- var _a, _b;
- throwIfThrottled(this._throttleData);
-
-
- const attestedClaimsToken = await getToken$1(this._app).catch(_e => {
-
- throw ERROR_FACTORY.create("recaptcha-error" );
- });
- let result;
- try {
- result = await exchangeToken(getExchangeRecaptchaV3TokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider);
- }
- catch (e) {
- if ((_a = e.code) === null || _a === void 0 ? void 0 : _a.includes("fetch-status-error" )) {
- this._throttleData = setBackoff(Number((_b = e.customData) === null || _b === void 0 ? void 0 : _b.httpStatus), this._throttleData);
- throw ERROR_FACTORY.create("throttled" , {
- time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
- httpStatus: this._throttleData.httpStatus
- });
- }
- else {
- throw e;
- }
- }
-
- this._throttleData = null;
- return result;
- }
-
-
- initialize(app) {
- this._app = app;
- this._heartbeatServiceProvider = _getProvider(app, 'heartbeat');
- initializeV3(app, this._siteKey).catch(() => {
-
- });
- }
-
-
- isEqual(otherProvider) {
- if (otherProvider instanceof ReCaptchaV3Provider) {
- return this._siteKey === otherProvider._siteKey;
- }
- else {
- return false;
- }
- }
- }
-
- class ReCaptchaEnterpriseProvider {
-
-
- constructor(_siteKey) {
- this._siteKey = _siteKey;
-
-
- this._throttleData = null;
- }
-
-
- async getToken() {
- var _a, _b;
- throwIfThrottled(this._throttleData);
-
-
- const attestedClaimsToken = await getToken$1(this._app).catch(_e => {
-
- throw ERROR_FACTORY.create("recaptcha-error" );
- });
- let result;
- try {
- result = await exchangeToken(getExchangeRecaptchaEnterpriseTokenRequest(this._app, attestedClaimsToken), this._heartbeatServiceProvider);
- }
- catch (e) {
- if ((_a = e.code) === null || _a === void 0 ? void 0 : _a.includes("fetch-status-error" )) {
- this._throttleData = setBackoff(Number((_b = e.customData) === null || _b === void 0 ? void 0 : _b.httpStatus), this._throttleData);
- throw ERROR_FACTORY.create("throttled" , {
- time: getDurationString(this._throttleData.allowRequestsAfter - Date.now()),
- httpStatus: this._throttleData.httpStatus
- });
- }
- else {
- throw e;
- }
- }
-
- this._throttleData = null;
- return result;
- }
-
-
- initialize(app) {
- this._app = app;
- this._heartbeatServiceProvider = _getProvider(app, 'heartbeat');
- initializeEnterprise(app, this._siteKey).catch(() => {
-
- });
- }
-
-
- isEqual(otherProvider) {
- if (otherProvider instanceof ReCaptchaEnterpriseProvider) {
- return this._siteKey === otherProvider._siteKey;
- }
- else {
- return false;
- }
- }
- }
-
- class CustomProvider {
- constructor(_customProviderOptions) {
- this._customProviderOptions = _customProviderOptions;
- }
-
-
- async getToken() {
-
- const customToken = await this._customProviderOptions.getToken();
-
-
- const issuedAtTimeSeconds = issuedAtTime(customToken.token);
-
-
- const issuedAtTimeMillis = issuedAtTimeSeconds !== null &&
- issuedAtTimeSeconds < Date.now() &&
- issuedAtTimeSeconds > 0
- ? issuedAtTimeSeconds * 1000
- : Date.now();
- return Object.assign(Object.assign({}, customToken), { issuedAtTimeMillis });
- }
-
-
- initialize(app) {
- this._app = app;
- }
-
-
- isEqual(otherProvider) {
- if (otherProvider instanceof CustomProvider) {
- return (this._customProviderOptions.getToken.toString() ===
- otherProvider._customProviderOptions.getToken.toString());
- }
- else {
- return false;
- }
- }
- }
-
- function setBackoff(httpStatus, throttleData) {
-
-
- if (httpStatus === 404 || httpStatus === 403) {
- return {
- backoffCount: 1,
- allowRequestsAfter: Date.now() + ONE_DAY,
- httpStatus
- };
- }
- else {
-
-
- const backoffCount = throttleData ? throttleData.backoffCount : 0;
- const backoffMillis = calculateBackoffMillis(backoffCount, 1000, 2);
- return {
- backoffCount: backoffCount + 1,
- allowRequestsAfter: Date.now() + backoffMillis,
- httpStatus
- };
- }
- }
- function throwIfThrottled(throttleData) {
- if (throttleData) {
- if (Date.now() - throttleData.allowRequestsAfter <= 0) {
-
- throw ERROR_FACTORY.create("throttled" , {
- time: getDurationString(throttleData.allowRequestsAfter - Date.now()),
- httpStatus: throttleData.httpStatus
- });
- }
- }
- }
-
-
-
- function initializeAppCheck(app = getApp(), options) {
- app = getModularInstance(app);
- const provider = _getProvider(app, 'app-check');
-
- if (!getDebugState().initialized) {
- initializeDebugMode();
- }
-
-
- if (isDebugMode()) {
-
- void getDebugToken().then(token =>
-
- 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.`));
- }
- if (provider.isInitialized()) {
- const existingInstance = provider.getImmediate();
- const initialOptions = provider.getOptions();
- if (initialOptions.isTokenAutoRefreshEnabled ===
- options.isTokenAutoRefreshEnabled &&
- initialOptions.provider.isEqual(options.provider)) {
- return existingInstance;
- }
- else {
- throw ERROR_FACTORY.create("already-initialized" , {
- appName: app.name
- });
- }
- }
- const appCheck = provider.initialize({ options });
- _activate(app, options.provider, options.isTokenAutoRefreshEnabled);
-
-
-
- if (getStateReference(app).isTokenAutoRefreshEnabled) {
-
-
-
-
-
- addTokenListener(appCheck, "INTERNAL" , () => { });
- }
- return appCheck;
- }
-
- function _activate(app, provider, isTokenAutoRefreshEnabled) {
-
-
- const state = setInitialState(app, Object.assign({}, DEFAULT_STATE));
- state.activated = true;
- state.provider = provider;
- state.cachedTokenPromise = readTokenFromStorage(app).then(cachedToken => {
- if (cachedToken && isValid(cachedToken)) {
- state.token = cachedToken;
-
- notifyTokenListeners(app, { token: cachedToken.token });
- }
- return cachedToken;
- });
-
-
-
- state.isTokenAutoRefreshEnabled =
- isTokenAutoRefreshEnabled === undefined
- ? app.automaticDataCollectionEnabled
- : isTokenAutoRefreshEnabled;
- state.provider.initialize(app);
- }
-
- function setTokenAutoRefreshEnabled(appCheckInstance, isTokenAutoRefreshEnabled) {
- const app = appCheckInstance.app;
- const state = getStateReference(app);
-
-
- if (state.tokenRefresher) {
- if (isTokenAutoRefreshEnabled === true) {
- state.tokenRefresher.start();
- }
- else {
- state.tokenRefresher.stop();
- }
- }
- state.isTokenAutoRefreshEnabled = isTokenAutoRefreshEnabled;
- }
-
- async function getToken(appCheckInstance, forceRefresh) {
- const result = await getToken$2(appCheckInstance, forceRefresh);
- if (result.error) {
- throw result.error;
- }
- return { token: result.token };
- }
-
- function onTokenChanged(appCheckInstance, onNextOrObserver, onError,
- /**
- * NOTE: Although an `onCompletion` callback can be provided, it will
- * never be called because the token stream is never-ending.
- * It is added only for API consistency with the observer pattern, which
- * we follow in JS APIs.
- */
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- onCompletion) {
- let nextFn = () => { };
- let errorFn = () => { };
- if (onNextOrObserver.next != null) {
- nextFn = onNextOrObserver.next.bind(onNextOrObserver);
- }
- else {
- nextFn = onNextOrObserver;
- }
- if (onNextOrObserver.error != null) {
- errorFn = onNextOrObserver.error.bind(onNextOrObserver);
- }
- else if (onError) {
- errorFn = onError;
- }
- addTokenListener(appCheckInstance, "EXTERNAL" /* ListenerType.EXTERNAL */, nextFn, errorFn);
- return () => removeTokenListener(appCheckInstance.app, nextFn);
- }
-
- /**
- * Firebase App Check
- *
- * @packageDocumentation
- */
- const APP_CHECK_NAME = 'app-check';
- const APP_CHECK_NAME_INTERNAL = 'app-check-internal';
- function registerAppCheck() {
- // The public interface
- _registerComponent(new Component(APP_CHECK_NAME, container => {
- // getImmediate for FirebaseApp will always succeed
- const app = container.getProvider('app').getImmediate();
- const heartbeatServiceProvider = container.getProvider('heartbeat');
- return factory(app, heartbeatServiceProvider);
- }, "PUBLIC" /* ComponentType.PUBLIC */)
- .setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */)
- /**
- * Initialize app-check-internal after app-check is initialized to make AppCheck available to
- * other Firebase SDKs
- */
- .setInstanceCreatedCallback((container, _identifier, _appcheckService) => {
- container.getProvider(APP_CHECK_NAME_INTERNAL).initialize();
- }));
- // The internal interface used by other Firebase products
- _registerComponent(new Component(APP_CHECK_NAME_INTERNAL, container => {
- const appCheck = container.getProvider('app-check').getImmediate();
- return internalFactory(appCheck);
- }, "PUBLIC" /* ComponentType.PUBLIC */).setInstantiationMode("EXPLICIT" /* InstantiationMode.EXPLICIT */));
- registerVersion(name, version);
- }
- registerAppCheck();
-
- export { CustomProvider, ReCaptchaEnterpriseProvider, ReCaptchaV3Provider, getToken, initializeAppCheck, onTokenChanged, setTokenAutoRefreshEnabled };
- //# sourceMappingURL=index.esm2017.js.map
|