mirror of
https://github.com/bitwarden/browser
synced 2026-02-12 14:34:02 +00:00
Merge branch 'main' into PM-14891-Sales-Tax-Estimation-For-Organizations
This commit is contained in:
4
.github/workflows/build-cli.yml
vendored
4
.github/workflows/build-cli.yml
vendored
@@ -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:
|
||||
|
||||
2
.github/workflows/build-desktop.yml
vendored
2
.github/workflows/build-desktop.yml
vendored
@@ -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: |
|
||||
|
||||
6
.github/workflows/deploy-web.yml
vendored
6
.github/workflows/deploy-web.yml
vendored
@@ -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 }}
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<string>(""), // Replace with mock subject
|
||||
};
|
||||
});
|
||||
|
||||
describe("ExtensionLoginDecryptionOptionsService", () => {
|
||||
let service: ExtensionLoginDecryptionOptionsService;
|
||||
|
||||
let messagingService: MockProxy<MessagingService>;
|
||||
let router: MockProxy<Router>;
|
||||
let postLogoutMessageSubject: BehaviorSubject<string>;
|
||||
|
||||
beforeEach(() => {
|
||||
messagingService = mock<MessagingService>();
|
||||
router = mock<Router>();
|
||||
|
||||
// Cast postLogoutMessageListener$ to BehaviorSubject for dynamic control
|
||||
postLogoutMessageSubject = postLogoutMessageListener$ as BehaviorSubject<string>;
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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<void> {
|
||||
// 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(["/"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<void> {
|
||||
try {
|
||||
await super.createUser();
|
||||
@@ -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);
|
||||
}),
|
||||
|
||||
@@ -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<Message<Record<string, unknown>>>;
|
||||
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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -313,6 +313,10 @@ export default {
|
||||
back: "Back",
|
||||
loading: "Loading",
|
||||
search: "Search",
|
||||
vault: "Vault",
|
||||
generator: "Generator",
|
||||
send: "Send",
|
||||
settings: "Settings",
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="tw-truncate tw-max-w-full">
|
||||
{{ button.label }}
|
||||
{{ button.label | i18n }}
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.",
|
||||
);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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<void> {
|
||||
try {
|
||||
await super.createUser();
|
||||
@@ -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],
|
||||
})
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
4
apps/desktop/src/package-lock.json
generated
4
apps/desktop/src/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||
"homepage": "https://bitwarden.com",
|
||||
"license": "GPL-3.0",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -84,12 +84,12 @@
|
||||
<bit-nav-item
|
||||
[text]="'importData' | i18n"
|
||||
route="settings/tools/import"
|
||||
*ngIf="organization.canAccessImportExport"
|
||||
*ngIf="organization.canAccessImport"
|
||||
></bit-nav-item>
|
||||
<bit-nav-item
|
||||
[text]="'exportVault' | i18n"
|
||||
route="settings/tools/export"
|
||||
*ngIf="organization.canAccessImportExport"
|
||||
*ngIf="canAccessExport$ | async"
|
||||
></bit-nav-item>
|
||||
<bit-nav-item
|
||||
[text]="'domainVerification' | i18n"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, RouterModule } from "@angular/router";
|
||||
import { combineLatest, map, mergeMap, Observable, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import { combineLatest, filter, map, Observable, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
canAccessReportingTab,
|
||||
canAccessSettingsTab,
|
||||
canAccessVaultTab,
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
@@ -22,6 +21,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { getById } from "@bitwarden/common/platform/misc";
|
||||
import { BannerModule, IconModule } from "@bitwarden/components";
|
||||
|
||||
import { OrgSwitcherComponent } from "../../../layouts/org-switcher/org-switcher.component";
|
||||
@@ -42,19 +42,18 @@ import { AdminConsoleLogo } from "../../icons/admin-console-logo";
|
||||
BannerModule,
|
||||
],
|
||||
})
|
||||
export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
||||
export class OrganizationLayoutComponent implements OnInit {
|
||||
protected readonly logo = AdminConsoleLogo;
|
||||
|
||||
protected orgFilter = (org: Organization) => canAccessOrgAdmin(org);
|
||||
|
||||
organization$: Observable<Organization>;
|
||||
canAccessExport$: Observable<boolean>;
|
||||
showPaymentAndHistory$: Observable<boolean>;
|
||||
hideNewOrgButton$: Observable<boolean>;
|
||||
organizationIsUnmanaged$: Observable<boolean>;
|
||||
isAccessIntelligenceFeatureEnabled = false;
|
||||
|
||||
private _destroy = new Subject<void>();
|
||||
|
||||
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<string>(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);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -52,11 +52,7 @@
|
||||
<form
|
||||
*ngIf="org && !loading"
|
||||
[bitSubmit]="submitCollectionManagement"
|
||||
[formGroup]="
|
||||
limitCollectionCreationDeletionSplitFeatureFlagIsEnabled
|
||||
? collectionManagementFormGroup_VNext
|
||||
: collectionManagementFormGroup
|
||||
"
|
||||
[formGroup]="collectionManagementFormGroup"
|
||||
>
|
||||
<h1 bitTypography="h1" class="tw-mt-16 tw-pb-2.5">{{ "collectionManagement" | i18n }}</h1>
|
||||
<p bitTypography="body1">{{ "collectionManagementDesc" | i18n }}</p>
|
||||
@@ -64,24 +60,15 @@
|
||||
<bit-label>{{ "allowAdminAccessToAllCollectionItemsDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="allowAdminAccessToAllCollectionItems" />
|
||||
</bit-form-control>
|
||||
<ng-container *ngIf="limitCollectionCreationDeletionSplitFeatureFlagIsEnabled">
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitCollectionCreationDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="limitCollectionCreation" />
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitCollectionDeletionDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="limitCollectionDeletion" />
|
||||
</bit-form-control>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!limitCollectionCreationDeletionSplitFeatureFlagIsEnabled">
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitCollectionCreationDeletionDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="limitCollectionCreationDeletion" />
|
||||
</bit-form-control>
|
||||
</ng-container>
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitCollectionCreationDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="limitCollectionCreation" />
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitCollectionDeletionDesc" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="limitCollectionDeletion" />
|
||||
</bit-form-control>
|
||||
<button
|
||||
*ngIf="!selfHosted || limitCollectionCreationDeletionSplitFeatureFlagIsEnabled"
|
||||
type="submit"
|
||||
bitButton
|
||||
bitFormButton
|
||||
|
||||
@@ -10,7 +10,6 @@ import { OrganizationCollectionManagementUpdateRequest } from "@bitwarden/common
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { OrganizationUpdateRequest } from "@bitwarden/common/admin-console/models/request/organization-update.request";
|
||||
import { OrganizationResponse } from "@bitwarden/common/admin-console/models/response/organization.response";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -40,8 +39,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
org: OrganizationResponse;
|
||||
taxFormPromise: Promise<unknown>;
|
||||
|
||||
limitCollectionCreationDeletionSplitFeatureFlagIsEnabled: boolean;
|
||||
|
||||
// FormGroup validators taken from server Organization domain object
|
||||
protected formGroup = this.formBuilder.group({
|
||||
orgName: this.formBuilder.control(
|
||||
@@ -57,16 +54,7 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
),
|
||||
});
|
||||
|
||||
// Deprecated. Delete with https://bitwarden.atlassian.net/browse/PM-10863
|
||||
protected collectionManagementFormGroup = this.formBuilder.group({
|
||||
limitCollectionCreationDeletion: this.formBuilder.control({ value: false, disabled: true }),
|
||||
allowAdminAccessToAllCollectionItems: this.formBuilder.control({
|
||||
value: false,
|
||||
disabled: true,
|
||||
}),
|
||||
});
|
||||
|
||||
protected collectionManagementFormGroup_VNext = this.formBuilder.group({
|
||||
limitCollectionCreation: this.formBuilder.control({ value: false, disabled: false }),
|
||||
limitCollectionDeletion: this.formBuilder.control({ value: false, disabled: false }),
|
||||
allowAdminAccessToAllCollectionItems: this.formBuilder.control({
|
||||
@@ -98,11 +86,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||
|
||||
this.configService
|
||||
.getFeatureFlag$(FeatureFlag.LimitCollectionCreationDeletionSplit)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((x) => (this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled = x));
|
||||
|
||||
this.route.params
|
||||
.pipe(
|
||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
@@ -123,16 +106,6 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
this.canEditSubscription = organization.canEditSubscription;
|
||||
this.canUseApi = organization.useApi;
|
||||
|
||||
// Disabling these fields for self hosted orgs is deprecated
|
||||
// This block can be completely removed as part of
|
||||
// https://bitwarden.atlassian.net/browse/PM-10863
|
||||
if (!this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
|
||||
if (!this.selfHosted) {
|
||||
this.collectionManagementFormGroup.get("limitCollectionCreationDeletion").enable();
|
||||
this.collectionManagementFormGroup.get("allowAdminAccessToAllCollectionItems").enable();
|
||||
}
|
||||
}
|
||||
|
||||
// Update disabled states - reactive forms prefers not using disabled attribute
|
||||
if (!this.selfHosted) {
|
||||
this.formGroup.get("orgName").enable();
|
||||
@@ -152,18 +125,11 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
orgName: this.org.name,
|
||||
billingEmail: this.org.billingEmail,
|
||||
});
|
||||
if (this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
|
||||
this.collectionManagementFormGroup_VNext.patchValue({
|
||||
limitCollectionCreation: this.org.limitCollectionCreation,
|
||||
limitCollectionDeletion: this.org.limitCollectionDeletion,
|
||||
allowAdminAccessToAllCollectionItems: this.org.allowAdminAccessToAllCollectionItems,
|
||||
});
|
||||
} else {
|
||||
this.collectionManagementFormGroup.patchValue({
|
||||
limitCollectionCreationDeletion: this.org.limitCollectionCreationDeletion,
|
||||
allowAdminAccessToAllCollectionItems: this.org.allowAdminAccessToAllCollectionItems,
|
||||
});
|
||||
}
|
||||
this.collectionManagementFormGroup.patchValue({
|
||||
limitCollectionCreation: this.org.limitCollectionCreation,
|
||||
limitCollectionDeletion: this.org.limitCollectionDeletion,
|
||||
allowAdminAccessToAllCollectionItems: this.org.allowAdminAccessToAllCollectionItems,
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
});
|
||||
@@ -211,24 +177,13 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
submitCollectionManagement = async () => {
|
||||
// Early exit if self-hosted
|
||||
if (this.selfHosted && !this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
|
||||
return;
|
||||
}
|
||||
const request = new OrganizationCollectionManagementUpdateRequest();
|
||||
if (this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
|
||||
request.limitCollectionCreation =
|
||||
this.collectionManagementFormGroup_VNext.value.limitCollectionCreation;
|
||||
request.limitCollectionDeletion =
|
||||
this.collectionManagementFormGroup_VNext.value.limitCollectionDeletion;
|
||||
request.allowAdminAccessToAllCollectionItems =
|
||||
this.collectionManagementFormGroup_VNext.value.allowAdminAccessToAllCollectionItems;
|
||||
} else {
|
||||
request.limitCreateDeleteOwnerAdmin =
|
||||
this.collectionManagementFormGroup.value.limitCollectionCreationDeletion;
|
||||
request.allowAdminAccessToAllCollectionItems =
|
||||
this.collectionManagementFormGroup.value.allowAdminAccessToAllCollectionItems;
|
||||
}
|
||||
request.limitCollectionCreation =
|
||||
this.collectionManagementFormGroup.value.limitCollectionCreation;
|
||||
request.limitCollectionDeletion =
|
||||
this.collectionManagementFormGroup.value.limitCollectionDeletion;
|
||||
request.allowAdminAccessToAllCollectionItems =
|
||||
this.collectionManagementFormGroup.value.allowAdminAccessToAllCollectionItems;
|
||||
|
||||
await this.organizationApiService.updateCollectionManagement(this.organizationId, request);
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { inject, NgModule } from "@angular/core";
|
||||
import { CanMatchFn, RouterModule, Routes } from "@angular/router";
|
||||
import { map } from "rxjs";
|
||||
|
||||
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
|
||||
import { organizationPermissionsGuard } from "../../organizations/guards/org-permissions.guard";
|
||||
import { organizationRedirectGuard } from "../../organizations/guards/org-redirect.guard";
|
||||
@@ -11,6 +14,11 @@ import { PoliciesComponent } from "../../organizations/policies";
|
||||
import { AccountComponent } from "./account.component";
|
||||
import { TwoFactorSetupComponent } from "./two-factor-setup.component";
|
||||
|
||||
const removeProviderExportPermission$: CanMatchFn = () =>
|
||||
inject(ConfigService)
|
||||
.getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission)
|
||||
.pipe(map((removeProviderExport) => removeProviderExport === true));
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
@@ -53,18 +61,32 @@ const routes: Routes = [
|
||||
path: "import",
|
||||
loadComponent: () =>
|
||||
import("./org-import.component").then((mod) => mod.OrgImportComponent),
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)],
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessImport)],
|
||||
data: {
|
||||
titleId: "importData",
|
||||
},
|
||||
},
|
||||
|
||||
// Export routing is temporarily duplicated to set the flag value passed into org.canAccessExport
|
||||
{
|
||||
path: "export",
|
||||
loadComponent: () =>
|
||||
import("../tools/vault-export/org-vault-export.component").then(
|
||||
(mod) => mod.OrganizationVaultExportComponent,
|
||||
),
|
||||
canMatch: [removeProviderExportPermission$], // if this matches, the flag is ON
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(true))],
|
||||
data: {
|
||||
titleId: "exportVault",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "export",
|
||||
loadComponent: () =>
|
||||
import("../tools/vault-export/org-vault-export.component").then(
|
||||
(mod) => mod.OrganizationVaultExportComponent,
|
||||
),
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)],
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(false))],
|
||||
data: {
|
||||
titleId: "exportVault",
|
||||
},
|
||||
@@ -82,7 +104,7 @@ function getSettingsRoute(organization: Organization) {
|
||||
if (organization.canManagePolicies) {
|
||||
return "policies";
|
||||
}
|
||||
if (organization.canAccessImportExport) {
|
||||
if (organization.canAccessImport) {
|
||||
return ["tools", "import"];
|
||||
}
|
||||
if (organization.canManageSso) {
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
<router-outlet></router-outlet>
|
||||
<ng-template #loadingState>
|
||||
<!-- This is the same html from index.html which presents the bitwarden logo and loading spinny properly
|
||||
when the body has the layout_frontend class. Having this match the index allows for a duplicative yet seamless
|
||||
loading state here for process reloading. -->
|
||||
<div class="tw-p-8 tw-flex">
|
||||
<img class="new-logo-themed" alt="Bitwarden" />
|
||||
<div class="spinner-container tw-justify-center">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-3x tw-text-muted"
|
||||
title="Loading"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-container *ngIf="!loading; else loadingState">
|
||||
<router-outlet></router-outlet>
|
||||
</ng-container>
|
||||
|
||||
@@ -6,7 +6,6 @@ import * as jq from "jquery";
|
||||
import { Subject, filter, firstValueFrom, map, takeUntil, timeout, catchError, of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
@@ -17,6 +16,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -28,7 +28,7 @@ import { StateEventRunnerService } from "@bitwarden/common/platform/state";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { DialogService, ToastOptions, ToastService } from "@bitwarden/components";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
import { KeyService, BiometricStateService } from "@bitwarden/key-management";
|
||||
|
||||
@@ -60,6 +60,8 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
private isIdle = false;
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
loading = false;
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
private broadcasterService: BroadcasterService,
|
||||
@@ -91,6 +93,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
private accountService: AccountService,
|
||||
private logService: LogService,
|
||||
private sdkService: SdkService,
|
||||
private processReloadService: ProcessReloadServiceAbstraction,
|
||||
) {
|
||||
if (flagEnabled("sdk")) {
|
||||
// Warn if the SDK for some reason can't be initialized
|
||||
@@ -161,7 +164,8 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
this.router.navigate(["/"]);
|
||||
break;
|
||||
case "logout":
|
||||
await this.logOut(message.logoutReason, message.redirect);
|
||||
// note: the message.logoutReason isn't consumed anymore because of the process reload clearing any toasts.
|
||||
await this.logOut(message.redirect);
|
||||
break;
|
||||
case "lockVault":
|
||||
await this.vaultTimeoutService.lock();
|
||||
@@ -170,9 +174,8 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.notificationsService.updateConnection(false);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["lock"]);
|
||||
|
||||
await this.processReloadService.startProcessReload(this.authService);
|
||||
break;
|
||||
case "lockedUrl":
|
||||
break;
|
||||
@@ -272,33 +275,16 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
private async displayLogoutReason(logoutReason: LogoutReason) {
|
||||
let toastOptions: ToastOptions;
|
||||
switch (logoutReason) {
|
||||
case "invalidSecurityStamp":
|
||||
case "sessionExpired": {
|
||||
toastOptions = {
|
||||
variant: "warning",
|
||||
title: this.i18nService.t("loggedOut"),
|
||||
message: this.i18nService.t("loginExpired"),
|
||||
};
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
toastOptions = {
|
||||
variant: "info",
|
||||
title: this.i18nService.t("loggedOut"),
|
||||
message: this.i18nService.t("loggedOutDesc"),
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
private async logOut(redirect = true) {
|
||||
// Ensure the loading state is applied before proceeding to avoid a flash
|
||||
// of the login screen before the process reload fires.
|
||||
this.ngZone.run(() => {
|
||||
this.loading = true;
|
||||
document.body.classList.add("layout_frontend");
|
||||
});
|
||||
|
||||
this.toastService.showToast(toastOptions);
|
||||
}
|
||||
|
||||
private async logOut(logoutReason: LogoutReason, redirect = true) {
|
||||
await this.displayLogoutReason(logoutReason);
|
||||
// Note: we don't display a toast logout reason anymore as the process reload
|
||||
// will prevent any toasts from being displayed long enough to be read
|
||||
|
||||
await this.eventUploadService.uploadEvents();
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
@@ -334,10 +320,14 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
await logoutPromise;
|
||||
|
||||
if (redirect) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/"]);
|
||||
await this.router.navigate(["/"]);
|
||||
}
|
||||
|
||||
await this.processReloadService.startProcessReload(this.authService);
|
||||
|
||||
// Normally we would need to reset the loading state to false or remove the layout_frontend
|
||||
// class from the body here, but the process reload completely reloads the app so
|
||||
// it handles it.
|
||||
}, userId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./login";
|
||||
export * from "./login-decryption-options";
|
||||
export * from "./webauthn-login";
|
||||
export * from "./set-password-jit";
|
||||
export * from "./registration";
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./web-login-decryption-options.service";
|
||||
@@ -0,0 +1,41 @@
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
|
||||
import { RouterService } from "../../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
import { WebLoginDecryptionOptionsService } from "./web-login-decryption-options.service";
|
||||
|
||||
describe("WebLoginDecryptionOptionsService", () => {
|
||||
let service: WebLoginDecryptionOptionsService;
|
||||
|
||||
let messagingService: MockProxy<MessagingService>;
|
||||
let routerService: MockProxy<RouterService>;
|
||||
let acceptOrganizationInviteService: MockProxy<AcceptOrganizationInviteService>;
|
||||
|
||||
beforeEach(() => {
|
||||
messagingService = mock<MessagingService>();
|
||||
routerService = mock<RouterService>();
|
||||
acceptOrganizationInviteService = mock<AcceptOrganizationInviteService>();
|
||||
|
||||
service = new WebLoginDecryptionOptionsService(
|
||||
messagingService,
|
||||
routerService,
|
||||
acceptOrganizationInviteService,
|
||||
);
|
||||
});
|
||||
|
||||
it("should instantiate the service", () => {
|
||||
expect(service).not.toBeFalsy();
|
||||
});
|
||||
|
||||
describe("handleCreateUserSuccess()", () => {
|
||||
it("should clear the redirect URL and the org invite", async () => {
|
||||
await service.handleCreateUserSuccess();
|
||||
|
||||
expect(routerService.getAndClearLoginRedirectUrl).toHaveBeenCalled();
|
||||
expect(acceptOrganizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
LoginDecryptionOptionsService,
|
||||
DefaultLoginDecryptionOptionsService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
|
||||
import { RouterService } from "../../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
export class WebLoginDecryptionOptionsService
|
||||
extends DefaultLoginDecryptionOptionsService
|
||||
implements LoginDecryptionOptionsService
|
||||
{
|
||||
constructor(
|
||||
protected messagingService: MessagingService,
|
||||
private routerService: RouterService,
|
||||
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
) {
|
||||
super(messagingService);
|
||||
}
|
||||
|
||||
override async handleCreateUserSuccess(): Promise<void> {
|
||||
try {
|
||||
// Invites from TDE orgs go through here, but the invite is
|
||||
// accepted while being enrolled in admin recovery. So we need to clear
|
||||
// the redirect and stored org invite.
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,12 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service";
|
||||
import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
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 { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
import { OrganizationInvite } from "../../../organization-invite/organization-invite";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { CipherResponse } from "@bitwarden/common/vault/models/response/cipher.response";
|
||||
import { KdfType } from "@bitwarden/key-management";
|
||||
|
||||
import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type";
|
||||
import { EmergencyAccessType } from "../enums/emergency-access-type";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BaseResponse } from "@bitwarden/common/models/response/base.response";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { CipherResponse } from "@bitwarden/common/vault/models/response/cipher.response";
|
||||
import { KdfType } from "@bitwarden/key-management";
|
||||
|
||||
import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type";
|
||||
import { EmergencyAccessType } from "../enums/emergency-access-type";
|
||||
|
||||
@@ -8,14 +8,14 @@ import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.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, MasterKey } from "@bitwarden/common/types/key";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { KdfType, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type";
|
||||
import { EmergencyAccessType } from "../enums/emergency-access-type";
|
||||
|
||||
@@ -3,17 +3,11 @@ import { Injectable } from "@angular/core";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.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";
|
||||
@@ -22,7 +16,14 @@ import { UserKey } from "@bitwarden/common/types/key";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { UserKeyRotationDataProvider, KeyService } from "@bitwarden/key-management";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
UserKeyRotationDataProvider,
|
||||
KeyService,
|
||||
KdfType,
|
||||
} from "@bitwarden/key-management";
|
||||
|
||||
import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type";
|
||||
import { EmergencyAccessType } from "../enums/emergency-access-type";
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Component, inject } 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";
|
||||
|
||||
import { RouterService } from "../../../core";
|
||||
import { AcceptOrganizationInviteService } from "../../organization-invite/accept-organization.service";
|
||||
@Component({
|
||||
selector: "web-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 {
|
||||
protected routerService = inject(RouterService);
|
||||
protected acceptOrganizationInviteService = inject(AcceptOrganizationInviteService);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CheckboxModule } from "@bitwarden/components";
|
||||
|
||||
import { SharedModule } from "../../../app/shared";
|
||||
|
||||
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";
|
||||
import { LoginViaWebAuthnComponent } from "./login-via-webauthn/login-via-webauthn.component";
|
||||
@@ -14,13 +14,13 @@ import { LoginViaWebAuthnComponent } from "./login-via-webauthn/login-via-webaut
|
||||
declarations: [
|
||||
LoginComponentV1,
|
||||
LoginViaAuthRequestComponentV1,
|
||||
LoginDecryptionOptionsComponent,
|
||||
LoginDecryptionOptionsComponentV1,
|
||||
LoginViaWebAuthnComponent,
|
||||
],
|
||||
exports: [
|
||||
LoginComponentV1,
|
||||
LoginViaAuthRequestComponentV1,
|
||||
LoginDecryptionOptionsComponent,
|
||||
LoginDecryptionOptionsComponentV1,
|
||||
LoginViaWebAuthnComponent,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { EmailTokenRequest } from "@bitwarden/common/auth/models/request/email-token.request";
|
||||
import { EmailRequest } from "@bitwarden/common/auth/models/request/email.request";
|
||||
@@ -12,7 +11,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
@Component({
|
||||
selector: "app-change-email",
|
||||
|
||||
@@ -7,7 +7,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.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 { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
@@ -23,7 +22,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
||||
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 { UserKeyRotationService } from "../../key-management/key-rotation/user-key-rotation.service";
|
||||
|
||||
|
||||
@@ -6,17 +6,15 @@ import { takeUntil } from "rxjs";
|
||||
import { ChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component";
|
||||
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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { KdfType, KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { EmergencyAccessService } from "../../../emergency-access";
|
||||
|
||||
|
||||
@@ -5,14 +5,12 @@ import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfRequest } from "@bitwarden/common/models/request/kdf.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 { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { KdfConfig, KdfType, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
@Component({
|
||||
selector: "app-change-kdf-confirmation",
|
||||
|
||||
@@ -2,15 +2,15 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, ValidatorFn, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import {
|
||||
KdfConfigService,
|
||||
Argon2KdfConfig,
|
||||
DEFAULT_KDF_CONFIG,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
KdfType,
|
||||
} from "@bitwarden/key-management";
|
||||
|
||||
import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.component";
|
||||
|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
</ng-container>
|
||||
<!-- Bank Account -->
|
||||
<ng-container *ngIf="showBankAccount && usingBankAccount">
|
||||
<app-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||
{{ "verifyBankAccountInitialDesc" | i18n }} {{ "verifyBankAccountFailureWarning" | i18n }}
|
||||
</app-callout>
|
||||
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||
{{ "verifyBankAccountWithStatementDescriptorWarning" | i18n }}
|
||||
</bit-callout>
|
||||
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankInformation">
|
||||
<bit-form-field class="tw-col-span-1" disableMargin>
|
||||
<bit-label>{{ "routingNumber" | i18n }}</bit-label>
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
<app-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||
<p>{{ "verifyBankAccountDesc" | i18n }} {{ "verifyBankAccountFailureWarning" | i18n }}</p>
|
||||
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||
<p>{{ "verifyBankAccountWithStatementDescriptorInstructions" | i18n }}</p>
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-form-field class="tw-mr-2 tw-w-40">
|
||||
<bit-label>{{ "amountX" | i18n: "1" }}</bit-label>
|
||||
<input bitInput type="number" step="1" placeholder="xx" formControlName="amount1" />
|
||||
<span bitPrefix>$0.</span>
|
||||
</bit-form-field>
|
||||
<bit-form-field class="tw-mr-2 tw-w-40">
|
||||
<bit-label>{{ "amountX" | i18n: "2" }}</bit-label>
|
||||
<input bitInput type="number" step="1" placeholder="xx" formControlName="amount2" />
|
||||
<span bitPrefix>$0.</span>
|
||||
<bit-form-field class="tw-mr-2 tw-w-48">
|
||||
<bit-label>{{ "descriptorCode" | i18n }}</bit-label>
|
||||
<input bitInput type="text" placeholder="SMAB12" formControlName="descriptorCode" />
|
||||
</bit-form-field>
|
||||
<button *ngIf="onSubmit" type="submit" bitButton bitFormButton buttonType="primary">
|
||||
{{ "submit" | i18n }}
|
||||
</button>
|
||||
</form>
|
||||
</app-callout>
|
||||
</bit-callout>
|
||||
|
||||
@@ -16,25 +16,17 @@ export class VerifyBankAccountComponent {
|
||||
@Output() submitted = new EventEmitter();
|
||||
|
||||
protected formGroup = this.formBuilder.group({
|
||||
amount1: new FormControl<number>(null, [
|
||||
descriptorCode: new FormControl<string>(null, [
|
||||
Validators.required,
|
||||
Validators.min(0),
|
||||
Validators.max(99),
|
||||
]),
|
||||
amount2: new FormControl<number>(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();
|
||||
};
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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<void> {
|
||||
this.window.location.reload();
|
||||
}
|
||||
|
||||
cancelProcessReload(): void {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -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[],
|
||||
},
|
||||
|
||||
@@ -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[],
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
</head>
|
||||
<body class="layout_frontend">
|
||||
<app-root>
|
||||
<!-- Note: any changes to this html need to be made in the app.component.html as well -->
|
||||
<div class="tw-p-8 tw-flex">
|
||||
<img class="new-logo-themed" alt="Bitwarden" />
|
||||
<div class="spinner-container tw-justify-center">
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<void>();
|
||||
|
||||
protected State = State;
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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(["/"]);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<MessagingService>;
|
||||
|
||||
beforeEach(() => {
|
||||
messagingService = mock<MessagingService>();
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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<void | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
async logOut(): Promise<void> {
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<ng-container *ngIf="loading">
|
||||
<div class="text-center">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-2x tw-text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<form *ngIf="!loading" [formGroup]="formGroup">
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox formControlName="rememberDevice" />
|
||||
<bit-label>{{ "rememberThisDevice" | i18n }}</bit-label>
|
||||
<bit-hint bitTypography="body2">{{ "uncheckIfPublicDevice" | i18n }}</bit-hint>
|
||||
</bit-form-control>
|
||||
</form>
|
||||
|
||||
<ng-container *ngIf="state === State.NewUser">
|
||||
<button type="button" bitButton block buttonType="primary" [bitAction]="createUser">
|
||||
{{ "continue" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="state === State.ExistingUserUntrustedDevice">
|
||||
<div class="tw-grid tw-gap-3">
|
||||
<ng-container *ngIf="canApproveFromOtherDevice">
|
||||
<button type="button" bitButton block buttonType="primary" (click)="approveFromOtherDevice()">
|
||||
{{ "approveFromYourOtherDevice" | i18n }}
|
||||
</button>
|
||||
|
||||
<div *ngIf="canApproveWithMasterPassword || canRequestAdminApproval" class="tw-text-center">
|
||||
{{ "or" | i18n }}
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
*ngIf="canApproveWithMasterPassword"
|
||||
type="button"
|
||||
bitButton
|
||||
block
|
||||
buttonType="secondary"
|
||||
(click)="approveWithMasterPassword()"
|
||||
>
|
||||
{{ "useMasterPassword" | i18n }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
*ngIf="canRequestAdminApproval"
|
||||
type="button"
|
||||
bitButton
|
||||
block
|
||||
buttonType="secondary"
|
||||
(click)="requestAdminApproval()"
|
||||
>
|
||||
{{ "requestAdminApproval" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
@@ -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<boolean> {
|
||||
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"]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export abstract class LoginDecryptionOptionsService {
|
||||
/**
|
||||
* Handles client-specific logic that runs after a user was successfully created
|
||||
*/
|
||||
abstract handleCreateUserSuccess(): Promise<void | null>;
|
||||
/**
|
||||
* Logs the user out
|
||||
*/
|
||||
abstract logOut(): Promise<void>;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user