diff --git a/.github/whitelist-capital-letters.txt b/.github/whitelist-capital-letters.txt index 3155ef348f7..b09829f7f4c 100644 --- a/.github/whitelist-capital-letters.txt +++ b/.github/whitelist-capital-letters.txt @@ -18,6 +18,7 @@ ./libs/admin-console/README.md ./libs/auth/README.md ./libs/billing/README.md +./libs/common/src/tools/integration/README.md ./libs/platform/README.md ./libs/tools/README.md ./libs/tools/export/vault-export/README.md diff --git a/apps/browser/src/auth/popup/two-factor-auth.component.ts b/apps/browser/src/auth/popup/two-factor-auth.component.ts new file mode 100644 index 00000000000..8fe735bd16d --- /dev/null +++ b/apps/browser/src/auth/popup/two-factor-auth.component.ts @@ -0,0 +1,151 @@ +import { CommonModule } from "@angular/common"; +import { Component, Inject, OnInit } from "@angular/core"; +import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; +import { ActivatedRoute, Router, RouterLink } from "@angular/router"; + +import { TwoFactorAuthAuthenticatorComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-auth-authenticator.component"; +import { TwoFactorAuthComponent as BaseTwoFactorAuthComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-auth.component"; +import { TwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-options.component"; +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe"; +import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; +import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SyncService } from "@bitwarden/common/platform/sync"; +import { + ButtonModule, + FormFieldModule, + AsyncActionsModule, + CheckboxModule, + DialogModule, + LinkModule, + TypographyModule, + DialogService, +} from "@bitwarden/components"; + +import { + LoginStrategyServiceAbstraction, + LoginEmailServiceAbstraction, + UserDecryptionOptionsServiceAbstraction, +} from "../../../../../libs/auth/src/common/abstractions"; +import { BrowserApi } from "../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; + +@Component({ + standalone: true, + templateUrl: + "../../../../../libs/angular/src/auth/components/two-factor-auth/two-factor-auth.component.html", + selector: "app-two-factor-auth", + imports: [ + CommonModule, + JslibModule, + DialogModule, + ButtonModule, + LinkModule, + TypographyModule, + ReactiveFormsModule, + FormFieldModule, + AsyncActionsModule, + RouterLink, + CheckboxModule, + TwoFactorOptionsComponent, + TwoFactorAuthAuthenticatorComponent, + ], + providers: [I18nPipe], +}) +export class TwoFactorAuthComponent extends BaseTwoFactorAuthComponent implements OnInit { + constructor( + protected loginStrategyService: LoginStrategyServiceAbstraction, + protected router: Router, + i18nService: I18nService, + platformUtilsService: PlatformUtilsService, + environmentService: EnvironmentService, + dialogService: DialogService, + protected route: ActivatedRoute, + logService: LogService, + protected twoFactorService: TwoFactorService, + loginEmailService: LoginEmailServiceAbstraction, + userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, + protected ssoLoginService: SsoLoginServiceAbstraction, + protected configService: ConfigService, + masterPasswordService: InternalMasterPasswordServiceAbstraction, + accountService: AccountService, + formBuilder: FormBuilder, + @Inject(WINDOW) protected win: Window, + private syncService: SyncService, + private messagingService: MessagingService, + ) { + super( + loginStrategyService, + router, + i18nService, + platformUtilsService, + environmentService, + dialogService, + route, + logService, + twoFactorService, + loginEmailService, + userDecryptionOptionsService, + ssoLoginService, + configService, + masterPasswordService, + accountService, + formBuilder, + win, + ); + super.onSuccessfulLoginTdeNavigate = async () => { + this.win.close(); + }; + this.onSuccessfulLoginNavigate = this.goAfterLogIn; + } + + async ngOnInit(): Promise { + await super.ngOnInit(); + + if (this.route.snapshot.paramMap.has("webAuthnResponse")) { + // WebAuthn fallback response + this.selectedProviderType = TwoFactorProviderType.WebAuthn; + this.token = this.route.snapshot.paramMap.get("webAuthnResponse"); + super.onSuccessfulLogin = async () => { + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.syncService.fullSync(true); + this.messagingService.send("reloadPopup"); + window.close(); + }; + this.remember = this.route.snapshot.paramMap.get("remember") === "true"; + await this.submit(); + return; + } + + if (await BrowserPopupUtils.inPopout(this.win)) { + this.selectedProviderType = TwoFactorProviderType.Email; + } + + // WebAuthn prompt appears inside the popup on linux, and requires a larger popup width + // than usual to avoid cutting off the dialog. + if (this.selectedProviderType === TwoFactorProviderType.WebAuthn && (await this.isLinux())) { + document.body.classList.add("linux-webauthn"); + } + } + + async ngOnDestroy() { + if (this.selectedProviderType === TwoFactorProviderType.WebAuthn && (await this.isLinux())) { + document.body.classList.remove("linux-webauthn"); + } + } + + async isLinux() { + return (await BrowserApi.getPlatformInfo()).os === "linux"; + } +} diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index 5598c27dd6e..9c2e63c1aa7 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -17,7 +17,6 @@ import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { BrowserApi } from "../../platform/browser/browser-api"; -import { DefaultBrowserStateService } from "../../platform/services/default-browser-state.service"; import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; import { FormData } from "../services/abstractions/autofill.service"; import AutofillService from "../services/autofill.service"; @@ -49,7 +48,6 @@ describe("NotificationBackground", () => { const authService = mock(); const policyService = mock(); const folderService = mock(); - const stateService = mock(); const userNotificationSettingsService = mock(); const domainSettingsService = mock(); const environmentService = mock(); @@ -64,7 +62,6 @@ describe("NotificationBackground", () => { authService, policyService, folderService, - stateService, userNotificationSettingsService, domainSettingsService, environmentService, diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 9b65e4db0b2..179598a8823 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -23,7 +23,6 @@ import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window"; import { BrowserApi } from "../../platform/browser/browser-api"; -import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window"; import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; import { AutofillService } from "../services/abstractions/autofill.service"; @@ -76,7 +75,6 @@ export default class NotificationBackground { private authService: AuthService, private policyService: PolicyService, private folderService: FolderService, - private stateService: BrowserStateService, private userNotificationSettingsService: UserNotificationSettingsServiceAbstraction, private domainSettingsService: DomainSettingsService, private environmentService: EnvironmentService, diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index df4867640f4..7be93b11e6b 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -33,7 +33,6 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { BrowserApi } from "../../platform/browser/browser-api"; -import { DefaultBrowserStateService } from "../../platform/services/default-browser-state.service"; import { BrowserPlatformUtilsService } from "../../platform/services/platform-utils/browser-platform-utils.service"; import { AutofillService } from "../services/abstractions/autofill.service"; import { @@ -73,7 +72,6 @@ describe("OverlayBackground", () => { urls: { icons: "https://icons.bitwarden.com/" }, }), ); - const stateService = mock(); const autofillSettingsService = mock(); const i18nService = mock(); const platformUtilsService = mock(); @@ -104,7 +102,6 @@ describe("OverlayBackground", () => { authService, environmentService, domainSettingsService, - stateService, autofillSettingsService, i18nService, platformUtilsService, diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index bf954c3419f..2f80790134e 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -9,7 +9,6 @@ import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -101,7 +100,6 @@ class OverlayBackground implements OverlayBackgroundInterface { private authService: AuthService, private environmentService: EnvironmentService, private domainSettingsService: DomainSettingsService, - private stateService: StateService, private autofillSettingsService: AutofillSettingsServiceAbstraction, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts index 67637da2fdd..21eadfaf668 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts @@ -6,16 +6,15 @@ import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/s import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; - import { MainContextMenuHandler } from "./main-context-menu-handler"; describe("context-menu", () => { - let stateService: MockProxy; + let stateService: MockProxy; let autofillSettingsService: MockProxy; let i18nService: MockProxy; let logService: MockProxy; diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.ts index a02a3a84d4b..7b074a566a2 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.ts @@ -20,12 +20,11 @@ import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/s import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; - import { InitContextMenuItems } from "./abstractions/main-context-menu-handler"; export class MainContextMenuHandler { @@ -143,7 +142,7 @@ export class MainContextMenuHandler { ]; constructor( - private stateService: BrowserStateService, + private stateService: StateService, private autofillSettingsService: AutofillSettingsServiceAbstraction, private i18nService: I18nService, private logService: LogService, diff --git a/apps/browser/src/background/idle.background.ts b/apps/browser/src/background/idle.background.ts index eef033b364b..c0cd3a86aae 100644 --- a/apps/browser/src/background/idle.background.ts +++ b/apps/browser/src/background/idle.background.ts @@ -7,8 +7,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; -import { BrowserStateService } from "../platform/services/abstractions/browser-state.service"; - const IdleInterval = 60 * 5; // 5 minutes export default class IdleBackground { @@ -18,7 +16,6 @@ export default class IdleBackground { constructor( private vaultTimeoutService: VaultTimeoutService, - private stateService: BrowserStateService, private notificationsService: NotificationsService, private accountService: AccountService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService, diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 8de3014fb2c..b1dbb8525f8 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -86,6 +86,7 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { AbstractStorageService, ObservableStorageService, @@ -101,6 +102,7 @@ import { Message, MessageListener, MessageSender } from "@bitwarden/common/platf import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { Lazy } from "@bitwarden/common/platform/misc/lazy"; import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize"; +import { Account } from "@bitwarden/common/platform/models/domain/account"; import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { AppIdService } from "@bitwarden/common/platform/services/app-id.service"; @@ -116,6 +118,7 @@ import { FileUploadService } from "@bitwarden/common/platform/services/file-uplo import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; +import { StateService } from "@bitwarden/common/platform/services/state.service"; import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; @@ -206,7 +209,6 @@ import { Fido2Background } from "../autofill/fido2/background/fido2.background"; import { AutofillService as AutofillServiceAbstraction } from "../autofill/services/abstractions/autofill.service"; import AutofillService from "../autofill/services/autofill.service"; import { SafariApp } from "../browser/safariApp"; -import { Account } from "../models/account"; import { BrowserApi } from "../platform/browser/browser-api"; import { flagEnabled } from "../platform/flags"; import { UpdateBadge } from "../platform/listeners/update-badge"; @@ -215,13 +217,11 @@ import { ChromeMessageSender } from "../platform/messaging/chrome-message.sender /* eslint-enable no-restricted-imports */ import { OffscreenDocumentService } from "../platform/offscreen-document/abstractions/offscreen-document"; import { DefaultOffscreenDocumentService } from "../platform/offscreen-document/offscreen-document.service"; -import { BrowserStateService as StateServiceAbstraction } from "../platform/services/abstractions/browser-state.service"; import { BrowserCryptoService } from "../platform/services/browser-crypto.service"; import { BrowserEnvironmentService } from "../platform/services/browser-environment.service"; import BrowserLocalStorageService from "../platform/services/browser-local-storage.service"; import BrowserMemoryStorageService from "../platform/services/browser-memory-storage.service"; import { BrowserScriptInjectorService } from "../platform/services/browser-script-injector.service"; -import { DefaultBrowserStateService } from "../platform/services/default-browser-state.service"; import I18nService from "../platform/services/i18n.service"; import { LocalBackedSessionStorageService } from "../platform/services/local-backed-session-storage.service"; import { BackgroundPlatformUtilsService } from "../platform/services/platform-utils/background-platform-utils.service"; @@ -540,7 +540,7 @@ export default class MainBackground { ClientType.Browser, ); - this.stateService = new DefaultBrowserStateService( + this.stateService = new StateService( this.storageService, this.secureStorageService, this.memoryStorageService, @@ -968,7 +968,6 @@ export default class MainBackground { this.messagingService, this.platformUtilsService, systemUtilsServiceReloadCallback, - this.stateService, this.autofillSettingsService, this.vaultTimeoutSettingsService, this.biometricStateService, @@ -1028,7 +1027,6 @@ export default class MainBackground { this.authService, this.policyService, this.folderService, - this.stateService, this.userNotificationSettingsService, this.domainSettingsService, this.environmentService, @@ -1042,7 +1040,6 @@ export default class MainBackground { this.authService, this.environmentService, this.domainSettingsService, - this.stateService, this.autofillSettingsService, this.i18nService, this.platformUtilsService, @@ -1100,7 +1097,6 @@ export default class MainBackground { this.idleBackground = new IdleBackground( this.vaultTimeoutService, - this.stateService, this.notificationsService, this.accountService, this.vaultTimeoutSettingsService, @@ -1227,11 +1223,6 @@ export default class MainBackground { async switchAccount(userId: UserId) { let nextAccountStatus: AuthenticationStatus; try { - const currentlyActiveAccount = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((account) => account?.id)), - ); - // can be removed once password generation history is migrated to state providers - await this.stateService.clearDecryptedData(currentlyActiveAccount); // HACK to ensure account is switched before proceeding const switchPromise = firstValueFrom( this.accountService.activeAccount$.pipe( diff --git a/apps/browser/src/models/account.ts b/apps/browser/src/models/account.ts deleted file mode 100644 index 519f1bda6bb..00000000000 --- a/apps/browser/src/models/account.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { Account as BaseAccount } from "@bitwarden/common/platform/models/domain/account"; - -import { BrowserComponentState } from "./browserComponentState"; -import { BrowserGroupingsComponentState } from "./browserGroupingsComponentState"; -import { BrowserSendComponentState } from "./browserSendComponentState"; - -export class Account extends BaseAccount { - groupings?: BrowserGroupingsComponentState; - send?: BrowserSendComponentState; - ciphers?: BrowserComponentState; - sendType?: BrowserComponentState; - - constructor(init: Partial) { - super(init); - - this.groupings = init?.groupings ?? new BrowserGroupingsComponentState(); - this.send = init?.send ?? new BrowserSendComponentState(); - this.ciphers = init?.ciphers ?? new BrowserComponentState(); - this.sendType = init?.sendType ?? new BrowserComponentState(); - } - - static fromJSON(json: Jsonify): Account { - if (json == null) { - return null; - } - - return Object.assign(new Account({}), json, super.fromJSON(json), { - groupings: BrowserGroupingsComponentState.fromJSON(json.groupings), - send: BrowserSendComponentState.fromJSON(json.send), - ciphers: BrowserComponentState.fromJSON(json.ciphers), - sendType: BrowserComponentState.fromJSON(json.sendType), - }); - } -} diff --git a/apps/browser/src/platform/services/abstractions/browser-state.service.ts b/apps/browser/src/platform/services/abstractions/browser-state.service.ts deleted file mode 100644 index c8e2c502e71..00000000000 --- a/apps/browser/src/platform/services/abstractions/browser-state.service.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; - -import { Account } from "../../../models/account"; - -export abstract class BrowserStateService extends BaseStateServiceAbstraction {} diff --git a/apps/browser/src/platform/services/browser-state.service.spec.ts b/apps/browser/src/platform/services/browser-state.service.spec.ts deleted file mode 100644 index 506f185b649..00000000000 --- a/apps/browser/src/platform/services/browser-state.service.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { mock, MockProxy } from "jest-mock-extended"; - -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; -import { State } from "@bitwarden/common/platform/models/domain/state"; -import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; -import { mockAccountServiceWith } from "@bitwarden/common/spec"; -import { UserId } from "@bitwarden/common/types/guid"; - -import { Account } from "../../models/account"; - -import { DefaultBrowserStateService } from "./default-browser-state.service"; - -describe("Browser State Service", () => { - let secureStorageService: MockProxy; - let diskStorageService: MockProxy; - let logService: MockProxy; - let stateFactory: MockProxy>; - let environmentService: MockProxy; - let tokenService: MockProxy; - let migrationRunner: MockProxy; - - let state: State; - const userId = "userId" as UserId; - const accountService = mockAccountServiceWith(userId); - - let sut: DefaultBrowserStateService; - - beforeEach(() => { - secureStorageService = mock(); - diskStorageService = mock(); - logService = mock(); - stateFactory = mock(); - environmentService = mock(); - tokenService = mock(); - migrationRunner = mock(); - - state = new State(new GlobalState()); - state.accounts[userId] = new Account({ - profile: { userId: userId }, - }); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - describe("state methods", () => { - let memoryStorageService: MockProxy; - - beforeEach(() => { - memoryStorageService = mock(); - const stateGetter = (key: string) => Promise.resolve(state); - memoryStorageService.get.mockImplementation(stateGetter); - - sut = new DefaultBrowserStateService( - diskStorageService, - secureStorageService, - memoryStorageService, - logService, - stateFactory, - accountService, - environmentService, - tokenService, - migrationRunner, - ); - }); - - it("exists", () => { - expect(sut).toBeDefined(); - }); - }); -}); diff --git a/apps/browser/src/platform/services/default-browser-state.service.ts b/apps/browser/src/platform/services/default-browser-state.service.ts deleted file mode 100644 index 92da28efa25..00000000000 --- a/apps/browser/src/platform/services/default-browser-state.service.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; -import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options"; -import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; -import { StateService as BaseStateService } from "@bitwarden/common/platform/services/state.service"; - -import { Account } from "../../models/account"; - -import { BrowserStateService } from "./abstractions/browser-state.service"; - -export class DefaultBrowserStateService - extends BaseStateService - implements BrowserStateService -{ - protected accountDeserializer = Account.fromJSON; - - constructor( - storageService: AbstractStorageService, - secureStorageService: AbstractStorageService, - memoryStorageService: AbstractStorageService, - logService: LogService, - stateFactory: StateFactory, - accountService: AccountService, - environmentService: EnvironmentService, - tokenService: TokenService, - migrationRunner: MigrationRunner, - ) { - super( - storageService, - secureStorageService, - memoryStorageService, - logService, - stateFactory, - accountService, - environmentService, - tokenService, - migrationRunner, - ); - } - - async addAccount(account: Account) { - // Apply browser overrides to default account values - account = new Account(account); - await super.addAccount(account); - } - - // Overriding the base class to prevent deleting the cache on save. We register a storage listener - // to delete the cache in the constructor above. - protected override async saveAccountToDisk( - account: Account, - options: StorageOptions, - ): Promise { - const storageLocation = options.useSecureStorage - ? this.secureStorageService - : this.storageService; - - await storageLocation.save(`${options.userId}`, account, options); - } -} diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 4b28444f9ba..ff8dc7eeb6d 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -19,6 +19,7 @@ import { } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { twofactorRefactorSwap } from "../../../../libs/angular/src/utils/two-factor-component-refactor-route-swap"; import { fido2AuthGuard } from "../auth/guards/fido2-auth.guard"; import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component"; import { EnvironmentComponent } from "../auth/popup/environment.component"; @@ -33,6 +34,7 @@ import { RemovePasswordComponent } from "../auth/popup/remove-password.component import { SetPasswordComponent } from "../auth/popup/set-password.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; import { SsoComponent } from "../auth/popup/sso.component"; +import { TwoFactorAuthComponent } from "../auth/popup/two-factor-auth.component"; import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component"; import { TwoFactorComponent } from "../auth/popup/two-factor.component"; import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component"; @@ -137,12 +139,26 @@ const routes: Routes = [ canActivate: [lockGuard()], data: { state: "lock", doNotSaveUrl: true }, }, - { - path: "2fa", - component: TwoFactorComponent, - canActivate: [unauthGuardFn(unauthRouteOverrides)], - data: { state: "2fa" }, - }, + ...twofactorRefactorSwap( + TwoFactorComponent, + AnonLayoutWrapperComponent, + { + path: "2fa", + canActivate: [unauthGuardFn(unauthRouteOverrides)], + data: { state: "2fa" }, + }, + { + path: "2fa", + canActivate: [unauthGuardFn(unauthRouteOverrides)], + data: { state: "2fa" }, + children: [ + { + path: "", + component: TwoFactorAuthComponent, + }, + ], + }, + ), { path: "2fa-options", component: TwoFactorOptionsComponent, diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index b70a5564ed9..287e9096684 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -8,6 +8,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { MessageListener } from "@bitwarden/common/platform/messaging"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -19,7 +20,6 @@ import { } from "@bitwarden/components"; import { BrowserApi } from "../platform/browser/browser-api"; -import { BrowserStateService } from "../platform/services/abstractions/browser-state.service"; import { BrowserSendStateService } from "../tools/popup/services/browser-send-state.service"; import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service"; @@ -45,7 +45,7 @@ export class AppComponent implements OnInit, OnDestroy { private authService: AuthService, private i18nService: I18nService, private router: Router, - private stateService: BrowserStateService, + private stateService: StateService, private browserSendStateService: BrowserSendStateService, private vaultBrowserStateService: VaultBrowserStateService, private cipherService: CipherService, diff --git a/apps/browser/src/popup/services/init.service.ts b/apps/browser/src/popup/services/init.service.ts index 63ce45c9b76..9e6471eaf28 100644 --- a/apps/browser/src/popup/services/init.service.ts +++ b/apps/browser/src/popup/services/init.service.ts @@ -6,16 +6,16 @@ import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { BrowserApi } from "../../platform/browser/browser-api"; import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; -import { BrowserStateService as StateServiceAbstraction } from "../../platform/services/abstractions/browser-state.service"; @Injectable() export class InitService { constructor( private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, - private stateService: StateServiceAbstraction, + private stateService: StateService, private twoFactorService: TwoFactorService, private logService: LogServiceAbstraction, private themingService: AbstractThemingService, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 7c187d00514..e82eb429a5a 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -17,7 +17,7 @@ import { CLIENT_TYPE, } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; -import { AuthRequestServiceAbstraction, PinServiceAbstraction } from "@bitwarden/auth/common"; +import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; @@ -32,7 +32,6 @@ import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AutofillSettingsService, @@ -57,20 +56,17 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { AbstractStorageService, ObservableStorageService, } from "@bitwarden/common/platform/abstractions/storage.service"; import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging"; // eslint-disable-next-line no-restricted-imports -- Used for dependency injection import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; -import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; import { @@ -94,7 +90,6 @@ import { UnauthGuardService } from "../../auth/popup/services"; import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service"; import AutofillService from "../../autofill/services/autofill.service"; import MainBackground from "../../background/main.background"; -import { Account } from "../../models/account"; import { BrowserApi } from "../../platform/browser/browser-api"; import { runInsideAngular } from "../../platform/browser/run-inside-angular.operator"; /* eslint-disable no-restricted-imports */ @@ -104,13 +99,11 @@ import { OffscreenDocumentService } from "../../platform/offscreen-document/abst import { DefaultOffscreenDocumentService } from "../../platform/offscreen-document/offscreen-document.service"; import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; import { BrowserFileDownloadService } from "../../platform/popup/services/browser-file-download.service"; -import { BrowserStateService as StateServiceAbstraction } from "../../platform/services/abstractions/browser-state.service"; import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service"; import { BrowserCryptoService } from "../../platform/services/browser-crypto.service"; import { BrowserEnvironmentService } from "../../platform/services/browser-environment.service"; import BrowserLocalStorageService from "../../platform/services/browser-local-storage.service"; import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service"; -import { DefaultBrowserStateService } from "../../platform/services/default-browser-state.service"; import I18nService from "../../platform/services/i18n.service"; import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service"; import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; @@ -219,7 +212,7 @@ const safeProviders: SafeProvider[] = [ encryptService: EncryptService, platformUtilsService: PlatformUtilsService, logService: LogService, - stateService: StateServiceAbstraction, + stateService: StateService, accountService: AccountServiceAbstraction, stateProvider: StateProvider, biometricStateService: BiometricStateService, @@ -250,7 +243,7 @@ const safeProviders: SafeProvider[] = [ EncryptService, PlatformUtilsService, LogService, - StateServiceAbstraction, + StateService, AccountServiceAbstraction, StateProvider, BiometricStateService, @@ -262,11 +255,6 @@ const safeProviders: SafeProvider[] = [ useClass: TotpService, deps: [CryptoFunctionService, LogService], }), - safeProvider({ - provide: AuthRequestServiceAbstraction, - useFactory: getBgService("authRequestService"), - deps: [], - }), safeProvider({ provide: DeviceTrustServiceAbstraction, useFactory: getBgService("deviceTrustService"), @@ -436,46 +424,6 @@ const safeProviders: SafeProvider[] = [ }, deps: [StateProvider], }), - safeProvider({ - provide: StateServiceAbstraction, - useFactory: ( - storageService: AbstractStorageService, - secureStorageService: AbstractStorageService, - memoryStorageService: AbstractStorageService, - logService: LogService, - accountService: AccountServiceAbstraction, - environmentService: EnvironmentService, - tokenService: TokenService, - migrationRunner: MigrationRunner, - ) => { - return new DefaultBrowserStateService( - storageService, - secureStorageService, - memoryStorageService, - logService, - new StateFactory(GlobalState, Account), - accountService, - environmentService, - tokenService, - migrationRunner, - ); - }, - deps: [ - AbstractStorageService, - SECURE_STORAGE, - MEMORY_STORAGE, - LogService, - AccountServiceAbstraction, - EnvironmentService, - TokenService, - MigrationRunner, - ], - }), - safeProvider({ - provide: BaseStateServiceAbstraction, - useExisting: StateServiceAbstraction, - deps: [], - }), safeProvider({ provide: FileDownloadService, useClass: BrowserFileDownloadService, diff --git a/apps/browser/src/tools/popup/send/send-add-edit.component.ts b/apps/browser/src/tools/popup/send/send-add-edit.component.ts index 7f172178163..697188e23ac 100644 --- a/apps/browser/src/tools/popup/send/send-add-edit.component.ts +++ b/apps/browser/src/tools/popup/send/send-add-edit.component.ts @@ -13,12 +13,12 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; -import { BrowserStateService } from "../../../platform/services/abstractions/browser-state.service"; import { FilePopoutUtilsService } from "../services/file-popout-utils.service"; @Component({ @@ -37,7 +37,7 @@ export class SendAddEditComponent extends BaseAddEditComponent { constructor( i18nService: I18nService, platformUtilsService: PlatformUtilsService, - stateService: BrowserStateService, + stateService: StateService, messagingService: MessagingService, policyService: PolicyService, environmentService: EnvironmentService, diff --git a/apps/browser/src/vault/popup/components/vault-v2/attachments/cipher-attachments/cipher-attachments.component.html b/apps/browser/src/vault/popup/components/vault-v2/attachments/cipher-attachments/cipher-attachments.component.html index 46e8092d905..159cab31e86 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/attachments/cipher-attachments/cipher-attachments.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/attachments/cipher-attachments/cipher-attachments.component.html @@ -47,7 +47,13 @@ (change)="onFileChange($event)" />