mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-27 17:18:04 +01:00
[BEEEP] Firefox Private Mode (#2294)
* Create background in popup if private mode, remove gates * Add messaging support to runtime in private mode * Fix messaging services and general bootstrap logic * Add private mode warning, remove old component * Deprecate launchGuardService * Require in memory account for user to be considered authenticated * Don't change icon for private mode windows * Set all icons from background page
This commit is contained in:
parent
7371ee344e
commit
06ba30fc6b
@ -980,8 +980,8 @@
|
|||||||
"commandLockVaultDesc": {
|
"commandLockVaultDesc": {
|
||||||
"message": "Lock the vault"
|
"message": "Lock the vault"
|
||||||
},
|
},
|
||||||
"privateModeMessage": {
|
"privateModeWarning": {
|
||||||
"message": "Unfortunately this window is not available in private mode for this browser."
|
"message": "Private mode support is experimental and some features are limited."
|
||||||
},
|
},
|
||||||
"customFields": {
|
"customFields": {
|
||||||
"message": "Custom Fields"
|
"message": "Custom Fields"
|
||||||
|
@ -92,6 +92,7 @@ import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
|||||||
import AutofillService from "../services/autofill.service";
|
import AutofillService from "../services/autofill.service";
|
||||||
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
||||||
import BrowserMessagingService from "../services/browserMessaging.service";
|
import BrowserMessagingService from "../services/browserMessaging.service";
|
||||||
|
import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service";
|
||||||
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
||||||
import BrowserStorageService from "../services/browserStorage.service";
|
import BrowserStorageService from "../services/browserStorage.service";
|
||||||
import I18nService from "../services/i18n.service";
|
import I18nService from "../services/i18n.service";
|
||||||
@ -100,7 +101,6 @@ import VaultTimeoutService from "../services/vaultTimeout.service";
|
|||||||
|
|
||||||
import { Account } from "../models/account";
|
import { Account } from "../models/account";
|
||||||
|
|
||||||
import { GlobalStateFactory } from "jslib-common/factories/globalStateFactory";
|
|
||||||
import { StateFactory } from "jslib-common/factories/stateFactory";
|
import { StateFactory } from "jslib-common/factories/stateFactory";
|
||||||
|
|
||||||
export default class MainBackground {
|
export default class MainBackground {
|
||||||
@ -165,9 +165,11 @@ export default class MainBackground {
|
|||||||
private isSafari: boolean;
|
private isSafari: boolean;
|
||||||
private nativeMessagingBackground: NativeMessagingBackground;
|
private nativeMessagingBackground: NativeMessagingBackground;
|
||||||
|
|
||||||
constructor() {
|
constructor(public isPrivateMode: boolean = false) {
|
||||||
// Services
|
// Services
|
||||||
this.messagingService = new BrowserMessagingService();
|
this.messagingService = isPrivateMode
|
||||||
|
? new BrowserMessagingPrivateModeBackgroundService()
|
||||||
|
: new BrowserMessagingService();
|
||||||
this.storageService = new BrowserStorageService();
|
this.storageService = new BrowserStorageService();
|
||||||
this.secureStorageService = new BrowserStorageService();
|
this.secureStorageService = new BrowserStorageService();
|
||||||
this.logService = new ConsoleLogService(false);
|
this.logService = new ConsoleLogService(false);
|
||||||
@ -362,7 +364,7 @@ export default class MainBackground {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService
|
this.stateService
|
||||||
);
|
);
|
||||||
this.popupUtilsService = new PopupUtilsService(this.platformUtilsService);
|
this.popupUtilsService = new PopupUtilsService(isPrivateMode);
|
||||||
|
|
||||||
this.userVerificationService = new UserVerificationService(
|
this.userVerificationService = new UserVerificationService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
@ -404,7 +406,6 @@ export default class MainBackground {
|
|||||||
this.systemService,
|
this.systemService,
|
||||||
this.environmentService,
|
this.environmentService,
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
this.stateService,
|
|
||||||
this.logService
|
this.logService
|
||||||
);
|
);
|
||||||
this.nativeMessagingBackground = new NativeMessagingBackground(
|
this.nativeMessagingBackground = new NativeMessagingBackground(
|
||||||
@ -502,6 +503,16 @@ export default class MainBackground {
|
|||||||
await this.webRequestBackground.init();
|
await this.webRequestBackground.init();
|
||||||
await this.windowsBackground.init();
|
await this.windowsBackground.init();
|
||||||
|
|
||||||
|
if (this.platformUtilsService.isFirefox && !this.isPrivateMode) {
|
||||||
|
// Set new Private Mode windows to the default icon - they do not share state with the background page
|
||||||
|
BrowserApi.onWindowCreated(async (win) => {
|
||||||
|
if (win.incognito) {
|
||||||
|
await this.actionSetIcon(chrome.browserAction, "", win.id);
|
||||||
|
await this.actionSetIcon(this.sidebarAction, "", win.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
await this.environmentService.setUrlsFromStorage();
|
await this.environmentService.setUrlsFromStorage();
|
||||||
@ -514,7 +525,7 @@ export default class MainBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setIcon() {
|
async setIcon() {
|
||||||
if (!chrome.browserAction && !this.sidebarAction) {
|
if ((!chrome.browserAction && !this.sidebarAction) || this.isPrivateMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,7 +939,7 @@ export default class MainBackground {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async actionSetIcon(theAction: any, suffix: string): Promise<any> {
|
private async actionSetIcon(theAction: any, suffix: string, windowId?: number): Promise<any> {
|
||||||
if (!theAction || !theAction.setIcon) {
|
if (!theAction || !theAction.setIcon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -938,6 +949,7 @@ export default class MainBackground {
|
|||||||
19: "images/icon19" + suffix + ".png",
|
19: "images/icon19" + suffix + ".png",
|
||||||
38: "images/icon38" + suffix + ".png",
|
38: "images/icon38" + suffix + ".png",
|
||||||
},
|
},
|
||||||
|
windowId: windowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.platformUtilsService.isFirefox()) {
|
if (this.platformUtilsService.isFirefox()) {
|
||||||
|
@ -31,7 +31,6 @@ export default class RuntimeBackground {
|
|||||||
private systemService: SystemService,
|
private systemService: SystemService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private stateService: StateService,
|
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {
|
) {
|
||||||
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
||||||
@ -46,12 +45,18 @@ export default class RuntimeBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.checkOnInstalled();
|
await this.checkOnInstalled();
|
||||||
BrowserApi.messageListener(
|
const backgroundMessageListener = async (
|
||||||
"runtime.background",
|
msg: any,
|
||||||
async (msg: any, sender: chrome.runtime.MessageSender, sendResponse: any) => {
|
sender: chrome.runtime.MessageSender,
|
||||||
await this.processMessage(msg, sender, sendResponse);
|
sendResponse: any
|
||||||
}
|
) => {
|
||||||
);
|
await this.processMessage(msg, sender, sendResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserApi.messageListener("runtime.background", backgroundMessageListener);
|
||||||
|
if (this.main.isPrivateMode) {
|
||||||
|
(window as any).bitwardenBackgroundMessageListener = backgroundMessageListener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async processMessage(msg: any, sender: any, sendResponse: any) {
|
async processMessage(msg: any, sender: any, sendResponse: any) {
|
||||||
@ -60,7 +65,7 @@ export default class RuntimeBackground {
|
|||||||
case "unlocked":
|
case "unlocked":
|
||||||
let item: LockedVaultPendingNotificationsItem;
|
let item: LockedVaultPendingNotificationsItem;
|
||||||
|
|
||||||
if (this.lockedVaultPendingNotifications.length > 0) {
|
if (this.lockedVaultPendingNotifications?.length > 0) {
|
||||||
await BrowserApi.closeLoginTab();
|
await BrowserApi.closeLoginTab();
|
||||||
|
|
||||||
item = this.lockedVaultPendingNotifications.pop();
|
item = this.lockedVaultPendingNotifications.pop();
|
||||||
|
@ -84,6 +84,14 @@ export class BrowserApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getPrivateModeWindows(): Promise<browser.windows.Window[]> {
|
||||||
|
return (await browser.windows.getAll()).filter((win) => win.incognito);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async onWindowCreated(callback: (win: chrome.windows.Window) => any) {
|
||||||
|
return chrome.windows.onCreated.addListener(callback);
|
||||||
|
}
|
||||||
|
|
||||||
static getBackgroundPage(): any {
|
static getBackgroundPage(): any {
|
||||||
return chrome.extension.getBackgroundPage();
|
return chrome.extension.getBackgroundPage();
|
||||||
}
|
}
|
||||||
|
@ -70,5 +70,6 @@
|
|||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<button type="button" appStopClick (click)="logOut()">{{ "logOut" | i18n }}</button>
|
<button type="button" appStopClick (click)="logOut()">{{ "logOut" | i18n }}</button>
|
||||||
</p>
|
</p>
|
||||||
|
<app-private-mode-warning></app-private-mode-warning>
|
||||||
</content>
|
</content>
|
||||||
</form>
|
</form>
|
||||||
|
@ -67,5 +67,6 @@
|
|||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
|
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
|
||||||
</p>
|
</p>
|
||||||
|
<app-private-mode-warning></app-private-mode-warning>
|
||||||
</content>
|
</content>
|
||||||
</form>
|
</form>
|
||||||
|
@ -3,9 +3,9 @@ import { ActivatedRouteSnapshot, RouteReuseStrategy, RouterModule, Routes } from
|
|||||||
|
|
||||||
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
||||||
import { LockGuardService } from "jslib-angular/services/lock-guard.service";
|
import { LockGuardService } from "jslib-angular/services/lock-guard.service";
|
||||||
|
import { UnauthGuardService } from "jslib-angular/services/unauth-guard.service";
|
||||||
|
|
||||||
import { DebounceNavigationService } from "./services/debounceNavigationService";
|
import { DebounceNavigationService } from "./services/debounceNavigationService";
|
||||||
import { LaunchGuardService } from "./services/launch-guard.service";
|
|
||||||
|
|
||||||
import { EnvironmentComponent } from "./accounts/environment.component";
|
import { EnvironmentComponent } from "./accounts/environment.component";
|
||||||
import { HintComponent } from "./accounts/hint.component";
|
import { HintComponent } from "./accounts/hint.component";
|
||||||
@ -23,7 +23,6 @@ import { UpdateTempPasswordComponent } from "./accounts/update-temp-password.com
|
|||||||
import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component";
|
import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component";
|
||||||
import { PasswordGeneratorComponent } from "./generator/password-generator.component";
|
import { PasswordGeneratorComponent } from "./generator/password-generator.component";
|
||||||
|
|
||||||
import { PrivateModeComponent } from "./private-mode.component";
|
|
||||||
import { TabsComponent } from "./tabs.component";
|
import { TabsComponent } from "./tabs.component";
|
||||||
|
|
||||||
import { ExcludedDomainsComponent } from "./settings/excluded-domains.component";
|
import { ExcludedDomainsComponent } from "./settings/excluded-domains.component";
|
||||||
@ -63,13 +62,13 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: "home",
|
path: "home",
|
||||||
component: HomeComponent,
|
component: HomeComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "home" },
|
data: { state: "home" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "login",
|
path: "login",
|
||||||
component: LoginComponent,
|
component: LoginComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "login" },
|
data: { state: "login" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -81,19 +80,19 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: "2fa",
|
path: "2fa",
|
||||||
component: TwoFactorComponent,
|
component: TwoFactorComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "2fa" },
|
data: { state: "2fa" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "2fa-options",
|
path: "2fa-options",
|
||||||
component: TwoFactorOptionsComponent,
|
component: TwoFactorOptionsComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "2fa-options" },
|
data: { state: "2fa-options" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "sso",
|
path: "sso",
|
||||||
component: SsoComponent,
|
component: SsoComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "sso" },
|
data: { state: "sso" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -110,19 +109,19 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: "register",
|
path: "register",
|
||||||
component: RegisterComponent,
|
component: RegisterComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "register" },
|
data: { state: "register" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "hint",
|
path: "hint",
|
||||||
component: HintComponent,
|
component: HintComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "hint" },
|
data: { state: "hint" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "environment",
|
path: "environment",
|
||||||
component: EnvironmentComponent,
|
component: EnvironmentComponent,
|
||||||
canActivate: [LaunchGuardService],
|
canActivate: [UnauthGuardService],
|
||||||
data: { state: "environment" },
|
data: { state: "environment" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -235,11 +234,6 @@ const routes: Routes = [
|
|||||||
canActivate: [AuthGuardService],
|
canActivate: [AuthGuardService],
|
||||||
data: { state: "options" },
|
data: { state: "options" },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "private-mode",
|
|
||||||
component: PrivateModeComponent,
|
|
||||||
data: { state: "private-mode" },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "clone-cipher",
|
path: "clone-cipher",
|
||||||
component: AddEditComponent,
|
component: AddEditComponent,
|
||||||
|
@ -8,7 +8,6 @@ import { BrowserApi } from "../browser/browserApi";
|
|||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
@ -39,14 +38,10 @@ export class AppComponent implements OnInit {
|
|||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private sanitizer: DomSanitizer,
|
private sanitizer: DomSanitizer,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService
|
||||||
private keyConnectoService: KeyConnectorService
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (BrowserApi.getBackgroundPage() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.stateService.activeAccount.subscribe((userId) => {
|
this.stateService.activeAccount.subscribe((userId) => {
|
||||||
this.activeUserId = userId;
|
this.activeUserId = userId;
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,6 @@ import { PasswordGeneratorHistoryComponent } from "./generator/password-generato
|
|||||||
import { PasswordGeneratorComponent } from "./generator/password-generator.component";
|
import { PasswordGeneratorComponent } from "./generator/password-generator.component";
|
||||||
|
|
||||||
import { AppComponent } from "./app.component";
|
import { AppComponent } from "./app.component";
|
||||||
import { PrivateModeComponent } from "./private-mode.component";
|
|
||||||
import { TabsComponent } from "./tabs.component";
|
import { TabsComponent } from "./tabs.component";
|
||||||
|
|
||||||
import { ExcludedDomainsComponent } from "./settings/excluded-domains.component";
|
import { ExcludedDomainsComponent } from "./settings/excluded-domains.component";
|
||||||
@ -78,6 +77,7 @@ import { ActionButtonsComponent } from "./components/action-buttons.component";
|
|||||||
import { CipherRowComponent } from "./components/cipher-row.component";
|
import { CipherRowComponent } from "./components/cipher-row.component";
|
||||||
import { PasswordRepromptComponent } from "./components/password-reprompt.component";
|
import { PasswordRepromptComponent } from "./components/password-reprompt.component";
|
||||||
import { PopOutComponent } from "./components/pop-out.component";
|
import { PopOutComponent } from "./components/pop-out.component";
|
||||||
|
import { PrivateModeWarningComponent } from "./components/private-mode-warning.component";
|
||||||
import { SendListComponent } from "./components/send-list.component";
|
import { SendListComponent } from "./components/send-list.component";
|
||||||
import { SetPinComponent } from "./components/set-pin.component";
|
import { SetPinComponent } from "./components/set-pin.component";
|
||||||
import { VerifyMasterPasswordComponent } from "./components/verify-master-password.component";
|
import { VerifyMasterPasswordComponent } from "./components/verify-master-password.component";
|
||||||
@ -230,7 +230,7 @@ registerLocaleData(localeZhTw, "zh-TW");
|
|||||||
PasswordRepromptComponent,
|
PasswordRepromptComponent,
|
||||||
PopOutComponent,
|
PopOutComponent,
|
||||||
PremiumComponent,
|
PremiumComponent,
|
||||||
PrivateModeComponent,
|
PrivateModeWarningComponent,
|
||||||
RegisterComponent,
|
RegisterComponent,
|
||||||
SearchCiphersPipe,
|
SearchCiphersPipe,
|
||||||
SelectCopyDirective,
|
SelectCopyDirective,
|
||||||
|
6
src/popup/components/private-mode-warning.component.html
Normal file
6
src/popup/components/private-mode-warning.component.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<app-callout type="warning" *ngIf="showWarning">
|
||||||
|
{{ "privateModeWarning" | i18n }}
|
||||||
|
<a href="https://bitwarden.com/help/article/private-mode/" target="_blank" rel="noopener">{{
|
||||||
|
"learnMore" | i18n
|
||||||
|
}}</a>
|
||||||
|
</app-callout>
|
16
src/popup/components/private-mode-warning.component.ts
Normal file
16
src/popup/components/private-mode-warning.component.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-private-mode-warning",
|
||||||
|
templateUrl: "private-mode-warning.component.html",
|
||||||
|
})
|
||||||
|
export class PrivateModeWarningComponent implements OnInit {
|
||||||
|
showWarning = false;
|
||||||
|
|
||||||
|
constructor(private popupUtilsService: PopupUtilsService) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.showWarning = this.popupUtilsService.inPrivateMode();
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
<div class="content">
|
|
||||||
<p class="text-center">{{ privateModeMessage }}</p>
|
|
||||||
<button type="button" class="btn primary block" (click)="learnMore()">
|
|
||||||
<b>{{ learnMoreMessage }}</b>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
@ -1,21 +0,0 @@
|
|||||||
import { BrowserApi } from "../browser/browserApi";
|
|
||||||
|
|
||||||
import { Component, OnInit } from "@angular/core";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-private-mode",
|
|
||||||
templateUrl: "private-mode.component.html",
|
|
||||||
})
|
|
||||||
export class PrivateModeComponent implements OnInit {
|
|
||||||
privateModeMessage: string;
|
|
||||||
learnMoreMessage: string;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.privateModeMessage = chrome.i18n.getMessage("privateModeMessage");
|
|
||||||
this.learnMoreMessage = chrome.i18n.getMessage("learnMore");
|
|
||||||
}
|
|
||||||
|
|
||||||
learnMore() {
|
|
||||||
BrowserApi.createNewTab("https://bitwarden.com/help/extension-wont-load-in-private-mode/");
|
|
||||||
}
|
|
||||||
}
|
|
@ -73,6 +73,11 @@ app-home {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app-private-mode-warning {
|
||||||
|
display: block;
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
body.body-sm,
|
body.body-sm,
|
||||||
body.body-xs {
|
body.body-xs {
|
||||||
app-home {
|
app-home {
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { BrowserApi } from "../../browser/browserApi";
|
|
||||||
|
|
||||||
import { Injectable } from "@angular/core";
|
|
||||||
import { CanActivate, Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { UnauthGuardService } from "jslib-angular/services/unauth-guard.service";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class LaunchGuardService implements CanActivate {
|
|
||||||
constructor(private router: Router, private unauthGuardService: UnauthGuardService) {}
|
|
||||||
|
|
||||||
async canActivate() {
|
|
||||||
if (BrowserApi.getBackgroundPage() == null) {
|
|
||||||
this.router.navigate(["private-mode"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return await this.unauthGuardService.canActivate();
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,11 +2,9 @@ import { Injectable } from "@angular/core";
|
|||||||
|
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
|
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PopupUtilsService {
|
export class PopupUtilsService {
|
||||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
constructor(private privateMode: boolean = false) {}
|
||||||
|
|
||||||
inSidebar(win: Window): boolean {
|
inSidebar(win: Window): boolean {
|
||||||
return win.location.search !== "" && win.location.search.indexOf("uilocation=sidebar") > -1;
|
return win.location.search !== "" && win.location.search.indexOf("uilocation=sidebar") > -1;
|
||||||
@ -28,6 +26,10 @@ export class PopupUtilsService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inPrivateMode(): boolean {
|
||||||
|
return this.privateMode;
|
||||||
|
}
|
||||||
|
|
||||||
getContentScrollY(win: Window, scrollingContainer: string = "content"): number {
|
getContentScrollY(win: Window, scrollingContainer: string = "content"): number {
|
||||||
const content = win.document.getElementsByTagName(scrollingContainer)[0];
|
const content = win.document.getElementsByTagName(scrollingContainer)[0];
|
||||||
return content.scrollTop;
|
return content.scrollTop;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { APP_INITIALIZER, LOCALE_ID, NgModule } from "@angular/core";
|
import { APP_INITIALIZER, LOCALE_ID, NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { DebounceNavigationService } from "./debounceNavigationService";
|
import { DebounceNavigationService } from "./debounceNavigationService";
|
||||||
import { LaunchGuardService } from "./launch-guard.service";
|
|
||||||
import { LockGuardService } from "./lock-guard.service";
|
import { LockGuardService } from "./lock-guard.service";
|
||||||
import { PasswordRepromptService } from "./password-reprompt.service";
|
import { PasswordRepromptService } from "./password-reprompt.service";
|
||||||
import { UnauthGuardService } from "./unauth-guard.service";
|
import { UnauthGuardService } from "./unauth-guard.service";
|
||||||
@ -49,7 +48,9 @@ import { UserVerificationService } from "jslib-common/abstractions/userVerificat
|
|||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
import { AutofillService } from "../../services/abstractions/autofill.service";
|
import { AutofillService } from "../../services/abstractions/autofill.service";
|
||||||
|
|
||||||
import BrowserMessagingService from "../../services/browserMessaging.service";
|
import BrowserMessagingService from "../../services/browserMessaging.service";
|
||||||
|
import BrowserMessagingPrivateModePopupService from "../../services/browserMessagingPrivateModePopup.service";
|
||||||
|
|
||||||
import { AuthService } from "jslib-common/services/auth.service";
|
import { AuthService } from "jslib-common/services/auth.service";
|
||||||
import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
|
import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
|
||||||
@ -62,14 +63,24 @@ import { ThemeType } from "jslib-common/enums/themeType";
|
|||||||
|
|
||||||
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
|
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
|
||||||
|
|
||||||
function getBgService<T>(service: string) {
|
import MainBackground from "../../background/main.background";
|
||||||
return (): T => {
|
|
||||||
const page = BrowserApi.getBackgroundPage();
|
|
||||||
return page ? (page.bitwardenMain[service] as T) : null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const isPrivateMode = BrowserApi.getBackgroundPage() == null;
|
const isPrivateMode = BrowserApi.getBackgroundPage() == null;
|
||||||
|
const mainBackground: MainBackground = isPrivateMode
|
||||||
|
? createLocalBgService()
|
||||||
|
: BrowserApi.getBackgroundPage().bitwardenMain;
|
||||||
|
|
||||||
|
function createLocalBgService() {
|
||||||
|
const localBgService = new MainBackground(true);
|
||||||
|
localBgService.bootstrap();
|
||||||
|
return localBgService;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBgService<T>(service: keyof MainBackground) {
|
||||||
|
return (): T => {
|
||||||
|
return mainBackground ? (mainBackground[service] as any as T) : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function initFactory(
|
export function initFactory(
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
@ -89,33 +100,47 @@ export function initFactory(
|
|||||||
window.document.body.classList.add("body-sm");
|
window.document.body.classList.add("body-sm");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPrivateMode) {
|
const htmlEl = window.document.documentElement;
|
||||||
const htmlEl = window.document.documentElement;
|
const theme = await platformUtilsService.getEffectiveTheme();
|
||||||
const theme = await platformUtilsService.getEffectiveTheme();
|
htmlEl.classList.add("theme_" + theme);
|
||||||
htmlEl.classList.add("theme_" + theme);
|
platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
|
||||||
platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
|
const bwTheme = await stateService.getTheme();
|
||||||
const bwTheme = await stateService.getTheme();
|
if (bwTheme == null || bwTheme === ThemeType.System) {
|
||||||
if (bwTheme == null || bwTheme === ThemeType.System) {
|
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
|
||||||
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
|
htmlEl.classList.add("theme_" + sysTheme);
|
||||||
htmlEl.classList.add("theme_" + sysTheme);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
htmlEl.classList.add("locale_" + i18nService.translationLocale);
|
|
||||||
|
|
||||||
// Workaround for slow performance on external monitors on Chrome + MacOS
|
|
||||||
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
|
|
||||||
if (
|
|
||||||
platformUtilsService.isChrome() &&
|
|
||||||
navigator.platform.indexOf("Mac") > -1 &&
|
|
||||||
popupUtilsService.inPopup(window) &&
|
|
||||||
(window.screenLeft < 0 ||
|
|
||||||
window.screenTop < 0 ||
|
|
||||||
window.screenLeft > window.screen.width ||
|
|
||||||
window.screenTop > window.screen.height)
|
|
||||||
) {
|
|
||||||
htmlEl.classList.add("force_redraw");
|
|
||||||
logService.info("Force redraw is on");
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
htmlEl.classList.add("locale_" + i18nService.translationLocale);
|
||||||
|
|
||||||
|
// Workaround for slow performance on external monitors on Chrome + MacOS
|
||||||
|
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
|
||||||
|
if (
|
||||||
|
platformUtilsService.isChrome() &&
|
||||||
|
navigator.platform.indexOf("Mac") > -1 &&
|
||||||
|
popupUtilsService.inPopup(window) &&
|
||||||
|
(window.screenLeft < 0 ||
|
||||||
|
window.screenTop < 0 ||
|
||||||
|
window.screenLeft > window.screen.width ||
|
||||||
|
window.screenTop > window.screen.height)
|
||||||
|
) {
|
||||||
|
htmlEl.classList.add("force_redraw");
|
||||||
|
logService.info("Force redraw is on");
|
||||||
|
}
|
||||||
|
htmlEl.classList.add("locale_" + i18nService.translationLocale);
|
||||||
|
|
||||||
|
// Workaround for slow performance on external monitors on Chrome + MacOS
|
||||||
|
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
|
||||||
|
if (
|
||||||
|
platformUtilsService.isChrome() &&
|
||||||
|
navigator.platform.indexOf("Mac") > -1 &&
|
||||||
|
popupUtilsService.inPopup(window) &&
|
||||||
|
(window.screenLeft < 0 ||
|
||||||
|
window.screenTop < 0 ||
|
||||||
|
window.screenLeft > window.screen.width ||
|
||||||
|
window.screenTop > window.screen.height)
|
||||||
|
) {
|
||||||
|
htmlEl.classList.add("force_redraw");
|
||||||
|
logService.info("Force redraw is on");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -126,8 +151,7 @@ export function initFactory(
|
|||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: LOCALE_ID,
|
provide: LOCALE_ID,
|
||||||
useFactory: () =>
|
useFactory: () => getBgService<I18nService>("i18nService")().translationLocale,
|
||||||
isPrivateMode ? null : getBgService<I18nService>("i18nService")().translationLocale,
|
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -142,12 +166,23 @@ export function initFactory(
|
|||||||
],
|
],
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
},
|
||||||
LaunchGuardService,
|
|
||||||
{ provide: BaseLockGuardService, useClass: LockGuardService },
|
{ provide: BaseLockGuardService, useClass: LockGuardService },
|
||||||
{ provide: BaseUnauthGuardService, useClass: UnauthGuardService },
|
{ provide: BaseUnauthGuardService, useClass: UnauthGuardService },
|
||||||
DebounceNavigationService,
|
DebounceNavigationService,
|
||||||
PopupUtilsService,
|
{ provide: PopupUtilsService, useFactory: () => new PopupUtilsService(isPrivateMode) },
|
||||||
{ provide: MessagingService, useClass: BrowserMessagingService },
|
{
|
||||||
|
provide: MessagingService,
|
||||||
|
useFactory: () => {
|
||||||
|
return isPrivateMode
|
||||||
|
? new BrowserMessagingPrivateModePopupService()
|
||||||
|
: new BrowserMessagingService();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: TwoFactorService,
|
||||||
|
useFactory: getBgService<TwoFactorService>("twoFactorService"),
|
||||||
|
deps: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: TwoFactorService,
|
provide: TwoFactorService,
|
||||||
useFactory: getBgService<TwoFactorService>("twoFactorService"),
|
useFactory: getBgService<TwoFactorService>("twoFactorService"),
|
||||||
@ -165,14 +200,12 @@ export function initFactory(
|
|||||||
logService: ConsoleLogService,
|
logService: ConsoleLogService,
|
||||||
i18nService: I18nService
|
i18nService: I18nService
|
||||||
) => {
|
) => {
|
||||||
return isPrivateMode
|
return new PopupSearchService(
|
||||||
? null
|
getBgService<SearchService>("searchService")(),
|
||||||
: new PopupSearchService(
|
cipherService,
|
||||||
getBgService<SearchService>("searchService")(),
|
logService,
|
||||||
cipherService,
|
i18nService
|
||||||
logService,
|
);
|
||||||
i18nService
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
deps: [CipherService, LogServiceAbstraction, I18nService],
|
deps: [CipherService, LogServiceAbstraction, I18nService],
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
|
|
||||||
|
export default class BrowserMessagingPrivateModeBackgroundService implements MessagingService {
|
||||||
|
send(subscriber: string, arg: any = {}) {
|
||||||
|
const message = Object.assign({}, { command: subscriber }, arg);
|
||||||
|
(window as any).bitwardenPopupMainMessageListener(message);
|
||||||
|
}
|
||||||
|
}
|
8
src/services/browserMessagingPrivateModePopup.service.ts
Normal file
8
src/services/browserMessagingPrivateModePopup.service.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
|
|
||||||
|
export default class BrowserMessagingPrivateModePopupService implements MessagingService {
|
||||||
|
send(subscriber: string, arg: any = {}) {
|
||||||
|
const message = Object.assign({}, { command: subscriber }, arg);
|
||||||
|
(window as any).bitwardenBackgroundMessageListener(message);
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,15 @@ export class StateService
|
|||||||
await super.addAccount(account);
|
await super.addAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getIsAuthenticated(options?: StorageOptions): Promise<boolean> {
|
||||||
|
// Firefox Private Mode can clash with non-Private Mode because they both read from the same onDiskOptions
|
||||||
|
// Check that there is an account in memory before considering the user authenticated
|
||||||
|
return (
|
||||||
|
(await super.getIsAuthenticated(options)) &&
|
||||||
|
(await this.getAccount(this.defaultInMemoryOptions)) != null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async getBrowserGroupingComponentState(
|
async getBrowserGroupingComponentState(
|
||||||
options?: StorageOptions
|
options?: StorageOptions
|
||||||
): Promise<BrowserGroupingsComponentState> {
|
): Promise<BrowserGroupingsComponentState> {
|
||||||
|
Loading…
Reference in New Issue
Block a user