diff --git a/apps/browser/src/auth/popup/guards/platform-popout.guard.ts b/apps/browser/src/auth/popup/guards/platform-popout.guard.ts index aad005e141b..c1218d918e2 100644 --- a/apps/browser/src/auth/popup/guards/platform-popout.guard.ts +++ b/apps/browser/src/auth/popup/guards/platform-popout.guard.ts @@ -1,7 +1,10 @@ import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from "@angular/router"; +import { DeviceType } from "@bitwarden/common/enums"; + import { BrowserApi } from "../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../platform/browser/browser-popup-utils"; +import { BrowserPlatformUtilsService } from "../../../platform/services/platform-utils/browser-platform-utils.service"; /** * Guard that forces a popout window for specific platforms. @@ -44,3 +47,35 @@ export function platformPopoutGuard( return true; // Allow navigation }; } + +/** + * Guard that forces a popout window on Firefox browser when a file picker could be exposed. + * Necessary to avoid a crash: https://bugzilla.mozilla.org/show_bug.cgi?id=1292701 + * Also disallows the user from closing a popout and re-opening the view exposing the file picker. + * + * @returns CanActivateFn that opens popout and blocks navigation on Firefox + */ +export function firefoxPopoutGuard(): CanActivateFn { + return async (_route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + // Check if browser is Firefox using the platform utils service + const deviceType = BrowserPlatformUtilsService.getDevice(window); + const isFirefox = deviceType === DeviceType.FirefoxExtension; + + // Check if already in popout/sidebar + const inPopout = BrowserPopupUtils.inPopout(window); + const inSidebar = BrowserPopupUtils.inSidebar(window); + + // Open popout if on Firefox and not already in popout/sidebar + if (isFirefox && !inPopout && !inSidebar) { + // Don't add autoClosePopout for file picker scenarios - user should manually close + await BrowserPopupUtils.openPopout(`popup/index.html#${state.url}`); + + // Close the original popup window + BrowserApi.closePopup(window); + + return false; // Block navigation - popout will reload + } + + return true; // Allow navigation + }; +} diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 48f06147cdf..14ff3c4a47a 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -48,7 +48,10 @@ import { LockComponent, ConfirmKeyConnectorDomainComponent } from "@bitwarden/ke import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component"; import { AuthExtensionRoute } from "../auth/popup/constants/auth-extension-route.constant"; import { fido2AuthGuard } from "../auth/popup/guards/fido2-auth.guard"; -import { platformPopoutGuard } from "../auth/popup/guards/platform-popout.guard"; +import { + firefoxPopoutGuard, + platformPopoutGuard, +} from "../auth/popup/guards/platform-popout.guard"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; import { ExtensionDeviceManagementComponent } from "../auth/popup/settings/extension-device-management.component"; import { Fido2Component } from "../autofill/popup/fido2/fido2.component"; @@ -246,7 +249,7 @@ const routes: Routes = [ { path: "import", component: ImportBrowserV2Component, - canActivate: [authGuard], + canActivate: [authGuard, firefoxPopoutGuard()], data: { elevation: 1 } satisfies RouteDataProperties, }, { @@ -324,13 +327,13 @@ const routes: Routes = [ { path: "add-send", component: SendAddEditV2Component, - canActivate: [authGuard], + canActivate: [authGuard, firefoxPopoutGuard()], data: { elevation: 1 } satisfies RouteDataProperties, }, { path: "edit-send", component: SendAddEditV2Component, - canActivate: [authGuard], + canActivate: [authGuard, firefoxPopoutGuard()], data: { elevation: 1 } satisfies RouteDataProperties, }, {