Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

expo-web-browser

Package Overview
Dependencies
Maintainers
24
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

expo-web-browser - npm Package Compare versions

Comparing version 9.2.0 to 9.3.0

2

build/ExpoWebBrowser.d.ts

@@ -1,2 +0,2 @@

declare const _default: import("@unimodules/core").ProxyNativeModule;
declare const _default: import("expo-modules-core").ProxyNativeModule;
export default _default;

@@ -1,3 +0,3 @@

import { NativeModulesProxy } from '@unimodules/core';
import { NativeModulesProxy } from 'expo-modules-core';
export default NativeModulesProxy.ExpoWebBrowser || {};
//# sourceMappingURL=ExpoWebBrowser.js.map

@@ -6,3 +6,3 @@ import { WebBrowserAuthSessionResult, WebBrowserOpenOptions, WebBrowserResult } from './WebBrowser.types';

dismissAuthSession(): void;
maybeCompleteAuthSession({ skipRedirectCheck, }: {
maybeCompleteAuthSession({ skipRedirectCheck }: {
skipRedirectCheck?: boolean | undefined;

@@ -9,0 +9,0 @@ }): {

@@ -1,3 +0,3 @@

import { CodedError, Platform } from '@unimodules/core';
import compareUrls from 'compare-urls';
import { CodedError, Platform } from 'expo-modules-core';
import { AppState, Dimensions } from 'react-native';

@@ -49,3 +49,3 @@ import { WebBrowserResultType, } from './WebBrowser.types';

},
maybeCompleteAuthSession({ skipRedirectCheck, }) {
maybeCompleteAuthSession({ skipRedirectCheck }) {
if (!Platform.isDOMAvailable) {

@@ -81,3 +81,3 @@ return {

// Send the URL back to the opening window.
parent.postMessage({ url, expoSender: handle }, parent.location);
parent.postMessage({ url, expoSender: handle }, parent.location.toString());
return { type: 'success', message: `Attempting to complete auth` };

@@ -84,0 +84,0 @@ // Maybe set timer to throw an error if the window is still open after attempting to complete.

@@ -1,21 +0,138 @@

import { WebBrowserAuthSessionResult, WebBrowserCoolDownResult, WebBrowserCustomTabsResults, WebBrowserMayInitWithUrlResult, WebBrowserOpenOptions, WebBrowserRedirectResult, WebBrowserResult, WebBrowserResultType, WebBrowserWarmUpResult, WebBrowserWindowFeatures } from './WebBrowser.types';
export { WebBrowserAuthSessionResult, WebBrowserCoolDownResult, WebBrowserCustomTabsResults, WebBrowserMayInitWithUrlResult, WebBrowserOpenOptions, WebBrowserRedirectResult, WebBrowserResult, WebBrowserResultType, WebBrowserWarmUpResult, WebBrowserWindowFeatures, };
import { WebBrowserAuthSessionResult, WebBrowserCompleteAuthSessionOptions, WebBrowserCompleteAuthSessionResult, WebBrowserCoolDownResult, WebBrowserCustomTabsResults, WebBrowserMayInitWithUrlResult, WebBrowserOpenOptions, WebBrowserRedirectResult, WebBrowserResult, WebBrowserResultType, WebBrowserWarmUpResult, WebBrowserWindowFeatures } from './WebBrowser.types';
export { WebBrowserAuthSessionResult, WebBrowserCompleteAuthSessionOptions, WebBrowserCompleteAuthSessionResult, WebBrowserCoolDownResult, WebBrowserCustomTabsResults, WebBrowserMayInitWithUrlResult, WebBrowserOpenOptions, WebBrowserRedirectResult, WebBrowserResult, WebBrowserResultType, WebBrowserWarmUpResult, WebBrowserWindowFeatures, };
/**
* _Android only_. Returns a list of applications package names supporting Custom Tabs, Custom Tabs
* service, user chosen and preferred one. This may not be fully reliable, since it uses
* `PackageManager.getResolvingActivities` under the hood. (For example, some browsers might not be
* present in browserPackages list once another browser is set to default.)
*
* @return The promise which fulfils with [`WebBrowserCustomTabsResults`](#webbrowsercustomtabsresults) object.
*/
export declare function getCustomTabsSupportingBrowsersAsync(): Promise<WebBrowserCustomTabsResults>;
/**
* _Android only_. This method calls `warmUp` method on [CustomTabsClient](https://developer.android.com/reference/android/support/customtabs/CustomTabsClient.html#warmup(long))
* for specified package.
*
* @param browserPackage _Optional_ - Package of browser to be warmed up. If not set, preferred browser will be warmed.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export declare function warmUpAsync(browserPackage?: string): Promise<WebBrowserWarmUpResult>;
/**
* _Android only_. This method initiates (if needed) [CustomTabsSession](https://developer.android.com/reference/android/support/customtabs/CustomTabsSession.html#maylaunchurl)
* and calls its `mayLaunchUrl` method for browser specified by the package.
*
* @param url The url of page that is likely to be loaded first when opening browser.
* @param browserPackage _Optional_ - Package of browser to be informed. If not set, preferred browser will be used.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export declare function mayInitWithUrlAsync(url: string, browserPackage?: string): Promise<WebBrowserMayInitWithUrlResult>;
/**
* _Android only_. This methods removes all bindings to services created by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage)
* or [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage). You should call
* this method once you don't need them to avoid potential memory leaks. However, those binding
* would be cleared once your application is destroyed, which might be sufficient in most cases.
*
* @param browserPackage _Optional_ - Package of browser to be cooled. If not set, preferred browser will be used.
*
* @return The promise which fulfils with `{ package: string }` when cooling is performed, or
* an empty object when there was no connection to be dismissed.
*/
export declare function coolDownAsync(browserPackage?: string): Promise<WebBrowserCoolDownResult>;
/**
* Opens the url with Safari in a modal on iOS using [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller),
* and Chrome in a new [custom tab](https://developer.chrome.com/multidevice/android/customtabs)
* on Android. On iOS, the modal Safari will not share cookies with the system Safari. If you need
* this, use [`openAuthSessionAsync`](#webbrowseropenauthsessionasyncurl-redirecturl-browserparams).
*
* @param url The url to open in the web browser.
* @param browserParams A dictionary of key-value pairs.
*
* @return The promise behaves differently based on the platform.
* On Android promise resolves with `{type: 'opened'}` if we were able to open browser.
* On iOS:
* - If the user closed the web browser, the Promise resolves with `{ type: 'cancel' }`.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser), the Promise resolves with `{ type: 'dismiss' }`.
*/
export declare function openBrowserAsync(url: string, browserParams?: WebBrowserOpenOptions): Promise<WebBrowserResult>;
/**
* _iOS only_. Dismisses the presented web browser.
*
* @return The promise which fulfils with `{ type: 'dismiss' }` object.
*/
export declare function dismissBrowser(): void;
/**
* # On iOS:
* Opens the url with Safari in a modal using `SFAuthenticationSession` on iOS 11 and greater,
* and falling back on a `SFSafariViewController`. The user will be asked whether to allow the app
* to authenticate using the given url.
*
* # On Android:
* This will be done using a "custom Chrome tabs" browser, [AppState](../react-native/appstate/),
* and [Linking](./linking/) APIs.
*
* # On web:
* > This API can only be used in a secure environment (`https`). You can use expo `start:web --https`
* to test this. Otherwise, an error with code [`ERR_WEB_BROWSER_CRYPTO`](#errwebbrowsercrypto) will be thrown.
* This will use the browser's [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) API.
* - _Desktop_: This will create a new web popup window in the browser that can be closed later using `WebBrowser.maybeCompleteAuthSession()`.
* - _Mobile_: This will open a new tab in the browser which can be closed using `WebBrowser.maybeCompleteAuthSession()`.
*
* How this works on web:
* - A crypto state will be created for verifying the redirect.
* - This means you need to run with `expo start:web --https`
* - The state will be added to the window's `localstorage`. This ensures that auth cannot complete
* unless it's done from a page running with the same origin as it was started.
* Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession`
* must be invoked on a page hosted from the origin `https://localhost:19006`. Using a different
* website, or even a different host like `https://128.0.0.*:19006` for example will not work.
* - A timer will be started to check for every 1000 milliseconds (1 second) to detect if the window
* has been closed by the user. If this happens then a promise will resolve with `{ type: 'dismiss' }`.
*
* > On mobile web, Chrome and Safari will block any call to [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open)
* which takes too long to fire after a user interaction. This method must be invoked immediately
* after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#errwebbrowserblocked) will be thrown.
*
* @param url The url to open in the web browser. This should be a login page.
* @param redirectUrl _Optional_ - The url to deep link back into your app. By default, this will be [`Constants.linkingUrl`](./constants/#expoconstantslinkinguri).
* @param browserParams _Optional_ - An object with the same keys as [`WebBrowserOpenOptions`](#webbrowseropenoptions).
* If there is no native AuthSession implementation available (which is the case on Android)
* these params will be used in the browser polyfill. If there is a native AuthSession implementation,
* these params will be ignored.
*
* @return
* - If the user does not permit the application to authenticate with the given url, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the user closed the web browser, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser),
* the Promise fulfills with `{ type: 'dismiss' }` object.
*/
export declare function openAuthSessionAsync(url: string, redirectUrl: string, browserParams?: WebBrowserOpenOptions): Promise<WebBrowserAuthSessionResult>;
export declare function dismissAuthSession(): void;
/**
* Attempts to complete an auth session in the browser.
* _Web only_. Possibly completes an authentication session on web in a window popup. The method
* should be invoked on the page that the window redirects to.
*
* @param options
*
* @return Returns an object with message about why the redirect failed or succeeded:
*
* If `type` is set to `failed`, the reason depends on the message:
* - `Not supported on this platform`: If the platform doesn't support this method (iOS, Android).
* - `Cannot use expo-web-browser in a non-browser environment`: If the code was executed in an SSR
* or node environment.
* - `No auth session is currently in progress`: (the cached state wasn't found in local storage).
* This can happen if the window redirects to an origin (website) that is different to the initial
* website origin. If this happens in development, it may be because the auth started on localhost
* and finished on your computer port (Ex: `128.0.0.*`). This is controlled by the `redirectUrl`
* and `returnUrl`.
* - `Current URL "<URL>" and original redirect URL "<URL>" do not match`: This can occur when the
* redirect URL doesn't match what was initial defined as the `returnUrl`. You can skip this test
* in development by passing `{ skipRedirectCheck: true }` to the function.
*
* If `type` is set to `success`, the parent window will attempt to close the child window immediately.
*
* If the error `ERR_WEB_BROWSER_REDIRECT` was thrown, it may mean that the parent window was
* reloaded before the auth was completed. In this case you'll need to close the child window manually.
*/
export declare function maybeCompleteAuthSession(options?: {
skipRedirectCheck?: boolean;
}): {
type: 'success' | 'failed';
message: string;
};
export declare function maybeCompleteAuthSession(options?: WebBrowserCompleteAuthSessionOptions): WebBrowserCompleteAuthSessionResult;

@@ -1,2 +0,2 @@

import { UnavailabilityError } from '@unimodules/core';
import { UnavailabilityError } from 'expo-modules-core';
import { AppState, Linking, Platform } from 'react-native';

@@ -12,2 +12,11 @@ import ExponentWebBrowser from './ExpoWebBrowser';

};
// @needsAudit
/**
* _Android only_. Returns a list of applications package names supporting Custom Tabs, Custom Tabs
* service, user chosen and preferred one. This may not be fully reliable, since it uses
* `PackageManager.getResolvingActivities` under the hood. (For example, some browsers might not be
* present in browserPackages list once another browser is set to default.)
*
* @return The promise which fulfils with [`WebBrowserCustomTabsResults`](#webbrowsercustomtabsresults) object.
*/
export async function getCustomTabsSupportingBrowsersAsync() {

@@ -24,2 +33,11 @@ if (!ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync) {

}
// @needsAudit
/**
* _Android only_. This method calls `warmUp` method on [CustomTabsClient](https://developer.android.com/reference/android/support/customtabs/CustomTabsClient.html#warmup(long))
* for specified package.
*
* @param browserPackage _Optional_ - Package of browser to be warmed up. If not set, preferred browser will be warmed.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export async function warmUpAsync(browserPackage) {

@@ -36,2 +54,12 @@ if (!ExponentWebBrowser.warmUpAsync) {

}
// @needsAudit
/**
* _Android only_. This method initiates (if needed) [CustomTabsSession](https://developer.android.com/reference/android/support/customtabs/CustomTabsSession.html#maylaunchurl)
* and calls its `mayLaunchUrl` method for browser specified by the package.
*
* @param url The url of page that is likely to be loaded first when opening browser.
* @param browserPackage _Optional_ - Package of browser to be informed. If not set, preferred browser will be used.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export async function mayInitWithUrlAsync(url, browserPackage) {

@@ -48,2 +76,14 @@ if (!ExponentWebBrowser.mayInitWithUrlAsync) {

}
// @needsAudit
/**
* _Android only_. This methods removes all bindings to services created by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage)
* or [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage). You should call
* this method once you don't need them to avoid potential memory leaks. However, those binding
* would be cleared once your application is destroyed, which might be sufficient in most cases.
*
* @param browserPackage _Optional_ - Package of browser to be cooled. If not set, preferred browser will be used.
*
* @return The promise which fulfils with `{ package: string }` when cooling is performed, or
* an empty object when there was no connection to be dismissed.
*/
export async function coolDownAsync(browserPackage) {

@@ -61,2 +101,18 @@ if (!ExponentWebBrowser.coolDownAsync) {

let browserLocked = false;
// @needsAudit
/**
* Opens the url with Safari in a modal on iOS using [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller),
* and Chrome in a new [custom tab](https://developer.chrome.com/multidevice/android/customtabs)
* on Android. On iOS, the modal Safari will not share cookies with the system Safari. If you need
* this, use [`openAuthSessionAsync`](#webbrowseropenauthsessionasyncurl-redirecturl-browserparams).
*
* @param url The url to open in the web browser.
* @param browserParams A dictionary of key-value pairs.
*
* @return The promise behaves differently based on the platform.
* On Android promise resolves with `{type: 'opened'}` if we were able to open browser.
* On iOS:
* - If the user closed the web browser, the Promise resolves with `{ type: 'cancel' }`.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser), the Promise resolves with `{ type: 'dismiss' }`.
*/
export async function openBrowserAsync(url, browserParams = {}) {

@@ -85,2 +141,8 @@ if (!ExponentWebBrowser.openBrowserAsync) {

}
// @needsAudit
/**
* _iOS only_. Dismisses the presented web browser.
*
* @return The promise which fulfils with `{ type: 'dismiss' }` object.
*/
export function dismissBrowser() {

@@ -92,2 +154,48 @@ if (!ExponentWebBrowser.dismissBrowser) {

}
// @needsAudit
/**
* # On iOS:
* Opens the url with Safari in a modal using `SFAuthenticationSession` on iOS 11 and greater,
* and falling back on a `SFSafariViewController`. The user will be asked whether to allow the app
* to authenticate using the given url.
*
* # On Android:
* This will be done using a "custom Chrome tabs" browser, [AppState](../react-native/appstate/),
* and [Linking](./linking/) APIs.
*
* # On web:
* > This API can only be used in a secure environment (`https`). You can use expo `start:web --https`
* to test this. Otherwise, an error with code [`ERR_WEB_BROWSER_CRYPTO`](#errwebbrowsercrypto) will be thrown.
* This will use the browser's [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) API.
* - _Desktop_: This will create a new web popup window in the browser that can be closed later using `WebBrowser.maybeCompleteAuthSession()`.
* - _Mobile_: This will open a new tab in the browser which can be closed using `WebBrowser.maybeCompleteAuthSession()`.
*
* How this works on web:
* - A crypto state will be created for verifying the redirect.
* - This means you need to run with `expo start:web --https`
* - The state will be added to the window's `localstorage`. This ensures that auth cannot complete
* unless it's done from a page running with the same origin as it was started.
* Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession`
* must be invoked on a page hosted from the origin `https://localhost:19006`. Using a different
* website, or even a different host like `https://128.0.0.*:19006` for example will not work.
* - A timer will be started to check for every 1000 milliseconds (1 second) to detect if the window
* has been closed by the user. If this happens then a promise will resolve with `{ type: 'dismiss' }`.
*
* > On mobile web, Chrome and Safari will block any call to [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open)
* which takes too long to fire after a user interaction. This method must be invoked immediately
* after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#errwebbrowserblocked) will be thrown.
*
* @param url The url to open in the web browser. This should be a login page.
* @param redirectUrl _Optional_ - The url to deep link back into your app. By default, this will be [`Constants.linkingUrl`](./constants/#expoconstantslinkinguri).
* @param browserParams _Optional_ - An object with the same keys as [`WebBrowserOpenOptions`](#webbrowseropenoptions).
* If there is no native AuthSession implementation available (which is the case on Android)
* these params will be used in the browser polyfill. If there is a native AuthSession implementation,
* these params will be ignored.
*
* @return
* - If the user does not permit the application to authenticate with the given url, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the user closed the web browser, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser),
* the Promise fulfills with `{ type: 'dismiss' }` object.
*/
export async function openAuthSessionAsync(url, redirectUrl, browserParams = {}) {

@@ -107,2 +215,3 @@ if (_authSessionIsNativelySupported()) {

}
// @docsMissing
export function dismissAuthSession() {

@@ -122,6 +231,28 @@ if (_authSessionIsNativelySupported()) {

}
// @needsAudit
/**
* Attempts to complete an auth session in the browser.
* _Web only_. Possibly completes an authentication session on web in a window popup. The method
* should be invoked on the page that the window redirects to.
*
* @param options
*
* @return Returns an object with message about why the redirect failed or succeeded:
*
* If `type` is set to `failed`, the reason depends on the message:
* - `Not supported on this platform`: If the platform doesn't support this method (iOS, Android).
* - `Cannot use expo-web-browser in a non-browser environment`: If the code was executed in an SSR
* or node environment.
* - `No auth session is currently in progress`: (the cached state wasn't found in local storage).
* This can happen if the window redirects to an origin (website) that is different to the initial
* website origin. If this happens in development, it may be because the auth started on localhost
* and finished on your computer port (Ex: `128.0.0.*`). This is controlled by the `redirectUrl`
* and `returnUrl`.
* - `Current URL "<URL>" and original redirect URL "<URL>" do not match`: This can occur when the
* redirect URL doesn't match what was initial defined as the `returnUrl`. You can skip this test
* in development by passing `{ skipRedirectCheck: true }` to the function.
*
* If `type` is set to `success`, the parent window will attempt to close the child window immediately.
*
* If the error `ERR_WEB_BROWSER_REDIRECT` was thrown, it may mean that the parent window was
* reloaded before the auth was completed. In this case you'll need to close the child window manually.
*/

@@ -168,3 +299,3 @@ export function maybeCompleteAuthSession(options = {}) {

async function _openBrowserAndWaitAndroidAsync(startUrl, browserParams = {}) {
const appStateChangedToActive = new Promise(resolve => {
const appStateChangedToActive = new Promise((resolve) => {
_onWebBrowserCloseAndroid = resolve;

@@ -174,3 +305,11 @@ AppState.addEventListener('change', _onAppStateChangeAndroid);

let result = { type: WebBrowserResultType.CANCEL };
const { type } = await openBrowserAsync(startUrl, browserParams);
let type = null;
try {
({ type } = await openBrowserAsync(startUrl, browserParams));
}
catch (e) {
AppState.removeEventListener('change', _onAppStateChangeAndroid);
_onWebBrowserCloseAndroid = null;
throw e;
}
if (type === 'opened') {

@@ -222,3 +361,3 @@ await appStateChangedToActive;

function _waitForRedirectAsync(returnUrl) {
return new Promise(resolve => {
return new Promise((resolve) => {
_redirectHandler = (event) => {

@@ -225,0 +364,0 @@ if (event.url.startsWith(returnUrl)) {

@@ -7,41 +7,56 @@ export declare type RedirectEvent = {

/**
* Color of the toolbar in either #AARRGGBB or #RRGGBB format.
* Color of the toolbar in either `#AARRGGBB` or `#RRGGBB` format.
*/
toolbarColor?: string;
/**
* __(Android only)__. Package name of a browser to be used to handle Custom Tabs. List of
* available packages is to be queried by [`getCustomTabsSupportingBrowsers`](#webbrowsergetcustomtabssupportingbrowsersasync) method.
*/
browserPackage?: string;
/**
* Whether the toolbar should be hiding when a user scrolls the website.
* A boolean determining whether the toolbar should be hiding when a user scrolls the website.
*/
enableBarCollapsing?: boolean;
/** Android only */
/**
* Color of the secondary toolbar in either #AARRGGBB or #RRGGBB format.
* __(Android only)__ Color of the secondary toolbar in either `#AARRGGBB` or `#RRGGBB` format.
*/
secondaryToolbarColor?: string;
/**
* Whether the browser should show the title of website on the toolbar.
* __(Android only)__ A boolean determining whether the browser should show the title of website on the toolbar.
*/
showTitle?: boolean;
/**
* __(Android only)__ A boolean determining whether a default share item should be added to the menu.
*/
enableDefaultShareMenuItem?: boolean;
/**
* Whether browsed website should be shown as separate entry in Android recents/multitasking view.
* Requires createTask to be `true` (default).
* Default: `false`
* __(Android only)__ A boolean determining whether browsed website should be shown as separate
* entry in Android recents/multitasking view. Requires `createTask` to be `true` (default).
* @default `false`
*/
showInRecents?: boolean;
/**
* Whether the browser should open as a new task or open within the existing task.
* Default: `true`
* __(Android only)__ A boolean determining whether the browser should open in a new task or in
* the same task as your app.
* @default `true`
*/
createTask?: boolean;
/** iOS only */
/**
* __(iOS only)__ Tint color for controls in SKSafariViewController in `#AARRGGBB` or `#RRGGBB` format.
*/
controlsColor?: string;
/**
* __(iOS only)__ The style of the dismiss button. Should be one of: `done`, `close`, or `cancel`.
*/
dismissButtonStyle?: 'done' | 'close' | 'cancel';
/**
* __(iOS only)__ A boolean determining whether Safari should enter Reader mode, if it is available.
*/
readerMode?: boolean;
/**
* **Web:** name to assign to the popup window.
* __(Web only)__ Name to assign to the popup window.
*/
windowName?: string;
/**
* **Web:** features to use with `window.open()`
* __(Web only)__ Features to use with `window.open()`.
*/

@@ -52,5 +67,25 @@ windowFeatures?: string | WebBrowserWindowFeatures;

export declare type WebBrowserCustomTabsResults = {
/**
* Default package chosen by user, `null` if there is no such packages. Also `null` usually means,
* that user will be prompted to choose from available packages.
*/
defaultBrowserPackage?: string;
/**
* Package preferred by `CustomTabsClient` to be used to handle Custom Tabs. It favors browser
* chosen by user as default, as long as it is present on both `browserPackages` and
* `servicePackages` lists. Only such browsers are considered as fully supporting Custom Tabs.
* It might be `null` when there is no such browser installed or when default browser is not in
* `servicePackages` list.
*/
preferredBrowserPackage?: string;
/**
* All packages recognized by `PackageManager` as capable of handling Custom Tabs. Empty array
* means there is no supporting browsers on device.
*/
browserPackages: string[];
/**
* All packages recognized by `PackageManager` as capable of handling Custom Tabs Service.
* This service is used by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage), [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage)
* and [`coolDownAsync`](#webbrowsercooldownasyncbrowserpackage).
*/
servicePackages: string[];

@@ -60,11 +95,11 @@ };

/**
* iOS only
* iOS only.
*/
CANCEL = "cancel",
/**
* iOS only
* iOS only.
*/
DISMISS = "dismiss",
/**
* Android only
* Android only.
*/

@@ -75,5 +110,11 @@ OPENED = "opened",

export declare type WebBrowserResult = {
/**
* Type of the result.
*/
type: WebBrowserResultType;
};
export declare type WebBrowserRedirectResult = {
/**
* Type of the result.
*/
type: 'success';

@@ -88,1 +129,17 @@ url: string;

export declare type WebBrowserCoolDownResult = ServiceActionResult;
export declare type WebBrowserCompleteAuthSessionOptions = {
/**
* Attempt to close the window without checking to see if the auth redirect matches the cached redirect URL.
*/
skipRedirectCheck?: boolean;
};
export declare type WebBrowserCompleteAuthSessionResult = {
/**
* Type of the result.
*/
type: 'success' | 'failed';
/**
* Additional description or reasoning of the result.
*/
message: string;
};

@@ -0,13 +1,14 @@

// @needsAudit @docsMissing
export var WebBrowserResultType;
(function (WebBrowserResultType) {
/**
* iOS only
* iOS only.
*/
WebBrowserResultType["CANCEL"] = "cancel";
/**
* iOS only
* iOS only.
*/
WebBrowserResultType["DISMISS"] = "dismiss";
/**
* Android only
* Android only.
*/

@@ -14,0 +15,0 @@ WebBrowserResultType["OPENED"] = "opened";

@@ -13,2 +13,12 @@ # Changelog

## 9.3.0 — 2021-09-09
### 🐛 Bug fixes
- Fixed `openAuthSessionAsync` erroneously stating a browser was open when it had failed to open. ([#14181](https://github.com/expo/expo/pull/14181) by [@sumnerwarren](https://github.com/sumnerwarren))
### 💡 Others
- Migrated from `@unimodules/core` to `expo-modules-core`. ([#13757](https://github.com/expo/expo/pull/13757) by [@tsapeta](https://github.com/tsapeta))
## 9.2.0 — 2021-06-16

@@ -19,2 +29,3 @@

- Added `createTask` (Android) flag for `WebBrowser`. ([#12462](https://github.com/expo/expo/pull/12462) by [@Ackuq](https://github.com/Ackuq))
- Added custom types definitions for argument and result of `maybeCompleteAuthSession` method. ([#13189](https://github.com/expo/expo/pull/13189) by [@Simek](https://github.com/Simek))

@@ -21,0 +32,0 @@ ### 🐛 Bug fixes

{
"name": "expo-web-browser",
"version": "9.2.0",
"version": "9.3.0",
"description": "Provides access to the system's web browser and supports handling redirects. On iOS, it uses SFSafariViewController or SFAuthenticationSession, depending on the method you call, and on Android it uses ChromeCustomTabs. As of iOS 11, SFSafariViewController no longer shares cookies with Safari, so if you are using WebBrowser for authentication you will want to use WebBrowser.openAuthSessionAsync, and if you just want to open a webpage (such as your app privacy policy), then use WebBrowser.openBrowserAsync.",

@@ -34,13 +34,14 @@ "main": "build/WebBrowser.js",

"license": "MIT",
"homepage": "https://docs.expo.io/versions/latest/sdk/webbrowser/",
"homepage": "https://docs.expo.dev/versions/latest/sdk/webbrowser/",
"jest": {
"preset": "expo-module-scripts"
},
"dependencies": {
"compare-urls": "^2.0.0",
"expo-modules-core": "~0.3.1"
},
"devDependencies": {
"expo-module-scripts": "^2.0.0"
},
"dependencies": {
"compare-urls": "^2.0.0"
},
"gitHead": "b33f5e224578564c3e4b1b467f258cc119b3b786"
"gitHead": "fe74edd44933f9f00a023544cafc4713594892fb"
}

@@ -1,2 +0,2 @@

import { NativeModulesProxy } from '@unimodules/core';
import { NativeModulesProxy } from 'expo-modules-core';
export default NativeModulesProxy.ExpoWebBrowser || ({} as any);

@@ -1,3 +0,3 @@

import { CodedError, Platform } from '@unimodules/core';
import compareUrls from 'compare-urls';
import { CodedError, Platform } from 'expo-modules-core';
import { AppState, Dimensions, AppStateStatus } from 'react-native';

@@ -65,7 +65,6 @@

},
maybeCompleteAuthSession({
skipRedirectCheck,
}: {
skipRedirectCheck?: boolean;
}): { type: 'success' | 'failed'; message: string } {
maybeCompleteAuthSession({ skipRedirectCheck }: { skipRedirectCheck?: boolean }): {
type: 'success' | 'failed';
message: string;
} {
if (!Platform.isDOMAvailable) {

@@ -109,3 +108,3 @@ return {

// Send the URL back to the opening window.
parent.postMessage({ url, expoSender: handle }, parent.location);
parent.postMessage({ url, expoSender: handle }, parent.location.toString());
return { type: 'success', message: `Attempting to complete auth` };

@@ -148,3 +147,3 @@

return new Promise(async resolve => {
return new Promise(async (resolve) => {
// Create a listener for messages sent from the popup

@@ -151,0 +150,0 @@ const listener = (event: MessageEvent) => {

@@ -1,2 +0,2 @@

import { UnavailabilityError } from '@unimodules/core';
import { UnavailabilityError } from 'expo-modules-core';
import { AppState, AppStateStatus, Linking, Platform } from 'react-native';

@@ -8,2 +8,4 @@

WebBrowserAuthSessionResult,
WebBrowserCompleteAuthSessionOptions,
WebBrowserCompleteAuthSessionResult,
WebBrowserCoolDownResult,

@@ -22,2 +24,4 @@ WebBrowserCustomTabsResults,

WebBrowserAuthSessionResult,
WebBrowserCompleteAuthSessionOptions,
WebBrowserCompleteAuthSessionResult,
WebBrowserCoolDownResult,

@@ -41,2 +45,11 @@ WebBrowserCustomTabsResults,

// @needsAudit
/**
* _Android only_. Returns a list of applications package names supporting Custom Tabs, Custom Tabs
* service, user chosen and preferred one. This may not be fully reliable, since it uses
* `PackageManager.getResolvingActivities` under the hood. (For example, some browsers might not be
* present in browserPackages list once another browser is set to default.)
*
* @return The promise which fulfils with [`WebBrowserCustomTabsResults`](#webbrowsercustomtabsresults) object.
*/
export async function getCustomTabsSupportingBrowsersAsync(): Promise<WebBrowserCustomTabsResults> {

@@ -53,2 +66,11 @@ if (!ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync) {

// @needsAudit
/**
* _Android only_. This method calls `warmUp` method on [CustomTabsClient](https://developer.android.com/reference/android/support/customtabs/CustomTabsClient.html#warmup(long))
* for specified package.
*
* @param browserPackage _Optional_ - Package of browser to be warmed up. If not set, preferred browser will be warmed.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export async function warmUpAsync(browserPackage?: string): Promise<WebBrowserWarmUpResult> {

@@ -65,2 +87,12 @@ if (!ExponentWebBrowser.warmUpAsync) {

// @needsAudit
/**
* _Android only_. This method initiates (if needed) [CustomTabsSession](https://developer.android.com/reference/android/support/customtabs/CustomTabsSession.html#maylaunchurl)
* and calls its `mayLaunchUrl` method for browser specified by the package.
*
* @param url The url of page that is likely to be loaded first when opening browser.
* @param browserPackage _Optional_ - Package of browser to be informed. If not set, preferred browser will be used.
*
* @return A promise which fulfils with `{ package: string }` object.
*/
export async function mayInitWithUrlAsync(

@@ -80,2 +112,14 @@ url: string,

// @needsAudit
/**
* _Android only_. This methods removes all bindings to services created by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage)
* or [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage). You should call
* this method once you don't need them to avoid potential memory leaks. However, those binding
* would be cleared once your application is destroyed, which might be sufficient in most cases.
*
* @param browserPackage _Optional_ - Package of browser to be cooled. If not set, preferred browser will be used.
*
* @return The promise which fulfils with `{ package: string }` when cooling is performed, or
* an empty object when there was no connection to be dismissed.
*/
export async function coolDownAsync(browserPackage?: string): Promise<WebBrowserCoolDownResult> {

@@ -94,2 +138,18 @@ if (!ExponentWebBrowser.coolDownAsync) {

// @needsAudit
/**
* Opens the url with Safari in a modal on iOS using [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller),
* and Chrome in a new [custom tab](https://developer.chrome.com/multidevice/android/customtabs)
* on Android. On iOS, the modal Safari will not share cookies with the system Safari. If you need
* this, use [`openAuthSessionAsync`](#webbrowseropenauthsessionasyncurl-redirecturl-browserparams).
*
* @param url The url to open in the web browser.
* @param browserParams A dictionary of key-value pairs.
*
* @return The promise behaves differently based on the platform.
* On Android promise resolves with `{type: 'opened'}` if we were able to open browser.
* On iOS:
* - If the user closed the web browser, the Promise resolves with `{ type: 'cancel' }`.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser), the Promise resolves with `{ type: 'dismiss' }`.
*/
export async function openBrowserAsync(

@@ -127,2 +187,8 @@ url: string,

// @needsAudit
/**
* _iOS only_. Dismisses the presented web browser.
*
* @return The promise which fulfils with `{ type: 'dismiss' }` object.
*/
export function dismissBrowser(): void {

@@ -135,2 +201,48 @@ if (!ExponentWebBrowser.dismissBrowser) {

// @needsAudit
/**
* # On iOS:
* Opens the url with Safari in a modal using `SFAuthenticationSession` on iOS 11 and greater,
* and falling back on a `SFSafariViewController`. The user will be asked whether to allow the app
* to authenticate using the given url.
*
* # On Android:
* This will be done using a "custom Chrome tabs" browser, [AppState](../react-native/appstate/),
* and [Linking](./linking/) APIs.
*
* # On web:
* > This API can only be used in a secure environment (`https`). You can use expo `start:web --https`
* to test this. Otherwise, an error with code [`ERR_WEB_BROWSER_CRYPTO`](#errwebbrowsercrypto) will be thrown.
* This will use the browser's [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) API.
* - _Desktop_: This will create a new web popup window in the browser that can be closed later using `WebBrowser.maybeCompleteAuthSession()`.
* - _Mobile_: This will open a new tab in the browser which can be closed using `WebBrowser.maybeCompleteAuthSession()`.
*
* How this works on web:
* - A crypto state will be created for verifying the redirect.
* - This means you need to run with `expo start:web --https`
* - The state will be added to the window's `localstorage`. This ensures that auth cannot complete
* unless it's done from a page running with the same origin as it was started.
* Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession`
* must be invoked on a page hosted from the origin `https://localhost:19006`. Using a different
* website, or even a different host like `https://128.0.0.*:19006` for example will not work.
* - A timer will be started to check for every 1000 milliseconds (1 second) to detect if the window
* has been closed by the user. If this happens then a promise will resolve with `{ type: 'dismiss' }`.
*
* > On mobile web, Chrome and Safari will block any call to [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open)
* which takes too long to fire after a user interaction. This method must be invoked immediately
* after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#errwebbrowserblocked) will be thrown.
*
* @param url The url to open in the web browser. This should be a login page.
* @param redirectUrl _Optional_ - The url to deep link back into your app. By default, this will be [`Constants.linkingUrl`](./constants/#expoconstantslinkinguri).
* @param browserParams _Optional_ - An object with the same keys as [`WebBrowserOpenOptions`](#webbrowseropenoptions).
* If there is no native AuthSession implementation available (which is the case on Android)
* these params will be used in the browser polyfill. If there is a native AuthSession implementation,
* these params will be ignored.
*
* @return
* - If the user does not permit the application to authenticate with the given url, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the user closed the web browser, the Promise fulfills with `{ type: 'cancel' }` object.
* - If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser),
* the Promise fulfills with `{ type: 'dismiss' }` object.
*/
export async function openAuthSessionAsync(

@@ -154,2 +266,3 @@ url: string,

// @docsMissing
export function dismissAuthSession(): void {

@@ -169,10 +282,32 @@ if (_authSessionIsNativelySupported()) {

// @needsAudit
/**
* Attempts to complete an auth session in the browser.
* _Web only_. Possibly completes an authentication session on web in a window popup. The method
* should be invoked on the page that the window redirects to.
*
* @param options
*
* @return Returns an object with message about why the redirect failed or succeeded:
*
* If `type` is set to `failed`, the reason depends on the message:
* - `Not supported on this platform`: If the platform doesn't support this method (iOS, Android).
* - `Cannot use expo-web-browser in a non-browser environment`: If the code was executed in an SSR
* or node environment.
* - `No auth session is currently in progress`: (the cached state wasn't found in local storage).
* This can happen if the window redirects to an origin (website) that is different to the initial
* website origin. If this happens in development, it may be because the auth started on localhost
* and finished on your computer port (Ex: `128.0.0.*`). This is controlled by the `redirectUrl`
* and `returnUrl`.
* - `Current URL "<URL>" and original redirect URL "<URL>" do not match`: This can occur when the
* redirect URL doesn't match what was initial defined as the `returnUrl`. You can skip this test
* in development by passing `{ skipRedirectCheck: true }` to the function.
*
* If `type` is set to `success`, the parent window will attempt to close the child window immediately.
*
* If the error `ERR_WEB_BROWSER_REDIRECT` was thrown, it may mean that the parent window was
* reloaded before the auth was completed. In this case you'll need to close the child window manually.
*/
export function maybeCompleteAuthSession(
options: { skipRedirectCheck?: boolean } = {}
): { type: 'success' | 'failed'; message: string } {
options: WebBrowserCompleteAuthSessionOptions = {}
): WebBrowserCompleteAuthSessionResult {
if (ExponentWebBrowser.maybeCompleteAuthSession) {

@@ -228,3 +363,3 @@ return ExponentWebBrowser.maybeCompleteAuthSession(options);

): Promise<WebBrowserResult> {
const appStateChangedToActive = new Promise(resolve => {
const appStateChangedToActive = new Promise<void>((resolve) => {
_onWebBrowserCloseAndroid = resolve;

@@ -235,4 +370,12 @@ AppState.addEventListener('change', _onAppStateChangeAndroid);

let result: WebBrowserResult = { type: WebBrowserResultType.CANCEL };
const { type } = await openBrowserAsync(startUrl, browserParams);
let type: string | null = null;
try {
({ type } = await openBrowserAsync(startUrl, browserParams));
} catch (e) {
AppState.removeEventListener('change', _onAppStateChangeAndroid);
_onWebBrowserCloseAndroid = null;
throw e;
}
if (type === 'opened') {

@@ -298,3 +441,3 @@ await appStateChangedToActive;

function _waitForRedirectAsync(returnUrl: string): Promise<WebBrowserRedirectResult> {
return new Promise(resolve => {
return new Promise((resolve) => {
_redirectHandler = (event: RedirectEvent) => {

@@ -301,0 +444,0 @@ if (event.url.startsWith(returnUrl)) {

@@ -5,49 +5,62 @@ export type RedirectEvent = {

// @needsAudit @docsMissing
export type WebBrowserWindowFeatures = Record<string, number | boolean | string>;
// @needsAudit
export type WebBrowserOpenOptions = {
/**
* Color of the toolbar in either #AARRGGBB or #RRGGBB format.
* Color of the toolbar in either `#AARRGGBB` or `#RRGGBB` format.
*/
toolbarColor?: string;
/**
* __(Android only)__. Package name of a browser to be used to handle Custom Tabs. List of
* available packages is to be queried by [`getCustomTabsSupportingBrowsers`](#webbrowsergetcustomtabssupportingbrowsersasync) method.
*/
browserPackage?: string;
/**
* Whether the toolbar should be hiding when a user scrolls the website.
* A boolean determining whether the toolbar should be hiding when a user scrolls the website.
*/
enableBarCollapsing?: boolean;
/** Android only */
/**
* Color of the secondary toolbar in either #AARRGGBB or #RRGGBB format.
* __(Android only)__ Color of the secondary toolbar in either `#AARRGGBB` or `#RRGGBB` format.
*/
secondaryToolbarColor?: string;
/**
* Whether the browser should show the title of website on the toolbar.
* __(Android only)__ A boolean determining whether the browser should show the title of website on the toolbar.
*/
showTitle?: boolean;
/**
* __(Android only)__ A boolean determining whether a default share item should be added to the menu.
*/
enableDefaultShareMenuItem?: boolean;
/**
* Whether browsed website should be shown as separate entry in Android recents/multitasking view.
* Requires createTask to be `true` (default).
* Default: `false`
* __(Android only)__ A boolean determining whether browsed website should be shown as separate
* entry in Android recents/multitasking view. Requires `createTask` to be `true` (default).
* @default `false`
*/
showInRecents?: boolean;
/**
* Whether the browser should open as a new task or open within the existing task.
* Default: `true`
* __(Android only)__ A boolean determining whether the browser should open in a new task or in
* the same task as your app.
* @default `true`
*/
createTask?: boolean;
/** iOS only */
/**
* __(iOS only)__ Tint color for controls in SKSafariViewController in `#AARRGGBB` or `#RRGGBB` format.
*/
controlsColor?: string;
/**
* __(iOS only)__ The style of the dismiss button. Should be one of: `done`, `close`, or `cancel`.
*/
dismissButtonStyle?: 'done' | 'close' | 'cancel';
/**
* __(iOS only)__ A boolean determining whether Safari should enter Reader mode, if it is available.
*/
readerMode?: boolean;
/**
* **Web:** name to assign to the popup window.
* __(Web only)__ Name to assign to the popup window.
*/
windowName?: string;
/**
* **Web:** features to use with `window.open()`
* __(Web only)__ Features to use with `window.open()`.
*/

@@ -59,20 +72,42 @@ windowFeatures?: string | WebBrowserWindowFeatures;

// @needsAudit
export type WebBrowserCustomTabsResults = {
/**
* Default package chosen by user, `null` if there is no such packages. Also `null` usually means,
* that user will be prompted to choose from available packages.
*/
defaultBrowserPackage?: string;
/**
* Package preferred by `CustomTabsClient` to be used to handle Custom Tabs. It favors browser
* chosen by user as default, as long as it is present on both `browserPackages` and
* `servicePackages` lists. Only such browsers are considered as fully supporting Custom Tabs.
* It might be `null` when there is no such browser installed or when default browser is not in
* `servicePackages` list.
*/
preferredBrowserPackage?: string;
/**
* All packages recognized by `PackageManager` as capable of handling Custom Tabs. Empty array
* means there is no supporting browsers on device.
*/
browserPackages: string[];
/**
* All packages recognized by `PackageManager` as capable of handling Custom Tabs Service.
* This service is used by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage), [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage)
* and [`coolDownAsync`](#webbrowsercooldownasyncbrowserpackage).
*/
servicePackages: string[];
};
// @needsAudit @docsMissing
export enum WebBrowserResultType {
/**
* iOS only
* iOS only.
*/
CANCEL = 'cancel',
/**
* iOS only
* iOS only.
*/
DISMISS = 'dismiss',
/**
* Android only
* Android only.
*/

@@ -83,8 +118,15 @@ OPENED = 'opened',

// @needsAudit
export type WebBrowserResult = {
// cancel and dismiss are iOS only, opened is Android only
/**
* Type of the result.
*/
type: WebBrowserResultType;
};
// @needsAudit @docsMissing
export type WebBrowserRedirectResult = {
/**
* Type of the result.
*/
type: 'success';

@@ -101,1 +143,21 @@ url: string;

export type WebBrowserCoolDownResult = ServiceActionResult;
// @needsAudit
export type WebBrowserCompleteAuthSessionOptions = {
/**
* Attempt to close the window without checking to see if the auth redirect matches the cached redirect URL.
*/
skipRedirectCheck?: boolean;
};
// @needsAudit
export type WebBrowserCompleteAuthSessionResult = {
/**
* Type of the result.
*/
type: 'success' | 'failed';
/**
* Additional description or reasoning of the result.
*/
message: string;
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc