mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 09:43:23 +00:00
[PM-5189] Merging main into current branch
This commit is contained in:
@@ -191,6 +191,15 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"files": ["libs/tools/export/vault-export/vault-export-ui/src/**/*.ts"],
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{ "patterns": ["@bitwarden/vault-export-ui/*", "src/**/*"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"files": ["libs/importer/src/**/*.ts"],
|
"files": ["libs/importer/src/**/*.ts"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import {
|
|||||||
factory,
|
factory,
|
||||||
} from "../../../platform/background/service-factories/factory-options";
|
} from "../../../platform/background/service-factories/factory-options";
|
||||||
import {
|
import {
|
||||||
messagingServiceFactory,
|
|
||||||
MessagingServiceInitOptions,
|
MessagingServiceInitOptions,
|
||||||
|
messagingServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/messaging-service.factory";
|
} from "../../../platform/background/service-factories/messaging-service.factory";
|
||||||
import {
|
import {
|
||||||
StateServiceInitOptions,
|
StateServiceInitOptions,
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ import {
|
|||||||
stateServiceFactory,
|
stateServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-service.factory";
|
||||||
|
|
||||||
|
import {
|
||||||
|
UserDecryptionOptionsServiceInitOptions,
|
||||||
|
userDecryptionOptionsServiceFactory,
|
||||||
|
} from "./user-decryption-options-service.factory";
|
||||||
|
|
||||||
type DeviceTrustCryptoServiceFactoryOptions = FactoryOptions;
|
type DeviceTrustCryptoServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactoryOptions &
|
export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactoryOptions &
|
||||||
@@ -54,7 +59,8 @@ export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactor
|
|||||||
AppIdServiceInitOptions &
|
AppIdServiceInitOptions &
|
||||||
DevicesApiServiceInitOptions &
|
DevicesApiServiceInitOptions &
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
PlatformUtilsServiceInitOptions;
|
PlatformUtilsServiceInitOptions &
|
||||||
|
UserDecryptionOptionsServiceInitOptions;
|
||||||
|
|
||||||
export function deviceTrustCryptoServiceFactory(
|
export function deviceTrustCryptoServiceFactory(
|
||||||
cache: { deviceTrustCryptoService?: DeviceTrustCryptoServiceAbstraction } & CachedServices,
|
cache: { deviceTrustCryptoService?: DeviceTrustCryptoServiceAbstraction } & CachedServices,
|
||||||
@@ -75,6 +81,7 @@ export function deviceTrustCryptoServiceFactory(
|
|||||||
await devicesApiServiceFactory(cache, opts),
|
await devicesApiServiceFactory(cache, opts),
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await platformUtilsServiceFactory(cache, opts),
|
await platformUtilsServiceFactory(cache, opts),
|
||||||
|
await userDecryptionOptionsServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import {
|
|||||||
ApiServiceInitOptions,
|
ApiServiceInitOptions,
|
||||||
} from "../../../platform/background/service-factories/api-service.factory";
|
} from "../../../platform/background/service-factories/api-service.factory";
|
||||||
import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory";
|
import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory";
|
||||||
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
|
import {
|
||||||
|
billingAccountProfileStateServiceFactory,
|
||||||
|
BillingAccountProfileStateServiceInitOptions,
|
||||||
|
} from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
|
||||||
import {
|
import {
|
||||||
CryptoServiceInitOptions,
|
CryptoServiceInitOptions,
|
||||||
cryptoServiceFactory,
|
cryptoServiceFactory,
|
||||||
@@ -70,6 +73,10 @@ import {
|
|||||||
} from "./key-connector-service.factory";
|
} from "./key-connector-service.factory";
|
||||||
import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory";
|
import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory";
|
||||||
import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory";
|
import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory";
|
||||||
|
import {
|
||||||
|
internalUserDecryptionOptionServiceFactory,
|
||||||
|
UserDecryptionOptionsServiceInitOptions,
|
||||||
|
} from "./user-decryption-options-service.factory";
|
||||||
|
|
||||||
type LoginStrategyServiceFactoryOptions = FactoryOptions;
|
type LoginStrategyServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
@@ -90,7 +97,9 @@ export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions
|
|||||||
PasswordStrengthServiceInitOptions &
|
PasswordStrengthServiceInitOptions &
|
||||||
DeviceTrustCryptoServiceInitOptions &
|
DeviceTrustCryptoServiceInitOptions &
|
||||||
AuthRequestServiceInitOptions &
|
AuthRequestServiceInitOptions &
|
||||||
GlobalStateProviderInitOptions;
|
UserDecryptionOptionsServiceInitOptions &
|
||||||
|
GlobalStateProviderInitOptions &
|
||||||
|
BillingAccountProfileStateServiceInitOptions;
|
||||||
|
|
||||||
export function loginStrategyServiceFactory(
|
export function loginStrategyServiceFactory(
|
||||||
cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices,
|
cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices,
|
||||||
@@ -119,6 +128,7 @@ export function loginStrategyServiceFactory(
|
|||||||
await policyServiceFactory(cache, opts),
|
await policyServiceFactory(cache, opts),
|
||||||
await deviceTrustCryptoServiceFactory(cache, opts),
|
await deviceTrustCryptoServiceFactory(cache, opts),
|
||||||
await authRequestServiceFactory(cache, opts),
|
await authRequestServiceFactory(cache, opts),
|
||||||
|
await internalUserDecryptionOptionServiceFactory(cache, opts),
|
||||||
await globalStateProviderFactory(cache, opts),
|
await globalStateProviderFactory(cache, opts),
|
||||||
await billingAccountProfileStateServiceFactory(cache, opts),
|
await billingAccountProfileStateServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
UserDecryptionOptionsService,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CachedServices,
|
||||||
|
factory,
|
||||||
|
FactoryOptions,
|
||||||
|
} from "../../../platform/background/service-factories/factory-options";
|
||||||
|
import {
|
||||||
|
stateProviderFactory,
|
||||||
|
StateProviderInitOptions,
|
||||||
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
|
type UserDecryptionOptionsServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type UserDecryptionOptionsServiceInitOptions = UserDecryptionOptionsServiceFactoryOptions &
|
||||||
|
StateProviderInitOptions;
|
||||||
|
|
||||||
|
export function userDecryptionOptionsServiceFactory(
|
||||||
|
cache: {
|
||||||
|
userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction;
|
||||||
|
} & CachedServices,
|
||||||
|
opts: UserDecryptionOptionsServiceInitOptions,
|
||||||
|
): Promise<UserDecryptionOptionsServiceAbstraction> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"userDecryptionOptionsService",
|
||||||
|
opts,
|
||||||
|
async () => new UserDecryptionOptionsService(await stateProviderFactory(cache, opts)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function internalUserDecryptionOptionServiceFactory(
|
||||||
|
cache: {
|
||||||
|
userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction;
|
||||||
|
} & CachedServices,
|
||||||
|
opts: UserDecryptionOptionsServiceInitOptions,
|
||||||
|
): Promise<InternalUserDecryptionOptionsServiceAbstraction> {
|
||||||
|
return (await userDecryptionOptionsServiceFactory(
|
||||||
|
cache,
|
||||||
|
opts,
|
||||||
|
)) as InternalUserDecryptionOptionsServiceAbstraction;
|
||||||
|
}
|
||||||
@@ -32,6 +32,10 @@ import {
|
|||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-service.factory";
|
||||||
|
|
||||||
import { PinCryptoServiceInitOptions, pinCryptoServiceFactory } from "./pin-crypto-service.factory";
|
import { PinCryptoServiceInitOptions, pinCryptoServiceFactory } from "./pin-crypto-service.factory";
|
||||||
|
import {
|
||||||
|
userDecryptionOptionsServiceFactory,
|
||||||
|
UserDecryptionOptionsServiceInitOptions,
|
||||||
|
} from "./user-decryption-options-service.factory";
|
||||||
import {
|
import {
|
||||||
UserVerificationApiServiceInitOptions,
|
UserVerificationApiServiceInitOptions,
|
||||||
userVerificationApiServiceFactory,
|
userVerificationApiServiceFactory,
|
||||||
@@ -44,6 +48,7 @@ export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryO
|
|||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
UserVerificationApiServiceInitOptions &
|
UserVerificationApiServiceInitOptions &
|
||||||
|
UserDecryptionOptionsServiceInitOptions &
|
||||||
PinCryptoServiceInitOptions &
|
PinCryptoServiceInitOptions &
|
||||||
LogServiceInitOptions &
|
LogServiceInitOptions &
|
||||||
VaultTimeoutSettingsServiceInitOptions &
|
VaultTimeoutSettingsServiceInitOptions &
|
||||||
@@ -63,6 +68,7 @@ export function userVerificationServiceFactory(
|
|||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await userVerificationApiServiceFactory(cache, opts),
|
await userVerificationApiServiceFactory(cache, opts),
|
||||||
|
await userDecryptionOptionsServiceFactory(cache, opts),
|
||||||
await pinCryptoServiceFactory(cache, opts),
|
await pinCryptoServiceFactory(cache, opts),
|
||||||
await logServiceFactory(cache, opts),
|
await logServiceFactory(cache, opts),
|
||||||
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
|||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
@@ -37,6 +38,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
|||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
organizationApiService: OrganizationApiServiceAbstraction,
|
organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
organizationUserService: OrganizationUserService,
|
organizationUserService: OrganizationUserService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
) {
|
) {
|
||||||
@@ -55,6 +57,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
|||||||
stateService,
|
stateService,
|
||||||
organizationApiService,
|
organizationApiService,
|
||||||
organizationUserService,
|
organizationUserService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
dialogService,
|
dialogService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
|
|
||||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
@@ -39,6 +42,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
syncService: SyncService,
|
syncService: SyncService,
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
@Inject(WINDOW) private win: Window,
|
@Inject(WINDOW) private win: Window,
|
||||||
@@ -56,6 +60,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
environmentService,
|
environmentService,
|
||||||
passwordGenerationService,
|
passwordGenerationService,
|
||||||
logService,
|
logService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
|
|
||||||
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
|
||||||
@@ -16,9 +17,10 @@ export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent {
|
|||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
environmentService: EnvironmentService,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
) {
|
) {
|
||||||
super(twoFactorService, router, i18nService, platformUtilsService, window);
|
super(twoFactorService, router, i18nService, platformUtilsService, window, environmentService);
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ import { filter, first, takeUntil } from "rxjs/operators";
|
|||||||
|
|
||||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
@@ -55,6 +58,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
appIdService: AppIdService,
|
appIdService: AppIdService,
|
||||||
loginService: LoginService,
|
loginService: LoginService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
@@ -75,6 +79,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
twoFactorService,
|
twoFactorService,
|
||||||
appIdService,
|
appIdService,
|
||||||
loginService,
|
loginService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -625,6 +625,22 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
* Updates the position of the overlay button.
|
* Updates the position of the overlay button.
|
||||||
*/
|
*/
|
||||||
private updateOverlayButtonPosition() {
|
private updateOverlayButtonPosition() {
|
||||||
|
// if (!this.overlayButtonElement) {
|
||||||
|
// this.createAutofillOverlayButton();
|
||||||
|
// this.updateCustomElementDefaultStyles(this.overlayButtonElement);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!this.isOverlayButtonVisible) {
|
||||||
|
// this.appendOverlayElementToBody(this.overlayButtonElement);
|
||||||
|
// this.isOverlayButtonVisible = true;
|
||||||
|
// this.setOverlayRepositionEventListeners();
|
||||||
|
// }
|
||||||
|
// // 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.sendExtensionMessage("updateAutofillOverlayPosition", {
|
||||||
|
// overlayElement: AutofillOverlayElement.Button,
|
||||||
|
// });
|
||||||
|
|
||||||
void this.sendExtensionMessage("updateAutofillOverlayPosition", {
|
void this.sendExtensionMessage("updateAutofillOverlayPosition", {
|
||||||
overlayElement: AutofillOverlayElement.Button,
|
overlayElement: AutofillOverlayElement.Button,
|
||||||
});
|
});
|
||||||
@@ -634,6 +650,22 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
* Updates the position of the overlay list.
|
* Updates the position of the overlay list.
|
||||||
*/
|
*/
|
||||||
private updateOverlayListPosition() {
|
private updateOverlayListPosition() {
|
||||||
|
// if (!this.overlayListElement) {
|
||||||
|
// this.createAutofillOverlayList();
|
||||||
|
// this.updateCustomElementDefaultStyles(this.overlayListElement);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!this.isOverlayListVisible) {
|
||||||
|
// this.appendOverlayElementToBody(this.overlayListElement);
|
||||||
|
// this.isOverlayListVisible = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 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.sendExtensionMessage("updateAutofillOverlayPosition", {
|
||||||
|
// overlayElement: AutofillOverlayElement.List,
|
||||||
|
// });
|
||||||
|
|
||||||
void this.sendExtensionMessage("updateAutofillOverlayPosition", {
|
void this.sendExtensionMessage("updateAutofillOverlayPosition", {
|
||||||
overlayElement: AutofillOverlayElement.List,
|
overlayElement: AutofillOverlayElement.List,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
PinCryptoService,
|
PinCryptoService,
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
LoginStrategyService,
|
LoginStrategyService,
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
UserDecryptionOptionsService,
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
AuthRequestService,
|
AuthRequestService,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
@@ -242,6 +244,7 @@ export default class MainBackground {
|
|||||||
environmentService: BrowserEnvironmentService;
|
environmentService: BrowserEnvironmentService;
|
||||||
cipherService: CipherServiceAbstraction;
|
cipherService: CipherServiceAbstraction;
|
||||||
folderService: InternalFolderServiceAbstraction;
|
folderService: InternalFolderServiceAbstraction;
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction;
|
||||||
collectionService: CollectionServiceAbstraction;
|
collectionService: CollectionServiceAbstraction;
|
||||||
vaultTimeoutService: VaultTimeoutService;
|
vaultTimeoutService: VaultTimeoutService;
|
||||||
vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction;
|
vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction;
|
||||||
@@ -539,6 +542,8 @@ export default class MainBackground {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
||||||
|
|
||||||
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
||||||
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
@@ -550,6 +555,7 @@ export default class MainBackground {
|
|||||||
this.devicesApiService,
|
this.devicesApiService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.devicesService = new DevicesServiceImplementation(this.devicesApiService);
|
this.devicesService = new DevicesServiceImplementation(this.devicesApiService);
|
||||||
@@ -590,6 +596,7 @@ export default class MainBackground {
|
|||||||
this.policyService,
|
this.policyService,
|
||||||
this.deviceTrustCryptoService,
|
this.deviceTrustCryptoService,
|
||||||
this.authRequestService,
|
this.authRequestService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
@@ -631,6 +638,7 @@ export default class MainBackground {
|
|||||||
this.folderApiService = new FolderApiService(this.folderService, this.apiService);
|
this.folderApiService = new FolderApiService(this.folderService, this.apiService);
|
||||||
|
|
||||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
this.policyService,
|
this.policyService,
|
||||||
@@ -650,6 +658,7 @@ export default class MainBackground {
|
|||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.userVerificationApiService,
|
this.userVerificationApiService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.pinCryptoService,
|
this.pinCryptoService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.vaultTimeoutSettingsService,
|
this.vaultTimeoutSettingsService,
|
||||||
@@ -717,6 +726,7 @@ export default class MainBackground {
|
|||||||
this.folderApiService,
|
this.folderApiService,
|
||||||
this.organizationService,
|
this.organizationService,
|
||||||
this.sendApiService,
|
this.sendApiService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.avatarService,
|
this.avatarService,
|
||||||
logoutCallback,
|
logoutCallback,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import {
|
|||||||
tokenServiceFactory,
|
tokenServiceFactory,
|
||||||
TokenServiceInitOptions,
|
TokenServiceInitOptions,
|
||||||
} from "../../auth/background/service-factories/token-service.factory";
|
} from "../../auth/background/service-factories/token-service.factory";
|
||||||
|
import {
|
||||||
|
userDecryptionOptionsServiceFactory,
|
||||||
|
UserDecryptionOptionsServiceInitOptions,
|
||||||
|
} from "../../auth/background/service-factories/user-decryption-options-service.factory";
|
||||||
import {
|
import {
|
||||||
biometricStateServiceFactory,
|
biometricStateServiceFactory,
|
||||||
BiometricStateServiceInitOptions,
|
BiometricStateServiceInitOptions,
|
||||||
@@ -30,6 +34,7 @@ import {
|
|||||||
type VaultTimeoutSettingsServiceFactoryOptions = FactoryOptions;
|
type VaultTimeoutSettingsServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type VaultTimeoutSettingsServiceInitOptions = VaultTimeoutSettingsServiceFactoryOptions &
|
export type VaultTimeoutSettingsServiceInitOptions = VaultTimeoutSettingsServiceFactoryOptions &
|
||||||
|
UserDecryptionOptionsServiceInitOptions &
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
TokenServiceInitOptions &
|
TokenServiceInitOptions &
|
||||||
PolicyServiceInitOptions &
|
PolicyServiceInitOptions &
|
||||||
@@ -46,6 +51,7 @@ export function vaultTimeoutSettingsServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new VaultTimeoutSettingsService(
|
new VaultTimeoutSettingsService(
|
||||||
|
await userDecryptionOptionsServiceFactory(cache, opts),
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await tokenServiceFactory(cache, opts),
|
await tokenServiceFactory(cache, opts),
|
||||||
await policyServiceFactory(cache, opts),
|
await policyServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|||||||
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||||
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||||
import { AvatarModule, ButtonModule } from "@bitwarden/components";
|
import { AvatarModule, ButtonModule } from "@bitwarden/components";
|
||||||
|
import { ExportScopeCalloutComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
|
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
|
||||||
import { AccountComponent } from "../auth/popup/account-switching/account.component";
|
import { AccountComponent } from "../auth/popup/account-switching/account.component";
|
||||||
@@ -107,6 +108,7 @@ import "../platform/popup/locales";
|
|||||||
AvatarModule,
|
AvatarModule,
|
||||||
AccountComponent,
|
AccountComponent,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
ExportScopeCalloutComponent,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ActionButtonsComponent,
|
ActionButtonsComponent,
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ import {
|
|||||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
|
||||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
||||||
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
@@ -96,7 +95,6 @@ import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/vau
|
|||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { ImportServiceAbstraction } from "@bitwarden/importer/core";
|
|
||||||
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
||||||
|
|
||||||
import { UnauthGuardService } from "../../auth/popup/services";
|
import { UnauthGuardService } from "../../auth/popup/services";
|
||||||
@@ -292,11 +290,6 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
},
|
},
|
||||||
deps: [DomSanitizer, ToastrService],
|
deps: [DomSanitizer, ToastrService],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
provide: PasswordStrengthServiceAbstraction,
|
|
||||||
useFactory: getBgService<PasswordStrengthServiceAbstraction>("passwordStrengthService"),
|
|
||||||
deps: [],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
provide: PasswordGenerationServiceAbstraction,
|
provide: PasswordGenerationServiceAbstraction,
|
||||||
useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"),
|
useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"),
|
||||||
@@ -350,11 +343,6 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
useFactory: getBgService<AutofillService>("autofillService"),
|
useFactory: getBgService<AutofillService>("autofillService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
provide: ImportServiceAbstraction,
|
|
||||||
useFactory: getBgService<ImportServiceAbstraction>("importService"),
|
|
||||||
deps: [],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
provide: VaultExportServiceAbstraction,
|
provide: VaultExportServiceAbstraction,
|
||||||
useFactory: getBgService<VaultExportServiceAbstraction>("exportService"),
|
useFactory: getBgService<VaultExportServiceAbstraction>("exportService"),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<app-callout type="warning" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
|
<app-callout type="warning" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
|
||||||
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
||||||
</app-callout>
|
</app-callout>
|
||||||
<app-export-scope-callout *ngIf="!disabledByPolicy"></app-export-scope-callout>
|
<tools-export-scope-callout *ngIf="!disabledByPolicy"></tools-export-scope-callout>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ActivatedRoute } from "@angular/router";
|
|||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||||
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -21,11 +22,19 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
|||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
|
organizationService: OrganizationService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
) {
|
) {
|
||||||
super(collectionService, platformUtilsService, i18nService, cipherService, logService);
|
super(
|
||||||
|
collectionService,
|
||||||
|
platformUtilsService,
|
||||||
|
i18nService,
|
||||||
|
cipherService,
|
||||||
|
organizationService,
|
||||||
|
logService,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@bitwarden/vault-export-core": [
|
"@bitwarden/vault-export-core": [
|
||||||
"../../libs/tools/export/vault-export/vault-export-core/src"
|
"../../libs/tools/export/vault-export/vault-export-core/src"
|
||||||
],
|
],
|
||||||
|
"@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"],
|
||||||
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
||||||
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
||||||
"@bitwarden/platform": ["../../libs/platform/src"],
|
"@bitwarden/platform": ["../../libs/platform/src"],
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import { program } from "commander";
|
|||||||
import * as jsdom from "jsdom";
|
import * as jsdom from "jsdom";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
AuthRequestService,
|
AuthRequestService,
|
||||||
LoginStrategyService,
|
LoginStrategyService,
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
PinCryptoService,
|
PinCryptoService,
|
||||||
PinCryptoServiceAbstraction,
|
PinCryptoServiceAbstraction,
|
||||||
|
UserDecryptionOptionsService,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
|
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
|
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||||
@@ -169,6 +171,7 @@ export class Main {
|
|||||||
eventUploadService: EventUploadServiceAbstraction;
|
eventUploadService: EventUploadServiceAbstraction;
|
||||||
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
||||||
passwordStrengthService: PasswordStrengthServiceAbstraction;
|
passwordStrengthService: PasswordStrengthServiceAbstraction;
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction;
|
||||||
totpService: TotpService;
|
totpService: TotpService;
|
||||||
containerService: ContainerService;
|
containerService: ContainerService;
|
||||||
auditService: AuditService;
|
auditService: AuditService;
|
||||||
@@ -436,6 +439,8 @@ export class Main {
|
|||||||
this.stateService,
|
this.stateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
||||||
|
|
||||||
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
||||||
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
@@ -447,6 +452,7 @@ export class Main {
|
|||||||
this.devicesApiService,
|
this.devicesApiService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.authRequestService = new AuthRequestService(
|
this.authRequestService = new AuthRequestService(
|
||||||
@@ -478,6 +484,7 @@ export class Main {
|
|||||||
this.policyService,
|
this.policyService,
|
||||||
this.deviceTrustCryptoService,
|
this.deviceTrustCryptoService,
|
||||||
this.authRequestService,
|
this.authRequestService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
@@ -529,6 +536,7 @@ export class Main {
|
|||||||
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
|
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
|
||||||
|
|
||||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
this.policyService,
|
this.policyService,
|
||||||
@@ -548,6 +556,7 @@ export class Main {
|
|||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.userVerificationApiService,
|
this.userVerificationApiService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.pinCryptoService,
|
this.pinCryptoService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.vaultTimeoutSettingsService,
|
this.vaultTimeoutSettingsService,
|
||||||
@@ -589,6 +598,7 @@ export class Main {
|
|||||||
this.folderApiService,
|
this.folderApiService,
|
||||||
this.organizationService,
|
this.organizationService,
|
||||||
this.sendApiService,
|
this.sendApiService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.avatarService,
|
this.avatarService,
|
||||||
async (expired: boolean) => await this.logout(),
|
async (expired: boolean) => await this.logout(),
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
|
|||||||
4
apps/desktop/desktop_native/Cargo.lock
generated
4
apps/desktop/desktop_native/Cargo.lock
generated
@@ -84,9 +84,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.5"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ manual_test = []
|
|||||||
aes = "=0.8.4"
|
aes = "=0.8.4"
|
||||||
anyhow = "=1.0.80"
|
anyhow = "=1.0.80"
|
||||||
arboard = { version = "=3.3.0", default-features = false, features = ["wayland-data-control"] }
|
arboard = { version = "=3.3.0", default-features = false, features = ["wayland-data-control"] }
|
||||||
base64 = "=0.21.5"
|
base64 = "=0.22.0"
|
||||||
cbc = { version = "=0.1.2", features = ["alloc"] }
|
cbc = { version = "=0.1.2", features = ["alloc"] }
|
||||||
napi = { version = "=2.13.3", features = ["async"] }
|
napi = { version = "=2.13.3", features = ["async"] }
|
||||||
napi-derive = "=2.13.0"
|
napi-derive = "=2.13.0"
|
||||||
|
|||||||
@@ -412,6 +412,23 @@
|
|||||||
"enableBrowserIntegrationFingerprintDesc" | i18n
|
"enableBrowserIntegrationFingerprintDesc" | i18n
|
||||||
}}</small>
|
}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label for="enableHardwareAcceleration">
|
||||||
|
<input
|
||||||
|
id="enableHardwareAcceleration"
|
||||||
|
type="checkbox"
|
||||||
|
aria-describedby="enableHardwareAccelerationHelp"
|
||||||
|
formControlName="enableHardwareAcceleration"
|
||||||
|
(change)="saveHardwareAcceleration()"
|
||||||
|
/>
|
||||||
|
{{ "enableHardwareAcceleration" | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<small id="enableHardwareAccelerationHelp" class="help-block">{{
|
||||||
|
"enableHardwareAccelerationDesc" | i18n
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
<div class="form-group" *ngIf="showDuckDuckGoIntegrationOption">
|
<div class="form-group" *ngIf="showDuckDuckGoIntegrationOption">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label for="enableDuckDuckGoBrowserIntegration">
|
<label for="enableDuckDuckGoBrowserIntegration">
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { DialogService } from "@bitwarden/components";
|
|||||||
|
|
||||||
import { SetPinComponent } from "../../auth/components/set-pin.component";
|
import { SetPinComponent } from "../../auth/components/set-pin.component";
|
||||||
import { flagEnabled } from "../../platform/flags";
|
import { flagEnabled } from "../../platform/flags";
|
||||||
|
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-settings",
|
selector: "app-settings",
|
||||||
@@ -96,6 +97,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
value: false,
|
value: false,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
}),
|
}),
|
||||||
|
enableHardwareAcceleration: true,
|
||||||
enableDuckDuckGoBrowserIntegration: false,
|
enableDuckDuckGoBrowserIntegration: false,
|
||||||
theme: [null as ThemeType | null],
|
theme: [null as ThemeType | null],
|
||||||
locale: [null as string | null],
|
locale: [null as string | null],
|
||||||
@@ -119,6 +121,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private userVerificationService: UserVerificationServiceAbstraction,
|
private userVerificationService: UserVerificationServiceAbstraction,
|
||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
|
private desktopSettingsService: DesktopSettingsService,
|
||||||
) {
|
) {
|
||||||
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||||
|
|
||||||
@@ -259,6 +262,9 @@ export class SettingsComponent implements OnInit {
|
|||||||
enableBrowserIntegration: await this.stateService.getEnableBrowserIntegration(),
|
enableBrowserIntegration: await this.stateService.getEnableBrowserIntegration(),
|
||||||
enableBrowserIntegrationFingerprint:
|
enableBrowserIntegrationFingerprint:
|
||||||
await this.stateService.getEnableBrowserIntegrationFingerprint(),
|
await this.stateService.getEnableBrowserIntegrationFingerprint(),
|
||||||
|
enableHardwareAcceleration: await firstValueFrom(
|
||||||
|
this.desktopSettingsService.hardwareAcceleration$,
|
||||||
|
),
|
||||||
enableDuckDuckGoBrowserIntegration:
|
enableDuckDuckGoBrowserIntegration:
|
||||||
await this.stateService.getEnableDuckDuckGoBrowserIntegration(),
|
await this.stateService.getEnableDuckDuckGoBrowserIntegration(),
|
||||||
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
||||||
@@ -655,6 +661,12 @@ export class SettingsComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveHardwareAcceleration() {
|
||||||
|
await this.desktopSettingsService.setHardwareAcceleration(
|
||||||
|
this.form.value.enableHardwareAcceleration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async updateApproveLoginRequests() {
|
async updateApproveLoginRequests() {
|
||||||
await this.stateService.setApproveLoginRequests(this.form.value.approveLoginRequests);
|
await this.stateService.setApproveLoginRequests(this.form.value.approveLoginRequests);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { NgModule } from "@angular/core";
|
|||||||
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||||
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||||
import { DialogModule } from "@bitwarden/components";
|
import { DialogModule } from "@bitwarden/components";
|
||||||
|
import { ExportScopeCalloutComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
import { AccessibilityCookieComponent } from "../auth/accessibility-cookie.component";
|
import { AccessibilityCookieComponent } from "../auth/accessibility-cookie.component";
|
||||||
import { DeleteAccountComponent } from "../auth/delete-account.component";
|
import { DeleteAccountComponent } from "../auth/delete-account.component";
|
||||||
@@ -61,6 +62,7 @@ import { SendComponent } from "./tools/send/send.component";
|
|||||||
DialogModule,
|
DialogModule,
|
||||||
DeleteAccountComponent,
|
DeleteAccountComponent,
|
||||||
UserVerificationComponent,
|
UserVerificationComponent,
|
||||||
|
ExportScopeCalloutComponent,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AccessibilityCookieComponent,
|
AccessibilityCookieComponent,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import { DialogService } from "@bitwarden/components";
|
|||||||
|
|
||||||
import { LoginGuard } from "../../auth/guards/login.guard";
|
import { LoginGuard } from "../../auth/guards/login.guard";
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
|
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
||||||
import { ElectronCryptoService } from "../../platform/services/electron-crypto.service";
|
import { ElectronCryptoService } from "../../platform/services/electron-crypto.service";
|
||||||
import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service";
|
import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service";
|
||||||
import {
|
import {
|
||||||
@@ -212,6 +213,11 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
BiometricStateService,
|
BiometricStateService,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: DesktopSettingsService,
|
||||||
|
useClass: DesktopSettingsService,
|
||||||
|
deps: [StateProvider],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ServicesModule {}
|
export class ServicesModule {}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
>
|
>
|
||||||
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
||||||
</app-callout>
|
</app-callout>
|
||||||
<app-export-scope-callout *ngIf="!disabledByPolicy"></app-export-scope-callout>
|
<tools-export-scope-callout *ngIf="!disabledByPolicy"></tools-export-scope-callout>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<h1 class="box-header" id="exportTitle">
|
<h1 class="box-header" id="exportTitle">
|
||||||
{{ "exportVault" | i18n }}
|
{{ "exportVault" | i18n }}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component, NgZone, OnDestroy } from "@angular/core";
|
|||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
@@ -44,6 +45,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
|
|||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
organizationApiService: OrganizationApiServiceAbstraction,
|
organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
organizationUserService: OrganizationUserService,
|
organizationUserService: OrganizationUserService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
) {
|
) {
|
||||||
@@ -62,6 +64,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
|
|||||||
stateService,
|
stateService,
|
||||||
organizationApiService,
|
organizationApiService,
|
||||||
organizationUserService,
|
organizationUserService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
dialogService,
|
dialogService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { Component } from "@angular/core";
|
|||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
@@ -34,6 +37,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -49,6 +53,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
environmentService,
|
environmentService,
|
||||||
passwordGenerationService,
|
passwordGenerationService,
|
||||||
logService,
|
logService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = async () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Router } from "@angular/router";
|
|||||||
|
|
||||||
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent {
|
|||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
environmentService: EnvironmentService,
|
||||||
) {
|
) {
|
||||||
super(twoFactorService, router, i18nService, platformUtilsService, window);
|
super(twoFactorService, router, i18nService, platformUtilsService, window, environmentService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
@@ -53,6 +56,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
appIdService: AppIdService,
|
appIdService: AppIdService,
|
||||||
loginService: LoginService,
|
loginService: LoginService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
@@ -71,6 +75,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
twoFactorService,
|
twoFactorService,
|
||||||
appIdService,
|
appIdService,
|
||||||
loginService,
|
loginService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1644,6 +1644,12 @@
|
|||||||
"enableBrowserIntegrationFingerprintDesc": {
|
"enableBrowserIntegrationFingerprintDesc": {
|
||||||
"message": "Add an additional layer of security by requiring fingerprint phrase confirmation when establishing a link between your desktop and browser. This requires user action and verification each time a connection is created."
|
"message": "Add an additional layer of security by requiring fingerprint phrase confirmation when establishing a link between your desktop and browser. This requires user action and verification each time a connection is created."
|
||||||
},
|
},
|
||||||
|
"enableHardwareAcceleration": {
|
||||||
|
"message": "Use hardware acceleration"
|
||||||
|
},
|
||||||
|
"enableHardwareAccelerationDesc": {
|
||||||
|
"message": "By default this setting is ON. Turn OFF only if you experience graphical issues. Restart is required."
|
||||||
|
},
|
||||||
"approve": {
|
"approve": {
|
||||||
"message": "Approve"
|
"message": "Approve"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||||
@@ -37,6 +38,7 @@ import { BiometricsService, BiometricsServiceAbstraction } from "./platform/main
|
|||||||
import { ClipboardMain } from "./platform/main/clipboard.main";
|
import { ClipboardMain } from "./platform/main/clipboard.main";
|
||||||
import { DesktopCredentialStorageListener } from "./platform/main/desktop-credential-storage-listener";
|
import { DesktopCredentialStorageListener } from "./platform/main/desktop-credential-storage-listener";
|
||||||
import { MainCryptoFunctionService } from "./platform/main/main-crypto-function.service";
|
import { MainCryptoFunctionService } from "./platform/main/main-crypto-function.service";
|
||||||
|
import { DesktopSettingsService } from "./platform/services/desktop-settings.service";
|
||||||
import { ElectronLogMainService } from "./platform/services/electron-log.main.service";
|
import { ElectronLogMainService } from "./platform/services/electron-log.main.service";
|
||||||
import { ELECTRON_SUPPORTS_SECURE_STORAGE } from "./platform/services/electron-platform-utils.service";
|
import { ELECTRON_SUPPORTS_SECURE_STORAGE } from "./platform/services/electron-platform-utils.service";
|
||||||
import { ElectronStateService } from "./platform/services/electron-state.service";
|
import { ElectronStateService } from "./platform/services/electron-state.service";
|
||||||
@@ -56,6 +58,7 @@ export class Main {
|
|||||||
mainCryptoFunctionService: MainCryptoFunctionService;
|
mainCryptoFunctionService: MainCryptoFunctionService;
|
||||||
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
||||||
migrationRunner: MigrationRunner;
|
migrationRunner: MigrationRunner;
|
||||||
|
desktopSettingsService: DesktopSettingsService;
|
||||||
tokenService: TokenServiceAbstraction;
|
tokenService: TokenServiceAbstraction;
|
||||||
|
|
||||||
windowMain: WindowMain;
|
windowMain: WindowMain;
|
||||||
@@ -189,6 +192,7 @@ export class Main {
|
|||||||
this.messagingMain = new MessagingMain(this, this.stateService);
|
this.messagingMain = new MessagingMain(this, this.stateService);
|
||||||
this.updaterMain = new UpdaterMain(this.i18nService, this.windowMain);
|
this.updaterMain = new UpdaterMain(this.i18nService, this.windowMain);
|
||||||
this.trayMain = new TrayMain(this.windowMain, this.i18nService, this.stateService);
|
this.trayMain = new TrayMain(this.windowMain, this.i18nService, this.stateService);
|
||||||
|
this.desktopSettingsService = new DesktopSettingsService(stateProvider);
|
||||||
|
|
||||||
this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => {
|
this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => {
|
||||||
this.messagingMain.onMessage(message);
|
this.messagingMain.onMessage(message);
|
||||||
@@ -237,6 +241,7 @@ export class Main {
|
|||||||
// Run migrations first, then other things
|
// Run migrations first, then other things
|
||||||
this.migrationRunner.run().then(
|
this.migrationRunner.run().then(
|
||||||
async () => {
|
async () => {
|
||||||
|
await this.toggleHardwareAcceleration();
|
||||||
await this.windowMain.init();
|
await this.windowMain.init();
|
||||||
await this.i18nService.init();
|
await this.i18nService.init();
|
||||||
this.messagingMain.init();
|
this.messagingMain.init();
|
||||||
@@ -307,4 +312,15 @@ export class Main {
|
|||||||
this.messagingService.send("deepLink", { urlString: s });
|
this.messagingService.send("deepLink", { urlString: s });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async toggleHardwareAcceleration(): Promise<void> {
|
||||||
|
const hardwareAcceleration = await firstValueFrom(
|
||||||
|
this.desktopSettingsService.hardwareAcceleration$,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hardwareAcceleration) {
|
||||||
|
this.logService.warning("Hardware acceleration is disabled");
|
||||||
|
app.disableHardwareAcceleration();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { map } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
DESKTOP_SETTINGS_DISK,
|
||||||
|
KeyDefinition,
|
||||||
|
StateProvider,
|
||||||
|
} from "@bitwarden/common/platform/state";
|
||||||
|
|
||||||
|
export const HARDWARE_ACCELERATION = new KeyDefinition<boolean>(
|
||||||
|
DESKTOP_SETTINGS_DISK,
|
||||||
|
"hardwareAcceleration",
|
||||||
|
{
|
||||||
|
deserializer: (v: boolean) => v,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export class DesktopSettingsService {
|
||||||
|
private hwState = this.stateProvider.getGlobal(HARDWARE_ACCELERATION);
|
||||||
|
hardwareAcceleration$ = this.hwState.state$.pipe(map((v) => v ?? true));
|
||||||
|
|
||||||
|
constructor(private stateProvider: StateProvider) {}
|
||||||
|
|
||||||
|
async setHardwareAcceleration(enabled: boolean) {
|
||||||
|
await this.hwState.update(() => enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||||
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -17,8 +18,16 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
|||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
collectionService: CollectionService,
|
collectionService: CollectionService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
organizationService: OrganizationService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
) {
|
) {
|
||||||
super(collectionService, platformUtilsService, i18nService, cipherService, logService);
|
super(
|
||||||
|
collectionService,
|
||||||
|
platformUtilsService,
|
||||||
|
i18nService,
|
||||||
|
cipherService,
|
||||||
|
organizationService,
|
||||||
|
logService,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@bitwarden/vault-export-core": [
|
"@bitwarden/vault-export-core": [
|
||||||
"../../libs/tools/export/vault-export/vault-export-core/src"
|
"../../libs/tools/export/vault-export/vault-export-core/src"
|
||||||
],
|
],
|
||||||
|
"@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"],
|
||||||
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
||||||
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
||||||
"@bitwarden/node/*": ["../../libs/node/src/*"],
|
"@bitwarden/node/*": ["../../libs/node/src/*"],
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
||||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import {
|
import {
|
||||||
OrganizationUserStatusType,
|
OrganizationUserStatusType,
|
||||||
OrganizationUserType,
|
OrganizationUserType,
|
||||||
@@ -17,7 +19,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
@@ -109,8 +110,8 @@ export abstract class BasePeopleComponent<
|
|||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private searchPipe: SearchPipe,
|
private searchPipe: SearchPipe,
|
||||||
protected userNamePipe: UserNamePipe,
|
protected userNamePipe: UserNamePipe,
|
||||||
protected stateService: StateService,
|
|
||||||
protected dialogService: DialogService,
|
protected dialogService: DialogService,
|
||||||
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
abstract edit(user: UserType): void;
|
abstract edit(user: UserType): void;
|
||||||
@@ -351,7 +352,9 @@ export abstract class BasePeopleComponent<
|
|||||||
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
||||||
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
||||||
|
|
||||||
const autoConfirm = await this.stateService.getAutoConfirmFingerPrints();
|
const autoConfirm = await firstValueFrom(
|
||||||
|
this.organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
if (autoConfirm == null || !autoConfirm) {
|
if (autoConfirm == null || !autoConfirm) {
|
||||||
const [modal] = await this.modalService.openViewRef(
|
const [modal] = await this.modalService.openViewRef(
|
||||||
UserConfirmComponent,
|
UserConfirmComponent,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
|
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-user-confirm",
|
selector: "app-user-confirm",
|
||||||
@@ -22,7 +22,7 @@ export class UserConfirmComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private stateService: StateService,
|
private organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -45,7 +45,7 @@ export class UserConfirmComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.dontAskAgain) {
|
if (this.dontAskAgain) {
|
||||||
await this.stateService.setAutoConfirmFingerprints(true);
|
await this.organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onConfirmedUser.emit();
|
this.onConfirmedUser.emit();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
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 { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
import { OrganizationUserConfirmRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
import { OrganizationUserConfirmRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
||||||
import {
|
import {
|
||||||
@@ -43,7 +44,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
@@ -117,7 +117,6 @@ export class PeopleComponent
|
|||||||
searchPipe: SearchPipe,
|
searchPipe: SearchPipe,
|
||||||
userNamePipe: UserNamePipe,
|
userNamePipe: UserNamePipe,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
stateService: StateService,
|
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
private organizationUserService: OrganizationUserService,
|
private organizationUserService: OrganizationUserService,
|
||||||
@@ -125,6 +124,7 @@ export class PeopleComponent
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private groupService: GroupService,
|
private groupService: GroupService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
|
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
apiService,
|
apiService,
|
||||||
@@ -137,8 +137,8 @@ export class PeopleComponent
|
|||||||
logService,
|
logService,
|
||||||
searchPipe,
|
searchPipe,
|
||||||
userNamePipe,
|
userNamePipe,
|
||||||
stateService,
|
|
||||||
dialogService,
|
dialogService,
|
||||||
|
organizationManagementPreferencesService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { ExportScopeCalloutComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
import { LooseComponentsModule, SharedModule } from "../../../../shared";
|
import { LooseComponentsModule, SharedModule } from "../../../../shared";
|
||||||
|
|
||||||
import { OrganizationVaultExportRoutingModule } from "./org-vault-export-routing.module";
|
import { OrganizationVaultExportRoutingModule } from "./org-vault-export-routing.module";
|
||||||
import { OrganizationVaultExportComponent } from "./org-vault-export.component";
|
import { OrganizationVaultExportComponent } from "./org-vault-export.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [SharedModule, LooseComponentsModule, OrganizationVaultExportRoutingModule],
|
imports: [
|
||||||
|
SharedModule,
|
||||||
|
LooseComponentsModule,
|
||||||
|
OrganizationVaultExportRoutingModule,
|
||||||
|
ExportScopeCalloutComponent,
|
||||||
|
],
|
||||||
declarations: [OrganizationVaultExportComponent],
|
declarations: [OrganizationVaultExportComponent],
|
||||||
})
|
})
|
||||||
export class OrganizationVaultExportModule {}
|
export class OrganizationVaultExportModule {}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { Component, OnInit, Inject } from "@angular/core";
|
|||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ export class EmergencyAccessConfirmComponent implements OnInit {
|
|||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private stateService: StateService,
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private dialogRef: DialogRef<EmergencyAccessConfirmDialogResult>,
|
private dialogRef: DialogRef<EmergencyAccessConfirmDialogResult>,
|
||||||
) {}
|
) {}
|
||||||
@@ -63,7 +63,7 @@ export class EmergencyAccessConfirmComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.confirmForm.get("dontAskAgain").value) {
|
if (this.confirmForm.get("dontAskAgain").value) {
|
||||||
await this.stateService.setAutoConfirmFingerprints(true);
|
await this.organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { lastValueFrom, Observable, firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@@ -64,6 +65,7 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
protected dialogService: DialogService,
|
protected dialogService: DialogService,
|
||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
|
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||||
}
|
}
|
||||||
@@ -136,7 +138,9 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoConfirm = await this.stateService.getAutoConfirmFingerPrints();
|
const autoConfirm = await firstValueFrom(
|
||||||
|
this.organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
if (autoConfirm == null || !autoConfirm) {
|
if (autoConfirm == null || !autoConfirm) {
|
||||||
const dialogRef = EmergencyAccessConfirmComponent.open(this.dialogService, {
|
const dialogRef = EmergencyAccessConfirmComponent.open(this.dialogService, {
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||||
import { OrganizationDomainSsoDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain-sso-details.response";
|
import { OrganizationDomainSsoDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain-sso-details.response";
|
||||||
@@ -41,6 +44,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
private orgDomainApiService: OrgDomainApiServiceAbstraction,
|
private orgDomainApiService: OrgDomainApiServiceAbstraction,
|
||||||
private validationService: ValidationService,
|
private validationService: ValidationService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -56,6 +60,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
environmentService,
|
environmentService,
|
||||||
passwordGenerationService,
|
passwordGenerationService,
|
||||||
logService,
|
logService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
this.redirectUri = window.location.origin + "/sso-connector.html";
|
this.redirectUri = window.location.origin + "/sso-connector.html";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Router } from "@angular/router";
|
|||||||
|
|
||||||
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent {
|
|||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
environmentService: EnvironmentService,
|
||||||
) {
|
) {
|
||||||
super(twoFactorService, router, i18nService, platformUtilsService, window);
|
super(twoFactorService, router, i18nService, platformUtilsService, window, environmentService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
@@ -44,6 +47,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest
|
|||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
appIdService: AppIdService,
|
appIdService: AppIdService,
|
||||||
loginService: LoginService,
|
loginService: LoginService,
|
||||||
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigServiceAbstraction,
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
@@ -62,6 +66,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest
|
|||||||
twoFactorService,
|
twoFactorService,
|
||||||
appIdService,
|
appIdService,
|
||||||
loginService,
|
loginService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
<bit-callout type="danger" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
|
<bit-callout type="danger" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
|
||||||
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
||||||
</bit-callout>
|
</bit-callout>
|
||||||
<app-export-scope-callout
|
<tools-export-scope-callout
|
||||||
[organizationId]="organizationId"
|
[organizationId]="organizationId"
|
||||||
*ngIf="!disabledByPolicy"
|
*ngIf="!disabledByPolicy"
|
||||||
></app-export-scope-callout>
|
></tools-export-scope-callout>
|
||||||
|
|
||||||
<ng-container *ngIf="organizations$ | async as organizations">
|
<ng-container *ngIf="organizations$ | async as organizations">
|
||||||
<bit-form-field *ngIf="organizations.length > 0">
|
<bit-form-field *ngIf="organizations.length > 0">
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { ExportScopeCalloutComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
import { LooseComponentsModule, SharedModule } from "../../shared";
|
import { LooseComponentsModule, SharedModule } from "../../shared";
|
||||||
|
|
||||||
import { ExportRoutingModule } from "./export-routing.module";
|
import { ExportRoutingModule } from "./export-routing.module";
|
||||||
import { ExportComponent } from "./export.component";
|
import { ExportComponent } from "./export.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [SharedModule, LooseComponentsModule, ExportRoutingModule],
|
imports: [SharedModule, LooseComponentsModule, ExportRoutingModule, ExportScopeCalloutComponent],
|
||||||
declarations: [ExportComponent],
|
declarations: [ExportComponent],
|
||||||
})
|
})
|
||||||
export class ExportModule {}
|
export class ExportModule {}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
[(ngModel)]="$any(c).checked"
|
[(ngModel)]="$any(c).checked"
|
||||||
name="Collection[{{ i }}].Checked"
|
name="Collection[{{ i }}].Checked"
|
||||||
appStopProp
|
appStopProp
|
||||||
|
[disabled]="!c.canEditItems(this.organization, this.flexibleCollectionsV1Enabled)"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component, OnDestroy } from "@angular/core";
|
import { Component, OnDestroy } from "@angular/core";
|
||||||
|
|
||||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||||
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -18,9 +19,17 @@ export class CollectionsComponent extends BaseCollectionsComponent implements On
|
|||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
|
organizationSerivce: OrganizationService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
) {
|
) {
|
||||||
super(collectionService, platformUtilsService, i18nService, cipherService, logService);
|
super(
|
||||||
|
collectionService,
|
||||||
|
platformUtilsService,
|
||||||
|
i18nService,
|
||||||
|
cipherService,
|
||||||
|
organizationSerivce,
|
||||||
|
logService,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -28,6 +37,9 @@ export class CollectionsComponent extends BaseCollectionsComponent implements On
|
|||||||
}
|
}
|
||||||
|
|
||||||
check(c: CollectionView, select?: boolean) {
|
check(c: CollectionView, select?: boolean) {
|
||||||
|
if (!c.canEditItems(this.organization, this.flexibleCollectionsV1Enabled)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
(c as any).checked = select == null ? !(c as any).checked : select;
|
(c as any).checked = select == null ? !(c as any).checked : select;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { combineLatest, map, Observable, Subject, takeUntil } from "rxjs";
|
import { combineLatest, map, Observable, Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
|
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
@@ -12,7 +13,6 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
|||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
private organizationUserService: OrganizationUserService,
|
private organizationUserService: OrganizationUserService,
|
||||||
|
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private stateService: StateService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -56,7 +56,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
|||||||
combineLatest([
|
combineLatest([
|
||||||
this.organization$,
|
this.organization$,
|
||||||
resetPasswordPolicies$,
|
resetPasswordPolicies$,
|
||||||
this.stateService.getAccountDecryptionOptions(),
|
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||||
])
|
])
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe(([organization, resetPasswordPolicies, decryptionOptions]) => {
|
.subscribe(([organization, resetPasswordPolicies, decryptionOptions]) => {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@@ -25,15 +26,27 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
|||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
|
organizationService: OrganizationService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
) {
|
) {
|
||||||
super(collectionService, platformUtilsService, i18nService, cipherService, logService);
|
super(
|
||||||
|
collectionService,
|
||||||
|
platformUtilsService,
|
||||||
|
i18nService,
|
||||||
|
cipherService,
|
||||||
|
organizationService,
|
||||||
|
logService,
|
||||||
|
);
|
||||||
this.allowSelectNone = true;
|
this.allowSelectNone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async loadCipher() {
|
protected async loadCipher() {
|
||||||
if (!this.organization.canViewAllCollections) {
|
// if cipher is unassigned use apiService. We can see this by looking at this.collectionIds
|
||||||
|
if (
|
||||||
|
!this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled) &&
|
||||||
|
this.collectionIds.length !== 0
|
||||||
|
) {
|
||||||
return await super.loadCipher();
|
return await super.loadCipher();
|
||||||
}
|
}
|
||||||
const response = await this.apiService.getCipherAdmin(this.cipherId);
|
const response = await this.apiService.getCipherAdmin(this.cipherId);
|
||||||
@@ -55,7 +68,10 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected saveCollections() {
|
protected saveCollections() {
|
||||||
if (this.organization.canEditAnyCollection) {
|
if (
|
||||||
|
this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled) ||
|
||||||
|
this.collectionIds.length === 0
|
||||||
|
) {
|
||||||
const request = new CipherCollectionsRequest(this.cipherDomain.collectionIds);
|
const request = new CipherCollectionsRequest(this.cipherDomain.collectionIds);
|
||||||
return this.apiService.putCipherCollectionsAdmin(this.cipherId, request);
|
return this.apiService.putCipherCollectionsAdmin(this.cipherId, request);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
protected showCollectionAccessRestricted: boolean;
|
protected showCollectionAccessRestricted: boolean;
|
||||||
protected currentSearchText$: Observable<string>;
|
protected currentSearchText$: Observable<string>;
|
||||||
protected editableCollections$: Observable<CollectionView[]>;
|
protected editableCollections$: Observable<CollectionView[]>;
|
||||||
|
protected allCollectionsWithoutUnassigned$: Observable<CollectionAdminView[]>;
|
||||||
protected showBulkEditCollectionAccess$ = this.configService.getFeatureFlag$(
|
protected showBulkEditCollectionAccess$ = this.configService.getFeatureFlag$(
|
||||||
FeatureFlag.BulkCollectionAccess,
|
FeatureFlag.BulkCollectionAccess,
|
||||||
false,
|
false,
|
||||||
@@ -253,7 +254,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||||
|
|
||||||
const allCollectionsWithoutUnassigned$ = combineLatest([
|
this.allCollectionsWithoutUnassigned$ = combineLatest([
|
||||||
organizationId$.pipe(switchMap((orgId) => this.collectionAdminService.getAll(orgId))),
|
organizationId$.pipe(switchMap((orgId) => this.collectionAdminService.getAll(orgId))),
|
||||||
defer(() => this.collectionService.getAllDecrypted()),
|
defer(() => this.collectionService.getAllDecrypted()),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
@@ -276,7 +277,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.editableCollections$ = allCollectionsWithoutUnassigned$.pipe(
|
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
||||||
map((collections) => {
|
map((collections) => {
|
||||||
// Users that can edit all ciphers can implicitly edit all collections
|
// Users that can edit all ciphers can implicitly edit all collections
|
||||||
if (this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled)) {
|
if (this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled)) {
|
||||||
@@ -287,7 +288,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const allCollections$ = combineLatest([organizationId$, allCollectionsWithoutUnassigned$]).pipe(
|
const allCollections$ = combineLatest([
|
||||||
|
organizationId$,
|
||||||
|
this.allCollectionsWithoutUnassigned$,
|
||||||
|
]).pipe(
|
||||||
map(([organizationId, allCollections]) => {
|
map(([organizationId, allCollections]) => {
|
||||||
const noneCollection = new CollectionAdminView();
|
const noneCollection = new CollectionAdminView();
|
||||||
noneCollection.name = this.i18nService.t("unassigned");
|
noneCollection.name = this.i18nService.t("unassigned");
|
||||||
@@ -680,16 +684,35 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (this.flexibleCollectionsV1Enabled) {
|
if (this.flexibleCollectionsV1Enabled) {
|
||||||
// V1 limits admins to only adding items to collections they have access to.
|
// V1 limits admins to only adding items to collections they have access to.
|
||||||
collections = await firstValueFrom(this.editableCollections$);
|
collections = await firstValueFrom(
|
||||||
} else {
|
this.allCollectionsWithoutUnassigned$.pipe(
|
||||||
collections = (await firstValueFrom(this.vaultFilterService.filteredCollections$)).filter(
|
map((c) => {
|
||||||
(c) => !c.readOnly && c.id != Unassigned,
|
return c.sort((a, b) => {
|
||||||
|
if (
|
||||||
|
a.canEditItems(this.organization, true) &&
|
||||||
|
!b.canEditItems(this.organization, true)
|
||||||
|
) {
|
||||||
|
return -1;
|
||||||
|
} else if (
|
||||||
|
!a.canEditItems(this.organization, true) &&
|
||||||
|
b.canEditItems(this.organization, true)
|
||||||
|
) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
collections = await firstValueFrom(this.allCollectionsWithoutUnassigned$);
|
||||||
}
|
}
|
||||||
const [modal] = await this.modalService.openViewRef(
|
const [modal] = await this.modalService.openViewRef(
|
||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
this.collectionsModalRef,
|
this.collectionsModalRef,
|
||||||
(comp) => {
|
(comp) => {
|
||||||
|
comp.flexibleCollectionsV1Enabled = this.flexibleCollectionsV1Enabled;
|
||||||
comp.collectionIds = cipher.collectionIds;
|
comp.collectionIds = cipher.collectionIds;
|
||||||
comp.collections = collections;
|
comp.collections = collections;
|
||||||
comp.organization = this.organization;
|
comp.organization = this.organization;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"@bitwarden/vault-export-core": [
|
"@bitwarden/vault-export-core": [
|
||||||
"../../libs/tools/export/vault-export/vault-export-core/src"
|
"../../libs/tools/export/vault-export/vault-export-core/src"
|
||||||
],
|
],
|
||||||
|
"@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"],
|
||||||
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
"@bitwarden/importer/core": ["../../libs/importer/src"],
|
||||||
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
"@bitwarden/importer/ui": ["../../libs/importer/src/components"],
|
||||||
"@bitwarden/platform": ["../../libs/platform/src"],
|
"@bitwarden/platform": ["../../libs/platform/src"],
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
|||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||||
import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
|
import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request";
|
import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request";
|
||||||
@@ -18,7 +19,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { BasePeopleComponent } from "@bitwarden/web-vault/app/admin-console/common/base.people.component";
|
import { BasePeopleComponent } from "@bitwarden/web-vault/app/admin-console/common/base.people.component";
|
||||||
@@ -67,9 +67,9 @@ export class PeopleComponent
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
searchPipe: SearchPipe,
|
searchPipe: SearchPipe,
|
||||||
userNamePipe: UserNamePipe,
|
userNamePipe: UserNamePipe,
|
||||||
stateService: StateService,
|
|
||||||
private providerService: ProviderService,
|
private providerService: ProviderService,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
|
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
apiService,
|
apiService,
|
||||||
@@ -82,8 +82,8 @@ export class PeopleComponent
|
|||||||
logService,
|
logService,
|
||||||
searchPipe,
|
searchPipe,
|
||||||
userNamePipe,
|
userNamePipe,
|
||||||
stateService,
|
|
||||||
dialogService,
|
dialogService,
|
||||||
|
organizationManagementPreferencesService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "sm",
|
path: "sm",
|
||||||
|
canActivate: [deepLinkGuard()],
|
||||||
loadChildren: async () =>
|
loadChildren: async () =>
|
||||||
(await import("./secrets-manager/secrets-manager.module")).SecretsManagerModule,
|
(await import("./secrets-manager/secrets-manager.module")).SecretsManagerModule,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"@bitwarden/vault-export-core": [
|
"@bitwarden/vault-export-core": [
|
||||||
"../../libs/tools/export/vault-export/vault-export-core/src"
|
"../../libs/tools/export/vault-export/vault-export-core/src"
|
||||||
],
|
],
|
||||||
|
"@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-core/src"],
|
||||||
"@bitwarden/platform": ["../../libs/platform/src"],
|
"@bitwarden/platform": ["../../libs/platform/src"],
|
||||||
"@bitwarden/vault": ["../../libs/vault/src"],
|
"@bitwarden/vault": ["../../libs/vault/src"],
|
||||||
"@bitwarden/web-vault/*": ["../../apps/web/src/*"]
|
"@bitwarden/web-vault/*": ["../../apps/web/src/*"]
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
|
|
||||||
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -19,6 +21,8 @@ export class CollectionsComponent implements OnInit {
|
|||||||
cipher: CipherView;
|
cipher: CipherView;
|
||||||
collectionIds: string[];
|
collectionIds: string[];
|
||||||
collections: CollectionView[] = [];
|
collections: CollectionView[] = [];
|
||||||
|
organization: Organization;
|
||||||
|
flexibleCollectionsV1Enabled: boolean;
|
||||||
|
|
||||||
protected cipherDomain: Cipher;
|
protected cipherDomain: Cipher;
|
||||||
|
|
||||||
@@ -27,6 +31,7 @@ export class CollectionsComponent implements OnInit {
|
|||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected cipherService: CipherService,
|
protected cipherService: CipherService,
|
||||||
|
protected organizationService: OrganizationService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -48,11 +53,21 @@ export class CollectionsComponent implements OnInit {
|
|||||||
(c as any).checked = this.collectionIds != null && this.collectionIds.indexOf(c.id) > -1;
|
(c as any).checked = this.collectionIds != null && this.collectionIds.indexOf(c.id) > -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.organization == null) {
|
||||||
|
this.organization = await this.organizationService.get(this.cipher.organizationId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
const selectedCollectionIds = this.collections
|
const selectedCollectionIds = this.collections
|
||||||
.filter((c) => !!(c as any).checked)
|
.filter((c) => {
|
||||||
|
if (this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled)) {
|
||||||
|
return !!(c as any).checked;
|
||||||
|
} else {
|
||||||
|
return !!(c as any).checked && c.readOnly == null;
|
||||||
|
}
|
||||||
|
})
|
||||||
.map((c) => c.id);
|
.map((c) => c.id);
|
||||||
if (!this.allowSelectNone && selectedCollectionIds.length === 0) {
|
if (!this.allowSelectNone && selectedCollectionIds.length === 0) {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ import {
|
|||||||
throwError,
|
throwError,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
UserDecryptionOptions,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
@@ -30,7 +34,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
NewUser,
|
NewUser,
|
||||||
@@ -88,6 +91,7 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy {
|
|||||||
protected validationService: ValidationService,
|
protected validationService: ValidationService,
|
||||||
protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
protected passwordResetEnrollmentService: PasswordResetEnrollmentServiceAbstraction,
|
protected passwordResetEnrollmentService: PasswordResetEnrollmentServiceAbstraction,
|
||||||
protected ssoLoginService: SsoLoginServiceAbstraction,
|
protected ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
) {}
|
) {}
|
||||||
@@ -101,14 +105,15 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy {
|
|||||||
await this.setRememberDeviceDefaultValue();
|
await this.setRememberDeviceDefaultValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const accountDecryptionOptions: AccountDecryptionOptions =
|
const userDecryptionOptions = await firstValueFrom(
|
||||||
await this.stateService.getAccountDecryptionOptions();
|
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||||
|
);
|
||||||
|
|
||||||
// see sso-login.strategy - to determine if a user is new or not it just checks if there is a key on the token response..
|
// see sso-login.strategy - to determine if a user is new or not it just checks if there is a key on the token response..
|
||||||
// can we check if they have a user key or master key in crypto service? Would that be sufficient?
|
// can we check if they have a user key or master key in crypto service? Would that be sufficient?
|
||||||
if (
|
if (
|
||||||
!accountDecryptionOptions?.trustedDeviceOption?.hasAdminApproval &&
|
!userDecryptionOptions?.trustedDeviceOption?.hasAdminApproval &&
|
||||||
!accountDecryptionOptions?.hasMasterPassword
|
!userDecryptionOptions?.hasMasterPassword
|
||||||
) {
|
) {
|
||||||
// We are dealing with a new account if:
|
// We are dealing with a new account if:
|
||||||
// - User does not have admin approval (i.e. has not enrolled into admin reset)
|
// - User does not have admin approval (i.e. has not enrolled into admin reset)
|
||||||
@@ -118,7 +123,7 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.loadNewUserData();
|
this.loadNewUserData();
|
||||||
} else {
|
} else {
|
||||||
this.loadUntrustedDeviceData(accountDecryptionOptions);
|
this.loadUntrustedDeviceData(userDecryptionOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this is probably not a comprehensive write up of all scenarios:
|
// Note: this is probably not a comprehensive write up of all scenarios:
|
||||||
@@ -195,7 +200,7 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUntrustedDeviceData(accountDecryptionOptions: AccountDecryptionOptions) {
|
loadUntrustedDeviceData(userDecryptionOptions: UserDecryptionOptions) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
const email$ = from(this.stateService.getEmail()).pipe(
|
const email$ = from(this.stateService.getEmail()).pipe(
|
||||||
@@ -215,13 +220,12 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy {
|
|||||||
)
|
)
|
||||||
.subscribe((email) => {
|
.subscribe((email) => {
|
||||||
const showApproveFromOtherDeviceBtn =
|
const showApproveFromOtherDeviceBtn =
|
||||||
accountDecryptionOptions?.trustedDeviceOption?.hasLoginApprovingDevice || false;
|
userDecryptionOptions?.trustedDeviceOption?.hasLoginApprovingDevice || false;
|
||||||
|
|
||||||
const showReqAdminApprovalBtn =
|
const showReqAdminApprovalBtn =
|
||||||
!!accountDecryptionOptions?.trustedDeviceOption?.hasAdminApproval || false;
|
!!userDecryptionOptions?.trustedDeviceOption?.hasAdminApproval || false;
|
||||||
|
|
||||||
const showApproveWithMasterPasswordBtn =
|
const showApproveWithMasterPasswordBtn = userDecryptionOptions?.hasMasterPassword || false;
|
||||||
accountDecryptionOptions?.hasMasterPassword || false;
|
|
||||||
|
|
||||||
const userEmail = email;
|
const userEmail = email;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Directive } from "@angular/core";
|
import { Directive } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { of } from "rxjs";
|
import { firstValueFrom, of } from "rxjs";
|
||||||
import { filter, first, switchMap, tap } from "rxjs/operators";
|
import { filter, first, switchMap, tap } from "rxjs/operators";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
@@ -26,7 +27,6 @@ import {
|
|||||||
DEFAULT_KDF_CONFIG,
|
DEFAULT_KDF_CONFIG,
|
||||||
} from "@bitwarden/common/platform/enums";
|
} from "@bitwarden/common/platform/enums";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
@@ -64,6 +64,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
private organizationUserService: OrganizationUserService,
|
private organizationUserService: OrganizationUserService,
|
||||||
|
private userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
private ssoLoginService: SsoLoginServiceAbstraction,
|
private ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
) {
|
) {
|
||||||
@@ -228,11 +229,11 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
await this.stateService.setForceSetPasswordReason(ForceSetPasswordReason.None);
|
await this.stateService.setForceSetPasswordReason(ForceSetPasswordReason.None);
|
||||||
|
|
||||||
// User now has a password so update account decryption options in state
|
// User now has a password so update account decryption options in state
|
||||||
const acctDecryptionOpts: AccountDecryptionOptions =
|
const userDecryptionOpts = await firstValueFrom(
|
||||||
await this.stateService.getAccountDecryptionOptions();
|
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||||
|
);
|
||||||
acctDecryptionOpts.hasMasterPassword = true;
|
userDecryptionOpts.hasMasterPassword = true;
|
||||||
await this.stateService.setAccountDecryptionOptions(acctDecryptionOpts);
|
await this.userDecryptionOptionsService.setUserDecryptionOptions(userDecryptionOpts);
|
||||||
|
|
||||||
await this.stateService.setKdfType(this.kdf);
|
await this.stateService.setKdfType(this.kdf);
|
||||||
await this.stateService.setKdfConfig(this.kdfConfig);
|
await this.stateService.setKdfConfig(this.kdfConfig);
|
||||||
|
|||||||
@@ -2,16 +2,20 @@ import { Component } from "@angular/core";
|
|||||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { MockProxy, mock } from "jest-mock-extended";
|
import { MockProxy, mock } from "jest-mock-extended";
|
||||||
import { Observable, of } from "rxjs";
|
import { BehaviorSubject, Observable, of } from "rxjs";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
FakeKeyConnectorUserDecryptionOption as KeyConnectorUserDecryptionOption,
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
FakeTrustedDeviceUserDecryptionOption as TrustedDeviceUserDecryptionOption,
|
||||||
|
FakeUserDecryptionOptions as UserDecryptionOptions,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { KeyConnectorUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/key-connector-user-decryption-option";
|
|
||||||
import { TrustedDeviceUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/trusted-device-user-decryption-option";
|
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
@@ -19,7 +23,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
|
||||||
import { SsoComponent } from "./sso.component";
|
import { SsoComponent } from "./sso.component";
|
||||||
@@ -62,6 +65,7 @@ describe("SsoComponent", () => {
|
|||||||
let mockEnvironmentService: MockProxy<EnvironmentService>;
|
let mockEnvironmentService: MockProxy<EnvironmentService>;
|
||||||
let mockPasswordGenerationService: MockProxy<PasswordGenerationServiceAbstraction>;
|
let mockPasswordGenerationService: MockProxy<PasswordGenerationServiceAbstraction>;
|
||||||
let mockLogService: MockProxy<LogService>;
|
let mockLogService: MockProxy<LogService>;
|
||||||
|
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
||||||
let mockConfigService: MockProxy<ConfigServiceAbstraction>;
|
let mockConfigService: MockProxy<ConfigServiceAbstraction>;
|
||||||
|
|
||||||
// Mock authService.logIn params
|
// Mock authService.logIn params
|
||||||
@@ -77,17 +81,19 @@ describe("SsoComponent", () => {
|
|||||||
let mockOnSuccessfulLoginForceResetNavigate: jest.Mock;
|
let mockOnSuccessfulLoginForceResetNavigate: jest.Mock;
|
||||||
let mockOnSuccessfulLoginTdeNavigate: jest.Mock;
|
let mockOnSuccessfulLoginTdeNavigate: jest.Mock;
|
||||||
|
|
||||||
let mockAcctDecryptionOpts: {
|
let mockUserDecryptionOpts: {
|
||||||
noMasterPassword: AccountDecryptionOptions;
|
noMasterPassword: UserDecryptionOptions;
|
||||||
withMasterPassword: AccountDecryptionOptions;
|
withMasterPassword: UserDecryptionOptions;
|
||||||
withMasterPasswordAndTrustedDevice: AccountDecryptionOptions;
|
withMasterPasswordAndTrustedDevice: UserDecryptionOptions;
|
||||||
withMasterPasswordAndTrustedDeviceWithManageResetPassword: AccountDecryptionOptions;
|
withMasterPasswordAndTrustedDeviceWithManageResetPassword: UserDecryptionOptions;
|
||||||
withMasterPasswordAndKeyConnector: AccountDecryptionOptions;
|
withMasterPasswordAndKeyConnector: UserDecryptionOptions;
|
||||||
noMasterPasswordWithTrustedDevice: AccountDecryptionOptions;
|
noMasterPasswordWithTrustedDevice: UserDecryptionOptions;
|
||||||
noMasterPasswordWithTrustedDeviceWithManageResetPassword: AccountDecryptionOptions;
|
noMasterPasswordWithTrustedDeviceWithManageResetPassword: UserDecryptionOptions;
|
||||||
noMasterPasswordWithKeyConnector: AccountDecryptionOptions;
|
noMasterPasswordWithKeyConnector: UserDecryptionOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let selectedUserDecryptionOptions: BehaviorSubject<UserDecryptionOptions>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Mock Services
|
// Mock Services
|
||||||
mockLoginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
mockLoginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
@@ -109,6 +115,7 @@ describe("SsoComponent", () => {
|
|||||||
mockEnvironmentService = mock<EnvironmentService>();
|
mockEnvironmentService = mock<EnvironmentService>();
|
||||||
mockPasswordGenerationService = mock<PasswordGenerationServiceAbstraction>();
|
mockPasswordGenerationService = mock<PasswordGenerationServiceAbstraction>();
|
||||||
mockLogService = mock<LogService>();
|
mockLogService = mock<LogService>();
|
||||||
|
mockUserDecryptionOptionsService = mock<UserDecryptionOptionsServiceAbstraction>();
|
||||||
mockConfigService = mock<ConfigServiceAbstraction>();
|
mockConfigService = mock<ConfigServiceAbstraction>();
|
||||||
|
|
||||||
// Mock loginStrategyService.logIn params
|
// Mock loginStrategyService.logIn params
|
||||||
@@ -124,49 +131,52 @@ describe("SsoComponent", () => {
|
|||||||
mockOnSuccessfulLoginForceResetNavigate = jest.fn();
|
mockOnSuccessfulLoginForceResetNavigate = jest.fn();
|
||||||
mockOnSuccessfulLoginTdeNavigate = jest.fn();
|
mockOnSuccessfulLoginTdeNavigate = jest.fn();
|
||||||
|
|
||||||
mockAcctDecryptionOpts = {
|
mockUserDecryptionOpts = {
|
||||||
noMasterPassword: new AccountDecryptionOptions({
|
noMasterPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPassword: new AccountDecryptionOptions({
|
withMasterPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndTrustedDevice: new AccountDecryptionOptions({
|
withMasterPasswordAndTrustedDevice: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndTrustedDeviceWithManageResetPassword: new AccountDecryptionOptions({
|
withMasterPasswordAndTrustedDeviceWithManageResetPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndKeyConnector: new AccountDecryptionOptions({
|
withMasterPasswordAndKeyConnector: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithTrustedDevice: new AccountDecryptionOptions({
|
noMasterPasswordWithTrustedDevice: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithTrustedDeviceWithManageResetPassword: new AccountDecryptionOptions({
|
noMasterPasswordWithTrustedDeviceWithManageResetPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithKeyConnector: new AccountDecryptionOptions({
|
noMasterPasswordWithKeyConnector: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
selectedUserDecryptionOptions = new BehaviorSubject<UserDecryptionOptions>(null);
|
||||||
|
mockUserDecryptionOptionsService.userDecryptionOptions$ = selectedUserDecryptionOptions;
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [TestSsoComponent],
|
declarations: [TestSsoComponent],
|
||||||
providers: [
|
providers: [
|
||||||
@@ -183,6 +193,10 @@ describe("SsoComponent", () => {
|
|||||||
{ provide: EnvironmentService, useValue: mockEnvironmentService },
|
{ provide: EnvironmentService, useValue: mockEnvironmentService },
|
||||||
{ provide: PasswordGenerationServiceAbstraction, useValue: mockPasswordGenerationService },
|
{ provide: PasswordGenerationServiceAbstraction, useValue: mockPasswordGenerationService },
|
||||||
|
|
||||||
|
{
|
||||||
|
provide: UserDecryptionOptionsServiceAbstraction,
|
||||||
|
useValue: mockUserDecryptionOptionsService,
|
||||||
|
},
|
||||||
{ provide: LogService, useValue: mockLogService },
|
{ provide: LogService, useValue: mockLogService },
|
||||||
{ provide: ConfigServiceAbstraction, useValue: mockConfigService },
|
{ provide: ConfigServiceAbstraction, useValue: mockConfigService },
|
||||||
],
|
],
|
||||||
@@ -230,9 +244,7 @@ describe("SsoComponent", () => {
|
|||||||
authResult.twoFactorProviders = new Map([[TwoFactorProviderType.Authenticator, {}]]);
|
authResult.twoFactorProviders = new Map([[TwoFactorProviderType.Authenticator, {}]]);
|
||||||
|
|
||||||
// use standard user with MP because this test is not concerned with password reset.
|
// use standard user with MP because this test is not concerned with password reset.
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.withMasterPassword);
|
||||||
mockAcctDecryptionOpts.withMasterPassword,
|
|
||||||
);
|
|
||||||
|
|
||||||
mockLoginStrategyService.logIn.mockResolvedValue(authResult);
|
mockLoginStrategyService.logIn.mockResolvedValue(authResult);
|
||||||
});
|
});
|
||||||
@@ -341,8 +353,8 @@ describe("SsoComponent", () => {
|
|||||||
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {
|
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {
|
||||||
let authResult;
|
let authResult;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.noMasterPasswordWithTrustedDeviceWithManageResetPassword,
|
mockUserDecryptionOpts.noMasterPasswordWithTrustedDeviceWithManageResetPassword,
|
||||||
);
|
);
|
||||||
|
|
||||||
authResult = new AuthResult();
|
authResult = new AuthResult();
|
||||||
@@ -377,8 +389,8 @@ describe("SsoComponent", () => {
|
|||||||
const reasonString = ForceSetPasswordReason[forceResetPasswordReason];
|
const reasonString = ForceSetPasswordReason[forceResetPasswordReason];
|
||||||
let authResult;
|
let authResult;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
mockUserDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
||||||
);
|
);
|
||||||
|
|
||||||
authResult = new AuthResult();
|
authResult = new AuthResult();
|
||||||
@@ -394,8 +406,8 @@ describe("SsoComponent", () => {
|
|||||||
describe("Given Trusted Device Encryption is enabled, user doesn't need to set a MP, and forcePasswordReset is not required", () => {
|
describe("Given Trusted Device Encryption is enabled, user doesn't need to set a MP, and forcePasswordReset is not required", () => {
|
||||||
let authResult;
|
let authResult;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
mockUserDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
||||||
);
|
);
|
||||||
|
|
||||||
authResult = new AuthResult();
|
authResult = new AuthResult();
|
||||||
@@ -440,9 +452,7 @@ describe("SsoComponent", () => {
|
|||||||
describe("Given user needs to set a master password", () => {
|
describe("Given user needs to set a master password", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Only need to test the case where the user has no master password to test the primary change mp flow here
|
// Only need to test the case where the user has no master password to test the primary change mp flow here
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.noMasterPassword);
|
||||||
mockAcctDecryptionOpts.noMasterPassword,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testChangePasswordOnSuccessfulLogin();
|
testChangePasswordOnSuccessfulLogin();
|
||||||
@@ -450,9 +460,7 @@ describe("SsoComponent", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not navigate to the change password route when the user has key connector even if user has no master password", async () => {
|
it("does not navigate to the change password route when the user has key connector even if user has no master password", async () => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.noMasterPasswordWithKeyConnector);
|
||||||
mockAcctDecryptionOpts.noMasterPasswordWithKeyConnector,
|
|
||||||
);
|
|
||||||
|
|
||||||
await _component.logIn(code, codeVerifier, orgIdFromState);
|
await _component.logIn(code, codeVerifier, orgIdFromState);
|
||||||
expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1);
|
expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1);
|
||||||
@@ -475,9 +483,7 @@ describe("SsoComponent", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// use standard user with MP because this test is not concerned with password reset.
|
// use standard user with MP because this test is not concerned with password reset.
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.withMasterPassword);
|
||||||
mockAcctDecryptionOpts.withMasterPassword,
|
|
||||||
);
|
|
||||||
|
|
||||||
const authResult = new AuthResult();
|
const authResult = new AuthResult();
|
||||||
authResult.forcePasswordReset = forceResetPasswordReason;
|
authResult.forcePasswordReset = forceResetPasswordReason;
|
||||||
@@ -494,9 +500,7 @@ describe("SsoComponent", () => {
|
|||||||
const authResult = new AuthResult();
|
const authResult = new AuthResult();
|
||||||
authResult.twoFactorProviders = null;
|
authResult.twoFactorProviders = null;
|
||||||
// use standard user with MP because this test is not concerned with password reset.
|
// use standard user with MP because this test is not concerned with password reset.
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.withMasterPassword);
|
||||||
mockAcctDecryptionOpts.withMasterPassword,
|
|
||||||
);
|
|
||||||
authResult.forcePasswordReset = ForceSetPasswordReason.None;
|
authResult.forcePasswordReset = ForceSetPasswordReason.None;
|
||||||
mockLoginStrategyService.logIn.mockResolvedValue(authResult);
|
mockLoginStrategyService.logIn.mockResolvedValue(authResult);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
import { Directive } from "@angular/core";
|
import { Directive } from "@angular/core";
|
||||||
import { ActivatedRoute, NavigationExtras, Router } from "@angular/router";
|
import { ActivatedRoute, NavigationExtras, Router } from "@angular/router";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction, SsoLoginCredentials } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
SsoLoginCredentials,
|
||||||
|
TrustedDeviceUserDecryptionOption,
|
||||||
|
UserDecryptionOptions,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { TrustedDeviceUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/trusted-device-user-decryption-option";
|
|
||||||
import { SsoPreValidateResponse } from "@bitwarden/common/auth/models/response/sso-pre-validate.response";
|
import { SsoPreValidateResponse } from "@bitwarden/common/auth/models/response/sso-pre-validate.response";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
@@ -17,7 +23,6 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
@@ -59,6 +64,7 @@ export class SsoComponent {
|
|||||||
protected environmentService: EnvironmentService,
|
protected environmentService: EnvironmentService,
|
||||||
protected passwordGenerationService: PasswordGenerationServiceAbstraction,
|
protected passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
|
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
protected configService: ConfigServiceAbstraction,
|
protected configService: ConfigServiceAbstraction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -194,9 +200,6 @@ export class SsoComponent {
|
|||||||
this.formPromise = this.loginStrategyService.logIn(credentials);
|
this.formPromise = this.loginStrategyService.logIn(credentials);
|
||||||
const authResult = await this.formPromise;
|
const authResult = await this.formPromise;
|
||||||
|
|
||||||
const acctDecryptionOpts: AccountDecryptionOptions =
|
|
||||||
await this.stateService.getAccountDecryptionOptions();
|
|
||||||
|
|
||||||
if (authResult.requiresTwoFactor) {
|
if (authResult.requiresTwoFactor) {
|
||||||
return await this.handleTwoFactorRequired(orgSsoIdentifier);
|
return await this.handleTwoFactorRequired(orgSsoIdentifier);
|
||||||
}
|
}
|
||||||
@@ -217,15 +220,20 @@ export class SsoComponent {
|
|||||||
return await this.handleForcePasswordReset(orgSsoIdentifier);
|
return await this.handleForcePasswordReset(orgSsoIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must come after 2fa check since user decryption options aren't available if 2fa is required
|
||||||
|
const userDecryptionOpts = await firstValueFrom(
|
||||||
|
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||||
|
);
|
||||||
|
|
||||||
const tdeEnabled = await this.isTrustedDeviceEncEnabled(
|
const tdeEnabled = await this.isTrustedDeviceEncEnabled(
|
||||||
acctDecryptionOpts.trustedDeviceOption,
|
userDecryptionOpts.trustedDeviceOption,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tdeEnabled) {
|
if (tdeEnabled) {
|
||||||
return await this.handleTrustedDeviceEncryptionEnabled(
|
return await this.handleTrustedDeviceEncryptionEnabled(
|
||||||
authResult,
|
authResult,
|
||||||
orgSsoIdentifier,
|
orgSsoIdentifier,
|
||||||
acctDecryptionOpts,
|
userDecryptionOpts,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,8 +241,8 @@ export class SsoComponent {
|
|||||||
// have one and they aren't using key connector.
|
// have one and they aren't using key connector.
|
||||||
// Note: TDE & Key connector are mutually exclusive org config options.
|
// Note: TDE & Key connector are mutually exclusive org config options.
|
||||||
const requireSetPassword =
|
const requireSetPassword =
|
||||||
!acctDecryptionOpts.hasMasterPassword &&
|
!userDecryptionOpts.hasMasterPassword &&
|
||||||
acctDecryptionOpts.keyConnectorOption === undefined;
|
userDecryptionOpts.keyConnectorOption === undefined;
|
||||||
|
|
||||||
if (requireSetPassword || authResult.resetMasterPassword) {
|
if (requireSetPassword || authResult.resetMasterPassword) {
|
||||||
// Change implies going no password -> password in this case
|
// Change implies going no password -> password in this case
|
||||||
@@ -270,12 +278,12 @@ export class SsoComponent {
|
|||||||
private async handleTrustedDeviceEncryptionEnabled(
|
private async handleTrustedDeviceEncryptionEnabled(
|
||||||
authResult: AuthResult,
|
authResult: AuthResult,
|
||||||
orgIdentifier: string,
|
orgIdentifier: string,
|
||||||
acctDecryptionOpts: AccountDecryptionOptions,
|
userDecryptionOpts: UserDecryptionOptions,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// If user doesn't have a MP, but has reset password permission, they must set a MP
|
// If user doesn't have a MP, but has reset password permission, they must set a MP
|
||||||
if (
|
if (
|
||||||
!acctDecryptionOpts.hasMasterPassword &&
|
!userDecryptionOpts.hasMasterPassword &&
|
||||||
acctDecryptionOpts.trustedDeviceOption.hasManageResetPasswordPermission
|
userDecryptionOpts.trustedDeviceOption.hasManageResetPasswordPermission
|
||||||
) {
|
) {
|
||||||
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
||||||
// Note: we cannot directly navigate in this scenario as we are in a pre-decryption state, and
|
// Note: we cannot directly navigate in this scenario as we are in a pre-decryption state, and
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Router } from "@angular/router";
|
|||||||
|
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ export class TwoFactorOptionsComponent implements OnInit {
|
|||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected win: Window,
|
protected win: Window,
|
||||||
|
protected environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -30,7 +32,8 @@ export class TwoFactorOptionsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
recover() {
|
recover() {
|
||||||
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/recover-2fa");
|
const webVault = this.environmentService.getWebVaultUrl();
|
||||||
|
this.platformUtilsService.launchUri(webVault + "/#/recover-2fa");
|
||||||
this.onRecoverSelected.emit();
|
this.onRecoverSelected.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||||
import { ActivatedRoute, Router, convertToParamMap } from "@angular/router";
|
import { ActivatedRoute, convertToParamMap, Router } from "@angular/router";
|
||||||
import { MockProxy, mock } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
FakeKeyConnectorUserDecryptionOption as KeyConnectorUserDecryptionOption,
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
FakeTrustedDeviceUserDecryptionOption as TrustedDeviceUserDecryptionOption,
|
||||||
|
FakeUserDecryptionOptions as UserDecryptionOptions,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { KeyConnectorUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/key-connector-user-decryption-option";
|
|
||||||
import { TrustedDeviceUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/trusted-device-user-decryption-option";
|
|
||||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
@@ -22,7 +27,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
|
|
||||||
import { TwoFactorComponent } from "./two-factor.component";
|
import { TwoFactorComponent } from "./two-factor.component";
|
||||||
|
|
||||||
@@ -56,20 +60,23 @@ describe("TwoFactorComponent", () => {
|
|||||||
let mockTwoFactorService: MockProxy<TwoFactorService>;
|
let mockTwoFactorService: MockProxy<TwoFactorService>;
|
||||||
let mockAppIdService: MockProxy<AppIdService>;
|
let mockAppIdService: MockProxy<AppIdService>;
|
||||||
let mockLoginService: MockProxy<LoginService>;
|
let mockLoginService: MockProxy<LoginService>;
|
||||||
|
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
||||||
let mockSsoLoginService: MockProxy<SsoLoginServiceAbstraction>;
|
let mockSsoLoginService: MockProxy<SsoLoginServiceAbstraction>;
|
||||||
let mockConfigService: MockProxy<ConfigServiceAbstraction>;
|
let mockConfigService: MockProxy<ConfigServiceAbstraction>;
|
||||||
|
|
||||||
let mockAcctDecryptionOpts: {
|
let mockUserDecryptionOpts: {
|
||||||
noMasterPassword: AccountDecryptionOptions;
|
noMasterPassword: UserDecryptionOptions;
|
||||||
withMasterPassword: AccountDecryptionOptions;
|
withMasterPassword: UserDecryptionOptions;
|
||||||
withMasterPasswordAndTrustedDevice: AccountDecryptionOptions;
|
withMasterPasswordAndTrustedDevice: UserDecryptionOptions;
|
||||||
withMasterPasswordAndTrustedDeviceWithManageResetPassword: AccountDecryptionOptions;
|
withMasterPasswordAndTrustedDeviceWithManageResetPassword: UserDecryptionOptions;
|
||||||
withMasterPasswordAndKeyConnector: AccountDecryptionOptions;
|
withMasterPasswordAndKeyConnector: UserDecryptionOptions;
|
||||||
noMasterPasswordWithTrustedDevice: AccountDecryptionOptions;
|
noMasterPasswordWithTrustedDevice: UserDecryptionOptions;
|
||||||
noMasterPasswordWithTrustedDeviceWithManageResetPassword: AccountDecryptionOptions;
|
noMasterPasswordWithTrustedDeviceWithManageResetPassword: UserDecryptionOptions;
|
||||||
noMasterPasswordWithKeyConnector: AccountDecryptionOptions;
|
noMasterPasswordWithKeyConnector: UserDecryptionOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let selectedUserDecryptionOptions: BehaviorSubject<UserDecryptionOptions>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockLoginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
mockLoginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
mockRouter = mock<Router>();
|
mockRouter = mock<Router>();
|
||||||
@@ -83,52 +90,56 @@ describe("TwoFactorComponent", () => {
|
|||||||
mockTwoFactorService = mock<TwoFactorService>();
|
mockTwoFactorService = mock<TwoFactorService>();
|
||||||
mockAppIdService = mock<AppIdService>();
|
mockAppIdService = mock<AppIdService>();
|
||||||
mockLoginService = mock<LoginService>();
|
mockLoginService = mock<LoginService>();
|
||||||
|
mockUserDecryptionOptionsService = mock<UserDecryptionOptionsServiceAbstraction>();
|
||||||
mockSsoLoginService = mock<SsoLoginServiceAbstraction>();
|
mockSsoLoginService = mock<SsoLoginServiceAbstraction>();
|
||||||
mockConfigService = mock<ConfigServiceAbstraction>();
|
mockConfigService = mock<ConfigServiceAbstraction>();
|
||||||
|
|
||||||
mockAcctDecryptionOpts = {
|
mockUserDecryptionOpts = {
|
||||||
noMasterPassword: new AccountDecryptionOptions({
|
noMasterPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPassword: new AccountDecryptionOptions({
|
withMasterPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndTrustedDevice: new AccountDecryptionOptions({
|
withMasterPasswordAndTrustedDevice: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndTrustedDeviceWithManageResetPassword: new AccountDecryptionOptions({
|
withMasterPasswordAndTrustedDeviceWithManageResetPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
withMasterPasswordAndKeyConnector: new AccountDecryptionOptions({
|
withMasterPasswordAndKeyConnector: new UserDecryptionOptions({
|
||||||
hasMasterPassword: true,
|
hasMasterPassword: true,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithTrustedDevice: new AccountDecryptionOptions({
|
noMasterPasswordWithTrustedDevice: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, false),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithTrustedDeviceWithManageResetPassword: new AccountDecryptionOptions({
|
noMasterPasswordWithTrustedDeviceWithManageResetPassword: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
trustedDeviceOption: new TrustedDeviceUserDecryptionOption(true, false, true),
|
||||||
keyConnectorOption: undefined,
|
keyConnectorOption: undefined,
|
||||||
}),
|
}),
|
||||||
noMasterPasswordWithKeyConnector: new AccountDecryptionOptions({
|
noMasterPasswordWithKeyConnector: new UserDecryptionOptions({
|
||||||
hasMasterPassword: false,
|
hasMasterPassword: false,
|
||||||
trustedDeviceOption: undefined,
|
trustedDeviceOption: undefined,
|
||||||
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
keyConnectorOption: new KeyConnectorUserDecryptionOption("http://example.com"),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
selectedUserDecryptionOptions = new BehaviorSubject<UserDecryptionOptions>(null);
|
||||||
|
mockUserDecryptionOptionsService.userDecryptionOptions$ = selectedUserDecryptionOptions;
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [TestTwoFactorComponent],
|
declarations: [TestTwoFactorComponent],
|
||||||
providers: [
|
providers: [
|
||||||
@@ -153,6 +164,10 @@ describe("TwoFactorComponent", () => {
|
|||||||
{ provide: TwoFactorService, useValue: mockTwoFactorService },
|
{ provide: TwoFactorService, useValue: mockTwoFactorService },
|
||||||
{ provide: AppIdService, useValue: mockAppIdService },
|
{ provide: AppIdService, useValue: mockAppIdService },
|
||||||
{ provide: LoginService, useValue: mockLoginService },
|
{ provide: LoginService, useValue: mockLoginService },
|
||||||
|
{
|
||||||
|
provide: UserDecryptionOptionsServiceAbstraction,
|
||||||
|
useValue: mockUserDecryptionOptionsService,
|
||||||
|
},
|
||||||
{ provide: SsoLoginServiceAbstraction, useValue: mockSsoLoginService },
|
{ provide: SsoLoginServiceAbstraction, useValue: mockSsoLoginService },
|
||||||
{ provide: ConfigServiceAbstraction, useValue: mockConfigService },
|
{ provide: ConfigServiceAbstraction, useValue: mockConfigService },
|
||||||
],
|
],
|
||||||
@@ -213,9 +228,7 @@ describe("TwoFactorComponent", () => {
|
|||||||
component.remember = remember;
|
component.remember = remember;
|
||||||
component.captchaToken = captchaToken;
|
component.captchaToken = captchaToken;
|
||||||
|
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.withMasterPassword);
|
||||||
mockAcctDecryptionOpts.withMasterPassword,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls authService.logInTwoFactor with correct parameters when form is submitted", async () => {
|
it("calls authService.logInTwoFactor with correct parameters when form is submitted", async () => {
|
||||||
@@ -289,17 +302,15 @@ describe("TwoFactorComponent", () => {
|
|||||||
describe("Given user needs to set a master password", () => {
|
describe("Given user needs to set a master password", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Only need to test the case where the user has no master password to test the primary change mp flow here
|
// Only need to test the case where the user has no master password to test the primary change mp flow here
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.noMasterPassword);
|
||||||
mockAcctDecryptionOpts.noMasterPassword,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testChangePasswordOnSuccessfulLogin();
|
testChangePasswordOnSuccessfulLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not navigate to the change password route when the user has key connector even if user has no master password", async () => {
|
it("does not navigate to the change password route when the user has key connector even if user has no master password", async () => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.noMasterPasswordWithKeyConnector,
|
mockUserDecryptionOpts.noMasterPasswordWithKeyConnector,
|
||||||
);
|
);
|
||||||
|
|
||||||
await component.doSubmit();
|
await component.doSubmit();
|
||||||
@@ -321,9 +332,7 @@ describe("TwoFactorComponent", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// use standard user with MP because this test is not concerned with password reset.
|
// use standard user with MP because this test is not concerned with password reset.
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.withMasterPassword);
|
||||||
mockAcctDecryptionOpts.withMasterPassword,
|
|
||||||
);
|
|
||||||
|
|
||||||
const authResult = new AuthResult();
|
const authResult = new AuthResult();
|
||||||
authResult.forcePasswordReset = forceResetPasswordReason;
|
authResult.forcePasswordReset = forceResetPasswordReason;
|
||||||
@@ -385,8 +394,8 @@ describe("TwoFactorComponent", () => {
|
|||||||
|
|
||||||
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {
|
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.noMasterPasswordWithTrustedDeviceWithManageResetPassword,
|
mockUserDecryptionOpts.noMasterPasswordWithTrustedDeviceWithManageResetPassword,
|
||||||
);
|
);
|
||||||
|
|
||||||
const authResult = new AuthResult();
|
const authResult = new AuthResult();
|
||||||
@@ -420,8 +429,8 @@ describe("TwoFactorComponent", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// use standard user with MP because this test is not concerned with password reset.
|
// use standard user with MP because this test is not concerned with password reset.
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
mockUserDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
||||||
);
|
);
|
||||||
|
|
||||||
const authResult = new AuthResult();
|
const authResult = new AuthResult();
|
||||||
@@ -436,8 +445,8 @@ describe("TwoFactorComponent", () => {
|
|||||||
describe("Given Trusted Device Encryption is enabled, user doesn't need to set a MP, and forcePasswordReset is not required", () => {
|
describe("Given Trusted Device Encryption is enabled, user doesn't need to set a MP, and forcePasswordReset is not required", () => {
|
||||||
let authResult;
|
let authResult;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStateService.getAccountDecryptionOptions.mockResolvedValue(
|
selectedUserDecryptionOptions.next(
|
||||||
mockAcctDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
mockUserDecryptionOpts.withMasterPasswordAndTrustedDevice,
|
||||||
);
|
);
|
||||||
|
|
||||||
authResult = new AuthResult();
|
authResult = new AuthResult();
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import { first } from "rxjs/operators";
|
|||||||
|
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
TrustedDeviceUserDecryptionOption,
|
||||||
|
UserDecryptionOptions,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
@@ -15,7 +20,6 @@ import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-
|
|||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { TrustedDeviceUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/trusted-device-user-decryption-option";
|
|
||||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||||
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
|
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
|
||||||
import { TwoFactorProviders } from "@bitwarden/common/auth/services/two-factor.service";
|
import { TwoFactorProviders } from "@bitwarden/common/auth/services/two-factor.service";
|
||||||
@@ -27,7 +31,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { AccountDecryptionOptions } from "@bitwarden/common/platform/models/domain/account";
|
|
||||||
|
|
||||||
import { CaptchaProtectedComponent } from "./captcha-protected.component";
|
import { CaptchaProtectedComponent } from "./captcha-protected.component";
|
||||||
|
|
||||||
@@ -86,6 +89,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
protected twoFactorService: TwoFactorService,
|
protected twoFactorService: TwoFactorService,
|
||||||
protected appIdService: AppIdService,
|
protected appIdService: AppIdService,
|
||||||
protected loginService: LoginService,
|
protected loginService: LoginService,
|
||||||
|
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
protected ssoLoginService: SsoLoginServiceAbstraction,
|
protected ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
protected configService: ConfigServiceAbstraction,
|
protected configService: ConfigServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
@@ -290,22 +294,23 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
return await this.handleForcePasswordReset(this.orgIdentifier);
|
return await this.handleForcePasswordReset(this.orgIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
const acctDecryptionOpts: AccountDecryptionOptions =
|
const userDecryptionOpts = await firstValueFrom(
|
||||||
await this.stateService.getAccountDecryptionOptions();
|
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||||
|
);
|
||||||
|
|
||||||
const tdeEnabled = await this.isTrustedDeviceEncEnabled(acctDecryptionOpts.trustedDeviceOption);
|
const tdeEnabled = await this.isTrustedDeviceEncEnabled(userDecryptionOpts.trustedDeviceOption);
|
||||||
|
|
||||||
if (tdeEnabled) {
|
if (tdeEnabled) {
|
||||||
return await this.handleTrustedDeviceEncryptionEnabled(
|
return await this.handleTrustedDeviceEncryptionEnabled(
|
||||||
authResult,
|
authResult,
|
||||||
this.orgIdentifier,
|
this.orgIdentifier,
|
||||||
acctDecryptionOpts,
|
userDecryptionOpts,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User must set password if they don't have one and they aren't using either TDE or key connector.
|
// User must set password if they don't have one and they aren't using either TDE or key connector.
|
||||||
const requireSetPassword =
|
const requireSetPassword =
|
||||||
!acctDecryptionOpts.hasMasterPassword && acctDecryptionOpts.keyConnectorOption === undefined;
|
!userDecryptionOpts.hasMasterPassword && userDecryptionOpts.keyConnectorOption === undefined;
|
||||||
|
|
||||||
if (requireSetPassword || authResult.resetMasterPassword) {
|
if (requireSetPassword || authResult.resetMasterPassword) {
|
||||||
// Change implies going no password -> password in this case
|
// Change implies going no password -> password in this case
|
||||||
@@ -326,12 +331,12 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
private async handleTrustedDeviceEncryptionEnabled(
|
private async handleTrustedDeviceEncryptionEnabled(
|
||||||
authResult: AuthResult,
|
authResult: AuthResult,
|
||||||
orgIdentifier: string,
|
orgIdentifier: string,
|
||||||
acctDecryptionOpts: AccountDecryptionOptions,
|
userDecryptionOpts: UserDecryptionOptions,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// If user doesn't have a MP, but has reset password permission, they must set a MP
|
// If user doesn't have a MP, but has reset password permission, they must set a MP
|
||||||
if (
|
if (
|
||||||
!acctDecryptionOpts.hasMasterPassword &&
|
!userDecryptionOpts.hasMasterPassword &&
|
||||||
acctDecryptionOpts.trustedDeviceOption.hasManageResetPasswordPermission
|
userDecryptionOpts.trustedDeviceOption.hasManageResetPasswordPermission
|
||||||
) {
|
) {
|
||||||
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
||||||
// Note: we cannot directly navigate to the set password screen in this scenario as we are in a pre-decryption state, and
|
// Note: we cannot directly navigate to the set password screen in this scenario as we are in a pre-decryption state, and
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function lockGuard(): CanActivateFn {
|
|||||||
|
|
||||||
// User is authN and in locked state.
|
// User is authN and in locked state.
|
||||||
|
|
||||||
const tdeEnabled = await deviceTrustCryptoService.supportsDeviceTrust();
|
const tdeEnabled = await firstValueFrom(deviceTrustCryptoService.supportsDeviceTrust$);
|
||||||
|
|
||||||
// Create special exception which allows users to go from the login-initiated page to the lock page for the approve w/ MP flow
|
// Create special exception which allows users to go from the login-initiated page to the lock page for the approve w/ MP flow
|
||||||
// The MP check is necessary to prevent direct manual navigation from other locked state pages for users who don't have a MP
|
// The MP check is necessary to prevent direct manual navigation from other locked state pages for users who don't have a MP
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function redirectGuard(overrides: Partial<RedirectRoutes> = {}): CanActiv
|
|||||||
|
|
||||||
// If locked, TDE is enabled, and the user hasn't decrypted yet, then redirect to the
|
// If locked, TDE is enabled, and the user hasn't decrypted yet, then redirect to the
|
||||||
// login decryption options component.
|
// login decryption options component.
|
||||||
const tdeEnabled = await deviceTrustCryptoService.supportsDeviceTrust();
|
const tdeEnabled = await firstValueFrom(deviceTrustCryptoService.supportsDeviceTrust$);
|
||||||
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
|
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
|
||||||
if (authStatus === AuthenticationStatus.Locked && tdeEnabled && !everHadUserKey) {
|
if (authStatus === AuthenticationStatus.Locked && tdeEnabled && !everHadUserKey) {
|
||||||
return router.createUrlTree([routes.notDecrypted], { queryParams: route.queryParams });
|
return router.createUrlTree([routes.notDecrypted], { queryParams: route.queryParams });
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export function tdeDecryptionRequiredGuard(): CanActivateFn {
|
|||||||
const router = inject(Router);
|
const router = inject(Router);
|
||||||
|
|
||||||
const authStatus = await authService.getAuthStatus();
|
const authStatus = await authService.getAuthStatus();
|
||||||
const tdeEnabled = await deviceTrustCryptoService.supportsDeviceTrust();
|
const tdeEnabled = await firstValueFrom(deviceTrustCryptoService.supportsDeviceTrust$);
|
||||||
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
|
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
|
||||||
if (authStatus !== AuthenticationStatus.Locked || !tdeEnabled || everHadUserKey) {
|
if (authStatus !== AuthenticationStatus.Locked || !tdeEnabled || everHadUserKey) {
|
||||||
return router.createUrlTree(["/"]);
|
return router.createUrlTree(["/"]);
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { UserTypePipe } from "./pipes/user-type.pipe";
|
|||||||
import { EllipsisPipe } from "./platform/pipes/ellipsis.pipe";
|
import { EllipsisPipe } from "./platform/pipes/ellipsis.pipe";
|
||||||
import { FingerprintPipe } from "./platform/pipes/fingerprint.pipe";
|
import { FingerprintPipe } from "./platform/pipes/fingerprint.pipe";
|
||||||
import { I18nPipe } from "./platform/pipes/i18n.pipe";
|
import { I18nPipe } from "./platform/pipes/i18n.pipe";
|
||||||
import { ExportScopeCalloutComponent } from "./tools/export/components/export-scope-callout.component";
|
|
||||||
import { PasswordStrengthComponent } from "./tools/password-strength/password-strength.component";
|
import { PasswordStrengthComponent } from "./tools/password-strength/password-strength.component";
|
||||||
import { IconComponent } from "./vault/components/icon.component";
|
import { IconComponent } from "./vault/components/icon.component";
|
||||||
|
|
||||||
@@ -54,7 +53,6 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||||||
CopyTextDirective,
|
CopyTextDirective,
|
||||||
CreditCardNumberPipe,
|
CreditCardNumberPipe,
|
||||||
EllipsisPipe,
|
EllipsisPipe,
|
||||||
ExportScopeCalloutComponent,
|
|
||||||
FallbackSrcDirective,
|
FallbackSrcDirective,
|
||||||
I18nPipe,
|
I18nPipe,
|
||||||
IconComponent,
|
IconComponent,
|
||||||
@@ -85,7 +83,6 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||||||
CopyTextDirective,
|
CopyTextDirective,
|
||||||
CreditCardNumberPipe,
|
CreditCardNumberPipe,
|
||||||
EllipsisPipe,
|
EllipsisPipe,
|
||||||
ExportScopeCalloutComponent,
|
|
||||||
FallbackSrcDirective,
|
FallbackSrcDirective,
|
||||||
I18nPipe,
|
I18nPipe,
|
||||||
IconComponent,
|
IconComponent,
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import {
|
|||||||
PinCryptoService,
|
PinCryptoService,
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
LoginStrategyService,
|
LoginStrategyService,
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
UserDecryptionOptionsService,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
||||||
@@ -27,6 +30,7 @@ import {
|
|||||||
OrgDomainInternalServiceAbstraction,
|
OrgDomainInternalServiceAbstraction,
|
||||||
OrgDomainServiceAbstraction,
|
OrgDomainServiceAbstraction,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
||||||
|
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
@@ -38,6 +42,7 @@ import { OrganizationApiService } from "@bitwarden/common/admin-console/services
|
|||||||
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
||||||
import { OrgDomainApiService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain-api.service";
|
import { OrgDomainApiService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain-api.service";
|
||||||
import { OrgDomainService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain.service";
|
import { OrgDomainService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain.service";
|
||||||
|
import { DefaultOrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/services/organization-management-preferences/default-organization-management-preferences.service";
|
||||||
import { OrganizationUserServiceImplementation } from "@bitwarden/common/admin-console/services/organization-user/organization-user.service.implementation";
|
import { OrganizationUserServiceImplementation } from "@bitwarden/common/admin-console/services/organization-user/organization-user.service.implementation";
|
||||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||||
@@ -241,8 +246,8 @@ import { safeProvider, SafeProvider } from "../platform/utils/safe-provider";
|
|||||||
import {
|
import {
|
||||||
LOCALES_DIRECTORY,
|
LOCALES_DIRECTORY,
|
||||||
LOCKED_CALLBACK,
|
LOCKED_CALLBACK,
|
||||||
LOG_MAC_FAILURES,
|
|
||||||
LOGOUT_CALLBACK,
|
LOGOUT_CALLBACK,
|
||||||
|
LOG_MAC_FAILURES,
|
||||||
MEMORY_STORAGE,
|
MEMORY_STORAGE,
|
||||||
OBSERVABLE_DISK_STORAGE,
|
OBSERVABLE_DISK_STORAGE,
|
||||||
OBSERVABLE_MEMORY_STORAGE,
|
OBSERVABLE_MEMORY_STORAGE,
|
||||||
@@ -367,6 +372,7 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
PolicyServiceAbstraction,
|
PolicyServiceAbstraction,
|
||||||
DeviceTrustCryptoServiceAbstraction,
|
DeviceTrustCryptoServiceAbstraction,
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
GlobalStateProvider,
|
GlobalStateProvider,
|
||||||
BillingAccountProfileStateService,
|
BillingAccountProfileStateService,
|
||||||
],
|
],
|
||||||
@@ -475,6 +481,15 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
useClass: EnvironmentService,
|
useClass: EnvironmentService,
|
||||||
deps: [StateProvider, AccountServiceAbstraction],
|
deps: [StateProvider, AccountServiceAbstraction],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
useClass: UserDecryptionOptionsService,
|
||||||
|
deps: [StateProvider],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: UserDecryptionOptionsServiceAbstraction,
|
||||||
|
useExisting: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: TotpServiceAbstraction,
|
provide: TotpServiceAbstraction,
|
||||||
useClass: TotpService,
|
useClass: TotpService,
|
||||||
@@ -575,6 +590,7 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
FolderApiServiceAbstraction,
|
FolderApiServiceAbstraction,
|
||||||
InternalOrganizationServiceAbstraction,
|
InternalOrganizationServiceAbstraction,
|
||||||
SendApiServiceAbstraction,
|
SendApiServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
AvatarServiceAbstraction,
|
AvatarServiceAbstraction,
|
||||||
LOGOUT_CALLBACK,
|
LOGOUT_CALLBACK,
|
||||||
BillingAccountProfileStateService,
|
BillingAccountProfileStateService,
|
||||||
@@ -585,6 +601,7 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
provide: VaultTimeoutSettingsServiceAbstraction,
|
provide: VaultTimeoutSettingsServiceAbstraction,
|
||||||
useClass: VaultTimeoutSettingsService,
|
useClass: VaultTimeoutSettingsService,
|
||||||
deps: [
|
deps: [
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
TokenServiceAbstraction,
|
TokenServiceAbstraction,
|
||||||
PolicyServiceAbstraction,
|
PolicyServiceAbstraction,
|
||||||
@@ -763,6 +780,7 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
UserVerificationApiServiceAbstraction,
|
UserVerificationApiServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
PinCryptoServiceAbstraction,
|
PinCryptoServiceAbstraction,
|
||||||
LogService,
|
LogService,
|
||||||
VaultTimeoutSettingsServiceAbstraction,
|
VaultTimeoutSettingsServiceAbstraction,
|
||||||
@@ -900,6 +918,7 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
DevicesApiServiceAbstraction,
|
DevicesApiServiceAbstraction,
|
||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
PlatformUtilsServiceAbstraction,
|
PlatformUtilsServiceAbstraction,
|
||||||
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
@@ -1048,6 +1067,11 @@ const typesafeProviders: Array<SafeProvider> = [
|
|||||||
useClass: DefaultBillingAccountProfileStateService,
|
useClass: DefaultBillingAccountProfileStateService,
|
||||||
deps: [ActiveUserStateProvider],
|
deps: [ActiveUserStateProvider],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: OrganizationManagementPreferencesService,
|
||||||
|
useClass: DefaultOrganizationManagementPreferencesService,
|
||||||
|
deps: [StateProvider],
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
function encryptServiceFactory(
|
function encryptServiceFactory(
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
{{ dialogOptions.bodyText | i18n }}
|
{{ dialogOptions.bodyText | i18n }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<app-callout
|
<bit-callout
|
||||||
*ngIf="dialogOptions.calloutOptions"
|
*ngIf="dialogOptions.calloutOptions"
|
||||||
[type]="dialogOptions.calloutOptions.type"
|
[type]="dialogOptions.calloutOptions.type"
|
||||||
>
|
>
|
||||||
{{ dialogOptions.calloutOptions.text | i18n }}
|
{{ dialogOptions.calloutOptions.text | i18n }}
|
||||||
</app-callout>
|
</bit-callout>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Shown when client side verification methods picked and no verification methods found -->
|
<!-- Shown when client side verification methods picked and no verification methods found -->
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import {
|
import {
|
||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
CalloutModule,
|
||||||
DialogModule,
|
DialogModule,
|
||||||
DialogService,
|
DialogService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
@@ -34,6 +35,7 @@ import { UserVerificationFormInputComponent } from "./user-verification-form-inp
|
|||||||
DialogModule,
|
DialogModule,
|
||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
UserVerificationFormInputComponent,
|
UserVerificationFormInputComponent,
|
||||||
|
CalloutModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class UserVerificationDialogComponent {
|
export class UserVerificationDialogComponent {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ export type UserVerificationCalloutOptions = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the callout.
|
* The type of the callout.
|
||||||
* Can be "warning", "danger", "error", or "tip".
|
* Can be "warning", "danger", "info", or "success".
|
||||||
*/
|
*/
|
||||||
type: "warning" | "danger" | "error" | "tip";
|
type: "warning" | "danger" | "info" | "success";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,12 +49,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-callout type="error" *ngIf="biometricsVerificationFailed">
|
<bit-callout type="danger" *ngIf="biometricsVerificationFailed">
|
||||||
{{ "couldNotCompleteBiometrics" | i18n }}
|
{{ "couldNotCompleteBiometrics" | i18n }}
|
||||||
<button bitLink type="button" linkType="primary" (click)="verifyUserViaBiometrics()">
|
<button bitLink type="button" linkType="primary" (click)="verifyUserViaBiometrics()">
|
||||||
{{ "tryAgain" | i18n }}
|
{{ "tryAgain" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</app-callout>
|
</bit-callout>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Alternate verification options if user has more than 1 -->
|
<!-- Alternate verification options if user has more than 1 -->
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|||||||
import {
|
import {
|
||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
CalloutModule,
|
||||||
FormFieldModule,
|
FormFieldModule,
|
||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
IconModule,
|
IconModule,
|
||||||
@@ -62,6 +63,7 @@ import { ActiveClientVerificationOption } from "./active-client-verification-opt
|
|||||||
IconModule,
|
IconModule,
|
||||||
LinkModule,
|
LinkModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
CalloutModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./pin-crypto.service.abstraction";
|
export * from "./pin-crypto.service.abstraction";
|
||||||
export * from "./login-strategy.service";
|
export * from "./login-strategy.service";
|
||||||
|
export * from "./user-decryption-options.service.abstraction";
|
||||||
export * from "./auth-request.service.abstraction";
|
export * from "./auth-request.service.abstraction";
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
|
import { UserDecryptionOptions } from "../models";
|
||||||
|
|
||||||
|
export abstract class UserDecryptionOptionsServiceAbstraction {
|
||||||
|
/**
|
||||||
|
* Returns what decryption options are available for the current user.
|
||||||
|
* @remark This is sent from the server on authentication.
|
||||||
|
*/
|
||||||
|
abstract userDecryptionOptions$: Observable<UserDecryptionOptions>;
|
||||||
|
/**
|
||||||
|
* Uses user decryption options to determine if current user has a master password.
|
||||||
|
* @remark This is sent from the server, and does not indicate if the master password
|
||||||
|
* was used to login and/or if a master key is saved locally.
|
||||||
|
*/
|
||||||
|
abstract hasMasterPassword$: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the user decryption options for the given user id.
|
||||||
|
* @param userId The user id to check.
|
||||||
|
*/
|
||||||
|
abstract userDecryptionOptionsById$(userId: string): Observable<UserDecryptionOptions>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class InternalUserDecryptionOptionsServiceAbstraction extends UserDecryptionOptionsServiceAbstraction {
|
||||||
|
/**
|
||||||
|
* Sets the current decryption options for the user, contains the current configuration
|
||||||
|
* of the users account related to how they can decrypt their vault.
|
||||||
|
* @remark Intended to be used when user decryption options are received from server, does
|
||||||
|
* not update the server. Consider syncing instead of updating locally.
|
||||||
|
* @param userDecryptionOptions Current user decryption options received from server.
|
||||||
|
*/
|
||||||
|
abstract setUserDecryptionOptions(userDecryptionOptions: UserDecryptionOptions): Promise<void>;
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym
|
|||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { AuthRequestLoginCredentials } from "../models/domain/login-credentials";
|
import { AuthRequestLoginCredentials } from "../models/domain/login-credentials";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -37,6 +38,7 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<StateService>;
|
||||||
let twoFactorService: MockProxy<TwoFactorService>;
|
let twoFactorService: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptions: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptions = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
|
|
||||||
@@ -83,6 +86,7 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptions,
|
||||||
deviceTrustCryptoService,
|
deviceTrustCryptoService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { AuthRequestLoginCredentials } from "../models/domain/login-credentials";
|
import { AuthRequestLoginCredentials } from "../models/domain/login-credentials";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
@@ -67,6 +69,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import {
|
|||||||
AccountProfile,
|
AccountProfile,
|
||||||
AccountTokens,
|
AccountTokens,
|
||||||
AccountKeys,
|
AccountKeys,
|
||||||
AccountDecryptionOptions,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/account";
|
} from "@bitwarden/common/platform/models/domain/account";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
@@ -39,8 +38,10 @@ import {
|
|||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserKey, MasterKey, DeviceKey } from "@bitwarden/common/types/key";
|
import { UserKey, MasterKey, DeviceKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "../abstractions/login-strategy.service";
|
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
||||||
import { PasswordLoginCredentials } from "../models/domain/login-credentials";
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
|
import { PasswordLoginCredentials } from "../models";
|
||||||
|
import { UserDecryptionOptions } from "../models/domain/user-decryption-options";
|
||||||
|
|
||||||
import { PasswordLoginStrategy, PasswordLoginStrategyData } from "./password-login.strategy";
|
import { PasswordLoginStrategy, PasswordLoginStrategyData } from "./password-login.strategy";
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ describe("LoginStrategy", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<StateService>;
|
||||||
let twoFactorService: MockProxy<TwoFactorService>;
|
let twoFactorService: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let policyService: MockProxy<PolicyService>;
|
let policyService: MockProxy<PolicyService>;
|
||||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
@@ -126,7 +128,7 @@ describe("LoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
policyService = mock<PolicyService>();
|
policyService = mock<PolicyService>();
|
||||||
passwordStrengthService = mock<PasswordStrengthService>();
|
passwordStrengthService = mock<PasswordStrengthService>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
@@ -146,6 +148,7 @@ describe("LoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
passwordStrengthService,
|
passwordStrengthService,
|
||||||
policyService,
|
policyService,
|
||||||
loginStrategyService,
|
loginStrategyService,
|
||||||
@@ -204,9 +207,11 @@ describe("LoginStrategy", () => {
|
|||||||
...new AccountTokens(),
|
...new AccountTokens(),
|
||||||
},
|
},
|
||||||
keys: new AccountKeys(),
|
keys: new AccountKeys(),
|
||||||
decryptionOptions: AccountDecryptionOptions.fromResponse(idTokenResponse),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
expect(userDecryptionOptionsService.setUserDecryptionOptions).toHaveBeenCalledWith(
|
||||||
|
UserDecryptionOptions.fromResponse(idTokenResponse),
|
||||||
|
);
|
||||||
expect(messagingService.send).toHaveBeenCalledWith("loggedIn");
|
expect(messagingService.send).toHaveBeenCalledWith("loggedIn");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -409,6 +414,7 @@ describe("LoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
passwordStrengthService,
|
passwordStrengthService,
|
||||||
policyService,
|
policyService,
|
||||||
loginStrategyService,
|
loginStrategyService,
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ import {
|
|||||||
Account,
|
Account,
|
||||||
AccountProfile,
|
AccountProfile,
|
||||||
AccountTokens,
|
AccountTokens,
|
||||||
AccountDecryptionOptions,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/account";
|
} from "@bitwarden/common/platform/models/domain/account";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import {
|
import {
|
||||||
UserApiLoginCredentials,
|
UserApiLoginCredentials,
|
||||||
PasswordLoginCredentials,
|
PasswordLoginCredentials,
|
||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
AuthRequestLoginCredentials,
|
AuthRequestLoginCredentials,
|
||||||
WebAuthnLoginCredentials,
|
WebAuthnLoginCredentials,
|
||||||
} from "../models/domain/login-credentials";
|
} from "../models/domain/login-credentials";
|
||||||
|
import { UserDecryptionOptions } from "../models/domain/user-decryption-options";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
type IdentityResponse = IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse;
|
type IdentityResponse = IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse;
|
||||||
@@ -69,6 +70,7 @@ export abstract class LoginStrategy {
|
|||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
protected stateService: StateService,
|
protected stateService: StateService,
|
||||||
protected twoFactorService: TwoFactorService,
|
protected twoFactorService: TwoFactorService,
|
||||||
|
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -203,11 +205,14 @@ export abstract class LoginStrategy {
|
|||||||
...new AccountTokens(),
|
...new AccountTokens(),
|
||||||
},
|
},
|
||||||
keys: accountKeys,
|
keys: accountKeys,
|
||||||
decryptionOptions: AccountDecryptionOptions.fromResponse(tokenResponse),
|
|
||||||
adminAuthRequest: adminAuthRequest?.toJSON(),
|
adminAuthRequest: adminAuthRequest?.toJSON(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await this.userDecryptionOptionsService.setUserDecryptionOptions(
|
||||||
|
UserDecryptionOptions.fromResponse(tokenResponse),
|
||||||
|
);
|
||||||
|
|
||||||
await this.billingAccountProfileStateService.setHasPremium(accountInformation.premium, false);
|
await this.billingAccountProfileStateService.setHasPremium(accountInformation.premium, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { CsprngArray } from "@bitwarden/common/types/csprng";
|
|||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { PasswordLoginCredentials } from "../models/domain/login-credentials";
|
import { PasswordLoginCredentials } from "../models/domain/login-credentials";
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
||||||
@@ -60,6 +61,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<StateService>;
|
||||||
let twoFactorService: MockProxy<TwoFactorService>;
|
let twoFactorService: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let policyService: MockProxy<PolicyService>;
|
let policyService: MockProxy<PolicyService>;
|
||||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
@@ -79,6 +81,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
policyService = mock<PolicyService>();
|
policyService = mock<PolicyService>();
|
||||||
passwordStrengthService = mock<PasswordStrengthService>();
|
passwordStrengthService = mock<PasswordStrengthService>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
@@ -108,6 +111,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
passwordStrengthService,
|
passwordStrengthService,
|
||||||
policyService,
|
policyService,
|
||||||
loginStrategyService,
|
loginStrategyService,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/pass
|
|||||||
import { MasterKey } from "@bitwarden/common/types/key";
|
import { MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { PasswordLoginCredentials } from "../models/domain/login-credentials";
|
import { PasswordLoginCredentials } from "../models/domain/login-credentials";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
@@ -84,6 +85,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
protected stateService: StateService,
|
protected stateService: StateService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
private passwordStrengthService: PasswordStrengthServiceAbstraction,
|
private passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private loginStrategyService: LoginStrategyServiceAbstraction,
|
private loginStrategyService: LoginStrategyServiceAbstraction,
|
||||||
@@ -99,6 +101,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym
|
|||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key";
|
import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../abstractions";
|
import {
|
||||||
|
AuthRequestServiceAbstraction,
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "../abstractions";
|
||||||
import { SsoLoginCredentials } from "../models/domain/login-credentials";
|
import { SsoLoginCredentials } from "../models/domain/login-credentials";
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
||||||
@@ -39,6 +42,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<StateService>;
|
||||||
let twoFactorService: MockProxy<TwoFactorService>;
|
let twoFactorService: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let keyConnectorService: MockProxy<KeyConnectorService>;
|
let keyConnectorService: MockProxy<KeyConnectorService>;
|
||||||
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
||||||
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
||||||
@@ -66,6 +70,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
keyConnectorService = mock<KeyConnectorService>();
|
keyConnectorService = mock<KeyConnectorService>();
|
||||||
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
||||||
authRequestService = mock<AuthRequestServiceAbstraction>();
|
authRequestService = mock<AuthRequestServiceAbstraction>();
|
||||||
@@ -87,6 +92,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
keyConnectorService,
|
keyConnectorService,
|
||||||
deviceTrustCryptoService,
|
deviceTrustCryptoService,
|
||||||
authRequestService,
|
authRequestService,
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../abstractions";
|
import {
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
AuthRequestServiceAbstraction,
|
||||||
|
} from "../abstractions";
|
||||||
import { SsoLoginCredentials } from "../models/domain/login-credentials";
|
import { SsoLoginCredentials } from "../models/domain/login-credentials";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
@@ -84,6 +87,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
private keyConnectorService: KeyConnectorService,
|
private keyConnectorService: KeyConnectorService,
|
||||||
private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
private authRequestService: AuthRequestServiceAbstraction,
|
private authRequestService: AuthRequestServiceAbstraction,
|
||||||
@@ -100,6 +104,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym
|
|||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { UserApiLoginCredentials } from "../models/domain/login-credentials";
|
import { UserApiLoginCredentials } from "../models/domain/login-credentials";
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
||||||
@@ -35,6 +36,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<StateService>;
|
||||||
let twoFactorService: MockProxy<TwoFactorService>;
|
let twoFactorService: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let keyConnectorService: MockProxy<KeyConnectorService>;
|
let keyConnectorService: MockProxy<KeyConnectorService>;
|
||||||
let environmentService: MockProxy<EnvironmentService>;
|
let environmentService: MockProxy<EnvironmentService>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
@@ -57,6 +59,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
keyConnectorService = mock<KeyConnectorService>();
|
keyConnectorService = mock<KeyConnectorService>();
|
||||||
environmentService = mock<EnvironmentService>();
|
environmentService = mock<EnvironmentService>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
@@ -76,6 +79,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
environmentService,
|
environmentService,
|
||||||
keyConnectorService,
|
keyConnectorService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { UserApiLoginCredentials } from "../models/domain/login-credentials";
|
import { UserApiLoginCredentials } from "../models/domain/login-credentials";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
private keyConnectorService: KeyConnectorService,
|
private keyConnectorService: KeyConnectorService,
|
||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
@@ -61,6 +63,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
this.cache = new BehaviorSubject(data);
|
this.cache = new BehaviorSubject(data);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { PrfKey, UserKey } from "@bitwarden/common/types/key";
|
import { PrfKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { WebAuthnLoginCredentials } from "../models/domain/login-credentials";
|
import { WebAuthnLoginCredentials } from "../models/domain/login-credentials";
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
import { identityTokenResponseFactory } from "./login.strategy.spec";
|
||||||
@@ -35,6 +36,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
let logService!: MockProxy<LogService>;
|
let logService!: MockProxy<LogService>;
|
||||||
let stateService!: MockProxy<StateService>;
|
let stateService!: MockProxy<StateService>;
|
||||||
let twoFactorService!: MockProxy<TwoFactorService>;
|
let twoFactorService!: MockProxy<TwoFactorService>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
|
|
||||||
let webAuthnLoginStrategy!: WebAuthnLoginStrategy;
|
let webAuthnLoginStrategy!: WebAuthnLoginStrategy;
|
||||||
@@ -70,6 +72,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<StateService>();
|
||||||
twoFactorService = mock<TwoFactorService>();
|
twoFactorService = mock<TwoFactorService>();
|
||||||
|
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
|
|
||||||
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
||||||
@@ -87,6 +90,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
|||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions";
|
||||||
import { WebAuthnLoginCredentials } from "../models/domain/login-credentials";
|
import { WebAuthnLoginCredentials } from "../models/domain/login-credentials";
|
||||||
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
import { CacheData } from "../services/login-strategies/login-strategy.state";
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -61,6 +63,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./rotateable-key-set";
|
export * from "./rotateable-key-set";
|
||||||
export * from "./login-credentials";
|
export * from "./login-credentials";
|
||||||
|
export * from "./user-decryption-options";
|
||||||
|
|||||||
153
libs/auth/src/common/models/domain/user-decryption-options.ts
Normal file
153
libs/auth/src/common/models/domain/user-decryption-options.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { KeyConnectorUserDecryptionOptionResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/key-connector-user-decryption-option.response";
|
||||||
|
import { TrustedDeviceUserDecryptionOptionResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/trusted-device-user-decryption-option.response";
|
||||||
|
import { IdentityTokenResponse } from "@bitwarden/common/src/auth/models/response/identity-token.response";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Connector decryption options. Intended to be sent to the client for use after authentication.
|
||||||
|
* @see {@link UserDecryptionOptions}
|
||||||
|
*/
|
||||||
|
export class KeyConnectorUserDecryptionOption {
|
||||||
|
/** The URL of the key connector configured for this user. */
|
||||||
|
keyConnectorUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the KeyConnectorUserDecryptionOption from a response object.
|
||||||
|
* @param response The key connector user decryption option response object.
|
||||||
|
* @returns A new instance of the KeyConnectorUserDecryptionOption. Will initialize even if the response is nullish.
|
||||||
|
*/
|
||||||
|
static fromResponse(
|
||||||
|
response: KeyConnectorUserDecryptionOptionResponse,
|
||||||
|
): KeyConnectorUserDecryptionOption {
|
||||||
|
const options = new KeyConnectorUserDecryptionOption();
|
||||||
|
options.keyConnectorUrl = response?.keyConnectorUrl ?? null;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of a KeyConnectorUserDecryptionOption from a JSON object.
|
||||||
|
* @param obj JSON object to deserialize.
|
||||||
|
* @returns A new instance of the KeyConnectorUserDecryptionOption. Will initialize even if the JSON object is nullish.
|
||||||
|
*/
|
||||||
|
static fromJSON(
|
||||||
|
obj: Jsonify<KeyConnectorUserDecryptionOption>,
|
||||||
|
): KeyConnectorUserDecryptionOption {
|
||||||
|
return Object.assign(new KeyConnectorUserDecryptionOption(), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trusted device decryption options. Intended to be sent to the client for use after authentication.
|
||||||
|
* @see {@link UserDecryptionOptions}
|
||||||
|
*/
|
||||||
|
export class TrustedDeviceUserDecryptionOption {
|
||||||
|
/** True if an admin has approved an admin auth request previously made from this device. */
|
||||||
|
hasAdminApproval: boolean;
|
||||||
|
/** True if the user has a device capable of approving an auth request. */
|
||||||
|
hasLoginApprovingDevice: boolean;
|
||||||
|
/** True if the user has manage reset password permission, as these users must be forced to have a master password. */
|
||||||
|
hasManageResetPasswordPermission: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the TrustedDeviceUserDecryptionOption from a response object.
|
||||||
|
* @param response The trusted device user decryption option response object.
|
||||||
|
* @returns A new instance of the TrustedDeviceUserDecryptionOption. Will initialize even if the response is nullish.
|
||||||
|
*/
|
||||||
|
static fromResponse(
|
||||||
|
response: TrustedDeviceUserDecryptionOptionResponse,
|
||||||
|
): TrustedDeviceUserDecryptionOption {
|
||||||
|
const options = new TrustedDeviceUserDecryptionOption();
|
||||||
|
options.hasAdminApproval = response?.hasAdminApproval ?? false;
|
||||||
|
options.hasLoginApprovingDevice = response?.hasLoginApprovingDevice ?? false;
|
||||||
|
options.hasManageResetPasswordPermission = response?.hasManageResetPasswordPermission ?? false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the TrustedDeviceUserDecryptionOption from a JSON object.
|
||||||
|
* @param obj JSON object to deserialize.
|
||||||
|
* @returns A new instance of the TrustedDeviceUserDecryptionOption. Will initialize even if the JSON object is nullish.
|
||||||
|
*/
|
||||||
|
static fromJSON(
|
||||||
|
obj: Jsonify<TrustedDeviceUserDecryptionOption>,
|
||||||
|
): TrustedDeviceUserDecryptionOption {
|
||||||
|
return Object.assign(new TrustedDeviceUserDecryptionOption(), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the decryption options the user has configured on the server. This is intended to be sent
|
||||||
|
* to the client on authentication, and can be used to determine how to decrypt the user's vault.
|
||||||
|
*/
|
||||||
|
export class UserDecryptionOptions {
|
||||||
|
/** True if the user has a master password configured on the server. */
|
||||||
|
hasMasterPassword: boolean;
|
||||||
|
/** {@link TrustedDeviceUserDecryptionOption} */
|
||||||
|
trustedDeviceOption?: TrustedDeviceUserDecryptionOption;
|
||||||
|
/** {@link KeyConnectorUserDecryptionOption} */
|
||||||
|
keyConnectorOption?: KeyConnectorUserDecryptionOption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the UserDecryptionOptions from a response object.
|
||||||
|
* @param response user decryption options response object
|
||||||
|
* @returns A new instance of the UserDecryptionOptions.
|
||||||
|
* @throws If the response is nullish, this method will throw an error. User decryption options
|
||||||
|
* are required for client initialization.
|
||||||
|
*/
|
||||||
|
// TODO: Change response type to `UserDecryptionOptionsResponse` after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537)
|
||||||
|
static fromResponse(response: IdentityTokenResponse): UserDecryptionOptions {
|
||||||
|
if (response == null) {
|
||||||
|
throw new Error("User Decryption Options are required for client initialization.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const decryptionOptions = new UserDecryptionOptions();
|
||||||
|
|
||||||
|
if (response.userDecryptionOptions) {
|
||||||
|
// If the response has userDecryptionOptions, this means it's on a post-TDE server version and can interrogate
|
||||||
|
// the new decryption options.
|
||||||
|
const responseOptions = response.userDecryptionOptions;
|
||||||
|
decryptionOptions.hasMasterPassword = responseOptions.hasMasterPassword;
|
||||||
|
|
||||||
|
decryptionOptions.trustedDeviceOption = TrustedDeviceUserDecryptionOption.fromResponse(
|
||||||
|
responseOptions.trustedDeviceOption,
|
||||||
|
);
|
||||||
|
|
||||||
|
decryptionOptions.keyConnectorOption = KeyConnectorUserDecryptionOption.fromResponse(
|
||||||
|
responseOptions.keyConnectorOption,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// If the response does not have userDecryptionOptions, this means it's on a pre-TDE server version and so
|
||||||
|
// we must base our decryption options on the presence of the keyConnectorUrl.
|
||||||
|
// Note that the presence of keyConnectorUrl implies that the user does not have a master password, as in pre-TDE
|
||||||
|
// server versions, a master password short-circuited the addition of the keyConnectorUrl to the response.
|
||||||
|
// TODO: remove this check after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537)
|
||||||
|
const usingKeyConnector = response.keyConnectorUrl != null;
|
||||||
|
decryptionOptions.hasMasterPassword = !usingKeyConnector;
|
||||||
|
if (usingKeyConnector) {
|
||||||
|
decryptionOptions.keyConnectorOption = new KeyConnectorUserDecryptionOption();
|
||||||
|
decryptionOptions.keyConnectorOption.keyConnectorUrl = response.keyConnectorUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decryptionOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the UserDecryptionOptions from a JSON object.
|
||||||
|
* @param obj JSON object to deserialize.
|
||||||
|
* @returns A new instance of the UserDecryptionOptions. Will initialize even if the JSON object is nullish.
|
||||||
|
*/
|
||||||
|
static fromJSON(obj: Jsonify<UserDecryptionOptions>): UserDecryptionOptions {
|
||||||
|
const decryptionOptions = Object.assign(new UserDecryptionOptions(), obj);
|
||||||
|
|
||||||
|
decryptionOptions.trustedDeviceOption = TrustedDeviceUserDecryptionOption.fromJSON(
|
||||||
|
obj?.trustedDeviceOption,
|
||||||
|
);
|
||||||
|
|
||||||
|
decryptionOptions.keyConnectorOption = KeyConnectorUserDecryptionOption.fromJSON(
|
||||||
|
obj?.keyConnectorOption,
|
||||||
|
);
|
||||||
|
|
||||||
|
return decryptionOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from "./domain";
|
export * from "./domain";
|
||||||
|
export * from "./spec";
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
KeyConnectorUserDecryptionOption,
|
||||||
|
TrustedDeviceUserDecryptionOption,
|
||||||
|
UserDecryptionOptions,
|
||||||
|
} from "../domain";
|
||||||
|
|
||||||
|
// To discourage creating new user decryption options, we don't expose a constructor.
|
||||||
|
// These helpers are for testing purposes only.
|
||||||
|
|
||||||
|
/** Testing helper for creating new instances of `UserDecryptionOptions` */
|
||||||
|
export class FakeUserDecryptionOptions extends UserDecryptionOptions {
|
||||||
|
constructor(init: Partial<UserDecryptionOptions>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Testing helper for creating new instances of `KeyConnectorUserDecryptionOption` */
|
||||||
|
export class FakeKeyConnectorUserDecryptionOption extends KeyConnectorUserDecryptionOption {
|
||||||
|
constructor(keyConnectorUrl: string) {
|
||||||
|
super();
|
||||||
|
this.keyConnectorUrl = keyConnectorUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Testing helper for creating new instances of `TrustedDeviceUserDecryptionOption` */
|
||||||
|
export class FakeTrustedDeviceUserDecryptionOption extends TrustedDeviceUserDecryptionOption {
|
||||||
|
constructor(
|
||||||
|
hasAdminApproval: boolean,
|
||||||
|
hasLoginApprovingDevice: boolean,
|
||||||
|
hasManageResetPasswordPermission: boolean,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.hasAdminApproval = hasAdminApproval;
|
||||||
|
this.hasLoginApprovingDevice = hasLoginApprovingDevice;
|
||||||
|
this.hasManageResetPasswordPermission = hasManageResetPasswordPermission;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
libs/auth/src/common/models/spec/index.ts
Normal file
1
libs/auth/src/common/models/spec/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./fake-user-decryption-options";
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./pin-crypto/pin-crypto.service.implementation";
|
export * from "./pin-crypto/pin-crypto.service.implementation";
|
||||||
export * from "./login-strategies/login-strategy.service";
|
export * from "./login-strategies/login-strategy.service";
|
||||||
|
export * from "./user-decryption-options/user-decryption-options.service";
|
||||||
export * from "./auth-request/auth-request.service";
|
export * from "./auth-request/auth-request.service";
|
||||||
|
|||||||
@@ -25,8 +25,12 @@ import { KdfType } from "@bitwarden/common/platform/enums";
|
|||||||
import { FakeGlobalState, FakeGlobalStateProvider } from "@bitwarden/common/spec";
|
import { FakeGlobalState, FakeGlobalStateProvider } from "@bitwarden/common/spec";
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../../abstractions";
|
import {
|
||||||
|
AuthRequestServiceAbstraction,
|
||||||
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
} from "../../abstractions";
|
||||||
import { PasswordLoginCredentials } from "../../models";
|
import { PasswordLoginCredentials } from "../../models";
|
||||||
|
import { UserDecryptionOptionsService } from "../user-decryption-options/user-decryption-options.service";
|
||||||
|
|
||||||
import { LoginStrategyService } from "./login-strategy.service";
|
import { LoginStrategyService } from "./login-strategy.service";
|
||||||
import { CACHE_EXPIRATION_KEY } from "./login-strategy.state";
|
import { CACHE_EXPIRATION_KEY } from "./login-strategy.state";
|
||||||
@@ -51,6 +55,7 @@ describe("LoginStrategyService", () => {
|
|||||||
let policyService: MockProxy<PolicyService>;
|
let policyService: MockProxy<PolicyService>;
|
||||||
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
||||||
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
||||||
|
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
|
|
||||||
let stateProvider: FakeGlobalStateProvider;
|
let stateProvider: FakeGlobalStateProvider;
|
||||||
@@ -74,6 +79,7 @@ describe("LoginStrategyService", () => {
|
|||||||
policyService = mock<PolicyService>();
|
policyService = mock<PolicyService>();
|
||||||
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
||||||
authRequestService = mock<AuthRequestServiceAbstraction>();
|
authRequestService = mock<AuthRequestServiceAbstraction>();
|
||||||
|
userDecryptionOptionsService = mock<UserDecryptionOptionsService>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
stateProvider = new FakeGlobalStateProvider();
|
stateProvider = new FakeGlobalStateProvider();
|
||||||
|
|
||||||
@@ -95,6 +101,7 @@ describe("LoginStrategyService", () => {
|
|||||||
policyService,
|
policyService,
|
||||||
deviceTrustCryptoService,
|
deviceTrustCryptoService,
|
||||||
authRequestService,
|
authRequestService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
stateProvider,
|
stateProvider,
|
||||||
billingAccountProfileStateService,
|
billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/pass
|
|||||||
import { MasterKey } from "@bitwarden/common/types/key";
|
import { MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction, LoginStrategyServiceAbstraction } from "../../abstractions";
|
import { AuthRequestServiceAbstraction, LoginStrategyServiceAbstraction } from "../../abstractions";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction";
|
||||||
import { AuthRequestLoginStrategy } from "../../login-strategies/auth-request-login.strategy";
|
import { AuthRequestLoginStrategy } from "../../login-strategies/auth-request-login.strategy";
|
||||||
import { PasswordLoginStrategy } from "../../login-strategies/password-login.strategy";
|
import { PasswordLoginStrategy } from "../../login-strategies/password-login.strategy";
|
||||||
import { SsoLoginStrategy } from "../../login-strategies/sso-login.strategy";
|
import { SsoLoginStrategy } from "../../login-strategies/sso-login.strategy";
|
||||||
@@ -101,6 +102,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
protected policyService: PolicyService,
|
protected policyService: PolicyService,
|
||||||
protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
protected authRequestService: AuthRequestServiceAbstraction,
|
protected authRequestService: AuthRequestServiceAbstraction,
|
||||||
|
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
protected stateProvider: GlobalStateProvider,
|
protected stateProvider: GlobalStateProvider,
|
||||||
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
@@ -354,6 +356,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.twoFactorService,
|
this.twoFactorService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.passwordStrengthService,
|
this.passwordStrengthService,
|
||||||
this.policyService,
|
this.policyService,
|
||||||
this,
|
this,
|
||||||
@@ -371,6 +374,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.twoFactorService,
|
this.twoFactorService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.keyConnectorService,
|
this.keyConnectorService,
|
||||||
this.deviceTrustCryptoService,
|
this.deviceTrustCryptoService,
|
||||||
this.authRequestService,
|
this.authRequestService,
|
||||||
@@ -389,6 +393,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.twoFactorService,
|
this.twoFactorService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.environmentService,
|
this.environmentService,
|
||||||
this.keyConnectorService,
|
this.keyConnectorService,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
@@ -405,6 +410,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.twoFactorService,
|
this.twoFactorService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.deviceTrustCryptoService,
|
this.deviceTrustCryptoService,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
@@ -420,6 +426,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.logService,
|
this.logService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.twoFactorService,
|
this.twoFactorService,
|
||||||
|
this.userDecryptionOptionsService,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
import {
|
||||||
|
FakeAccountService,
|
||||||
|
FakeStateProvider,
|
||||||
|
mockAccountServiceWith,
|
||||||
|
} from "@bitwarden/common/spec";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
|
import {
|
||||||
|
USER_DECRYPTION_OPTIONS,
|
||||||
|
UserDecryptionOptionsService,
|
||||||
|
} from "./user-decryption-options.service";
|
||||||
|
|
||||||
|
describe("UserDecryptionOptionsService", () => {
|
||||||
|
let sut: UserDecryptionOptionsService;
|
||||||
|
|
||||||
|
const fakeUserId = Utils.newGuid() as UserId;
|
||||||
|
let fakeAccountService: FakeAccountService;
|
||||||
|
let fakeStateProvider: FakeStateProvider;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fakeAccountService = mockAccountServiceWith(fakeUserId);
|
||||||
|
fakeStateProvider = new FakeStateProvider(fakeAccountService);
|
||||||
|
|
||||||
|
sut = new UserDecryptionOptionsService(fakeStateProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
const userDecryptionOptions = {
|
||||||
|
hasMasterPassword: true,
|
||||||
|
trustedDeviceOption: {
|
||||||
|
hasAdminApproval: false,
|
||||||
|
hasLoginApprovingDevice: false,
|
||||||
|
hasManageResetPasswordPermission: true,
|
||||||
|
},
|
||||||
|
keyConnectorOption: {
|
||||||
|
keyConnectorUrl: "https://keyconnector.bitwarden.com",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("userDecryptionOptions$", () => {
|
||||||
|
it("should return the active user's decryption options", async () => {
|
||||||
|
await fakeStateProvider.setUserState(USER_DECRYPTION_OPTIONS, userDecryptionOptions);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(sut.userDecryptionOptions$);
|
||||||
|
|
||||||
|
expect(result).toEqual(userDecryptionOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("hasMasterPassword$", () => {
|
||||||
|
it("should return the hasMasterPassword property of the active user's decryption options", async () => {
|
||||||
|
await fakeStateProvider.setUserState(USER_DECRYPTION_OPTIONS, userDecryptionOptions);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(sut.hasMasterPassword$);
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("userDecryptionOptionsById$", () => {
|
||||||
|
it("should return the user decryption options for the given user", async () => {
|
||||||
|
const givenUser = Utils.newGuid() as UserId;
|
||||||
|
await fakeAccountService.addAccount(givenUser, {
|
||||||
|
name: "Test User 1",
|
||||||
|
email: "test1@email.com",
|
||||||
|
status: AuthenticationStatus.Locked,
|
||||||
|
});
|
||||||
|
await fakeStateProvider.setUserState(
|
||||||
|
USER_DECRYPTION_OPTIONS,
|
||||||
|
userDecryptionOptions,
|
||||||
|
givenUser,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(sut.userDecryptionOptionsById$(givenUser));
|
||||||
|
|
||||||
|
expect(result).toEqual(userDecryptionOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("setUserDecryptionOptions", () => {
|
||||||
|
it("should set the active user's decryption options", async () => {
|
||||||
|
await sut.setUserDecryptionOptions(userDecryptionOptions);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(
|
||||||
|
fakeStateProvider.getActive(USER_DECRYPTION_OPTIONS).state$,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual(userDecryptionOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { map } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActiveUserState,
|
||||||
|
StateProvider,
|
||||||
|
USER_DECRYPTION_OPTIONS_DISK,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/common/platform/state";
|
||||||
|
import { UserId } from "@bitwarden/common/src/types/guid";
|
||||||
|
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction";
|
||||||
|
import { UserDecryptionOptions } from "../../models";
|
||||||
|
|
||||||
|
export const USER_DECRYPTION_OPTIONS = new UserKeyDefinition<UserDecryptionOptions>(
|
||||||
|
USER_DECRYPTION_OPTIONS_DISK,
|
||||||
|
"decryptionOptions",
|
||||||
|
{
|
||||||
|
deserializer: (decryptionOptions) => UserDecryptionOptions.fromJSON(decryptionOptions),
|
||||||
|
clearOn: ["logout"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export class UserDecryptionOptionsService
|
||||||
|
implements InternalUserDecryptionOptionsServiceAbstraction
|
||||||
|
{
|
||||||
|
private userDecryptionOptionsState: ActiveUserState<UserDecryptionOptions>;
|
||||||
|
|
||||||
|
userDecryptionOptions$;
|
||||||
|
hasMasterPassword$;
|
||||||
|
|
||||||
|
constructor(private stateProvider: StateProvider) {
|
||||||
|
this.userDecryptionOptionsState = this.stateProvider.getActive(USER_DECRYPTION_OPTIONS);
|
||||||
|
|
||||||
|
this.userDecryptionOptions$ = this.userDecryptionOptionsState.state$;
|
||||||
|
this.hasMasterPassword$ = this.userDecryptionOptions$.pipe(
|
||||||
|
map((options) => options?.hasMasterPassword ?? false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
userDecryptionOptionsById$(userId: UserId) {
|
||||||
|
return this.stateProvider.getUser(userId, USER_DECRYPTION_OPTIONS).state$;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setUserDecryptionOptions(userDecryptionOptions: UserDecryptionOptions): Promise<void> {
|
||||||
|
await this.userDecryptionOptionsState.update((_) => userDecryptionOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the state of a single organization management preference.
|
||||||
|
* Can be used to subscribe to or update a given property.
|
||||||
|
*/
|
||||||
|
export class OrganizationManagementPreference<T> {
|
||||||
|
state$: Observable<T>;
|
||||||
|
set: (value: T) => Promise<void>;
|
||||||
|
|
||||||
|
constructor(state$: Observable<T>, setFn: (value: T) => Promise<void>) {
|
||||||
|
this.state$ = state$;
|
||||||
|
this.set = setFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes state of a given user's personal settings relating to the user experience of managing an organization.
|
||||||
|
*/
|
||||||
|
export abstract class OrganizationManagementPreferencesService {
|
||||||
|
autoConfirmFingerPrints: OrganizationManagementPreference<boolean>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { MockProxy } from "jest-mock-extended";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { FakeStateProvider, mockAccountServiceWith } from "../../../../spec";
|
||||||
|
import { UserId } from "../../../types/guid";
|
||||||
|
|
||||||
|
import { DefaultOrganizationManagementPreferencesService } from "./default-organization-management-preferences.service";
|
||||||
|
|
||||||
|
describe("OrganizationManagementPreferencesService", () => {
|
||||||
|
let stateProvider: FakeStateProvider;
|
||||||
|
let organizationManagementPreferencesService: MockProxy<DefaultOrganizationManagementPreferencesService>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const accountService = mockAccountServiceWith("userId" as UserId);
|
||||||
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
organizationManagementPreferencesService = new DefaultOrganizationManagementPreferencesService(
|
||||||
|
stateProvider,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("autoConfirmFingerPrints", () => {
|
||||||
|
it("returns false by default", async () => {
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(false);
|
||||||
|
});
|
||||||
|
it("returns true if set", async () => {
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(true);
|
||||||
|
});
|
||||||
|
it("can be unset", async () => {
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(true);
|
||||||
|
await organizationManagementPreferencesService.autoConfirmFingerPrints.set(false);
|
||||||
|
const value = await firstValueFrom(
|
||||||
|
organizationManagementPreferencesService.autoConfirmFingerPrints.state$,
|
||||||
|
);
|
||||||
|
expect(value).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { map } from "rxjs";
|
||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ORGANIZATION_MANAGEMENT_PREFERENCES_DISK,
|
||||||
|
StateProvider,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "../../../platform/state";
|
||||||
|
import {
|
||||||
|
OrganizationManagementPreference,
|
||||||
|
OrganizationManagementPreferencesService,
|
||||||
|
} from "../../abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This helper function can be used to quickly create `KeyDefinitions` that
|
||||||
|
* target the `ORGANIZATION_MANAGEMENT_PREFERENCES_DISK` `StateDefinition`
|
||||||
|
* and that have the default deserializer and `clearOn` options. Any
|
||||||
|
* contenders for options to add to this service will likely use these same
|
||||||
|
* options.
|
||||||
|
*/
|
||||||
|
function buildKeyDefinition<T>(key: string): UserKeyDefinition<T> {
|
||||||
|
return new UserKeyDefinition<T>(ORGANIZATION_MANAGEMENT_PREFERENCES_DISK, key, {
|
||||||
|
deserializer: (obj: Jsonify<T>) => obj as T,
|
||||||
|
clearOn: ["logout"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AUTO_CONFIRM_FINGERPRINTS = buildKeyDefinition<boolean>("autoConfirmFingerPrints");
|
||||||
|
|
||||||
|
export class DefaultOrganizationManagementPreferencesService
|
||||||
|
implements OrganizationManagementPreferencesService
|
||||||
|
{
|
||||||
|
constructor(private stateProvider: StateProvider) {}
|
||||||
|
|
||||||
|
autoConfirmFingerPrints = this.buildOrganizationManagementPreference(
|
||||||
|
AUTO_CONFIRM_FINGERPRINTS,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an `OrganizationManagementPreference` object for the provided
|
||||||
|
* `KeyDefinition`. This object can then be used by callers to subscribe to
|
||||||
|
* a given key, or set its value in state.
|
||||||
|
*/
|
||||||
|
private buildOrganizationManagementPreference<T>(
|
||||||
|
keyDefinition: UserKeyDefinition<T>,
|
||||||
|
defaultValue: T,
|
||||||
|
) {
|
||||||
|
return new OrganizationManagementPreference<T>(
|
||||||
|
this.getKeyFromState(keyDefinition).state$.pipe(map((x) => x ?? defaultValue)),
|
||||||
|
this.setKeyInStateFn(keyDefinition),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the full `ActiveUserState` value for a given `keyDefinition`
|
||||||
|
* The returned value can then be called for subscription || set operations
|
||||||
|
*/
|
||||||
|
private getKeyFromState<T>(keyDefinition: UserKeyDefinition<T>) {
|
||||||
|
return this.stateProvider.getActive(keyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function that can be called to set the given `keyDefinition` in state
|
||||||
|
*/
|
||||||
|
private setKeyInStateFn<T>(keyDefinition: UserKeyDefinition<T>) {
|
||||||
|
return async (value: T) => {
|
||||||
|
await this.getKeyFromState(keyDefinition).update(() => value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user