Skip to content

Importing core.ts can lead to unhandled rejections at global scope in restricted security contexts #3138

Closed
@abierbaum

Description

@abierbaum

Version info

Angular: 13.2.0

Firebase: 9.6.5-canary.0a04a1c06

AngularFire: 7.2.0

Other (e.g. Ionic/Cordova, Node, browser, operating system):

OS: Ubuntu 20.04.3 LTS
Node: 14.18.1

How to reproduce these conditions

Failing test unit, Stackblitz demonstrating the problem

N/A

Steps to set up and reproduce

The way to reproduce is to simply import angular/fire in such a way that angularfire/src/core.ts is evaluated.

If you look at these lines in core.ts: (https://github.com/angular/angularfire/blob/master/src/core.ts#L17)

globalThis[isAnalyticsSupportedPromiseSymbol] ||= isAnalyticsSupported().then(it =>
  globalThis[isAnalyticsSupportedValueSymbol] = it
);

globalThis[isMessagingSupportedPromiseSymbol] ||= isMessagingSupported().then(it =>
  globalThis[isMessagingSupportedValueSymbol] = it
);

globalThis[isRemoteConfigSupportedPromiseSymbol] ||= isRemoteConfigSupported().then(it =>
  globalThis[isRemoteConfigSupportedValueSymbol] = it
);

It looks like isAnalyticsSupported(), isMessagingSupported(), and isRemoteConfigSupported() will all three be called at import type with a Promise that gets evaluated but does not catch errors. This can cause problems when the code inside firebase that is doing the evaluation runs into a problem. You will end up with an unhandled rejection at the global application scope.

In my specific case, isRemoteConfigSupported is throwing an exception because the application is being run inside a restricted security context that can't access indexedDB, so this line: https://github.com/firebase/firebase-js-sdk/blob/b835b4cbabc4b7b180ae38b908c49205ce31a422/packages/util/src/environment.ts#L143 throws a browser SecurityError. The exception ends up propogating up to the promise evaluation above and is unhandled.

I may be misunderstanding how these methods are being used though so I am filing this bug to double check if this is expected behavior. If it isn't expected behavior then I suggest adding something that catches the exception and handles it. Maybe something like this:

globalThis[isRemoteConfigSupportedPromiseSymbol] ||= isRemoteConfigSupported().then(it =>
  globalThis[isRemoteConfigSupportedValueSymbol] = it;
).catch(() => {
  globalThis[isRemoteConfigSupportedValueSymbol] = false;
});

Sample data and security rules

N/A

Debug output

N/A

Expected behavior

I would expect that importing angular/fire will not run code that throws unhandled rejections.

Actual behavior

See above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions