mirror of
https://github.com/bitwarden/browser
synced 2026-02-13 15:03:26 +00:00
Merge branch 'main' into ps/extension-refresh
This commit is contained in:
@@ -24,7 +24,6 @@ export class CollectionsComponent implements OnInit {
|
||||
collectionIds: string[];
|
||||
collections: CollectionView[] = [];
|
||||
organization: Organization;
|
||||
flexibleCollectionsV1Enabled: boolean;
|
||||
restrictProviderAccess: boolean;
|
||||
|
||||
protected cipherDomain: Cipher;
|
||||
@@ -40,9 +39,6 @@ export class CollectionsComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
this.restrictProviderAccess = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@@ -72,12 +68,7 @@ export class CollectionsComponent implements OnInit {
|
||||
async submit(): Promise<boolean> {
|
||||
const selectedCollectionIds = this.collections
|
||||
.filter((c) => {
|
||||
if (
|
||||
this.organization.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
)
|
||||
) {
|
||||
if (this.organization.canEditAllCiphers(this.restrictProviderAccess)) {
|
||||
return !!(c as any).checked;
|
||||
} else {
|
||||
return !!(c as any).checked && c.readOnly == null;
|
||||
|
||||
@@ -16,14 +16,12 @@ import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractio
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import {
|
||||
MasterPasswordVerification,
|
||||
MasterPasswordVerificationResponse,
|
||||
} from "@bitwarden/common/auth/types/verification";
|
||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -136,10 +134,13 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
await this.biometricStateService.setUserPromptCancelled();
|
||||
const userKey = await this.cryptoService.getUserKeyFromStorage(KeySuffixOptions.Biometric);
|
||||
const userKey = await this.cryptoService.getUserKeyFromStorage(
|
||||
KeySuffixOptions.Biometric,
|
||||
this.activeUserId,
|
||||
);
|
||||
|
||||
if (userKey) {
|
||||
await this.setUserKeyAndContinue(userKey, false);
|
||||
await this.setUserKeyAndContinue(userKey, this.activeUserId, false);
|
||||
}
|
||||
|
||||
return !!userKey;
|
||||
@@ -176,7 +177,7 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
const userKey = await this.pinService.decryptUserKeyWithPin(this.pin, userId);
|
||||
|
||||
if (userKey) {
|
||||
await this.setUserKeyAndContinue(userKey);
|
||||
await this.setUserKeyAndContinue(userKey, userId);
|
||||
return; // successfully unlocked
|
||||
}
|
||||
|
||||
@@ -259,11 +260,15 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
const userKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(
|
||||
response.masterKey,
|
||||
);
|
||||
await this.setUserKeyAndContinue(userKey, true);
|
||||
await this.setUserKeyAndContinue(userKey, userId, true);
|
||||
}
|
||||
|
||||
private async setUserKeyAndContinue(key: UserKey, evaluatePasswordAfterUnlock = false) {
|
||||
await this.cryptoService.setUserKey(key);
|
||||
private async setUserKeyAndContinue(
|
||||
key: UserKey,
|
||||
userId: UserId,
|
||||
evaluatePasswordAfterUnlock = false,
|
||||
) {
|
||||
await this.cryptoService.setUserKey(key, userId);
|
||||
|
||||
// Now that we have a decrypted user key in memory, we can check if we
|
||||
// need to establish trust on the current device
|
||||
@@ -316,42 +321,9 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async load(userId: UserId) {
|
||||
// TODO: Investigate PM-3515
|
||||
|
||||
// The loading of the lock component works as follows:
|
||||
// 1. If the user is unlocked, we're here in error so we navigate to the home page
|
||||
// 2. First, is locking a valid timeout action? If not, we will log the user out.
|
||||
// 3. If locking IS a valid timeout action, we proceed to show the user the lock screen.
|
||||
// The user will be able to unlock as follows:
|
||||
// - If they have a PIN set, they will be presented with the PIN input
|
||||
// - If they have a master password and no PIN, they will be presented with the master password input
|
||||
// - If they have biometrics enabled, they will be presented with the biometric prompt
|
||||
|
||||
const isUnlocked = await firstValueFrom(
|
||||
this.authService
|
||||
.authStatusFor$(userId)
|
||||
.pipe(map((status) => status === AuthenticationStatus.Unlocked)),
|
||||
);
|
||||
if (isUnlocked) {
|
||||
// navigate to home
|
||||
await this.router.navigate(["/"]);
|
||||
return;
|
||||
}
|
||||
|
||||
const availableVaultTimeoutActions = await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService.availableVaultTimeoutActions$(userId),
|
||||
);
|
||||
const supportsLock = availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock);
|
||||
if (!supportsLock) {
|
||||
return await this.vaultTimeoutService.logOut(userId);
|
||||
}
|
||||
|
||||
this.pinLockType = await this.pinService.getPinLockType(userId);
|
||||
|
||||
const ephemeralPinSet = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
|
||||
|
||||
this.pinEnabled =
|
||||
(this.pinLockType === "EPHEMERAL" && !!ephemeralPinSet) || this.pinLockType === "PERSISTENT";
|
||||
this.pinEnabled = await this.pinService.isPinDecryptionAvailable(userId);
|
||||
|
||||
this.masterPasswordEnabled = await this.userVerificationService.hasMasterPassword();
|
||||
|
||||
|
||||
@@ -386,6 +386,7 @@ export class LoginViaAuthRequestComponent
|
||||
await this.authRequestService.setKeysAfterDecryptingSharedMasterKeyAndHash(
|
||||
adminAuthReqResponse,
|
||||
privateKey,
|
||||
userId,
|
||||
);
|
||||
} else {
|
||||
// Flow 3: masterPasswordHash is null
|
||||
@@ -393,6 +394,7 @@ export class LoginViaAuthRequestComponent
|
||||
await this.authRequestService.setUserKeyAfterDecryptingSharedUserKey(
|
||||
adminAuthReqResponse,
|
||||
privateKey,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
bitInput
|
||||
appAutofocus
|
||||
appInputVerbatim
|
||||
autocomplete="new-password"
|
||||
[(ngModel)]="tokenValue"
|
||||
(input)="token.emit(tokenValue)"
|
||||
/>
|
||||
|
||||
235
libs/angular/src/auth/guards/lock.guard.spec.ts
Normal file
235
libs/angular/src/auth/guards/lock.guard.spec.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { Router } from "@angular/router";
|
||||
import { RouterTestingModule } from "@angular/router/testing";
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { lockGuard } from "./lock.guard";
|
||||
|
||||
interface SetupParams {
|
||||
authStatus: AuthenticationStatus;
|
||||
canLock?: boolean;
|
||||
isLegacyUser?: boolean;
|
||||
clientType?: ClientType;
|
||||
everHadUserKey?: boolean;
|
||||
supportsDeviceTrust?: boolean;
|
||||
hasMasterPassword?: boolean;
|
||||
}
|
||||
|
||||
describe("lockGuard", () => {
|
||||
const setup = (setupParams: SetupParams) => {
|
||||
const authService: MockProxy<AuthService> = mock<AuthService>();
|
||||
authService.authStatusFor$.mockReturnValue(of(setupParams.authStatus));
|
||||
|
||||
const vaultTimeoutSettingsService: MockProxy<VaultTimeoutSettingsService> =
|
||||
mock<VaultTimeoutSettingsService>();
|
||||
vaultTimeoutSettingsService.canLock.mockResolvedValue(setupParams.canLock);
|
||||
|
||||
const cryptoService: MockProxy<CryptoService> = mock<CryptoService>();
|
||||
cryptoService.isLegacyUser.mockResolvedValue(setupParams.isLegacyUser);
|
||||
cryptoService.everHadUserKey$ = of(setupParams.everHadUserKey);
|
||||
|
||||
const platformUtilService: MockProxy<PlatformUtilsService> = mock<PlatformUtilsService>();
|
||||
platformUtilService.getClientType.mockReturnValue(setupParams.clientType);
|
||||
|
||||
const messagingService: MockProxy<MessagingService> = mock<MessagingService>();
|
||||
|
||||
const deviceTrustService: MockProxy<DeviceTrustServiceAbstraction> =
|
||||
mock<DeviceTrustServiceAbstraction>();
|
||||
deviceTrustService.supportsDeviceTrust$ = of(setupParams.supportsDeviceTrust);
|
||||
|
||||
const userVerificationService: MockProxy<UserVerificationService> =
|
||||
mock<UserVerificationService>();
|
||||
userVerificationService.hasMasterPassword.mockResolvedValue(setupParams.hasMasterPassword);
|
||||
|
||||
const accountService: MockProxy<AccountService> = mock<AccountService>();
|
||||
const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>(null);
|
||||
accountService.activeAccount$ = activeAccountSubject;
|
||||
activeAccountSubject.next(
|
||||
Object.assign(
|
||||
{
|
||||
name: "Test User 1",
|
||||
email: "test@email.com",
|
||||
emailVerified: true,
|
||||
} as AccountInfo,
|
||||
{ id: "test-id" as UserId },
|
||||
),
|
||||
);
|
||||
|
||||
const testBed = TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: "", component: EmptyComponent },
|
||||
{ path: "lock", component: EmptyComponent, canActivate: [lockGuard()] },
|
||||
{ path: "non-lock-route", component: EmptyComponent },
|
||||
{ path: "migrate-legacy-encryption", component: EmptyComponent },
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
{ provide: AuthService, useValue: authService },
|
||||
{ provide: MessagingService, useValue: messagingService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: VaultTimeoutSettingsService, useValue: vaultTimeoutSettingsService },
|
||||
{ provide: CryptoService, useValue: cryptoService },
|
||||
{ provide: PlatformUtilsService, useValue: platformUtilService },
|
||||
{ provide: DeviceTrustServiceAbstraction, useValue: deviceTrustService },
|
||||
{ provide: UserVerificationService, useValue: userVerificationService },
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
router: testBed.inject(Router),
|
||||
messagingService,
|
||||
};
|
||||
};
|
||||
|
||||
it("should be created", () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
});
|
||||
expect(router).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should redirect to the root route when the user is Unlocked", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Unlocked,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
});
|
||||
|
||||
it("should redirect to the root route when the user is LoggedOut", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.LoggedOut,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
});
|
||||
|
||||
it("should allow navigation to the lock route when the user is Locked and they can lock", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/lock");
|
||||
});
|
||||
|
||||
it("should allow navigation to the lock route when the user is locked, they can lock, and device trust is not supported", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
supportsDeviceTrust: false,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/lock");
|
||||
});
|
||||
|
||||
it("should not allow navigation to the lock route when canLock is false", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: false,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
});
|
||||
|
||||
it("should log user out if they are a legacy user on a desktop client", async () => {
|
||||
const { router, messagingService } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
isLegacyUser: true,
|
||||
clientType: ClientType.Desktop,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
expect(messagingService.send).toHaveBeenCalledWith("logout");
|
||||
});
|
||||
|
||||
it("should log user out if they are a legacy user on a browser extension client", async () => {
|
||||
const { router, messagingService } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
isLegacyUser: true,
|
||||
clientType: ClientType.Browser,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
expect(messagingService.send).toHaveBeenCalledWith("logout");
|
||||
});
|
||||
|
||||
it("should send the user to migrate-legacy-encryption if they are a legacy user on a web client", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
isLegacyUser: true,
|
||||
clientType: ClientType.Web,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/migrate-legacy-encryption");
|
||||
});
|
||||
|
||||
it("should allow navigation to the lock route when device trust is supported, the user has a MP, and the user is coming from the login-initiated page", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
isLegacyUser: false,
|
||||
clientType: ClientType.Web,
|
||||
everHadUserKey: false,
|
||||
supportsDeviceTrust: true,
|
||||
hasMasterPassword: true,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"], { queryParams: { from: "login-initiated" } });
|
||||
expect(router.url).toBe("/lock?from=login-initiated");
|
||||
});
|
||||
|
||||
it("should allow navigation to the lock route when TDE is disabled, the user doesn't have a MP, and the user has had a user key", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
supportsDeviceTrust: false,
|
||||
hasMasterPassword: false,
|
||||
everHadUserKey: true,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/lock");
|
||||
});
|
||||
|
||||
it("should not allow navigation to the lock route when device trust is supported and the user has not ever had a user key", async () => {
|
||||
const { router } = setup({
|
||||
authStatus: AuthenticationStatus.Locked,
|
||||
canLock: true,
|
||||
isLegacyUser: false,
|
||||
clientType: ClientType.Web,
|
||||
everHadUserKey: false,
|
||||
supportsDeviceTrust: true,
|
||||
hasMasterPassword: false,
|
||||
});
|
||||
|
||||
await router.navigate(["lock"]);
|
||||
expect(router.url).toBe("/");
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
} from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
@@ -19,7 +21,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
/**
|
||||
* Only allow access to this route if the vault is locked.
|
||||
* If TDE is enabled then the user must also have had a user key at some point.
|
||||
* Otherwise redirect to root.
|
||||
* Otherwise reject navigation.
|
||||
*
|
||||
* TODO: This should return Observable<boolean | UrlTree> once we can remove all the promises
|
||||
*/
|
||||
@@ -35,12 +37,22 @@ export function lockGuard(): CanActivateFn {
|
||||
const messagingService = inject(MessagingService);
|
||||
const router = inject(Router);
|
||||
const userVerificationService = inject(UserVerificationService);
|
||||
const vaultTimeoutSettingsService = inject(VaultTimeoutSettingsService);
|
||||
const accountService = inject(AccountService);
|
||||
|
||||
const authStatus = await authService.getAuthStatus();
|
||||
const activeUser = await firstValueFrom(accountService.activeAccount$);
|
||||
|
||||
const authStatus = await firstValueFrom(authService.authStatusFor$(activeUser.id));
|
||||
if (authStatus !== AuthenticationStatus.Locked) {
|
||||
return router.createUrlTree(["/"]);
|
||||
}
|
||||
|
||||
// if user can't lock, they can't access the lock screen
|
||||
const canLock = await vaultTimeoutSettingsService.canLock(activeUser.id);
|
||||
if (!canLock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If legacy user on web, redirect to migration page
|
||||
if (await cryptoService.isLegacyUser()) {
|
||||
if (platformUtilService.getClientType() === ClientType.Web) {
|
||||
@@ -65,11 +77,10 @@ export function lockGuard(): CanActivateFn {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If authN user with TDE directly navigates to lock, kick them upwards so redirect guard can
|
||||
// properly route them to the login decryption options component.
|
||||
// If authN user with TDE directly navigates to lock, reject that navigation
|
||||
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
|
||||
if (tdeEnabled && !everHadUserKey) {
|
||||
return router.createUrlTree(["/"]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -34,7 +34,6 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||
|
||||
usernameGeneratingPromise: Promise<string>;
|
||||
typeOptions: any[];
|
||||
passTypeOptions: any[];
|
||||
usernameTypeOptions: any[];
|
||||
subaddressOptions: any[];
|
||||
catchallOptions: any[];
|
||||
@@ -48,6 +47,11 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||
enforcedPasswordPolicyOptions: PasswordGeneratorPolicyOptions;
|
||||
usernameWebsite: string = null;
|
||||
|
||||
get passTypeOptions() {
|
||||
return this._passTypeOptions.filter((o) => !o.disabled);
|
||||
}
|
||||
private _passTypeOptions: { name: string; value: GeneratorType; disabled: boolean }[];
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
private isInitialized$ = new BehaviorSubject(false);
|
||||
|
||||
@@ -79,9 +83,9 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||
{ name: i18nService.t("password"), value: "password" },
|
||||
{ name: i18nService.t("username"), value: "username" },
|
||||
];
|
||||
this.passTypeOptions = [
|
||||
{ name: i18nService.t("password"), value: "password" },
|
||||
{ name: i18nService.t("passphrase"), value: "passphrase" },
|
||||
this._passTypeOptions = [
|
||||
{ name: i18nService.t("password"), value: "password", disabled: false },
|
||||
{ name: i18nService.t("passphrase"), value: "passphrase", disabled: false },
|
||||
];
|
||||
this.usernameTypeOptions = [
|
||||
{
|
||||
@@ -138,6 +142,14 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||
this.passwordOptions.type =
|
||||
this.passwordOptions.type === "passphrase" ? "passphrase" : "password";
|
||||
|
||||
const overrideType = this.enforcedPasswordPolicyOptions.overridePasswordType ?? "";
|
||||
const isDisabled = overrideType.length
|
||||
? (value: string, policyValue: string) => value !== policyValue
|
||||
: (_value: string, _policyValue: string) => false;
|
||||
for (const option of this._passTypeOptions) {
|
||||
option.disabled = isDisabled(option.value, overrideType);
|
||||
}
|
||||
|
||||
if (this.usernameOptions.type == null) {
|
||||
this.usernameOptions.type = "word";
|
||||
}
|
||||
|
||||
@@ -90,7 +90,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
private personalOwnershipPolicyAppliesToActiveUser: boolean;
|
||||
private previousCipherId: string;
|
||||
|
||||
protected flexibleCollectionsV1Enabled = false;
|
||||
protected restrictProviderAccess = false;
|
||||
|
||||
get fido2CredentialCreationDateValue(): string {
|
||||
@@ -181,9 +180,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.flexibleCollectionsV1Enabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
);
|
||||
this.restrictProviderAccess = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.RestrictProviderAccess,
|
||||
);
|
||||
@@ -674,10 +670,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected saveCipher(cipher: Cipher) {
|
||||
const isNotClone = this.editMode && !this.cloneMode;
|
||||
let orgAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
let orgAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
|
||||
// if a cipher is unassigned we want to check if they are an admin or have permission to edit any collection
|
||||
if (!cipher.collectionIds) {
|
||||
@@ -690,20 +683,14 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
protected deleteCipher() {
|
||||
const asAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
return this.cipher.isDeleted
|
||||
? this.cipherService.deleteWithServer(this.cipher.id, asAdmin)
|
||||
: this.cipherService.softDeleteWithServer(this.cipher.id, asAdmin);
|
||||
}
|
||||
|
||||
protected restoreCipher() {
|
||||
const asAdmin = this.organization?.canEditAllCiphers(
|
||||
this.flexibleCollectionsV1Enabled,
|
||||
this.restrictProviderAccess,
|
||||
);
|
||||
const asAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
||||
return this.cipherService.restoreWithServer(this.cipher.id, asAdmin);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user