diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 883dc61f49f..d480879fb15 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -72,7 +72,7 @@ jobs: echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT cli: - name: "${{ matrix.os.base }} - ${{ matrix.license_type.readable }}" + name: CLI ${{ matrix.os.base }} - ${{ matrix.license_type.readable }} strategy: matrix: os: @@ -177,7 +177,7 @@ jobs: if-no-files-found: error cli-windows: - name: "windows - ${{ matrix.license_type.readable }}" + name: Windows - ${{ matrix.license_type.readable }} strategy: matrix: license_type: diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 27995f1c787..dc15f841c2b 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -272,7 +272,7 @@ jobs: name: ${{ needs.setup.outputs.release_channel }}-linux.yml path: apps/desktop/dist/${{ needs.setup.outputs.release_channel }}-linux.yml if-no-files-found: error - + - name: Build flatpak working-directory: apps/desktop run: | diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index 5cc4eb90861..b5e84ff875b 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -266,7 +266,8 @@ jobs: channel_id: ${{ steps.slack-message.outputs.channel_id }} ts: ${{ steps.slack-message.outputs.ts }} steps: - - uses: bitwarden/gh-actions/report-deployment-status-to-slack@main + - name: Notify Slack with start message + uses: bitwarden/gh-actions/report-deployment-status-to-slack@main id: slack-message with: project: Clients @@ -419,7 +420,8 @@ jobs: - azure-deploy - artifact-check steps: - - uses: bitwarden/gh-actions/report-deployment-status-to-slack@main + - name: Notify Slack with result + uses: bitwarden/gh-actions/report-deployment-status-to-slack@main with: project: Clients environment: ${{ needs.setup.outputs.environment-name }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c324cb8748..72bc3594beb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,14 +98,14 @@ jobs: rust: name: Run Rust tests on ${{ matrix.os }} - runs-on: ${{ matrix.os || 'ubuntu-latest' }} + runs-on: ${{ matrix.os || 'ubuntu-22.04' }} permissions: contents: read strategy: matrix: os: - - ubuntu-latest + - ubuntu-22.04 - macos-latest - windows-latest diff --git a/apps/browser/package.json b/apps/browser/package.json index ed0a8d36342..53500a83d2b 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2024.11.1", + "version": "2024.11.2", "scripts": { "build": "npm run build:chrome", "build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 webpack", diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 26fe9186cfe..5200cf81d09 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1851,6 +1851,9 @@ "secureNotes": { "message": "Secure notes" }, + "sshKeys": { + "message": "SSH Keys" + }, "clear": { "message": "Clear", "description": "To clear something out. example: To clear browser history." @@ -3284,9 +3287,18 @@ "opensInANewWindow": { "message": "Opens in a new window" }, + "rememberThisDeviceToMakeFutureLoginsSeamless": { + "message": "Remember this device to make future logins seamless" + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, + "deviceApprovalRequiredV2": { + "message": "Device approval required" + }, + "selectAnApprovalOptionBelow": { + "message": "Select an approval option below" + }, "rememberThisDevice": { "message": "Remember this device" }, @@ -3360,6 +3372,9 @@ "userEmailMissing": { "message": "User email missing" }, + "activeUserEmailNotFoundLoggingYouOut": { + "message": "Active user email not found. Logging you out." + }, "deviceTrusted": { "message": "Device trusted" }, @@ -3796,6 +3811,9 @@ "accessing": { "message": "Accessing" }, + "loggedInExclamation": { + "message": "Logged in!" + }, "passkeyNotCopied": { "message": "Passkey will not be copied" }, diff --git a/apps/browser/src/auth/popup/lock.component.ts b/apps/browser/src/auth/popup/lock.component.ts index c7fb108de80..1d1ed619995 100644 --- a/apps/browser/src/auth/popup/lock.component.ts +++ b/apps/browser/src/auth/popup/lock.component.ts @@ -12,7 +12,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -25,7 +24,12 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService, BiometricsService, BiometricStateService } from "@bitwarden/key-management"; +import { + KdfConfigService, + KeyService, + BiometricsService, + BiometricStateService, +} from "@bitwarden/key-management"; import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors"; import { BrowserRouterService } from "../../platform/popup/services/browser-router.service"; diff --git a/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.spec.ts b/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.spec.ts new file mode 100644 index 00000000000..8f3199cdfce --- /dev/null +++ b/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.spec.ts @@ -0,0 +1,64 @@ +import { Router } from "@angular/router"; +import { MockProxy, mock } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; + +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; + +import { postLogoutMessageListener$ } from "../utils/post-logout-message-listener"; + +import { ExtensionLoginDecryptionOptionsService } from "./extension-login-decryption-options.service"; + +// Mock the module providing postLogoutMessageListener$ +jest.mock("../utils/post-logout-message-listener", () => { + return { + postLogoutMessageListener$: new BehaviorSubject(""), // Replace with mock subject + }; +}); + +describe("ExtensionLoginDecryptionOptionsService", () => { + let service: ExtensionLoginDecryptionOptionsService; + + let messagingService: MockProxy; + let router: MockProxy; + let postLogoutMessageSubject: BehaviorSubject; + + beforeEach(() => { + messagingService = mock(); + router = mock(); + + // Cast postLogoutMessageListener$ to BehaviorSubject for dynamic control + postLogoutMessageSubject = postLogoutMessageListener$ as BehaviorSubject; + + service = new ExtensionLoginDecryptionOptionsService(messagingService, router); + }); + + it("should instantiate the service", () => { + expect(service).not.toBeFalsy(); + }); + + describe("logOut()", () => { + it("should send a logout message", async () => { + postLogoutMessageSubject.next("switchAccountFinish"); + + await service.logOut(); + + expect(messagingService.send).toHaveBeenCalledWith("logout"); + }); + + it("should navigate to root on 'switchAccountFinish'", async () => { + postLogoutMessageSubject.next("switchAccountFinish"); + + await service.logOut(); + + expect(router.navigate).toHaveBeenCalledWith(["/"]); + }); + + it("should not navigate for 'doneLoggingOut'", async () => { + postLogoutMessageSubject.next("doneLoggingOut"); + + await service.logOut(); + + expect(router.navigate).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.ts b/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.ts new file mode 100644 index 00000000000..ea529e277e6 --- /dev/null +++ b/apps/browser/src/auth/popup/login-decryption-options/extension-login-decryption-options.service.ts @@ -0,0 +1,37 @@ +import { Router } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +import { + DefaultLoginDecryptionOptionsService, + LoginDecryptionOptionsService, +} from "@bitwarden/auth/angular"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; + +import { postLogoutMessageListener$ } from "../utils/post-logout-message-listener"; + +export class ExtensionLoginDecryptionOptionsService + extends DefaultLoginDecryptionOptionsService + implements LoginDecryptionOptionsService +{ + constructor( + protected messagingService: MessagingService, + private router: Router, + ) { + super(messagingService); + } + + override async logOut(): Promise { + // start listening for "switchAccountFinish" or "doneLoggingOut" + const messagePromise = firstValueFrom(postLogoutMessageListener$); + + super.logOut(); + + // wait for messages + const command = await messagePromise; + + // doneLoggingOut already has a message handler that will navigate us + if (command === "switchAccountFinish") { + await this.router.navigate(["/"]); + } + } +} diff --git a/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.html b/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options-v1.component.html similarity index 100% rename from apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.html rename to apps/browser/src/auth/popup/login-decryption-options/login-decryption-options-v1.component.html diff --git a/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts b/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options-v1.component.ts similarity index 80% rename from apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts rename to apps/browser/src/auth/popup/login-decryption-options/login-decryption-options-v1.component.ts index 6231b027749..bd8f808c910 100644 --- a/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts +++ b/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options-v1.component.ts @@ -1,15 +1,15 @@ import { Component } from "@angular/core"; import { firstValueFrom } from "rxjs"; -import { BaseLoginDecryptionOptionsComponent } from "@bitwarden/angular/auth/components/base-login-decryption-options.component"; +import { BaseLoginDecryptionOptionsComponentV1 } from "@bitwarden/angular/auth/components/base-login-decryption-options-v1.component"; import { postLogoutMessageListener$ } from "../utils/post-logout-message-listener"; @Component({ selector: "browser-login-decryption-options", - templateUrl: "login-decryption-options.component.html", + templateUrl: "login-decryption-options-v1.component.html", }) -export class LoginDecryptionOptionsComponent extends BaseLoginDecryptionOptionsComponent { +export class LoginDecryptionOptionsComponentV1 extends BaseLoginDecryptionOptionsComponentV1 { override async createUser(): Promise { try { await super.createUser(); diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index 1617ed84767..68b46ad8810 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -215,7 +215,6 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { this.form.controls.vaultTimeoutAction.valueChanges .pipe( - startWith(initialValues.vaultTimeoutAction), // emit to init pairwise map(async (value) => { await this.saveVaultTimeoutAction(value); }), diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index fdfd5740ba0..764304f4ff9 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -33,7 +33,6 @@ import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/aut import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; -import { KdfConfigService as kdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } 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"; @@ -48,7 +47,6 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; -import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; @@ -76,7 +74,7 @@ import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/bill import { ClientType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; -import { ProcessReloadService } from "@bitwarden/common/key-management/services/process-reload.service"; +import { DefaultProcessReloadService } from "@bitwarden/common/key-management/services/default-process-reload.service"; import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -201,6 +199,8 @@ import { ImportServiceAbstraction, } from "@bitwarden/importer/core"; import { + DefaultKdfConfigService, + KdfConfigService, BiometricStateService, BiometricsService, DefaultBiometricStateService, @@ -369,7 +369,7 @@ export default class MainBackground { intraprocessMessagingSubject: Subject>>; userAutoUnlockKeyService: UserAutoUnlockKeyService; scriptInjectorService: BrowserScriptInjectorService; - kdfConfigService: kdfConfigServiceAbstraction; + kdfConfigService: KdfConfigService; offscreenDocumentService: OffscreenDocumentService; syncServiceListener: SyncServiceListener; themeStateService: DefaultThemeStateService; @@ -630,7 +630,7 @@ export default class MainBackground { runtimeNativeMessagingBackground, ); - this.kdfConfigService = new KdfConfigService(this.stateProvider); + this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider); this.pinService = new PinService( this.accountService, @@ -1068,7 +1068,7 @@ export default class MainBackground { this.taskSchedulerService, ); - this.processReloadService = new ProcessReloadService( + this.processReloadService = new DefaultProcessReloadService( this.pinService, this.messagingService, systemUtilsServiceReloadCallback, diff --git a/apps/browser/src/key-management/browser-key.service.ts b/apps/browser/src/key-management/browser-key.service.ts index 1fa3e111fed..ad2524dbc4b 100644 --- a/apps/browser/src/key-management/browser-key.service.ts +++ b/apps/browser/src/key-management/browser-key.service.ts @@ -2,7 +2,6 @@ import { firstValueFrom } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -16,6 +15,7 @@ import { StateProvider } from "@bitwarden/common/platform/state"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; import { + KdfConfigService, DefaultKeyService, BiometricsService, BiometricStateService, diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 9c2d2d610bc..e81409e6e2f 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.11.1", + "version": "2024.11.2", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", @@ -171,6 +171,8 @@ "open_at_install": false, "browser_style": false }, - "storage": { "managed_schema": "managed_schema.json" }, + "storage": { + "managed_schema": "managed_schema.json" + }, "__firefox__storage": null } diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index fb44505ae8d..1ece5626227 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.11.1", + "version": "2024.11.2", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index 5b9417a6a19..e80ac249ac1 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -313,6 +313,10 @@ export default { back: "Back", loading: "Loading", search: "Search", + vault: "Vault", + generator: "Generator", + send: "Send", + settings: "Settings", }); }, }, diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html index e53e8905e69..78b859f33b1 100644 --- a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html @@ -28,7 +28,7 @@ aria-hidden="true" > - {{ button.label }} + {{ button.label | i18n }} diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts index ced3f6462e9..e01b4efd71b 100644 --- a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts @@ -2,13 +2,14 @@ import { CommonModule } from "@angular/common"; import { Component } from "@angular/core"; import { RouterModule } from "@angular/router"; +import { JslibModule } from "@bitwarden/angular/jslib.module"; import { LinkModule } from "@bitwarden/components"; @Component({ selector: "popup-tab-navigation", templateUrl: "popup-tab-navigation.component.html", standalone: true, - imports: [CommonModule, LinkModule, RouterModule], + imports: [CommonModule, LinkModule, RouterModule, JslibModule], host: { class: "tw-block tw-h-full tw-w-full tw-flex tw-flex-col", }, @@ -16,25 +17,25 @@ import { LinkModule } from "@bitwarden/components"; export class PopupTabNavigationComponent { navButtons = [ { - label: "Vault", + label: "vault", page: "/tabs/vault", iconKey: "lock", iconKeyActive: "lock-f", }, { - label: "Generator", + label: "generator", page: "/tabs/generator", iconKey: "generate", iconKeyActive: "generate-f", }, { - label: "Send", + label: "send", page: "/tabs/send", iconKey: "send", iconKeyActive: "send-f", }, { - label: "Settings", + label: "settings", page: "/tabs/settings", iconKey: "cog", iconKeyActive: "cog-f", diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index ba8ab1e7aaf..5e6f38e80b0 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -21,7 +21,6 @@ import { extensionRefreshSwap } from "@bitwarden/angular/utils/extension-refresh import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, - DevicesIcon, LoginComponent, LoginSecondaryContentComponent, LockIcon, @@ -37,6 +36,8 @@ import { SetPasswordJitComponent, UserLockIcon, VaultIcon, + LoginDecryptionOptionsComponent, + DevicesIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -51,7 +52,7 @@ import { import { HintComponent } from "../auth/popup/hint.component"; import { HomeComponent } from "../auth/popup/home.component"; import { LockComponent } from "../auth/popup/lock.component"; -import { LoginDecryptionOptionsComponent } from "../auth/popup/login-decryption-options/login-decryption-options.component"; +import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "../auth/popup/login-v1.component"; import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component"; import { RegisterComponent } from "../auth/popup/register.component"; @@ -206,12 +207,6 @@ const routes: Routes = [ canActivate: [unauthGuardFn(unauthRouteOverrides)], data: { state: "2fa-options" } satisfies RouteDataProperties, }, - { - path: "login-initiated", - component: LoginDecryptionOptionsComponent, - canActivate: [tdeDecryptionRequiredGuard()], - data: { state: "login-initiated" } satisfies RouteDataProperties, - }, { path: "sso", component: SsoComponent, @@ -534,6 +529,23 @@ const routes: Routes = [ ], }, ), + ...unauthUiRefreshSwap( + LoginDecryptionOptionsComponentV1, + ExtensionAnonLayoutWrapperComponent, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + data: { state: "login-initiated" } satisfies RouteDataProperties, + }, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + data: { + pageIcon: DevicesIcon, + }, + children: [{ path: "", component: LoginDecryptionOptionsComponent }], + }, + ), { path: "", component: ExtensionAnonLayoutWrapperComponent, diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index d6e46de6ba0..d637f695e81 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -24,7 +24,7 @@ import { ExtensionAnonLayoutWrapperComponent } from "../auth/popup/extension-ano import { HintComponent } from "../auth/popup/hint.component"; import { HomeComponent } from "../auth/popup/home.component"; import { LockComponent } from "../auth/popup/lock.component"; -import { LoginDecryptionOptionsComponent } from "../auth/popup/login-decryption-options/login-decryption-options.component"; +import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "../auth/popup/login-v1.component"; import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component"; import { RegisterComponent } from "../auth/popup/register.component"; @@ -161,7 +161,7 @@ import "../platform/popup/locales"; LockComponent, LoginViaAuthRequestComponentV1, LoginComponentV1, - LoginDecryptionOptionsComponent, + LoginDecryptionOptionsComponentV1, NotificationsSettingsV1Component, AppearanceComponent, GeneratorComponent, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index c4b79fcae58..b68102033bb 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -1,4 +1,5 @@ import { APP_INITIALIZER, NgModule, NgZone } from "@angular/core"; +import { Router } from "@angular/router"; import { Subject, merge, of } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; @@ -22,6 +23,7 @@ import { AnonLayoutWrapperDataService, LoginComponentService, LockComponentService, + LoginDecryptionOptionsService, } from "@bitwarden/auth/angular"; import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -34,7 +36,6 @@ import { AccountService as AccountServiceAbstraction, } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -105,12 +106,18 @@ import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/a import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { CompactModeService, DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { BiometricStateService, BiometricsService, KeyService } from "@bitwarden/key-management"; +import { + KdfConfigService, + KeyService, + BiometricStateService, + BiometricsService, +} from "@bitwarden/key-management"; import { PasswordRepromptService } from "@bitwarden/vault"; import { ForegroundLockService } from "../../auth/popup/accounts/foreground-lock.service"; import { ExtensionAnonLayoutWrapperDataService } from "../../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service"; import { ExtensionLoginComponentService } from "../../auth/popup/login/extension-login-component.service"; +import { ExtensionLoginDecryptionOptionsService } from "../../auth/popup/login-decryption-options/extension-login-decryption-options.service"; import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service"; import AutofillService from "../../autofill/services/autofill.service"; import { InlineMenuFieldQualificationService } from "../../autofill/services/inline-menu-field-qualification.service"; @@ -587,6 +594,11 @@ const safeProviders: SafeProvider[] = [ useExisting: PopupCompactModeService, deps: [], }), + safeProvider({ + provide: LoginDecryptionOptionsService, + useClass: ExtensionLoginDecryptionOptionsService, + deps: [MessagingServiceAbstraction, Router], + }), ]; @NgModule({ diff --git a/apps/cli/package.json b/apps/cli/package.json index e48507373f5..8be8f9ca34a 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2024.11.0", + "version": "2024.11.1", "keywords": [ "bitwarden", "password", diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 57477ee2bc8..db7ddb2e51c 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -17,7 +17,6 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -37,7 +36,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { NodeUtils } from "@bitwarden/node/node-utils"; import { Response } from "../../models/response"; diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index ae627e82e75..21e8f9f2082 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -33,14 +33,12 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; -import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; -import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; @@ -149,6 +147,8 @@ import { ImportServiceAbstraction, } from "@bitwarden/importer/core"; import { + DefaultKdfConfigService, + KdfConfigService, DefaultKeyService as KeyService, BiometricStateService, DefaultBiometricStateService, @@ -260,7 +260,7 @@ export class ServiceContainer { billingAccountProfileStateService: BillingAccountProfileStateService; providerApiService: ProviderApiServiceAbstraction; userAutoUnlockKeyService: UserAutoUnlockKeyService; - kdfConfigService: KdfConfigServiceAbstraction; + kdfConfigService: KdfConfigService; taskSchedulerService: TaskSchedulerService; sdkService: SdkService; cipherAuthorizationService: CipherAuthorizationService; @@ -407,7 +407,7 @@ export class ServiceContainer { this.logService, ); - this.kdfConfigService = new KdfConfigService(this.stateProvider); + this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider); this.pinService = new PinService( this.accountService, diff --git a/apps/cli/src/tools/import.command.ts b/apps/cli/src/tools/import.command.ts index 1cb3ac19f6b..879b2313baf 100644 --- a/apps/cli/src/tools/import.command.ts +++ b/apps/cli/src/tools/import.command.ts @@ -27,7 +27,7 @@ export class ImportCommand { ); } - if (!organization.canAccessImportExport) { + if (!organization.canAccessImport) { return Response.badRequest( "You are not authorized to import into the provided organization.", ); diff --git a/apps/desktop/package.json b/apps/desktop/package.json index be285f2cc18..cfdd76ec21e 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2024.11.1", + "version": "2024.11.2", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index c1e4fd18692..e61335859c4 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -18,7 +18,6 @@ import { extensionRefreshRedirect } from "@bitwarden/angular/utils/extension-ref import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, - DevicesIcon, LoginComponent, LoginSecondaryContentComponent, LockIcon, @@ -34,6 +33,8 @@ import { SetPasswordJitComponent, UserLockIcon, VaultIcon, + LoginDecryptionOptionsComponent, + DevicesIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -42,7 +43,7 @@ import { AccessibilityCookieComponent } from "../auth/accessibility-cookie.compo import { maxAccountsGuardFn } from "../auth/guards/max-accounts.guard"; import { HintComponent } from "../auth/hint.component"; import { LockComponent } from "../auth/lock.component"; -import { LoginDecryptionOptionsComponent } from "../auth/login/login-decryption-options/login-decryption-options.component"; +import { LoginDecryptionOptionsComponentV1 } from "../auth/login/login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "../auth/login/login-v1.component"; import { LoginViaAuthRequestComponentV1 } from "../auth/login/login-via-auth-request-v1.component"; import { RegisterComponent } from "../auth/register.component"; @@ -95,11 +96,6 @@ const routes: Routes = [ ], }, ), - { - path: "login-initiated", - component: LoginDecryptionOptionsComponent, - canActivate: [tdeDecryptionRequiredGuard()], - }, { path: "register", component: RegisterComponent }, { path: "vault", @@ -241,6 +237,22 @@ const routes: Routes = [ ], }, ), + ...unauthUiRefreshSwap( + LoginDecryptionOptionsComponentV1, + AnonLayoutWrapperComponent, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + }, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + data: { + pageIcon: DevicesIcon, + }, + children: [{ path: "", component: LoginDecryptionOptionsComponent }], + }, + ), { path: "", component: AnonLayoutWrapperComponent, diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index a2195fbd5a8..2a11c78a579 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -41,16 +41,12 @@ import { AuthService, AuthService as AuthServiceAbstraction, } from "@bitwarden/common/auth/abstractions/auth.service"; -import { - KdfConfigService, - KdfConfigService as KdfConfigServiceAbstraction, -} from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { ClientType } from "@bitwarden/common/enums"; import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; -import { ProcessReloadService } from "@bitwarden/common/key-management/services/process-reload.service"; +import { DefaultProcessReloadService } from "@bitwarden/common/key-management/services/default-process-reload.service"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -84,6 +80,7 @@ import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vau import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; import { + KdfConfigService, KeyService, KeyService as KeyServiceAbstraction, BiometricStateService, @@ -221,7 +218,7 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: ProcessReloadServiceAbstraction, - useClass: ProcessReloadService, + useClass: DefaultProcessReloadService, deps: [ PinServiceAbstraction, MessagingServiceAbstraction, @@ -289,7 +286,7 @@ const safeProviders: SafeProvider[] = [ AccountServiceAbstraction, StateProvider, BiometricStateService, - KdfConfigServiceAbstraction, + KdfConfigService, ], }), safeProvider({ diff --git a/apps/desktop/src/auth/lock.component.spec.ts b/apps/desktop/src/auth/lock.component.spec.ts index b67a386845f..6890754fca9 100644 --- a/apps/desktop/src/auth/lock.component.spec.ts +++ b/apps/desktop/src/auth/lock.component.spec.ts @@ -15,7 +15,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; @@ -33,6 +32,7 @@ import { UserId } from "@bitwarden/common/types/guid"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; import { + KdfConfigService, KeyService, BiometricsService as AbstractBiometricService, BiometricStateService, diff --git a/apps/desktop/src/auth/lock.component.ts b/apps/desktop/src/auth/lock.component.ts index cc062965f35..f0323f3e7da 100644 --- a/apps/desktop/src/auth/lock.component.ts +++ b/apps/desktop/src/auth/lock.component.ts @@ -12,7 +12,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { DeviceType } from "@bitwarden/common/enums"; @@ -26,7 +25,12 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService, BiometricsService, BiometricStateService } from "@bitwarden/key-management"; +import { + KdfConfigService, + KeyService, + BiometricsService, + BiometricStateService, +} from "@bitwarden/key-management"; const BroadcasterSubscriptionId = "LockComponent"; diff --git a/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options.component.html b/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options-v1.component.html similarity index 100% rename from apps/desktop/src/auth/login/login-decryption-options/login-decryption-options.component.html rename to apps/desktop/src/auth/login/login-decryption-options/login-decryption-options-v1.component.html diff --git a/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options.component.ts b/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options-v1.component.ts similarity index 56% rename from apps/desktop/src/auth/login/login-decryption-options/login-decryption-options.component.ts rename to apps/desktop/src/auth/login/login-decryption-options/login-decryption-options-v1.component.ts index f64ec977ce7..d9cc07adb7e 100644 --- a/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options.component.ts +++ b/apps/desktop/src/auth/login/login-decryption-options/login-decryption-options-v1.component.ts @@ -1,12 +1,12 @@ import { Component } from "@angular/core"; -import { BaseLoginDecryptionOptionsComponent } from "@bitwarden/angular/auth/components/base-login-decryption-options.component"; +import { BaseLoginDecryptionOptionsComponentV1 } from "@bitwarden/angular/auth/components/base-login-decryption-options-v1.component"; @Component({ selector: "desktop-login-decryption-options", - templateUrl: "login-decryption-options.component.html", + templateUrl: "login-decryption-options-v1.component.html", }) -export class LoginDecryptionOptionsComponent extends BaseLoginDecryptionOptionsComponent { +export class LoginDecryptionOptionsComponentV1 extends BaseLoginDecryptionOptionsComponentV1 { override async createUser(): Promise { try { await super.createUser(); diff --git a/apps/desktop/src/auth/login/login.module.ts b/apps/desktop/src/auth/login/login.module.ts index 20c0bc97c6c..427cbcb2069 100644 --- a/apps/desktop/src/auth/login/login.module.ts +++ b/apps/desktop/src/auth/login/login.module.ts @@ -5,7 +5,7 @@ import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components import { SharedModule } from "../../app/shared/shared.module"; -import { LoginDecryptionOptionsComponent } from "./login-decryption-options/login-decryption-options.component"; +import { LoginDecryptionOptionsComponentV1 } from "./login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "./login-v1.component"; import { LoginViaAuthRequestComponentV1 } from "./login-via-auth-request-v1.component"; @@ -15,7 +15,7 @@ import { LoginViaAuthRequestComponentV1 } from "./login-via-auth-request-v1.comp LoginComponentV1, LoginViaAuthRequestComponentV1, EnvironmentSelectorComponent, - LoginDecryptionOptionsComponent, + LoginDecryptionOptionsComponentV1, ], exports: [LoginComponentV1, LoginViaAuthRequestComponentV1], }) diff --git a/apps/desktop/src/auth/set-password.component.ts b/apps/desktop/src/auth/set-password.component.ts index 61ab198b613..902fa59791c 100644 --- a/apps/desktop/src/auth/set-password.component.ts +++ b/apps/desktop/src/auth/set-password.component.ts @@ -9,7 +9,6 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -23,7 +22,7 @@ import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; const BroadcasterSubscriptionId = "SetPasswordComponent"; diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index e9f26d23e94..ab6fb586948 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2832,6 +2832,9 @@ "checkForBreaches": { "message": "Check known data breaches for this password" }, + "loggedInExclamation": { + "message": "Logged in!" + }, "important": { "message": "Important:" }, @@ -2862,9 +2865,18 @@ "windowsBiometricUpdateWarningTitle": { "message": "Recommended Settings Update" }, + "rememberThisDeviceToMakeFutureLoginsSeamless": { + "message": "Remember this device to make future logins seamless" + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, + "deviceApprovalRequiredV2": { + "message": "Device approval required" + }, + "selectAnApprovalOptionBelow": { + "message": "Select an approval option below" + }, "rememberThisDevice": { "message": "Remember this device" }, @@ -2917,6 +2929,9 @@ "userEmailMissing": { "message": "User email missing" }, + "activeUserEmailNotFoundLoggingYouOut": { + "message": "Active user email not found. Logging you out." + }, "deviceTrusted": { "message": "Device trusted" }, diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index f47f0f6a281..85a47fa6b2f 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.11.1", + "version": "2024.11.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.11.1", + "version": "2024.11.2", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi", diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index ca700eff2c6..c23baf37acf 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2024.11.1", + "version": "2024.11.2", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/apps/desktop/src/platform/services/electron-key.service.spec.ts b/apps/desktop/src/platform/services/electron-key.service.spec.ts index 8705f1fba6e..e85bfe4ee03 100644 --- a/apps/desktop/src/platform/services/electron-key.service.spec.ts +++ b/apps/desktop/src/platform/services/electron-key.service.spec.ts @@ -2,7 +2,6 @@ import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider import { mock } from "jest-mock-extended"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -15,7 +14,7 @@ import { makeEncString } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; -import { BiometricStateService } from "@bitwarden/key-management"; +import { KdfConfigService, BiometricStateService } from "@bitwarden/key-management"; import { FakeAccountService, diff --git a/apps/desktop/src/platform/services/electron-key.service.ts b/apps/desktop/src/platform/services/electron-key.service.ts index f7cfb3cf92f..c8beef76c0a 100644 --- a/apps/desktop/src/platform/services/electron-key.service.ts +++ b/apps/desktop/src/platform/services/electron-key.service.ts @@ -2,7 +2,6 @@ import { firstValueFrom } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -17,7 +16,11 @@ import { StateProvider } from "@bitwarden/common/platform/state"; import { CsprngString } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; -import { DefaultKeyService, BiometricStateService } from "@bitwarden/key-management"; +import { + KdfConfigService, + DefaultKeyService, + BiometricStateService, +} from "@bitwarden/key-management"; export class ElectronKeyService extends DefaultKeyService { constructor( diff --git a/apps/web/package.json b/apps/web/package.json index 5dd0e442f2d..02ee6babe92 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2024.11.0", + "version": "2024.11.1", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index aaba492dff8..1e811b6c29d 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -84,12 +84,12 @@ canAccessOrgAdmin(org); organization$: Observable; + canAccessExport$: Observable; showPaymentAndHistory$: Observable; hideNewOrgButton$: Observable; organizationIsUnmanaged$: Observable; isAccessIntelligenceFeatureEnabled = false; - private _destroy = new Subject(); - constructor( private route: ActivatedRoute, private organizationService: OrganizationService, @@ -71,23 +70,23 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { FeatureFlag.AccessIntelligence, ); - this.organization$ = this.route.params - .pipe(takeUntil(this._destroy)) - .pipe(map((p) => p.organizationId)) - .pipe( - mergeMap((id) => { - return this.organizationService.organizations$ - .pipe(takeUntil(this._destroy)) - .pipe(getOrganizationById(id)); - }), - ); + this.organization$ = this.route.params.pipe( + map((p) => p.organizationId), + switchMap((id) => this.organizationService.organizations$.pipe(getById(id))), + filter((org) => org != null), + ); + + this.canAccessExport$ = combineLatest([ + this.organization$, + this.configService.getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission), + ]).pipe(map(([org, removeProviderExport]) => org.canAccessExport(removeProviderExport))); this.showPaymentAndHistory$ = this.organization$.pipe( map( (org) => !this.platformUtilsService.isSelfHost() && - org?.canViewBillingHistory && - org?.canEditPaymentMethods, + org.canViewBillingHistory && + org.canEditPaymentMethods, ), ); @@ -107,11 +106,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { ); } - ngOnDestroy() { - this._destroy.next(); - this._destroy.complete(); - } - canShowVaultTab(organization: Organization): boolean { return canAccessVaultTab(organization); } diff --git a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.spec.ts b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.spec.ts index feb95df40c3..1178b4d65e9 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.spec.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.spec.ts @@ -10,13 +10,13 @@ import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { EncryptionType, KdfType } from "@bitwarden/common/platform/enums"; +import { EncryptionType } from "@bitwarden/common/platform/enums"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey, OrgKey, MasterKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfType, KeyService } from "@bitwarden/key-management"; import { OrganizationUserResetPasswordService } from "./organization-user-reset-password.service"; diff --git a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts index 88cb75b087e..002a6613079 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts @@ -7,20 +7,21 @@ import { } from "@bitwarden/admin-console/common"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { - Argon2KdfConfig, - KdfConfig, - PBKDF2KdfConfig, -} from "@bitwarden/common/auth/models/domain/kdf-config"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; -import { UserKeyRotationDataProvider, KeyService } from "@bitwarden/key-management"; +import { + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, + UserKeyRotationDataProvider, + KeyService, + KdfType, +} from "@bitwarden/key-management"; @Injectable({ providedIn: "root", diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html index d1a1a091929..b3fac56c0bb 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.html +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html @@ -52,11 +52,7 @@

{{ "collectionManagement" | i18n }}

{{ "collectionManagementDesc" | i18n }}

@@ -64,24 +60,15 @@ {{ "allowAdminAccessToAllCollectionItemsDesc" | i18n }} - - - {{ "limitCollectionCreationDesc" | i18n }} - - - - {{ "limitCollectionDeletionDesc" | i18n }} - - - - - - {{ "limitCollectionCreationDeletionDesc" | i18n }} - - - + + {{ "limitCollectionCreationDesc" | i18n }} + + + + {{ "limitCollectionDeletionDesc" | i18n }} + +
- + diff --git a/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts index 2f9e34f877b..6f98ddad35d 100644 --- a/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts +++ b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts @@ -16,25 +16,17 @@ export class VerifyBankAccountComponent { @Output() submitted = new EventEmitter(); protected formGroup = this.formBuilder.group({ - amount1: new FormControl(null, [ + descriptorCode: new FormControl(null, [ Validators.required, - Validators.min(0), - Validators.max(99), - ]), - amount2: new FormControl(null, [ - Validators.required, - Validators.min(0), - Validators.max(99), + Validators.minLength(6), + Validators.maxLength(6), ]), }); constructor(private formBuilder: FormBuilder) {} submit = async () => { - const request = new VerifyBankAccountRequest( - this.formGroup.value.amount1, - this.formGroup.value.amount2, - ); + const request = new VerifyBankAccountRequest(this.formGroup.value.descriptorCode); await this.onSubmit?.(request); this.submitted.emit(); }; diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index d1fa3f8ba8c..79a7862178f 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -30,6 +30,7 @@ import { LoginComponentService, LockComponentService, SetPasswordJitService, + LoginDecryptionOptionsService, } from "@bitwarden/auth/angular"; import { InternalUserDecryptionOptionsServiceAbstraction, @@ -45,10 +46,10 @@ import { import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/account-api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { ClientType } from "@bitwarden/common/enums"; +import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; @@ -60,6 +61,7 @@ import { import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService as I18nServiceAbstraction } 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 { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; @@ -82,7 +84,11 @@ import { } from "@bitwarden/common/platform/theming/theme-state.service"; import { VaultTimeout, VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService as KeyServiceAbstraction, BiometricsService } from "@bitwarden/key-management"; +import { + KdfConfigService, + KeyService as KeyServiceAbstraction, + BiometricsService, +} from "@bitwarden/key-management"; import { flagEnabled } from "../../utils/flags"; import { PolicyListService } from "../admin-console/core/policy-list.service"; @@ -91,10 +97,12 @@ import { WebRegistrationFinishService, WebLoginComponentService, WebLockComponentService, + WebLoginDecryptionOptionsService, } from "../auth"; import { AcceptOrganizationInviteService } from "../auth/organization-invite/accept-organization.service"; import { HtmlStorageService } from "../core/html-storage.service"; import { I18nService } from "../core/i18n.service"; +import { WebProcessReloadService } from "../key-management/services/web-process-reload.service"; import { WebBiometricsService } from "../key-management/web-biometric.service"; import { WebEnvironmentService } from "../platform/web-environment.service"; import { WebMigrationRunner } from "../platform/web-migration-runner"; @@ -281,11 +289,21 @@ const safeProviders: SafeProvider[] = [ useClass: flagEnabled("sdk") ? WebSdkClientFactory : NoopSdkClientFactory, deps: [], }), + safeProvider({ + provide: ProcessReloadServiceAbstraction, + useClass: WebProcessReloadService, + deps: [WINDOW], + }), safeProvider({ provide: LoginEmailService, useClass: LoginEmailService, deps: [AccountService, AuthService, StateProvider], }), + safeProvider({ + provide: LoginDecryptionOptionsService, + useClass: WebLoginDecryptionOptionsService, + deps: [MessagingService, RouterService, AcceptOrganizationInviteService], + }), ]; @NgModule({ diff --git a/apps/web/src/app/key-management/services/web-process-reload.service.ts b/apps/web/src/app/key-management/services/web-process-reload.service.ts new file mode 100644 index 00000000000..c542c97c0e0 --- /dev/null +++ b/apps/web/src/app/key-management/services/web-process-reload.service.ts @@ -0,0 +1,14 @@ +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; + +export class WebProcessReloadService implements ProcessReloadServiceAbstraction { + constructor(private window: Window) {} + + async startProcessReload(authService: AuthService): Promise { + this.window.location.reload(); + } + + cancelProcessReload(): void { + return; + } +} diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts index cd1a77a9ec4..a7ff50b4264 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts @@ -152,7 +152,13 @@ export const SMAvailable: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: false, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: false, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [], }, @@ -162,7 +168,13 @@ export const SMAndACAvailable: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: true, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [], }, @@ -172,7 +184,13 @@ export const WithAllOptions: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: true, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [{ id: "provider-a" }] as Provider[], }, diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts index b9d1d394920..b53d0243f64 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts @@ -171,7 +171,13 @@ export const WithSM: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: false, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: false, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [], }, @@ -181,7 +187,13 @@ export const WithSMAndAC: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: true, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [], }, @@ -191,7 +203,13 @@ export const WithAllOptions: Story = { ...Template, args: { mockOrgs: [ - { id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true }, + { + id: "org-a", + canManageUsers: true, + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => false, + }, ] as Organization[], mockProviders: [{ id: "provider-a" }] as Provider[], }, diff --git a/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts b/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts index 07a41e7c94c..7c53cd86d3b 100644 --- a/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts +++ b/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts @@ -110,7 +110,12 @@ describe("ProductSwitcherService", () => { it("is included in bento when there is an organization with SM", async () => { organizationService.organizations$ = of([ - { id: "1234", canAccessSecretsManager: true, enabled: true }, + { + id: "1234", + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => true, + }, ] as Organization[]); initiateService(); @@ -220,8 +225,20 @@ describe("ProductSwitcherService", () => { router.url = "/sm/4243"; organizationService.organizations$ = of([ - { id: "23443234", canAccessSecretsManager: true, enabled: true, name: "Org 2" }, - { id: "4243", canAccessSecretsManager: true, enabled: true, name: "Org 32" }, + { + id: "23443234", + canAccessSecretsManager: true, + enabled: true, + name: "Org 2", + canAccessExport: (_) => true, + }, + { + id: "4243", + canAccessSecretsManager: true, + enabled: true, + name: "Org 32", + canAccessExport: (_) => true, + }, ] as Organization[]); initiateService(); diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 614401e8708..6e2e97d8e06 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -33,6 +33,7 @@ import { RegistrationLockAltIcon, RegistrationExpiredLinkIcon, VaultIcon, + LoginDecryptionOptionsComponent, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -46,7 +47,7 @@ import { CreateOrganizationComponent } from "./admin-console/settings/create-org import { deepLinkGuard } from "./auth/guards/deep-link.guard"; import { HintComponent } from "./auth/hint.component"; import { LockComponent } from "./auth/lock.component"; -import { LoginDecryptionOptionsComponent } from "./auth/login/login-decryption-options/login-decryption-options.component"; +import { LoginDecryptionOptionsComponentV1 } from "./auth/login/login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "./auth/login/login-v1.component"; import { LoginViaAuthRequestComponentV1 } from "./auth/login/login-via-auth-request-v1.component"; import { LoginViaWebAuthnComponent } from "./auth/login/login-via-webauthn/login-via-webauthn.component"; @@ -103,16 +104,11 @@ const routes: Routes = [ component: LoginViaWebAuthnComponent, data: { titleId: "logInWithPasskey" } satisfies RouteDataProperties, }, - { - path: "login-initiated", - component: LoginDecryptionOptionsComponent, - canActivate: [tdeDecryptionRequiredGuard()], - }, { path: "register", component: TrialInitiationComponent, canActivate: [ - canAccessFeature(FeatureFlag.EmailVerification, false, "/signup"), + canAccessFeature(FeatureFlag.EmailVerification, false, "/signup", false), unauthGuardFn(), ], data: { titleId: "createAccount" } satisfies RouteDataProperties, @@ -272,6 +268,22 @@ const routes: Routes = [ ], }, ), + ...unauthUiRefreshSwap( + LoginDecryptionOptionsComponentV1, + AnonLayoutWrapperComponent, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + }, + { + path: "login-initiated", + canActivate: [tdeDecryptionRequiredGuard()], + data: { + pageIcon: DevicesIcon, + }, + children: [{ path: "", component: LoginDecryptionOptionsComponent }], + }, + ), ...unauthUiRefreshSwap( AnonLayoutWrapperComponent, AnonLayoutWrapperComponent, diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts index c09451addda..9a5537985b8 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts @@ -1,16 +1,15 @@ import { TestBed } from "@angular/core/testing"; import { BehaviorSubject, firstValueFrom } from "rxjs"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { StateProvider } from "@bitwarden/common/platform/state"; import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; +import { KdfConfigService, KdfType } from "@bitwarden/key-management"; import { PREMIUM_BANNER_REPROMPT_KEY, diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts index 172d81c48af..6ab37ea0cdd 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts @@ -2,13 +2,10 @@ import { Injectable } from "@angular/core"; import { Subject, Observable, combineLatest, firstValueFrom, map } from "rxjs"; import { mergeMap, take } from "rxjs/operators"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { StateProvider, ActiveUserState, @@ -17,6 +14,7 @@ import { UserKeyDefinition, } from "@bitwarden/common/platform/state"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; +import { PBKDF2KdfConfig, KdfConfigService, KdfType } from "@bitwarden/key-management"; export enum VisibleVaultBanner { KDFSettings = "kdf-settings", diff --git a/apps/web/src/app/vault/individual-vault/view.component.ts b/apps/web/src/app/vault/individual-vault/view.component.ts index d30c453a4bd..779035c972b 100644 --- a/apps/web/src/app/vault/individual-vault/view.component.ts +++ b/apps/web/src/app/vault/individual-vault/view.component.ts @@ -184,6 +184,8 @@ export class ViewComponent implements OnInit { return this.i18nService.t("viewItemType", this.i18nService.t("typeCard").toLowerCase()); case CipherType.Identity: return this.i18nService.t("viewItemType", this.i18nService.t("typeIdentity").toLowerCase()); + case CipherType.SshKey: + return this.i18nService.t("viewItemType", this.i18nService.t("typeSshKey").toLowerCase()); default: return null; } diff --git a/apps/web/src/index.html b/apps/web/src/index.html index ce1a955b88c..0b8ea864914 100644 --- a/apps/web/src/index.html +++ b/apps/web/src/index.html @@ -15,6 +15,7 @@ +
Bitwarden
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index f316ba44e1c..81e84424783 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -8051,9 +8051,18 @@ "loginInitiated": { "message": "Login initiated" }, + "rememberThisDeviceToMakeFutureLoginsSeamless": { + "message": "Remember this device to make future logins seamless" + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, + "deviceApprovalRequiredV2": { + "message": "Device approval required" + }, + "selectAnApprovalOptionBelow": { + "message": "Select an approval option below" + }, "rememberThisDevice": { "message": "Remember this device" }, @@ -8283,6 +8292,9 @@ "userEmailMissing": { "message": "User email missing" }, + "activeUserEmailNotFoundLoggingYouOut": { + "message": "Active user email not found. Logging you out." + }, "deviceTrusted": { "message": "Device trusted" }, @@ -8378,9 +8390,6 @@ "collectionManagementDesc": { "message": "Manage the collection behavior for the organization" }, - "limitCollectionCreationDeletionDesc": { - "message": "Limit collection creation and deletion to owners and admins" - }, "limitCollectionCreationDesc": { "message": "Limit collection creation to owners and admins" }, @@ -9763,5 +9772,14 @@ }, "freeFamiliesSponsorshipPolicyDesc": { "message": "Do not allow members to redeem a Families plan through this organization." + }, + "verifyBankAccountWithStatementDescriptorWarning": { + "message": "Payment with a bank account is only available to customers in the United States. You will be required to verify your bank account. We will make a micro-deposit within the next 1-2 business days. Enter the statement descriptor code from this deposit on the organization's billing page to verify the bank account. Failure to verify the bank account will result in a missed payment and your subscription being suspended." + }, + "verifyBankAccountWithStatementDescriptorInstructions": { + "message": "We have made a micro-deposit to your bank account (this may take 1-2 business days). Enter the six-digit code starting with 'SM' found on the deposit description. Failure to verify the bank account will result in a missed payment and your subscription being suspended." + }, + "descriptorCode": { + "message": "Descriptor code" } } diff --git a/libs/admin-console/src/common/organization-user/models/responses/organization-user.response.ts b/libs/admin-console/src/common/organization-user/models/responses/organization-user.response.ts index f61d9325c2a..1e426696d92 100644 --- a/libs/admin-console/src/common/organization-user/models/responses/organization-user.response.ts +++ b/libs/admin-console/src/common/organization-user/models/responses/organization-user.response.ts @@ -5,7 +5,7 @@ import { import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api"; import { SelectionReadOnlyResponse } from "@bitwarden/common/admin-console/models/response/selection-read-only.response"; import { BaseResponse } from "@bitwarden/common/models/response/base.response"; -import { KdfType } from "@bitwarden/common/platform/enums"; +import { KdfType } from "@bitwarden/key-management"; export class OrganizationUserResponse extends BaseResponse { id: string; diff --git a/libs/angular/src/auth/components/base-login-decryption-options.component.ts b/libs/angular/src/auth/components/base-login-decryption-options-v1.component.ts similarity index 99% rename from libs/angular/src/auth/components/base-login-decryption-options.component.ts rename to libs/angular/src/auth/components/base-login-decryption-options-v1.component.ts index f674a32af8b..df99503b6d7 100644 --- a/libs/angular/src/auth/components/base-login-decryption-options.component.ts +++ b/libs/angular/src/auth/components/base-login-decryption-options-v1.component.ts @@ -63,7 +63,7 @@ type ExistingUserUntrustedDeviceData = { type Data = NewUserData | ExistingUserUntrustedDeviceData; @Directive() -export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy { +export class BaseLoginDecryptionOptionsComponentV1 implements OnInit, OnDestroy { private destroy$ = new Subject(); protected State = State; diff --git a/libs/angular/src/auth/components/change-password.component.ts b/libs/angular/src/auth/components/change-password.component.ts index 92b34c08f4a..dc181c54066 100644 --- a/libs/angular/src/auth/components/change-password.component.ts +++ b/libs/angular/src/auth/components/change-password.component.ts @@ -4,9 +4,7 @@ import { Subject, firstValueFrom, map, takeUntil } from "rxjs"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -16,7 +14,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserKey, MasterKey } from "@bitwarden/common/types/key"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfig, KdfConfigService, KeyService } from "@bitwarden/key-management"; import { PasswordColorText } from "../../tools/password-strength/password-strength.component"; diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts index f28156803c1..f0d1163c24d 100644 --- a/libs/angular/src/auth/components/lock.component.ts +++ b/libs/angular/src/auth/components/lock.component.ts @@ -13,7 +13,6 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -35,7 +34,12 @@ import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService, BiometricStateService, BiometricsService } from "@bitwarden/key-management"; +import { + KdfConfigService, + KeyService, + BiometricStateService, + BiometricsService, +} from "@bitwarden/key-management"; @Directive() export class LockComponent implements OnInit, OnDestroy { diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts index 94f60ff637e..ec78a1692ad 100644 --- a/libs/angular/src/auth/components/register.component.ts +++ b/libs/angular/src/auth/components/register.component.ts @@ -5,7 +5,6 @@ import { Router } from "@angular/router"; import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { RegisterResponse } from "@bitwarden/common/auth/models/response/register.response"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request"; @@ -18,7 +17,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management"; import { AllValidationErrors, diff --git a/libs/angular/src/auth/components/set-password.component.ts b/libs/angular/src/auth/components/set-password.component.ts index 81981de79d2..b323f7ef1a4 100644 --- a/libs/angular/src/auth/components/set-password.component.ts +++ b/libs/angular/src/auth/components/set-password.component.ts @@ -15,11 +15,9 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { OrganizationAutoEnrollStatusResponse } from "@bitwarden/common/admin-console/models/response/organization-auto-enroll-status.response"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -35,7 +33,7 @@ import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component"; diff --git a/libs/angular/src/auth/components/update-password.component.ts b/libs/angular/src/auth/components/update-password.component.ts index bc31be283e0..3c442b7913e 100644 --- a/libs/angular/src/auth/components/update-password.component.ts +++ b/libs/angular/src/auth/components/update-password.component.ts @@ -5,7 +5,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -20,7 +19,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component"; diff --git a/libs/angular/src/auth/components/update-temp-password.component.ts b/libs/angular/src/auth/components/update-temp-password.component.ts index 2019d6f73c9..e00e21fe811 100644 --- a/libs/angular/src/auth/components/update-temp-password.component.ts +++ b/libs/angular/src/auth/components/update-temp-password.component.ts @@ -6,7 +6,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -25,7 +24,7 @@ import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component"; diff --git a/libs/angular/src/auth/guards/lock.guard.ts b/libs/angular/src/auth/guards/lock.guard.ts index 8665c09b1ee..244e9935281 100644 --- a/libs/angular/src/auth/guards/lock.guard.ts +++ b/libs/angular/src/auth/guards/lock.guard.ts @@ -42,6 +42,12 @@ export function lockGuard(): CanActivateFn { const activeUser = await firstValueFrom(accountService.activeAccount$); + // If no active user, redirect to root: + // scenario context: user logs out on lock screen and app will reload lock comp without active user + if (!activeUser) { + return router.createUrlTree(["/"]); + } + const authStatus = await firstValueFrom(authService.authStatusFor$(activeUser.id)); if (authStatus !== AuthenticationStatus.Locked) { return router.createUrlTree(["/"]); diff --git a/libs/angular/src/platform/guard/feature-flag.guard.ts b/libs/angular/src/platform/guard/feature-flag.guard.ts index 1f82d810e36..65a29e4d8d8 100644 --- a/libs/angular/src/platform/guard/feature-flag.guard.ts +++ b/libs/angular/src/platform/guard/feature-flag.guard.ts @@ -16,11 +16,13 @@ type FlagValue = boolean | number | string; * @param featureFlag - The feature flag to check * @param requiredFlagValue - Optional value to the feature flag must be equal to, defaults to true * @param redirectUrlOnDisabled - Optional url to redirect to if the feature flag is disabled + * @param showToast - Optional boolean to show a toast if the feature flag is disabled - defaults to true */ export const canAccessFeature = ( featureFlag: FeatureFlag, requiredFlagValue: FlagValue = true, redirectUrlOnDisabled?: string, + showToast = true, ): CanActivateFn => { return async () => { const configService = inject(ConfigService); @@ -36,11 +38,13 @@ export const canAccessFeature = ( return true; } - toastService.showToast({ - variant: "error", - title: null, - message: i18nService.t("accessDenied"), - }); + if (showToast) { + toastService.showToast({ + variant: "error", + title: null, + message: i18nService.t("accessDenied"), + }); + } if (redirectUrlOnDisabled != null) { return router.createUrlTree([redirectUrlOnDisabled]); diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index a8474884278..f63202af506 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -16,6 +16,8 @@ import { DefaultAnonLayoutWrapperDataService, LoginComponentService, DefaultLoginComponentService, + LoginDecryptionOptionsService, + DefaultLoginDecryptionOptionsService, } from "@bitwarden/auth/angular"; import { AuthRequestServiceAbstraction, @@ -80,7 +82,6 @@ import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/aut import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; -import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction, @@ -103,7 +104,6 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; -import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation"; @@ -279,6 +279,8 @@ import { DefaultKeyService as KeyService, BiometricStateService, DefaultBiometricStateService, + KdfConfigService, + DefaultKdfConfigService, } from "@bitwarden/key-management"; import { PasswordRepromptService } from "@bitwarden/vault"; import { @@ -438,7 +440,7 @@ const safeProviders: SafeProvider[] = [ GlobalStateProvider, BillingAccountProfileStateService, VaultTimeoutSettingsServiceAbstraction, - KdfConfigServiceAbstraction, + KdfConfigService, TaskSchedulerService, ], }), @@ -607,7 +609,7 @@ const safeProviders: SafeProvider[] = [ StateServiceAbstraction, AccountServiceAbstraction, StateProvider, - KdfConfigServiceAbstraction, + KdfConfigService, ], }), safeProvider({ @@ -826,7 +828,7 @@ const safeProviders: SafeProvider[] = [ KeyServiceAbstraction, EncryptService, CryptoFunctionServiceAbstraction, - KdfConfigServiceAbstraction, + KdfConfigService, AccountServiceAbstraction, ], }), @@ -841,7 +843,7 @@ const safeProviders: SafeProvider[] = [ EncryptService, CryptoFunctionServiceAbstraction, CollectionService, - KdfConfigServiceAbstraction, + KdfConfigService, AccountServiceAbstraction, ], }), @@ -968,7 +970,7 @@ const safeProviders: SafeProvider[] = [ LogService, VaultTimeoutSettingsServiceAbstraction, PlatformUtilsServiceAbstraction, - KdfConfigServiceAbstraction, + KdfConfigService, ], }), safeProvider({ @@ -1134,7 +1136,7 @@ const safeProviders: SafeProvider[] = [ AccountServiceAbstraction, CryptoFunctionServiceAbstraction, EncryptService, - KdfConfigServiceAbstraction, + KdfConfigService, KeyGenerationServiceAbstraction, LogService, MasterPasswordServiceAbstraction, @@ -1313,8 +1315,8 @@ const safeProviders: SafeProvider[] = [ deps: [ApiServiceAbstraction], }), safeProvider({ - provide: KdfConfigServiceAbstraction, - useClass: KdfConfigService, + provide: KdfConfigService, + useClass: DefaultKdfConfigService, deps: [StateProvider], }), safeProvider({ @@ -1325,7 +1327,7 @@ const safeProviders: SafeProvider[] = [ KeyServiceAbstraction, EncryptService, I18nServiceAbstraction, - KdfConfigServiceAbstraction, + KdfConfigService, InternalMasterPasswordServiceAbstraction, OrganizationApiServiceAbstraction, OrganizationUserApiService, @@ -1376,7 +1378,7 @@ const safeProviders: SafeProvider[] = [ EnvironmentService, PlatformUtilsServiceAbstraction, AccountServiceAbstraction, - KdfConfigServiceAbstraction, + KdfConfigService, KeyServiceAbstraction, ApiServiceAbstraction, ], @@ -1391,6 +1393,11 @@ const safeProviders: SafeProvider[] = [ useClass: DefaultAuthRequestApiService, deps: [ApiServiceAbstraction, LogService], }), + safeProvider({ + provide: LoginDecryptionOptionsService, + useClass: DefaultLoginDecryptionOptionsService, + deps: [MessagingServiceAbstraction], + }), ]; @NgModule({ diff --git a/libs/auth/src/angular/index.ts b/libs/auth/src/angular/index.ts index 5c028065c62..16ae77e937f 100644 --- a/libs/auth/src/angular/index.ts +++ b/libs/auth/src/angular/index.ts @@ -24,6 +24,11 @@ export * from "./login/login-secondary-content.component"; export * from "./login/login-component.service"; export * from "./login/default-login-component.service"; +// login decryption options +export * from "./login-decryption-options/login-decryption-options.component"; +export * from "./login-decryption-options/login-decryption-options.service"; +export * from "./login-decryption-options/default-login-decryption-options.service"; + // login via auth request export * from "./login-via-auth-request/login-via-auth-request.component"; diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts index e110d2d53e3..8d5d4a56dcc 100644 --- a/libs/auth/src/angular/input-password/input-password.component.ts +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -9,7 +9,6 @@ import { import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { HashPurpose } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -23,7 +22,7 @@ import { InputModule, ToastService, } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; +import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management"; import { InputsFieldMatch } from "../../../../angular/src/auth/validators/inputs-field-match.validator"; import { SharedModule } from "../../../../components/src/shared"; diff --git a/libs/auth/src/angular/input-password/password-input-result.ts b/libs/auth/src/angular/input-password/password-input-result.ts index 66bb338dc16..07157aaf4ca 100644 --- a/libs/auth/src/angular/input-password/password-input-result.ts +++ b/libs/auth/src/angular/input-password/password-input-result.ts @@ -1,5 +1,5 @@ -import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { MasterKey } from "@bitwarden/common/types/key"; +import { PBKDF2KdfConfig } from "@bitwarden/key-management"; export interface PasswordInputResult { masterKey: MasterKey; diff --git a/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.spec.ts b/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.spec.ts new file mode 100644 index 00000000000..735b7667540 --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.spec.ts @@ -0,0 +1,37 @@ +import { MockProxy, mock } from "jest-mock-extended"; + +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; + +import { DefaultLoginDecryptionOptionsService } from "./default-login-decryption-options.service"; + +describe("DefaultLoginDecryptionOptionsService", () => { + let service: DefaultLoginDecryptionOptionsService; + + let messagingService: MockProxy; + + beforeEach(() => { + messagingService = mock(); + + service = new DefaultLoginDecryptionOptionsService(messagingService); + }); + + it("should instantiate the service", () => { + expect(service).not.toBeFalsy(); + }); + + describe("handleCreateUserSuccess()", () => { + it("should return null", async () => { + const result = await service.handleCreateUserSuccess(); + + expect(result).toBeNull(); + }); + }); + + describe("logOut()", () => { + it("should send a logout message", async () => { + await service.logOut(); + + expect(messagingService.send).toHaveBeenCalledWith("logout"); + }); + }); +}); diff --git a/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.ts b/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.ts new file mode 100644 index 00000000000..17ea0bc9653 --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/default-login-decryption-options.service.ts @@ -0,0 +1,15 @@ +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; + +import { LoginDecryptionOptionsService } from "./login-decryption-options.service"; + +export class DefaultLoginDecryptionOptionsService implements LoginDecryptionOptionsService { + constructor(protected messagingService: MessagingService) {} + + handleCreateUserSuccess(): Promise { + return null; + } + + async logOut(): Promise { + this.messagingService.send("logout"); + } +} diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.html b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.html new file mode 100644 index 00000000000..cb340f646f1 --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.html @@ -0,0 +1,60 @@ + +
+ + {{ "loading" | i18n }} +
+
+ +
+ + + {{ "rememberThisDevice" | i18n }} + {{ "uncheckIfPublicDevice" | i18n }} + +
+ + + + + + +
+ + + +
+ {{ "or" | i18n }} +
+
+ + + + +
+
diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts new file mode 100644 index 00000000000..38771f9dada --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts @@ -0,0 +1,299 @@ +import { CommonModule } from "@angular/common"; +import { Component, DestroyRef, OnInit } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { FormBuilder, FormControl, ReactiveFormsModule } from "@angular/forms"; +import { Router } from "@angular/router"; +import { catchError, defer, firstValueFrom, from, map, of, switchMap, throwError } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { + LoginEmailServiceAbstraction, + UserDecryptionOptions, + UserDecryptionOptionsServiceAbstraction, +} from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction"; +import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { ClientType } from "@bitwarden/common/enums"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { + AsyncActionsModule, + ButtonModule, + CheckboxModule, + FormFieldModule, + ToastService, + TypographyModule, +} from "@bitwarden/components"; +import { KeyService } from "@bitwarden/key-management"; + +import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service"; + +import { LoginDecryptionOptionsService } from "./login-decryption-options.service"; + +enum State { + NewUser, + ExistingUserUntrustedDevice, +} + +@Component({ + standalone: true, + templateUrl: "./login-decryption-options.component.html", + imports: [ + AsyncActionsModule, + ButtonModule, + CheckboxModule, + CommonModule, + FormFieldModule, + JslibModule, + ReactiveFormsModule, + TypographyModule, + ], +}) +export class LoginDecryptionOptionsComponent implements OnInit { + private activeAccountId: UserId; + private clientType: ClientType; + private email: string; + + protected loading = false; + protected state: State; + protected State = State; + + protected formGroup = this.formBuilder.group({ + rememberDevice: [true], // Remember device means for the user to trust the device + }); + + private get rememberDeviceControl(): FormControl { + return this.formGroup.controls.rememberDevice; + } + + // New User Properties + private newUserOrgId: string; + + // Existing User Untrusted Device Properties + protected canApproveFromOtherDevice = false; + protected canRequestAdminApproval = false; + protected canApproveWithMasterPassword = false; + + constructor( + private accountService: AccountService, + private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private apiService: ApiService, + private destroyRef: DestroyRef, + private deviceTrustService: DeviceTrustServiceAbstraction, + private formBuilder: FormBuilder, + private i18nService: I18nService, + private keyService: KeyService, + private loginDecryptionOptionsService: LoginDecryptionOptionsService, + private loginEmailService: LoginEmailServiceAbstraction, + private messagingService: MessagingService, + private organizationApiService: OrganizationApiServiceAbstraction, + private passwordResetEnrollmentService: PasswordResetEnrollmentServiceAbstraction, + private platformUtilsService: PlatformUtilsService, + private router: Router, + private ssoLoginService: SsoLoginServiceAbstraction, + private toastService: ToastService, + private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, + private validationService: ValidationService, + ) { + this.clientType === this.platformUtilsService.getClientType(); + } + + async ngOnInit() { + this.loading = true; + + this.activeAccountId = (await firstValueFrom(this.accountService.activeAccount$))?.id; + + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); + + if (!this.email) { + await this.handleMissingEmail(); + return; + } + + this.observeAndPersistRememberDeviceValueChanges(); + await this.setRememberDeviceDefaultValueFromState(); + + try { + const userDecryptionOptions = await firstValueFrom( + this.userDecryptionOptionsService.userDecryptionOptions$, + ); + + if ( + !userDecryptionOptions?.trustedDeviceOption?.hasAdminApproval && + !userDecryptionOptions?.hasMasterPassword + ) { + /** + * We are dealing with a new account if both are true: + * - User does NOT have admin approval (i.e. has not enrolled in admin reset) + * - User does NOT have a master password + */ + await this.loadNewUserData(); + } else { + this.loadExistingUserUntrustedDeviceData(userDecryptionOptions); + } + } catch (err) { + this.validationService.showError(err); + } finally { + this.loading = false; + } + } + + private async handleMissingEmail() { + this.toastService.showToast({ + variant: "error", + title: null, + message: this.i18nService.t("activeUserEmailNotFoundLoggingYouOut"), + }); + + setTimeout(async () => { + // We can't simply redirect to `/login` because the user is authed and the unauthGuard + // will prevent navigation. We must logout the user first via messagingService, which + // redirects to `/`, which will be handled by the redirectGuard to navigate the user to `/login`. + // The timeout just gives the user a chance to see the error toast before process reload runs on logout. + await this.loginDecryptionOptionsService.logOut(); + }, 5000); + } + + private observeAndPersistRememberDeviceValueChanges() { + this.rememberDeviceControl.valueChanges + .pipe( + takeUntilDestroyed(this.destroyRef), + switchMap((value) => + defer(() => this.deviceTrustService.setShouldTrustDevice(this.activeAccountId, value)), + ), + ) + .subscribe(); + } + + private async setRememberDeviceDefaultValueFromState() { + const rememberDeviceFromState = await this.deviceTrustService.getShouldTrustDevice( + this.activeAccountId, + ); + + const rememberDevice = rememberDeviceFromState ?? true; + + this.rememberDeviceControl.setValue(rememberDevice); + } + + private async loadNewUserData() { + this.state = State.NewUser; + + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { + key: "loggedInExclamation", + }, + pageSubtitle: { + key: "rememberThisDeviceToMakeFutureLoginsSeamless", + }, + }); + + const autoEnrollStatus$ = defer(() => + this.ssoLoginService.getActiveUserOrganizationSsoIdentifier(), + ).pipe( + switchMap((organizationIdentifier) => { + if (organizationIdentifier == undefined) { + return throwError(() => new Error(this.i18nService.t("ssoIdentifierRequired"))); + } + + return from(this.organizationApiService.getAutoEnrollStatus(organizationIdentifier)); + }), + catchError((err: unknown) => { + this.validationService.showError(err); + return of(undefined); + }), + ); + + const autoEnrollStatus = await firstValueFrom(autoEnrollStatus$); + + this.newUserOrgId = autoEnrollStatus.id; + } + + private loadExistingUserUntrustedDeviceData(userDecryptionOptions: UserDecryptionOptions) { + this.state = State.ExistingUserUntrustedDevice; + + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { + key: "deviceApprovalRequiredV2", + }, + pageSubtitle: { + key: "selectAnApprovalOptionBelow", + }, + }); + + this.canApproveFromOtherDevice = + userDecryptionOptions?.trustedDeviceOption?.hasLoginApprovingDevice || false; + this.canRequestAdminApproval = + userDecryptionOptions?.trustedDeviceOption?.hasAdminApproval || false; + this.canApproveWithMasterPassword = userDecryptionOptions?.hasMasterPassword || false; + } + + protected createUser = async () => { + if (this.state !== State.NewUser) { + return; + } + + try { + const { publicKey, privateKey } = await this.keyService.initAccount(); + const keysRequest = new KeysRequest(publicKey, privateKey.encryptedString); + await this.apiService.postAccountKeys(keysRequest); + + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("accountSuccessfullyCreated"), + }); + + await this.passwordResetEnrollmentService.enroll(this.newUserOrgId); + + if (this.formGroup.value.rememberDevice) { + await this.deviceTrustService.trustDevice(this.activeAccountId); + } + + await this.loginDecryptionOptionsService.handleCreateUserSuccess(); + + if (this.clientType === ClientType.Desktop) { + this.messagingService.send("redrawMenu"); + } + + await this.handleCreateUserSuccessNavigation(); + } catch (err) { + this.validationService.showError(err); + } + }; + + private async handleCreateUserSuccessNavigation() { + if (this.clientType === ClientType.Browser) { + await this.router.navigate(["/tabs/vault"]); + } else { + await this.router.navigate(["/vault"]); + } + } + + protected async approveFromOtherDevice() { + this.loginEmailService.setLoginEmail(this.email); + await this.router.navigate(["/login-with-device"]); + } + + protected async approveWithMasterPassword() { + await this.router.navigate(["/lock"], { + queryParams: { + from: "login-initiated", + }, + }); + } + + protected async requestAdminApproval() { + this.loginEmailService.setLoginEmail(this.email); + await this.router.navigate(["/admin-approval-requested"]); + } +} diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.service.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.service.ts new file mode 100644 index 00000000000..d81d56d6393 --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.service.ts @@ -0,0 +1,10 @@ +export abstract class LoginDecryptionOptionsService { + /** + * Handles client-specific logic that runs after a user was successfully created + */ + abstract handleCreateUserSuccess(): Promise; + /** + * Logs the user out + */ + abstract logOut(): Promise; +} diff --git a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts index e034e23de43..14600cebf1d 100644 --- a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts +++ b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts @@ -1,12 +1,11 @@ import { MockProxy, mock } from "jest-mock-extended"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management"; import { PasswordInputResult } from "../../input-password/password-input-result"; diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts index da49067d7b6..7a2b334eb42 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts @@ -9,9 +9,7 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -22,7 +20,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; import { PasswordInputResult } from "../input-password/password-input-result"; diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts index 76477a0e5df..a2163025771 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts @@ -7,10 +7,8 @@ import { import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -19,7 +17,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { PBKDF2KdfConfig, KdfConfigService, KeyService } from "@bitwarden/key-management"; import { SetPasswordCredentials, diff --git a/libs/auth/src/angular/set-password-jit/set-password-jit.service.abstraction.ts b/libs/auth/src/angular/set-password-jit/set-password-jit.service.abstraction.ts index 165b4a61805..fc0756458c9 100644 --- a/libs/auth/src/angular/set-password-jit/set-password-jit.service.abstraction.ts +++ b/libs/auth/src/angular/set-password-jit/set-password-jit.service.abstraction.ts @@ -1,6 +1,6 @@ -import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey } from "@bitwarden/common/types/key"; +import { PBKDF2KdfConfig } from "@bitwarden/key-management"; export interface SetPasswordCredentials { masterKey: MasterKey; diff --git a/libs/auth/src/common/abstractions/pin.service.abstraction.ts b/libs/auth/src/common/abstractions/pin.service.abstraction.ts index 00ccf934f61..eb1cfaf0ec3 100644 --- a/libs/auth/src/common/abstractions/pin.service.abstraction.ts +++ b/libs/auth/src/common/abstractions/pin.service.abstraction.ts @@ -1,7 +1,7 @@ -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { EncString, EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserId } from "@bitwarden/common/types/guid"; import { PinKey, UserKey } from "@bitwarden/common/types/key"; +import { KdfConfig } from "@bitwarden/key-management"; import { PinLockType } from "../services"; diff --git a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts index c0e7d2c00ae..cec4481cd8d 100644 --- a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts @@ -3,7 +3,6 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; @@ -23,7 +22,7 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { AuthRequestLoginCredentials } from "../models/domain/login-credentials"; diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index 49140cc2cc0..50443bab0ea 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -4,7 +4,6 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -38,7 +37,7 @@ import { import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey, MasterKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { LoginStrategyServiceAbstraction } from "../abstractions"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index 67a286d8195..e440e1d35b6 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -3,14 +3,12 @@ import { BehaviorSubject, filter, firstValueFrom, timeout } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { Argon2KdfConfig, PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { DeviceRequest } from "@bitwarden/common/auth/models/request/identity-token/device.request"; import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request"; @@ -30,10 +28,15 @@ 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 { KdfType } from "@bitwarden/common/platform/enums"; import { Account, AccountProfile } from "@bitwarden/common/platform/models/domain/account"; import { UserId } from "@bitwarden/common/types/guid"; -import { KeyService } from "@bitwarden/key-management"; +import { + KeyService, + Argon2KdfConfig, + PBKDF2KdfConfig, + KdfConfigService, + KdfType, +} from "@bitwarden/key-management"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts index 4da6272ccab..4ee4fcaeb38 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts @@ -3,7 +3,6 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -32,7 +31,7 @@ import { import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { LoginStrategyServiceAbstraction } from "../abstractions"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index 7b5ad4a31b6..ec3ec43134f 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -3,7 +3,6 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; @@ -29,7 +28,7 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { AuthRequestServiceAbstraction, diff --git a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts index 07d06a7567d..2bb41faa0e1 100644 --- a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts @@ -2,7 +2,6 @@ import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; @@ -26,7 +25,7 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey, MasterKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { UserApiLoginCredentials } from "../models/domain/login-credentials"; diff --git a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts index 88392b57c53..9dacce2cf00 100644 --- a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts @@ -2,7 +2,6 @@ import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; @@ -24,7 +23,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-ti import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { PrfKey, UserKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { WebAuthnLoginCredentials } from "../models/domain/login-credentials"; diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts index b0d9228f446..5fcbefbef2f 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts @@ -5,13 +5,11 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; -import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; @@ -27,7 +25,6 @@ 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 { KdfType } from "@bitwarden/common/platform/enums"; import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling"; import { FakeAccountService, @@ -37,7 +34,7 @@ import { } from "@bitwarden/common/spec"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { UserId } from "@bitwarden/common/types/guid"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KdfType, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; import { AuthRequestServiceAbstraction, diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts index 721ee984974..b86d1e3f3b4 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -12,18 +12,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; -import { - Argon2KdfConfig, - KdfConfig, - PBKDF2KdfConfig, -} from "@bitwarden/common/auth/models/domain/kdf-config"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { PreloginRequest } from "@bitwarden/common/models/request/prelogin.request"; @@ -36,13 +30,19 @@ 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 { KdfType } from "@bitwarden/common/platform/enums/kdf-type.enum"; import { TaskSchedulerService, ScheduledTaskNames } from "@bitwarden/common/platform/scheduling"; import { GlobalState, GlobalStateProvider } from "@bitwarden/common/platform/state"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/src/auth/abstractions/device-trust.service.abstraction"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { MasterKey } from "@bitwarden/common/types/key"; -import { KeyService } from "@bitwarden/key-management"; +import { + KdfType, + KeyService, + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, + KdfConfigService, +} from "@bitwarden/key-management"; import { AuthRequestServiceAbstraction, LoginStrategyServiceAbstraction } from "../../abstractions"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction"; diff --git a/libs/auth/src/common/services/pin/pin.service.implementation.ts b/libs/auth/src/common/services/pin/pin.service.implementation.ts index 2a01802fa57..0f3d16fb625 100644 --- a/libs/auth/src/common/services/pin/pin.service.implementation.ts +++ b/libs/auth/src/common/services/pin/pin.service.implementation.ts @@ -1,9 +1,7 @@ import { firstValueFrom, map } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service"; @@ -19,6 +17,7 @@ import { } from "@bitwarden/common/platform/state"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, PinKey, UserKey } from "@bitwarden/common/types/key"; +import { KdfConfig, KdfConfigService } from "@bitwarden/key-management"; import { PinServiceAbstraction } from "../../abstractions/pin.service.abstraction"; diff --git a/libs/auth/src/common/services/pin/pin.service.spec.ts b/libs/auth/src/common/services/pin/pin.service.spec.ts index 6befec06994..d254be4e875 100644 --- a/libs/auth/src/common/services/pin/pin.service.spec.ts +++ b/libs/auth/src/common/services/pin/pin.service.spec.ts @@ -1,7 +1,5 @@ import { mock } from "jest-mock-extended"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; -import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -18,6 +16,7 @@ import { } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, PinKey, UserKey } from "@bitwarden/common/types/key"; +import { DEFAULT_KDF_CONFIG, KdfConfigService } from "@bitwarden/key-management"; import { PinService, diff --git a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts index a2ea6aa8861..e687c0a34a7 100644 --- a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts +++ b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts @@ -1,7 +1,5 @@ import { map, Observable } from "rxjs"; -import { I18nService } from "../../../platform/abstractions/i18n.service"; -import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { OrganizationData } from "../../models/data/organization.data"; import { Organization } from "../../models/domain/organization"; @@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManagePolicies || org.canManageSso || org.canManageScim || - org.canAccessImportExport || + org.canAccessImport || + org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway org.canManageDeviceApprovals ); } @@ -56,32 +55,6 @@ export function getOrganizationById(id: string) { return map((orgs) => orgs.find((o) => o.id === id)); } -export function canAccessAdmin(i18nService: I18nService) { - return map((orgs) => - orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -/** - * @deprecated - * To be removed after Flexible Collections. - **/ -export function canAccessImportExport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -export function canAccessImport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport || org.canCreateNewCollections) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - /** * Returns `true` if a user is a member of an organization (rather than only being a ProviderUser) * @deprecated Use organizationService.organizations$ with a filter instead diff --git a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts index 45c00e3fd4a..68c61e298ae 100644 --- a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts +++ b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts @@ -1,7 +1,5 @@ import { map, Observable } from "rxjs"; -import { I18nService } from "../../../platform/abstractions/i18n.service"; -import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { OrganizationData } from "../../models/data/organization.data"; import { Organization } from "../../models/domain/organization"; @@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManagePolicies || org.canManageSso || org.canManageScim || - org.canAccessImportExport || + org.canAccessImport || + org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway org.canManageDeviceApprovals ); } @@ -56,20 +55,6 @@ export function getOrganizationById(id: string) { return map((orgs) => orgs.find((o) => o.id === id)); } -export function canAccessAdmin(i18nService: I18nService) { - return map((orgs) => - orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -export function canAccessImport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport || org.canCreateNewCollections) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - /** * Publishes an observable stream of organizations. This service is meant to * be used widely across Bitwarden as the primary way of fetching organizations. diff --git a/libs/common/src/admin-console/models/data/organization.data.spec.ts b/libs/common/src/admin-console/models/data/organization.data.spec.ts index 0b3d512817b..12c5339a245 100644 --- a/libs/common/src/admin-console/models/data/organization.data.spec.ts +++ b/libs/common/src/admin-console/models/data/organization.data.spec.ts @@ -53,8 +53,6 @@ describe("ORGANIZATIONS state", () => { accessSecretsManager: false, limitCollectionCreation: false, limitCollectionDeletion: false, - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCollectionCreationDeletion: false, allowAdminAccessToAllCollectionItems: false, familySponsorshipLastSyncDate: new Date(), userIsManagedByOrganization: false, diff --git a/libs/common/src/admin-console/models/data/organization.data.ts b/libs/common/src/admin-console/models/data/organization.data.ts index 0c0dedad256..d8032fd6fcf 100644 --- a/libs/common/src/admin-console/models/data/organization.data.ts +++ b/libs/common/src/admin-console/models/data/organization.data.ts @@ -54,8 +54,6 @@ export class OrganizationData { accessSecretsManager: boolean; limitCollectionCreation: boolean; limitCollectionDeletion: boolean; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCollectionCreationDeletion: boolean; allowAdminAccessToAllCollectionItems: boolean; userIsManagedByOrganization: boolean; @@ -116,8 +114,6 @@ export class OrganizationData { this.accessSecretsManager = response.accessSecretsManager; this.limitCollectionCreation = response.limitCollectionCreation; this.limitCollectionDeletion = response.limitCollectionDeletion; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - this.limitCollectionCreationDeletion = response.limitCollectionCreationDeletion; this.allowAdminAccessToAllCollectionItems = response.allowAdminAccessToAllCollectionItems; this.userIsManagedByOrganization = response.userIsManagedByOrganization; diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts index 070617b9e5f..e0be19986cf 100644 --- a/libs/common/src/admin-console/models/domain/organization.ts +++ b/libs/common/src/admin-console/models/domain/organization.ts @@ -70,8 +70,6 @@ export class Organization { */ limitCollectionCreation: boolean; limitCollectionDeletion: boolean; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCollectionCreationDeletion: boolean; /** * Refers to the ability for an owner/admin to access all collection items, regardless of assigned collections @@ -137,8 +135,6 @@ export class Organization { this.accessSecretsManager = obj.accessSecretsManager; this.limitCollectionCreation = obj.limitCollectionCreation; this.limitCollectionDeletion = obj.limitCollectionDeletion; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - this.limitCollectionCreationDeletion = obj.limitCollectionCreationDeletion; this.allowAdminAccessToAllCollectionItems = obj.allowAdminAccessToAllCollectionItems; this.userIsManagedByOrganization = obj.userIsManagedByOrganization; } @@ -168,8 +164,27 @@ export class Organization { return (this.isAdmin || this.permissions.accessEventLogs) && this.useEvents; } - get canAccessImportExport() { - return this.isAdmin || this.permissions.accessImportExport; + get canAccessImport() { + return ( + this.isProviderUser || + this.type === OrganizationUserType.Owner || + this.type === OrganizationUserType.Admin || + this.permissions.accessImportExport || + this.canCreateNewCollections // To allow users to create collections and then import into them + ); + } + + canAccessExport(removeProviderExport: boolean) { + if (!removeProviderExport && this.isProviderUser) { + return true; + } + + return ( + this.isMember && + (this.type === OrganizationUserType.Owner || + this.type === OrganizationUserType.Admin || + this.permissions.accessImportExport) + ); } get canAccessReports() { @@ -222,7 +237,7 @@ export class Organization { return true; } - // If AllowAdminAccessToAllCollectionItems is true, Owners and Admins can delete any collection, regardless of LimitCollectionCreationDeletion setting + // If AllowAdminAccessToAllCollectionItems is true, Owners and Admins can delete any collection, regardless of LimitCollectionDeletion setting // Using explicit type checks because provider users are handled above and this mimics the server's permission checks closely if (this.allowAdminAccessToAllCollectionItems) { return this.type == OrganizationUserType.Owner || this.type == OrganizationUserType.Admin; diff --git a/libs/common/src/admin-console/models/request/organization-collection-management-update.request.ts b/libs/common/src/admin-console/models/request/organization-collection-management-update.request.ts index baf9a2ca458..8995e482bcc 100644 --- a/libs/common/src/admin-console/models/request/organization-collection-management-update.request.ts +++ b/libs/common/src/admin-console/models/request/organization-collection-management-update.request.ts @@ -1,7 +1,5 @@ export class OrganizationCollectionManagementUpdateRequest { limitCollectionCreation: boolean; limitCollectionDeletion: boolean; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCreateDeleteOwnerAdmin: boolean; allowAdminAccessToAllCollectionItems: boolean; } diff --git a/libs/common/src/admin-console/models/response/organization.response.ts b/libs/common/src/admin-console/models/response/organization.response.ts index aaa28e48a5c..e033646797d 100644 --- a/libs/common/src/admin-console/models/response/organization.response.ts +++ b/libs/common/src/admin-console/models/response/organization.response.ts @@ -34,8 +34,6 @@ export class OrganizationResponse extends BaseResponse { maxAutoscaleSmServiceAccounts?: number; limitCollectionCreation: boolean; limitCollectionDeletion: boolean; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCollectionCreationDeletion: boolean; allowAdminAccessToAllCollectionItems: boolean; constructor(response: any) { @@ -74,10 +72,6 @@ export class OrganizationResponse extends BaseResponse { this.maxAutoscaleSmServiceAccounts = this.getResponseProperty("MaxAutoscaleSmServiceAccounts"); this.limitCollectionCreation = this.getResponseProperty("LimitCollectionCreation"); this.limitCollectionDeletion = this.getResponseProperty("LimitCollectionDeletion"); - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - this.limitCollectionCreationDeletion = this.getResponseProperty( - "LimitCollectionCreationDeletion", - ); this.allowAdminAccessToAllCollectionItems = this.getResponseProperty( "AllowAdminAccessToAllCollectionItems", ); diff --git a/libs/common/src/admin-console/models/response/profile-organization.response.ts b/libs/common/src/admin-console/models/response/profile-organization.response.ts index 4d9366e6627..ed1f45d4917 100644 --- a/libs/common/src/admin-console/models/response/profile-organization.response.ts +++ b/libs/common/src/admin-console/models/response/profile-organization.response.ts @@ -51,8 +51,6 @@ export class ProfileOrganizationResponse extends BaseResponse { accessSecretsManager: boolean; limitCollectionCreation: boolean; limitCollectionDeletion: boolean; - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - limitCollectionCreationDeletion: boolean; allowAdminAccessToAllCollectionItems: boolean; userIsManagedByOrganization: boolean; @@ -115,10 +113,6 @@ export class ProfileOrganizationResponse extends BaseResponse { this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager"); this.limitCollectionCreation = this.getResponseProperty("LimitCollectionCreation"); this.limitCollectionDeletion = this.getResponseProperty("LimitCollectionDeletion"); - // Deprecated: https://bitwarden.atlassian.net/browse/PM-10863 - this.limitCollectionCreationDeletion = this.getResponseProperty( - "LimitCollectionCreationDeletion", - ); this.allowAdminAccessToAllCollectionItems = this.getResponseProperty( "AllowAdminAccessToAllCollectionItems", ); diff --git a/libs/common/src/auth/models/request/registration/register-finish.request.ts b/libs/common/src/auth/models/request/registration/register-finish.request.ts index 7ffac6bfe6c..645bcf05b1b 100644 --- a/libs/common/src/auth/models/request/registration/register-finish.request.ts +++ b/libs/common/src/auth/models/request/registration/register-finish.request.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { KeysRequest } from "../../../../models/request/keys.request"; -import { KdfType } from "../../../../platform/enums"; import { EncryptedString } from "../../../../platform/models/domain/enc-string"; export class RegisterFinishRequest { diff --git a/libs/common/src/auth/models/request/set-key-connector-key.request.ts b/libs/common/src/auth/models/request/set-key-connector-key.request.ts index c8081bdec2a..14132ab79f2 100644 --- a/libs/common/src/auth/models/request/set-key-connector-key.request.ts +++ b/libs/common/src/auth/models/request/set-key-connector-key.request.ts @@ -1,6 +1,6 @@ +import { KdfConfig, KdfType } from "@bitwarden/key-management"; + import { KeysRequest } from "../../../models/request/keys.request"; -import { KdfType } from "../../../platform/enums"; -import { KdfConfig } from "../domain/kdf-config"; export class SetKeyConnectorKeyRequest { key: string; diff --git a/libs/common/src/auth/models/request/set-password.request.ts b/libs/common/src/auth/models/request/set-password.request.ts index 0fc5d84c097..5aa74068591 100644 --- a/libs/common/src/auth/models/request/set-password.request.ts +++ b/libs/common/src/auth/models/request/set-password.request.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { KeysRequest } from "../../../models/request/keys.request"; -import { KdfType } from "../../../platform/enums"; export class SetPasswordRequest { masterPasswordHash: string; diff --git a/libs/common/src/auth/models/response/identity-token.response.ts b/libs/common/src/auth/models/response/identity-token.response.ts index 9ddec9d0f70..c85e7a9444a 100644 --- a/libs/common/src/auth/models/response/identity-token.response.ts +++ b/libs/common/src/auth/models/response/identity-token.response.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { BaseResponse } from "../../../models/response/base.response"; -import { KdfType } from "../../../platform/enums"; import { MasterPasswordPolicyResponse } from "./master-password-policy.response"; import { UserDecryptionOptionsResponse } from "./user-decryption-options/user-decryption-options.response"; diff --git a/libs/common/src/auth/models/response/prelogin.response.ts b/libs/common/src/auth/models/response/prelogin.response.ts index c6762e22376..b5ca78c3b79 100644 --- a/libs/common/src/auth/models/response/prelogin.response.ts +++ b/libs/common/src/auth/models/response/prelogin.response.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { BaseResponse } from "../../../models/response/base.response"; -import { KdfType } from "../../../platform/enums"; export class PreloginResponse extends BaseResponse { kdf: KdfType; diff --git a/libs/common/src/auth/services/key-connector.service.ts b/libs/common/src/auth/services/key-connector.service.ts index 111f82e6e52..1f10141c756 100644 --- a/libs/common/src/auth/services/key-connector.service.ts +++ b/libs/common/src/auth/services/key-connector.service.ts @@ -1,8 +1,14 @@ import { firstValueFrom } from "rxjs"; import { LogoutReason } from "@bitwarden/auth/common"; +import { + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, + KeyService, + KdfType, +} from "@bitwarden/key-management"; -import { KeyService } from "../../../../key-management/src/abstractions/key.service"; import { ApiService } from "../../abstractions/api.service"; import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserType } from "../../admin-console/enums"; @@ -10,7 +16,6 @@ import { Organization } from "../../admin-console/models/domain/organization"; import { KeysRequest } from "../../models/request/keys.request"; import { KeyGenerationService } from "../../platform/abstractions/key-generation.service"; import { LogService } from "../../platform/abstractions/log.service"; -import { KdfType } from "../../platform/enums/kdf-type.enum"; import { Utils } from "../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; import { @@ -25,7 +30,6 @@ import { AccountService } from "../abstractions/account.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "../abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "../abstractions/master-password.service.abstraction"; import { TokenService } from "../abstractions/token.service"; -import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config"; import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request"; import { SetKeyConnectorKeyRequest } from "../models/request/set-key-connector-key.request"; import { IdentityTokenResponse } from "../models/response/identity-token.response"; diff --git a/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts b/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts index 1538f571cfd..4aa3a632855 100644 --- a/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts +++ b/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts @@ -7,8 +7,9 @@ import { UserDecryptionOptions, UserDecryptionOptionsServiceAbstraction, } from "@bitwarden/auth/common"; +import { KdfConfig, KeyService } from "@bitwarden/key-management"; -import { KeyService } from "../../../../../key-management/src/abstractions/key.service"; +import { KdfConfigService } from "../../../../../key-management/src/abstractions/kdf-config.service"; import { FakeAccountService, mockAccountServiceWith } from "../../../../spec"; import { VaultTimeoutSettingsService } from "../../../abstractions/vault-timeout/vault-timeout-settings.service"; import { I18nService } from "../../../platform/abstractions/i18n.service"; @@ -18,11 +19,9 @@ import { HashPurpose } from "../../../platform/enums"; import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { MasterKey } from "../../../types/key"; -import { KdfConfigService } from "../../abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction"; import { UserVerificationApiServiceAbstraction } from "../../abstractions/user-verification/user-verification-api.service.abstraction"; import { VerificationType } from "../../enums/verification-type"; -import { KdfConfig } from "../../models/domain/kdf-config"; import { MasterPasswordPolicyResponse } from "../../models/response/master-password-policy.response"; import { MasterPasswordVerification } from "../../types/verification"; diff --git a/libs/common/src/auth/services/user-verification/user-verification.service.ts b/libs/common/src/auth/services/user-verification/user-verification.service.ts index 5446558a540..5d6c6a8f5f9 100644 --- a/libs/common/src/auth/services/user-verification/user-verification.service.ts +++ b/libs/common/src/auth/services/user-verification/user-verification.service.ts @@ -1,9 +1,9 @@ import { firstValueFrom, map } from "rxjs"; import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { PinServiceAbstraction } from "../../../../../auth/src/common/abstractions/pin.service.abstraction"; -import { KeyService } from "../../../../../key-management/src/abstractions/key.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "../../../abstractions/vault-timeout/vault-timeout-settings.service"; import { I18nService } from "../../../platform/abstractions/i18n.service"; import { LogService } from "../../../platform/abstractions/log.service"; @@ -13,7 +13,6 @@ import { KeySuffixOptions } from "../../../platform/enums/key-suffix-options.enu import { UserId } from "../../../types/guid"; import { UserKey } from "../../../types/key"; import { AccountService } from "../../abstractions/account.service"; -import { KdfConfigService } from "../../abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction"; import { UserVerificationApiServiceAbstraction } from "../../abstractions/user-verification/user-verification-api.service.abstraction"; import { UserVerificationService as UserVerificationServiceAbstraction } from "../../abstractions/user-verification/user-verification.service.abstraction"; diff --git a/libs/common/src/billing/models/request/verify-bank-account.request.ts b/libs/common/src/billing/models/request/verify-bank-account.request.ts index cadf4b97099..ee85d1a2aad 100644 --- a/libs/common/src/billing/models/request/verify-bank-account.request.ts +++ b/libs/common/src/billing/models/request/verify-bank-account.request.ts @@ -1,9 +1,7 @@ export class VerifyBankAccountRequest { - amount1: number; - amount2: number; + descriptorCode: string; - constructor(amount1: number, amount2: number) { - this.amount1 = amount1; - this.amount2 = amount2; + constructor(descriptorCode: string) { + this.descriptorCode = descriptorCode; } } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index ec5a8e47d73..6b8af3ef78d 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -33,13 +33,13 @@ export enum FeatureFlag { PM11901_RefactorSelfHostingLicenseUploader = "PM-11901-refactor-self-hosting-license-uploader", AccessIntelligence = "pm-13227-access-intelligence", Pm13322AddPolicyDefinitions = "pm-13322-add-policy-definitions", - LimitCollectionCreationDeletionSplit = "pm-10863-limit-collection-creation-deletion-split", CriticalApps = "pm-14466-risk-insights-critical-application", TrialPaymentOptional = "PM-8163-trial-payment", SecurityTasks = "security-tasks", NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss", NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss", DisableFreeFamiliesSponsorship = "PM-12274-disable-free-families-sponsorship", + PM11360RemoveProviderExportPermission = "pm-11360-remove-provider-export-permission", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -83,13 +83,13 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.PM11901_RefactorSelfHostingLicenseUploader]: FALSE, [FeatureFlag.AccessIntelligence]: FALSE, [FeatureFlag.Pm13322AddPolicyDefinitions]: FALSE, - [FeatureFlag.LimitCollectionCreationDeletionSplit]: FALSE, [FeatureFlag.CriticalApps]: FALSE, [FeatureFlag.TrialPaymentOptional]: FALSE, [FeatureFlag.SecurityTasks]: FALSE, [FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE, [FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE, [FeatureFlag.DisableFreeFamiliesSponsorship]: FALSE, + [FeatureFlag.PM11360RemoveProviderExportPermission]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; diff --git a/libs/common/src/key-management/services/process-reload.service.ts b/libs/common/src/key-management/services/default-process-reload.service.ts similarity index 97% rename from libs/common/src/key-management/services/process-reload.service.ts rename to libs/common/src/key-management/services/default-process-reload.service.ts index 2f25d63b0fd..63082493622 100644 --- a/libs/common/src/key-management/services/process-reload.service.ts +++ b/libs/common/src/key-management/services/default-process-reload.service.ts @@ -12,7 +12,7 @@ import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum"; import { UserId } from "../../types/guid"; import { ProcessReloadServiceAbstraction } from "../abstractions/process-reload.service"; -export class ProcessReloadService implements ProcessReloadServiceAbstraction { +export class DefaultProcessReloadService implements ProcessReloadServiceAbstraction { private reloadInterval: any = null; constructor( diff --git a/libs/common/src/models/request/kdf.request.ts b/libs/common/src/models/request/kdf.request.ts index 8f27b0ec10f..12f0306edbe 100644 --- a/libs/common/src/models/request/kdf.request.ts +++ b/libs/common/src/models/request/kdf.request.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { PasswordRequest } from "../../auth/models/request/password.request"; -import { KdfType } from "../../platform/enums"; export class KdfRequest extends PasswordRequest { kdf: KdfType; diff --git a/libs/common/src/models/request/register.request.ts b/libs/common/src/models/request/register.request.ts index f01d89f4b22..7ea7af84c5c 100644 --- a/libs/common/src/models/request/register.request.ts +++ b/libs/common/src/models/request/register.request.ts @@ -1,5 +1,6 @@ +import { KdfType } from "@bitwarden/key-management"; + import { CaptchaProtectedRequest } from "../../auth/models/request/captcha-protected.request"; -import { KdfType } from "../../platform/enums"; import { KeysRequest } from "./keys.request"; import { ReferenceEventRequest } from "./reference-event.request"; diff --git a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts index 535248e7ecd..d878d70b56e 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts @@ -64,7 +64,7 @@ export class Fido2AuthenticatorError extends Error { } export interface PublicKeyCredentialDescriptor { - id: BufferSource; + id: Uint8Array; transports?: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[]; type: "public-key"; } diff --git a/libs/common/src/platform/abstractions/key-generation.service.ts b/libs/common/src/platform/abstractions/key-generation.service.ts index 5c6119919a3..8314efe3469 100644 --- a/libs/common/src/platform/abstractions/key-generation.service.ts +++ b/libs/common/src/platform/abstractions/key-generation.service.ts @@ -1,4 +1,5 @@ -import { KdfConfig } from "../../auth/models/domain/kdf-config"; +import { KdfConfig } from "@bitwarden/key-management"; + import { CsprngArray } from "../../types/csprng"; import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; diff --git a/libs/common/src/platform/enums/index.ts b/libs/common/src/platform/enums/index.ts index bac3f4ec41a..389f867e645 100644 --- a/libs/common/src/platform/enums/index.ts +++ b/libs/common/src/platform/enums/index.ts @@ -2,7 +2,6 @@ export * from "./encryption-type.enum"; export * from "./file-upload-type.enum"; export * from "./hash-purpose.enum"; export * from "./html-storage-location.enum"; -export * from "./kdf-type.enum"; export * from "./key-suffix-options.enum"; export * from "./log-level-type.enum"; export * from "./storage-location.enum"; diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts new file mode 100644 index 00000000000..76e068ac01c --- /dev/null +++ b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts @@ -0,0 +1,68 @@ +import { compareCredentialIds, parseCredentialId } from "./credential-id-utils"; + +describe("credential-id-utils", () => { + describe("parseCredentialId", () => { + it("returns credentialId in binary format when given a valid UUID string", () => { + const result = parseCredentialId("08d70b74-e9f5-4522-a425-e5dcd40107e7"); + + expect(result).toEqual( + new Uint8Array([ + 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, + 0xe7, + ]), + ); + }); + + it("returns credentialId in binary format when given a valid Base64Url string", () => { + const result = parseCredentialId("b64.CNcLdOn1RSKkJeXc1AEH5w"); + + expect(result).toEqual( + new Uint8Array([ + 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, + 0xe7, + ]), + ); + }); + + it("returns undefined when given an invalid Base64 string", () => { + const result = parseCredentialId("b64.#$%&"); + + expect(result).toBeUndefined(); + }); + + it("returns undefined when given an invalid UUID string", () => { + const result = parseCredentialId("invalid"); + + expect(result).toBeUndefined(); + }); + }); + + describe("compareCredentialIds", () => { + it("returns true when the two credential IDs are equal", () => { + const a = new Uint8Array([0x01, 0x02, 0x03]); + const b = new Uint8Array([0x01, 0x02, 0x03]); + + const result = compareCredentialIds(a, b); + + expect(result).toBe(true); + }); + + it("returns false when the two credential IDs are not equal", () => { + const a = new Uint8Array([0x01, 0x02, 0x03]); + const b = new Uint8Array([0x01, 0x02, 0x04]); + + const result = compareCredentialIds(a, b); + + expect(result).toBe(false); + }); + + it("returns false when the two credential IDs have different lengths", () => { + const a = new Uint8Array([0x01, 0x02, 0x03]); + const b = new Uint8Array([0x01, 0x02, 0x03, 0x04]); + + const result = compareCredentialIds(a, b); + + expect(result).toBe(false); + }); + }); +}); diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.ts b/libs/common/src/platform/services/fido2/credential-id-utils.ts new file mode 100644 index 00000000000..a548b8befd3 --- /dev/null +++ b/libs/common/src/platform/services/fido2/credential-id-utils.ts @@ -0,0 +1,31 @@ +import { Fido2Utils } from "./fido2-utils"; +import { guidToRawFormat } from "./guid-utils"; + +export function parseCredentialId(encodedCredentialId: string): Uint8Array { + try { + if (encodedCredentialId.startsWith("b64.")) { + return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4)); + } + + return guidToRawFormat(encodedCredentialId); + } catch { + return undefined; + } +} + +/** + * Compares two credential IDs for equality. + */ +export function compareCredentialIds(a: Uint8Array, b: Uint8Array): boolean { + if (a.length !== b.length) { + return false; + } + + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + + return true; +} diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts index 5f15005d71c..e3f79ff9d58 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts @@ -26,9 +26,9 @@ import { import { Utils } from "../../misc/utils"; import { CBOR } from "./cbor"; +import { parseCredentialId } from "./credential-id-utils"; import { AAGUID, Fido2AuthenticatorService } from "./fido2-authenticator.service"; import { Fido2Utils } from "./fido2-utils"; -import { guidToRawFormat } from "./guid-utils"; const RpId = "bitwarden.com"; @@ -139,7 +139,7 @@ describe("FidoAuthenticatorService", () => { params = await createParams({ excludeCredentialDescriptorList: [ { - id: guidToRawFormat(excludedCipher.login.fido2Credentials[0].credentialId), + id: parseCredentialId(excludedCipher.login.fido2Credentials[0].credentialId), type: "public-key", }, ], @@ -482,7 +482,7 @@ describe("FidoAuthenticatorService", () => { credentialId = Utils.newGuid(); params = await createParams({ allowCredentialDescriptorList: [ - { id: guidToRawFormat(credentialId), type: "public-key" }, + { id: parseCredentialId(credentialId), type: "public-key" }, ], rpId: RpId, }); @@ -546,7 +546,7 @@ describe("FidoAuthenticatorService", () => { let params: Fido2AuthenticatorGetAssertionParams; beforeEach(async () => { - credentialIds = [Utils.newGuid(), Utils.newGuid()]; + credentialIds = [Utils.newGuid(), "b64.Lb5SVTumSV6gYJpeWh3laA"]; ciphers = [ await createCipherView( { type: CipherType.Login }, @@ -559,7 +559,7 @@ describe("FidoAuthenticatorService", () => { ]; params = await createParams({ allowCredentialDescriptorList: credentialIds.map((credentialId) => ({ - id: guidToRawFormat(credentialId), + id: parseCredentialId(credentialId), type: "public-key", })), rpId: RpId, @@ -667,7 +667,7 @@ describe("FidoAuthenticatorService", () => { selectedCredentialId = credentialIds[0]; params = await createParams({ allowCredentialDescriptorList: credentialIds.map((credentialId) => ({ - id: guidToRawFormat(credentialId), + id: parseCredentialId(credentialId), type: "public-key", })), rpId: RpId, @@ -723,7 +723,7 @@ describe("FidoAuthenticatorService", () => { const flags = encAuthData.slice(32, 33); const counter = encAuthData.slice(33, 37); - expect(result.selectedCredential.id).toEqual(guidToRawFormat(selectedCredentialId)); + expect(result.selectedCredential.id).toEqual(parseCredentialId(selectedCredentialId)); expect(result.selectedCredential.userHandle).toEqual( Fido2Utils.stringToBuffer(fido2Credentials[0].userHandle), ); diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts index 8f0523769d9..e5d3685b9c2 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts @@ -23,9 +23,10 @@ import { LogService } from "../../abstractions/log.service"; import { Utils } from "../../misc/utils"; import { CBOR } from "./cbor"; +import { compareCredentialIds, parseCredentialId } from "./credential-id-utils"; import { p1363ToDer } from "./ecdsa-utils"; import { Fido2Utils } from "./fido2-utils"; -import { guidToRawFormat, guidToStandardFormat } from "./guid-utils"; +import { guidToStandardFormat } from "./guid-utils"; // AAGUID: d548826e-79b4-db40-a3d8-11116f7e8349 export const AAGUID = new Uint8Array([ @@ -178,7 +179,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr const authData = await generateAuthData({ rpId: params.rpEntity.id, - credentialId: guidToRawFormat(credentialId), + credentialId: parseCredentialId(credentialId), counter: fido2Credential.counter, userPresence: true, userVerification: userVerified, @@ -193,7 +194,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr ); return { - credentialId: guidToRawFormat(credentialId), + credentialId: parseCredentialId(credentialId), attestationObject, authData, publicKey: pubKeyDer, @@ -313,7 +314,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr const authenticatorData = await generateAuthData({ rpId: selectedFido2Credential.rpId, - credentialId: guidToRawFormat(selectedCredentialId), + credentialId: parseCredentialId(selectedCredentialId), counter: selectedFido2Credential.counter, userPresence: true, userVerification: userVerified, @@ -328,7 +329,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr return { authenticatorData, selectedCredential: { - id: guidToRawFormat(selectedCredentialId), + id: parseCredentialId(selectedCredentialId), userHandle: Fido2Utils.stringToBuffer(selectedFido2Credential.userHandle), }, signature, @@ -412,16 +413,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr credentials: PublicKeyCredentialDescriptor[], rpId: string, ): Promise { - const ids: string[] = []; - - for (const credential of credentials) { - try { - ids.push(guidToStandardFormat(credential.id)); - // eslint-disable-next-line no-empty - } catch {} - } - - if (ids.length === 0) { + if (credentials.length === 0) { return []; } @@ -432,7 +424,12 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr cipher.type === CipherType.Login && cipher.login.hasFido2Credentials && cipher.login.fido2Credentials[0].rpId === rpId && - ids.includes(cipher.login.fido2Credentials[0].credentialId), + credentials.some((credential) => + compareCredentialIds( + credential.id, + parseCredentialId(cipher.login.fido2Credentials[0].credentialId), + ), + ), ); } diff --git a/libs/common/src/platform/services/fido2/guid-utils.spec.ts b/libs/common/src/platform/services/fido2/guid-utils.spec.ts new file mode 100644 index 00000000000..098ea4bee75 --- /dev/null +++ b/libs/common/src/platform/services/fido2/guid-utils.spec.ts @@ -0,0 +1,28 @@ +import { guidToRawFormat } from "./guid-utils"; + +describe("guid-utils", () => { + describe("guidToRawFormat", () => { + it.each([ + [ + "00000000-0000-0000-0000-000000000000", + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + ], + "08d70b74-e9f5-4522-a425-e5dcd40107e7", + [ + 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, + 0xe7, + ], + ], + ])("returns UUID in binary format when given a valid UUID string", (input, expected) => { + const result = guidToRawFormat(input); + + expect(result).toEqual(new Uint8Array(expected)); + }); + + it("throws an error when given an invalid UUID string", () => { + expect(() => guidToRawFormat("invalid")).toThrow(TypeError); + }); + }); +}); diff --git a/libs/common/src/platform/services/key-generation.service.spec.ts b/libs/common/src/platform/services/key-generation.service.spec.ts index 4f04eebd04e..7bc547dac17 100644 --- a/libs/common/src/platform/services/key-generation.service.spec.ts +++ b/libs/common/src/platform/services/key-generation.service.spec.ts @@ -1,6 +1,7 @@ import { mock } from "jest-mock-extended"; -import { Argon2KdfConfig, PBKDF2KdfConfig } from "../../auth/models/domain/kdf-config"; +import { PBKDF2KdfConfig, Argon2KdfConfig } from "@bitwarden/key-management"; + import { CsprngArray } from "../../types/csprng"; import { CryptoFunctionService } from "../abstractions/crypto-function.service"; diff --git a/libs/common/src/platform/services/key-generation.service.ts b/libs/common/src/platform/services/key-generation.service.ts index b1c1ddfcf17..911d9d1c095 100644 --- a/libs/common/src/platform/services/key-generation.service.ts +++ b/libs/common/src/platform/services/key-generation.service.ts @@ -1,8 +1,8 @@ -import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "../../auth/models/domain/kdf-config"; +import { KdfConfig, PBKDF2KdfConfig, Argon2KdfConfig, KdfType } from "@bitwarden/key-management"; + import { CsprngArray } from "../../types/csprng"; import { CryptoFunctionService } from "../abstractions/crypto-function.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "../abstractions/key-generation.service"; -import { KdfType } from "../enums"; import { Utils } from "../misc/utils"; import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts index ff82b3aa764..de8b079621a 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts @@ -1,13 +1,11 @@ import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject, firstValueFrom, of } from "rxjs"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; import { BitwardenClient } from "@bitwarden/sdk-internal"; import { ApiService } from "../../../abstractions/api.service"; import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service"; -import { KdfConfigService } from "../../../auth/abstractions/kdf-config.service"; -import { PBKDF2KdfConfig } from "../../../auth/models/domain/kdf-config"; import { UserId } from "../../../types/guid"; import { UserKey } from "../../../types/key"; import { Environment, EnvironmentService } from "../../abstractions/environment.service"; diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index ccadfe7cca3..4506319eed1 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -11,7 +11,7 @@ import { catchError, } from "rxjs"; -import { KeyService } from "@bitwarden/key-management"; +import { KeyService, KdfConfigService, KdfConfig, KdfType } from "@bitwarden/key-management"; import { BitwardenClient, ClientSettings, @@ -22,8 +22,6 @@ import { import { ApiService } from "../../../abstractions/api.service"; import { EncryptedOrganizationKeyData } from "../../../admin-console/models/data/encrypted-organization-key.data"; import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service"; -import { KdfConfigService } from "../../../auth/abstractions/kdf-config.service"; -import { KdfConfig } from "../../../auth/models/domain/kdf-config"; import { DeviceType } from "../../../enums/device-type.enum"; import { OrganizationId, UserId } from "../../../types/guid"; import { UserKey } from "../../../types/key"; @@ -31,7 +29,6 @@ import { Environment, EnvironmentService } from "../../abstractions/environment. import { PlatformUtilsService } from "../../abstractions/platform-utils.service"; import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory"; import { SdkService } from "../../abstractions/sdk/sdk.service"; -import { KdfType } from "../../enums"; import { compareValues } from "../../misc/compare-values"; import { EncryptedString } from "../../models/domain/enc-string"; diff --git a/libs/common/src/tools/send/services/send.service.ts b/libs/common/src/tools/send/services/send.service.ts index 3ba1cb92e2c..aa4aa6033e1 100644 --- a/libs/common/src/tools/send/services/send.service.ts +++ b/libs/common/src/tools/send/services/send.service.ts @@ -1,7 +1,7 @@ import { Observable, concatMap, distinctUntilChanged, firstValueFrom, map } from "rxjs"; -import { KeyService } from "../../../../../key-management/src/abstractions/key.service"; -import { PBKDF2KdfConfig } from "../../../auth/models/domain/kdf-config"; +import { PBKDF2KdfConfig, KeyService } from "@bitwarden/key-management"; + import { EncryptService } from "../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../platform/abstractions/i18n.service"; import { KeyGenerationService } from "../../../platform/abstractions/key-generation.service"; diff --git a/libs/common/tsconfig.json b/libs/common/tsconfig.json index 99c58f3cf24..27d8acbd360 100644 --- a/libs/common/tsconfig.json +++ b/libs/common/tsconfig.json @@ -1,12 +1,5 @@ { "extends": "../shared/tsconfig.libs", - "include": [ - "src", - "spec", - "./custom-matchers.d.ts", - "../key-management/src/key.service.spec.ts", - "../key-management/src/key.service.ts", - "../key-management/src/abstractions/key.service.ts" - ], + "include": ["src", "spec", "./custom-matchers.d.ts", "../key-management/src/index.ts"], "exclude": ["node_modules", "dist"] } diff --git a/libs/components/src/navigation/nav-group.component.html b/libs/components/src/navigation/nav-group.component.html index c22a067ffed..9f6d9ac034d 100644 --- a/libs/components/src/navigation/nav-group.component.html +++ b/libs/components/src/navigation/nav-group.component.html @@ -1,54 +1,56 @@ - - - - + + + + + - - - - - - - + + - - + + + + + + + - - -
- -
+ + +
+ +
+
diff --git a/libs/components/src/navigation/nav-group.component.ts b/libs/components/src/navigation/nav-group.component.ts index 1ebe7338648..07494c0b7da 100644 --- a/libs/components/src/navigation/nav-group.component.ts +++ b/libs/components/src/navigation/nav-group.component.ts @@ -1,5 +1,6 @@ import { AfterContentInit, + booleanAttribute, Component, ContentChildren, EventEmitter, @@ -40,6 +41,12 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI @Input() open = false; + /** + * Automatically hide the nav group if there are no child buttons + */ + @Input({ transform: booleanAttribute }) + hideIfEmpty = false; + @Output() openChange = new EventEmitter(); diff --git a/libs/components/src/navigation/nav-group.stories.ts b/libs/components/src/navigation/nav-group.stories.ts index de150ebc0d7..a6fa53ff187 100644 --- a/libs/components/src/navigation/nav-group.stories.ts +++ b/libs/components/src/navigation/nav-group.stories.ts @@ -88,6 +88,30 @@ export const Default: StoryObj = { }), }; +export const HideEmptyGroups: StoryObj = { + args: { + hideIfEmpty: true, + renderChildren: false, + }, + render: (args) => ({ + props: args, + template: /*html*/ ` + + + + + + + + + + + + + `, + }), +}; + export const Tree: StoryObj = { render: (args) => ({ props: args, diff --git a/libs/importer/spec/bitwarden-password-protected-importer.spec.ts b/libs/importer/spec/bitwarden-password-protected-importer.spec.ts index d15aa61c8a7..008d6e25f92 100644 --- a/libs/importer/spec/bitwarden-password-protected-importer.spec.ts +++ b/libs/importer/spec/bitwarden-password-protected-importer.spec.ts @@ -4,10 +4,9 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfType, KeyService } from "@bitwarden/key-management"; import { BitwardenPasswordProtectedImporter, diff --git a/libs/importer/src/components/import.component.ts b/libs/importer/src/components/import.component.ts index 1ffe2728b05..1ab300fc378 100644 --- a/libs/importer/src/components/import.component.ts +++ b/libs/importer/src/components/import.component.ts @@ -21,10 +21,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { safeProvider, SafeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { - canAccessImport, - OrganizationService, -} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; @@ -226,7 +223,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { this.setImportOptions(); await this.initializeOrganizations(); - if (this.organizationId && (await this.canAccessImportExport(this.organizationId))) { + if (this.organizationId && (await this.canAccessImport(this.organizationId))) { this.handleOrganizationImportInit(); } else { this.handleImportInit(); @@ -289,7 +286,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { private async initializeOrganizations() { this.organizations$ = concat( this.organizationService.memberOrganizations$.pipe( - canAccessImport(this.i18nService), + map((orgs) => orgs.filter((org) => org.canAccessImport)), map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))), ), ); @@ -375,7 +372,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { importContents, this.organizationId, this.formGroup.controls.targetSelector.value, - (await this.canAccessImportExport(this.organizationId)) && this.isFromAC, + (await this.canAccessImport(this.organizationId)) && this.isFromAC, ); //No errors, display success message @@ -395,11 +392,11 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { } } - private async canAccessImportExport(organizationId?: string): Promise { + private async canAccessImport(organizationId?: string): Promise { if (!organizationId) { return false; } - return (await this.organizationService.get(this.organizationId))?.canAccessImportExport; + return (await this.organizationService.get(this.organizationId))?.canAccessImport; } getFormatInstructionTitle() { diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts index fa19e3c0001..446694b8d27 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts @@ -1,17 +1,17 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig, -} from "@bitwarden/common/auth/models/domain/kdf-config"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; -import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { KeyService } from "@bitwarden/key-management"; + KeyService, + KdfType, +} from "@bitwarden/key-management"; import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/vault-export-core"; import { ImportResult } from "../../models/import-result"; diff --git a/libs/common/src/auth/abstractions/kdf-config.service.ts b/libs/key-management/src/abstractions/kdf-config.service.ts similarity index 71% rename from libs/common/src/auth/abstractions/kdf-config.service.ts rename to libs/key-management/src/abstractions/kdf-config.service.ts index f4ffe31baa4..d5f613828d4 100644 --- a/libs/common/src/auth/abstractions/kdf-config.service.ts +++ b/libs/key-management/src/abstractions/kdf-config.service.ts @@ -1,7 +1,8 @@ import { Observable } from "rxjs"; -import { UserId } from "../../types/guid"; -import { KdfConfig } from "../models/domain/kdf-config"; +import { UserId } from "@bitwarden/common/types/guid"; + +import { KdfConfig } from "../models/kdf-config"; export abstract class KdfConfigService { abstract setKdfConfig(userId: UserId, KdfConfig: KdfConfig): Promise; diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index 0ec3aaafdc6..d43a9aeb624 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -1,11 +1,11 @@ import { Observable } from "rxjs"; import { EncryptedOrganizationKeyData } from "@bitwarden/common/admin-console/models/data/encrypted-organization-key.data"; +import { KdfConfig } from "@bitwarden/key-management"; import { ProfileOrganizationResponse } from "../../../common/src/admin-console/models/response/profile-organization.response"; import { ProfileProviderOrganizationResponse } from "../../../common/src/admin-console/models/response/profile-provider-organization.response"; import { ProfileProviderResponse } from "../../../common/src/admin-console/models/response/profile-provider.response"; -import { KdfConfig } from "../../../common/src/auth/models/domain/kdf-config"; import { KeySuffixOptions, HashPurpose } from "../../../common/src/platform/enums"; import { EncryptedString, EncString } from "../../../common/src/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "../../../common/src/platform/models/domain/symmetric-crypto-key"; diff --git a/libs/common/src/platform/enums/kdf-type.enum.ts b/libs/key-management/src/enums/kdf-type.enum.ts similarity index 100% rename from libs/common/src/platform/enums/kdf-type.enum.ts rename to libs/key-management/src/enums/kdf-type.enum.ts diff --git a/libs/key-management/src/index.ts b/libs/key-management/src/index.ts index 5ad96ddeba7..a779d3a9caf 100644 --- a/libs/key-management/src/index.ts +++ b/libs/key-management/src/index.ts @@ -8,3 +8,12 @@ export * from "./biometrics/biometric.state"; export { KeyService } from "./abstractions/key.service"; export { DefaultKeyService } from "./key.service"; export { UserKeyRotationDataProvider } from "./abstractions/user-key-rotation-data-provider.abstraction"; +export { + PBKDF2KdfConfig, + Argon2KdfConfig, + KdfConfig, + DEFAULT_KDF_CONFIG, +} from "./models/kdf-config"; +export { KdfConfigService } from "./abstractions/kdf-config.service"; +export { DefaultKdfConfigService } from "./kdf-config.service"; +export { KdfType } from "./enums/kdf-type.enum"; diff --git a/libs/common/src/auth/services/kdf-config.service.spec.ts b/libs/key-management/src/kdf-config.service.spec.ts similarity index 91% rename from libs/common/src/auth/services/kdf-config.service.spec.ts rename to libs/key-management/src/kdf-config.service.spec.ts index 7f3613294e7..c9912930e2c 100644 --- a/libs/common/src/auth/services/kdf-config.service.spec.ts +++ b/libs/key-management/src/kdf-config.service.spec.ts @@ -1,12 +1,17 @@ -import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../spec"; -import { Utils } from "../../platform/misc/utils"; -import { UserId } from "../../types/guid"; -import { Argon2KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config"; +import { + FakeAccountService, + FakeStateProvider, + mockAccountServiceWith, +} from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/src/types/guid"; -import { KdfConfigService } from "./kdf-config.service"; +import { Utils } from "../../common/src/platform/misc/utils"; + +import { DefaultKdfConfigService } from "./kdf-config.service"; +import { Argon2KdfConfig, PBKDF2KdfConfig } from "./models/kdf-config"; describe("KdfConfigService", () => { - let sutKdfConfigService: KdfConfigService; + let sutKdfConfigService: DefaultKdfConfigService; let fakeStateProvider: FakeStateProvider; let fakeAccountService: FakeAccountService; @@ -17,7 +22,7 @@ describe("KdfConfigService", () => { fakeAccountService = mockAccountServiceWith(mockUserId); fakeStateProvider = new FakeStateProvider(fakeAccountService); - sutKdfConfigService = new KdfConfigService(fakeStateProvider); + sutKdfConfigService = new DefaultKdfConfigService(fakeStateProvider); }); it("setKdfConfig(): should set the KDF config", async () => { diff --git a/libs/common/src/auth/services/kdf-config.service.ts b/libs/key-management/src/kdf-config.service.ts similarity index 76% rename from libs/common/src/auth/services/kdf-config.service.ts rename to libs/key-management/src/kdf-config.service.ts index 604a186d765..59907195f04 100644 --- a/libs/common/src/auth/services/kdf-config.service.ts +++ b/libs/key-management/src/kdf-config.service.ts @@ -1,10 +1,12 @@ import { firstValueFrom, Observable } from "rxjs"; -import { KdfType } from "../../platform/enums/kdf-type.enum"; -import { KDF_CONFIG_DISK, StateProvider, UserKeyDefinition } from "../../platform/state"; -import { UserId } from "../../types/guid"; -import { KdfConfigService as KdfConfigServiceAbstraction } from "../abstractions/kdf-config.service"; -import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config"; +import { UserId } from "@bitwarden/common/src/types/guid"; + +import { KDF_CONFIG_DISK, StateProvider, UserKeyDefinition } from "../../common/src/platform/state"; + +import { KdfConfigService } from "./abstractions/kdf-config.service"; +import { KdfType } from "./enums/kdf-type.enum"; +import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "./models/kdf-config"; export const KDF_CONFIG = new UserKeyDefinition(KDF_CONFIG_DISK, "kdfConfig", { deserializer: (kdfConfig: KdfConfig) => { @@ -18,7 +20,7 @@ export const KDF_CONFIG = new UserKeyDefinition(KDF_CONFIG_DISK, "kdf clearOn: ["logout"], }); -export class KdfConfigService implements KdfConfigServiceAbstraction { +export class DefaultKdfConfigService implements KdfConfigService { constructor(private stateProvider: StateProvider) {} async setKdfConfig(userId: UserId, kdfConfig: KdfConfig) { if (!userId) { diff --git a/libs/key-management/src/key.service.spec.ts b/libs/key-management/src/key.service.spec.ts index 2b2c6514eb4..142a8bbeb86 100644 --- a/libs/key-management/src/key.service.spec.ts +++ b/libs/key-management/src/key.service.spec.ts @@ -1,6 +1,8 @@ import { mock } from "jest-mock-extended"; import { bufferCount, firstValueFrom, lastValueFrom, of, take, tap } from "rxjs"; +import { EncryptedOrganizationKeyData } from "@bitwarden/common/admin-console/models/data/encrypted-organization-key.data"; + import { PinServiceAbstraction } from "../../auth/src/common/abstractions"; import { awaitAsync, @@ -11,8 +13,6 @@ import { import { FakeAccountService, mockAccountServiceWith } from "../../common/spec/fake-account-service"; import { FakeActiveUserState, FakeSingleUserState } from "../../common/spec/fake-state"; import { FakeStateProvider } from "../../common/spec/fake-state-provider"; -import { EncryptedOrganizationKeyData } from "../../common/src/admin-console/models/data/encrypted-organization-key.data"; -import { KdfConfigService } from "../../common/src/auth/abstractions/kdf-config.service"; import { FakeMasterPasswordService } from "../../common/src/auth/services/master-password/fake-master-password.service"; import { CryptoFunctionService } from "../../common/src/platform/abstractions/crypto-function.service"; import { EncryptService } from "../../common/src/platform/abstractions/encrypt.service"; @@ -38,6 +38,7 @@ import { OrganizationId, UserId } from "../../common/src/types/guid"; import { UserKey, MasterKey } from "../../common/src/types/key"; import { VaultTimeoutStringType } from "../../common/src/types/vault-timeout.type"; +import { KdfConfigService } from "./abstractions/kdf-config.service"; import { UserPrivateKeyDecryptionFailedError } from "./abstractions/key.service"; import { DefaultKeyService } from "./key.service"; diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index f2ba24ef5df..ae0b6263de7 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -17,9 +17,7 @@ import { ProfileOrganizationResponse } from "../../common/src/admin-console/mode import { ProfileProviderOrganizationResponse } from "../../common/src/admin-console/models/response/profile-provider-organization.response"; import { ProfileProviderResponse } from "../../common/src/admin-console/models/response/profile-provider.response"; import { AccountService } from "../../common/src/auth/abstractions/account.service"; -import { KdfConfigService } from "../../common/src/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "../../common/src/auth/abstractions/master-password.service.abstraction"; -import { KdfConfig } from "../../common/src/auth/models/domain/kdf-config"; import { CryptoFunctionService } from "../../common/src/platform/abstractions/crypto-function.service"; import { EncryptService } from "../../common/src/platform/abstractions/encrypt.service"; import { KeyGenerationService } from "../../common/src/platform/abstractions/key-generation.service"; @@ -54,11 +52,13 @@ import { } from "../../common/src/types/key"; import { VaultTimeoutStringType } from "../../common/src/types/vault-timeout.type"; +import { KdfConfigService } from "./abstractions/kdf-config.service"; import { CipherDecryptionKeys, KeyService as KeyServiceAbstraction, UserPrivateKeyDecryptionFailedError, } from "./abstractions/key.service"; +import { KdfConfig } from "./models/kdf-config"; export class DefaultKeyService implements KeyServiceAbstraction { private readonly activeUserEverHadUserKey: ActiveUserState; diff --git a/libs/common/src/auth/models/domain/kdf-config.ts b/libs/key-management/src/models/kdf-config.ts similarity index 96% rename from libs/common/src/auth/models/domain/kdf-config.ts rename to libs/key-management/src/models/kdf-config.ts index 1909aa875e5..11431337a39 100644 --- a/libs/common/src/auth/models/domain/kdf-config.ts +++ b/libs/key-management/src/models/kdf-config.ts @@ -1,7 +1,7 @@ import { Jsonify } from "type-fest"; -import { KdfType } from "../../../platform/enums/kdf-type.enum"; -import { RangeWithDefault } from "../../../platform/misc/range-with-default"; +import { RangeWithDefault } from "../../../common/src/platform/misc/range-with-default"; +import { KdfType } from "../enums/kdf-type.enum"; /** * Represents a type safe KDF configuration. diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/base-vault-export.service.ts b/libs/tools/export/vault-export/vault-export-core/src/services/base-vault-export.service.ts index 76b008be620..60f0f003948 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/base-vault-export.service.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/base-vault-export.service.ts @@ -1,12 +1,10 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; 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 { KdfConfig, KdfConfigService, KdfType } from "@bitwarden/key-management"; import { BitwardenCsvExportType, BitwardenPasswordProtectedFileFormat } from "../types"; export class BaseVaultExportService { diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts index d264991ae40..9d58bcbf559 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts @@ -3,15 +3,9 @@ import { BehaviorSubject } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; -import { - DEFAULT_KDF_CONFIG, - PBKDF2KdfConfig, -} from "@bitwarden/common/auth/models/domain/kdf-config"; import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserId } from "@bitwarden/common/types/guid"; @@ -24,7 +18,13 @@ import { Login } from "@bitwarden/common/vault/models/domain/login"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; -import { KeyService } from "@bitwarden/key-management"; +import { + DEFAULT_KDF_CONFIG, + PBKDF2KdfConfig, + KdfConfigService, + KeyService, + KdfType, +} from "@bitwarden/key-management"; import { BuildTestObject, GetUniqueString } from "../../../../../../common/spec"; diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts index 04dba1299d7..529c2ff3de9 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts @@ -3,7 +3,6 @@ import { firstValueFrom, map } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { CipherWithIdExport, FolderWithIdExport } from "@bitwarden/common/models/export"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -15,7 +14,7 @@ import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { Folder } from "@bitwarden/common/vault/models/domain/folder"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { BitwardenCsvIndividualExportType, diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/org-vault-export.service.ts b/libs/tools/export/vault-export/vault-export-core/src/services/org-vault-export.service.ts index 4e23a0ed25c..2408aeb6cdf 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/org-vault-export.service.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/org-vault-export.service.ts @@ -11,7 +11,6 @@ import { import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -22,7 +21,7 @@ import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { KeyService } from "@bitwarden/key-management"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; import { BitwardenCsvOrgExportType, diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/vault-export.service.spec.ts b/libs/tools/export/vault-export/vault-export-core/src/services/vault-export.service.spec.ts index 525e769957f..6bf05796070 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/vault-export.service.spec.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/vault-export.service.spec.ts @@ -3,15 +3,9 @@ import { BehaviorSubject } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; -import { - DEFAULT_KDF_CONFIG, - PBKDF2KdfConfig, -} from "@bitwarden/common/auth/models/domain/kdf-config"; import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserId } from "@bitwarden/common/types/guid"; @@ -24,7 +18,13 @@ import { Login } from "@bitwarden/common/vault/models/domain/login"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; -import { KeyService } from "@bitwarden/key-management"; +import { + DEFAULT_KDF_CONFIG, + PBKDF2KdfConfig, + KdfConfigService, + KeyService, + KdfType, +} from "@bitwarden/key-management"; import { BuildTestObject, GetUniqueString } from "../../../../../../common/spec"; diff --git a/libs/tools/generator/components/src/password-generator.component.ts b/libs/tools/generator/components/src/password-generator.component.ts index 715904dc984..affd162d398 100644 --- a/libs/tools/generator/components/src/password-generator.component.ts +++ b/libs/tools/generator/components/src/password-generator.component.ts @@ -249,7 +249,7 @@ export class PasswordGeneratorComponent implements OnInit, OnDestroy { private toOptions(algorithms: AlgorithmInfo[]) { const options: Option[] = algorithms.map((algorithm) => ({ value: algorithm.id, - label: this.i18nService.t(algorithm.name), + label: algorithm.name, })); return options; diff --git a/package-lock.json b/package-lock.json index 3eb6b9322f6..226ceaca156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -189,11 +189,11 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2024.11.1" + "version": "2024.11.2" }, "apps/cli": { "name": "@bitwarden/cli", - "version": "2024.11.0", + "version": "2024.11.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@koa/multer": "3.0.2", @@ -229,7 +229,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.11.1", + "version": "2024.11.2", "hasInstallScript": true, "license": "GPL-3.0" }, @@ -243,7 +243,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2024.11.0" + "version": "2024.11.1" }, "libs/admin-console": { "name": "@bitwarden/admin-console",