mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[PM-21451] [Vault] [CLI] Changes to Enforce "Remove card item type policy" (#15187)
* Created new service to get restricted types for the CLI * Created service for cli to get restricted types * Utilized restriction service in commands * Renamed function * Refactored service and made it simpler to check when a cipher type is restricted or not * Moved service to common so it can be utilized on the cli * Refactored service to use restricted type service * Removed userId passing from commands * Exclude restrict types from export * Added missing dependency * Added missing dependency * Added missing dependency * Added service utils commit from desktop PR * refactored to use reusable function * updated reference * updated reference * Fixed merge conflicts * Refactired services to use isCipherRestricted * Refactored restricted item types service * Updated services to use the reafctored item types service
This commit is contained in:
@@ -24,6 +24,7 @@ import { Response } from "../models/response";
|
||||
import { CliUtils } from "../utils";
|
||||
import { CipherResponse } from "../vault/models/cipher.response";
|
||||
import { FolderResponse } from "../vault/models/folder.response";
|
||||
import { CliRestrictedItemTypesService } from "../vault/services/cli-restricted-item-types.service";
|
||||
|
||||
export class EditCommand {
|
||||
constructor(
|
||||
@@ -34,6 +35,7 @@ export class EditCommand {
|
||||
private apiService: ApiService,
|
||||
private folderApiService: FolderApiServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
private cliRestrictedItemTypesService: CliRestrictedItemTypesService,
|
||||
) {}
|
||||
|
||||
async run(
|
||||
@@ -95,6 +97,13 @@ export class EditCommand {
|
||||
return Response.badRequest("You may not edit a deleted item. Use the restore command first.");
|
||||
}
|
||||
cipherView = CipherExport.toView(req, cipherView);
|
||||
|
||||
const isCipherRestricted =
|
||||
await this.cliRestrictedItemTypesService.isCipherRestricted(cipherView);
|
||||
if (isCipherRestricted) {
|
||||
return Response.error("Editing this item type is restricted by organizational policy.");
|
||||
}
|
||||
|
||||
const encCipher = await this.cipherService.encrypt(cipherView, activeUserId);
|
||||
try {
|
||||
const updatedCipher = await this.cipherService.updateWithServer(encCipher);
|
||||
|
||||
@@ -27,7 +27,7 @@ import { ErrorResponse } from "@bitwarden/common/models/response/error.response"
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { CipherId, OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherId, OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
@@ -48,6 +48,7 @@ import { SendResponse } from "../tools/send/models/send.response";
|
||||
import { CliUtils } from "../utils";
|
||||
import { CipherResponse } from "../vault/models/cipher.response";
|
||||
import { FolderResponse } from "../vault/models/folder.response";
|
||||
import { CliRestrictedItemTypesService } from "../vault/services/cli-restricted-item-types.service";
|
||||
|
||||
import { DownloadCommand } from "./download.command";
|
||||
|
||||
@@ -66,6 +67,7 @@ export class GetCommand extends DownloadCommand {
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
private accountService: AccountService,
|
||||
private cliRestrictedItemTypesService: CliRestrictedItemTypesService,
|
||||
) {
|
||||
super(encryptService, apiService);
|
||||
}
|
||||
@@ -110,16 +112,16 @@ export class GetCommand extends DownloadCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async getCipherView(id: string): Promise<CipherView | CipherView[]> {
|
||||
private async getCipherView(id: string, userId: UserId): Promise<CipherView | CipherView[]> {
|
||||
let decCipher: CipherView = null;
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
if (Utils.isGuid(id)) {
|
||||
const cipher = await this.cipherService.get(id, activeUserId);
|
||||
const cipher = await this.cipherService.get(id, userId);
|
||||
if (cipher != null) {
|
||||
decCipher = await this.cipherService.decrypt(cipher, activeUserId);
|
||||
decCipher = await this.cipherService.decrypt(cipher, userId);
|
||||
}
|
||||
} else if (id.trim() !== "") {
|
||||
let ciphers = await this.cipherService.getAllDecrypted(activeUserId);
|
||||
let ciphers = await this.cipherService.getAllDecrypted(userId);
|
||||
ciphers = this.searchService.searchCiphersBasic(ciphers, id);
|
||||
if (ciphers.length > 1) {
|
||||
return ciphers;
|
||||
@@ -133,20 +135,45 @@ export class GetCommand extends DownloadCommand {
|
||||
}
|
||||
|
||||
private async getCipher(id: string, filter?: (c: CipherView) => boolean) {
|
||||
let decCipher = await this.getCipherView(id);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
let decCipher = await this.getCipherView(id, activeUserId);
|
||||
if (decCipher == null) {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
if (Array.isArray(decCipher)) {
|
||||
// Apply restricted ciphers filter
|
||||
decCipher = await this.cliRestrictedItemTypesService.filterRestrictedCiphers(decCipher);
|
||||
|
||||
if (decCipher.length === 0) {
|
||||
return Response.error("Access to this item type is restricted by organizational policy.");
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
decCipher = decCipher.filter(filter);
|
||||
if (decCipher.length === 1) {
|
||||
decCipher = decCipher[0];
|
||||
}
|
||||
}
|
||||
if (Array.isArray(decCipher)) {
|
||||
|
||||
if (decCipher.length === 0) {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
if (decCipher.length === 1) {
|
||||
decCipher = decCipher[0];
|
||||
} else {
|
||||
return Response.multipleResults(decCipher.map((c) => c.id));
|
||||
}
|
||||
} else {
|
||||
const isCipherRestricted =
|
||||
await this.cliRestrictedItemTypesService.isCipherRestricted(decCipher);
|
||||
if (isCipherRestricted) {
|
||||
return Response.error("Access to this item type is restricted by organizational policy.");
|
||||
}
|
||||
|
||||
// Apply filter if provided to single cipher
|
||||
if (filter != null && !filter(decCipher)) {
|
||||
return Response.notFound();
|
||||
}
|
||||
}
|
||||
|
||||
await this.eventCollectionService.collect(
|
||||
@@ -317,7 +344,8 @@ export class GetCommand extends DownloadCommand {
|
||||
return cipherResponse;
|
||||
}
|
||||
|
||||
const cipher = await this.getCipherView(itemId);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const cipher = await this.getCipherView(itemId, activeUserId);
|
||||
if (
|
||||
cipher == null ||
|
||||
Array.isArray(cipher) ||
|
||||
@@ -345,7 +373,6 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.multipleResults(attachments.map((a) => a.id));
|
||||
}
|
||||
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.accountProfileService.hasPremiumFromAnySource$(activeUserId),
|
||||
);
|
||||
|
||||
@@ -29,6 +29,7 @@ import { ListResponse } from "../models/response/list.response";
|
||||
import { CliUtils } from "../utils";
|
||||
import { CipherResponse } from "../vault/models/cipher.response";
|
||||
import { FolderResponse } from "../vault/models/folder.response";
|
||||
import { CliRestrictedItemTypesService } from "../vault/services/cli-restricted-item-types.service";
|
||||
|
||||
export class ListCommand {
|
||||
constructor(
|
||||
@@ -41,6 +42,7 @@ export class ListCommand {
|
||||
private apiService: ApiService,
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private accountService: AccountService,
|
||||
private cliRestrictedItemTypesService: CliRestrictedItemTypesService,
|
||||
) {}
|
||||
|
||||
async run(object: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
@@ -134,6 +136,8 @@ export class ListCommand {
|
||||
ciphers = this.searchService.searchCiphersBasic(ciphers, options.search, options.trash);
|
||||
}
|
||||
|
||||
ciphers = await this.cliRestrictedItemTypesService.filterRestrictedCiphers(ciphers);
|
||||
|
||||
await this.eventCollectionService.collectMany(EventType.Cipher_ClientViewed, ciphers, true);
|
||||
|
||||
const res = new ListResponse(ciphers.map((o) => new CipherResponse(o)));
|
||||
|
||||
@@ -66,6 +66,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.eventCollectionService,
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
this.listCommand = new ListCommand(
|
||||
this.serviceContainer.cipherService,
|
||||
@@ -77,6 +78,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.eventCollectionService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
this.createCommand = new CreateCommand(
|
||||
this.serviceContainer.cipherService,
|
||||
@@ -88,6 +90,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.organizationService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
this.editCommand = new EditCommand(
|
||||
this.serviceContainer.cipherService,
|
||||
@@ -97,6 +100,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.folderApiService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
this.generateCommand = new GenerateCommand(
|
||||
this.serviceContainer.passwordGenerationService,
|
||||
@@ -117,6 +121,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.cipherAuthorizationService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
this.confirmCommand = new ConfirmCommand(
|
||||
this.serviceContainer.apiService,
|
||||
|
||||
@@ -150,6 +150,7 @@ import { DefaultCipherEncryptionService } from "@bitwarden/common/vault/services
|
||||
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
||||
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
import {
|
||||
legacyPasswordGenerationServiceFactory,
|
||||
@@ -187,6 +188,7 @@ import { I18nService } from "../platform/services/i18n.service";
|
||||
import { LowdbStorageService } from "../platform/services/lowdb-storage.service";
|
||||
import { NodeApiService } from "../platform/services/node-api.service";
|
||||
import { NodeEnvSecureStorageService } from "../platform/services/node-env-secure-storage.service";
|
||||
import { CliRestrictedItemTypesService } from "../vault/services/cli-restricted-item-types.service";
|
||||
|
||||
// Polyfills
|
||||
global.DOMParser = new jsdom.JSDOM().window.DOMParser;
|
||||
@@ -287,6 +289,8 @@ export class ServiceContainer {
|
||||
masterPasswordApiService: MasterPasswordApiServiceAbstraction;
|
||||
bulkEncryptService: FallbackBulkEncryptService;
|
||||
cipherEncryptionService: CipherEncryptionService;
|
||||
restrictedItemTypesService: RestrictedItemTypesService;
|
||||
cliRestrictedItemTypesService: CliRestrictedItemTypesService;
|
||||
|
||||
constructor() {
|
||||
let p = null;
|
||||
@@ -811,6 +815,7 @@ export class ServiceContainer {
|
||||
this.kdfConfigService,
|
||||
this.accountService,
|
||||
this.apiService,
|
||||
this.restrictedItemTypesService,
|
||||
);
|
||||
|
||||
this.organizationExportService = new OrganizationVaultExportService(
|
||||
@@ -823,6 +828,7 @@ export class ServiceContainer {
|
||||
this.collectionService,
|
||||
this.kdfConfigService,
|
||||
this.accountService,
|
||||
this.restrictedItemTypesService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
@@ -864,6 +870,17 @@ export class ServiceContainer {
|
||||
);
|
||||
|
||||
this.masterPasswordApiService = new MasterPasswordApiService(this.apiService, this.logService);
|
||||
|
||||
this.restrictedItemTypesService = new RestrictedItemTypesService(
|
||||
this.configService,
|
||||
this.accountService,
|
||||
this.organizationService,
|
||||
this.policyService,
|
||||
);
|
||||
|
||||
this.cliRestrictedItemTypesService = new CliRestrictedItemTypesService(
|
||||
this.restrictedItemTypesService,
|
||||
);
|
||||
}
|
||||
|
||||
async logout() {
|
||||
|
||||
@@ -153,6 +153,7 @@ export class SendProgram extends BaseProgram {
|
||||
this.serviceContainer.eventCollectionService,
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await cmd.run("template", object, null);
|
||||
this.processResponse(response);
|
||||
|
||||
@@ -114,6 +114,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.eventCollectionService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await command.run(object, cmd);
|
||||
|
||||
@@ -188,6 +189,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.eventCollectionService,
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await command.run(object, id, cmd);
|
||||
this.processResponse(response);
|
||||
@@ -233,6 +235,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.organizationService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await command.run(object, encodedJson, cmd);
|
||||
this.processResponse(response);
|
||||
@@ -280,6 +283,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.folderApiService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await command.run(object, id, encodedJson, cmd);
|
||||
this.processResponse(response);
|
||||
@@ -323,6 +327,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.billingAccountProfileStateService,
|
||||
this.serviceContainer.cipherAuthorizationService,
|
||||
this.serviceContainer.accountService,
|
||||
this.serviceContainer.cliRestrictedItemTypesService,
|
||||
);
|
||||
const response = await command.run(object, id, cmd);
|
||||
this.processResponse(response);
|
||||
|
||||
@@ -29,6 +29,7 @@ import { CliUtils } from "../utils";
|
||||
|
||||
import { CipherResponse } from "./models/cipher.response";
|
||||
import { FolderResponse } from "./models/folder.response";
|
||||
import { CliRestrictedItemTypesService } from "./services/cli-restricted-item-types.service";
|
||||
|
||||
export class CreateCommand {
|
||||
constructor(
|
||||
@@ -41,6 +42,7 @@ export class CreateCommand {
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private cliRestrictedItemTypesService: CliRestrictedItemTypesService,
|
||||
) {}
|
||||
|
||||
async run(
|
||||
@@ -90,6 +92,15 @@ export class CreateCommand {
|
||||
|
||||
private async createCipher(req: CipherExport) {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
const cipherView = CipherExport.toView(req);
|
||||
const isCipherTypeRestricted =
|
||||
await this.cliRestrictedItemTypesService.isCipherRestricted(cipherView);
|
||||
|
||||
if (isCipherTypeRestricted) {
|
||||
return Response.error("Creating this item type is restricted by organizational policy.");
|
||||
}
|
||||
|
||||
const cipher = await this.cipherService.encrypt(CipherExport.toView(req), activeUserId);
|
||||
try {
|
||||
const newCipher = await this.cipherService.createWithServer(cipher);
|
||||
|
||||
@@ -13,6 +13,8 @@ import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cip
|
||||
import { Response } from "../models/response";
|
||||
import { CliUtils } from "../utils";
|
||||
|
||||
import { CliRestrictedItemTypesService } from "./services/cli-restricted-item-types.service";
|
||||
|
||||
export class DeleteCommand {
|
||||
constructor(
|
||||
private cipherService: CipherService,
|
||||
@@ -22,6 +24,7 @@ export class DeleteCommand {
|
||||
private accountProfileService: BillingAccountProfileStateService,
|
||||
private cipherAuthorizationService: CipherAuthorizationService,
|
||||
private accountService: AccountService,
|
||||
private cliRestrictedItemTypesService: CliRestrictedItemTypesService,
|
||||
) {}
|
||||
|
||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
@@ -60,6 +63,12 @@ export class DeleteCommand {
|
||||
return Response.error("You do not have permission to delete this item.");
|
||||
}
|
||||
|
||||
const isCipherTypeRestricted =
|
||||
await this.cliRestrictedItemTypesService.isCipherRestricted(cipher);
|
||||
if (isCipherTypeRestricted) {
|
||||
return Response.error("Deleting this item type is restricted by organizational policy.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (options.permanent) {
|
||||
await this.cipherService.deleteWithServer(id, activeUserId);
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import {
|
||||
RestrictedItemTypesService,
|
||||
RestrictedCipherType,
|
||||
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||
|
||||
import { CliRestrictedItemTypesService } from "./cli-restricted-item-types.service";
|
||||
|
||||
describe("CliRestrictedItemTypesService", () => {
|
||||
let service: CliRestrictedItemTypesService;
|
||||
let restrictedSubject: BehaviorSubject<RestrictedCipherType[]>;
|
||||
let restrictedItemTypesService: Partial<RestrictedItemTypesService>;
|
||||
|
||||
const cardCipher: CipherView = {
|
||||
id: "cipher1",
|
||||
type: CipherType.Card,
|
||||
organizationId: "org1",
|
||||
} as CipherView;
|
||||
|
||||
const loginCipher: CipherView = {
|
||||
id: "cipher2",
|
||||
type: CipherType.Login,
|
||||
organizationId: "org1",
|
||||
} as CipherView;
|
||||
|
||||
const identityCipher: CipherView = {
|
||||
id: "cipher3",
|
||||
type: CipherType.Identity,
|
||||
organizationId: "org2",
|
||||
} as CipherView;
|
||||
|
||||
beforeEach(() => {
|
||||
restrictedSubject = new BehaviorSubject<RestrictedCipherType[]>([]);
|
||||
|
||||
restrictedItemTypesService = {
|
||||
restricted$: restrictedSubject,
|
||||
isCipherRestricted: jest.fn(),
|
||||
isCipherRestricted$: jest.fn(),
|
||||
};
|
||||
|
||||
service = new CliRestrictedItemTypesService(
|
||||
restrictedItemTypesService as RestrictedItemTypesService,
|
||||
);
|
||||
});
|
||||
|
||||
describe("filterRestrictedCiphers", () => {
|
||||
it("filters out restricted cipher types from array", async () => {
|
||||
restrictedSubject.next([{ cipherType: CipherType.Card, allowViewOrgIds: [] }]);
|
||||
|
||||
(restrictedItemTypesService.isCipherRestricted as jest.Mock)
|
||||
.mockReturnValueOnce(true)
|
||||
.mockReturnValueOnce(false)
|
||||
.mockReturnValueOnce(false);
|
||||
const ciphers = [cardCipher, loginCipher, identityCipher];
|
||||
|
||||
const result = await service.filterRestrictedCiphers(ciphers);
|
||||
|
||||
expect(result).toEqual([loginCipher, identityCipher]);
|
||||
});
|
||||
|
||||
it("returns all ciphers when no restrictions exist", async () => {
|
||||
restrictedSubject.next([]);
|
||||
|
||||
(restrictedItemTypesService.isCipherRestricted as jest.Mock).mockReturnValue(false);
|
||||
|
||||
const ciphers = [cardCipher, loginCipher, identityCipher];
|
||||
const result = await service.filterRestrictedCiphers(ciphers);
|
||||
|
||||
expect(result).toEqual(ciphers);
|
||||
});
|
||||
|
||||
it("handles empty cipher array", async () => {
|
||||
const result = await service.filterRestrictedCiphers([]);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isCipherRestricted", () => {
|
||||
it("returns true for restricted cipher type with no organization exemptions", async () => {
|
||||
(restrictedItemTypesService.isCipherRestricted$ as jest.Mock).mockReturnValue(of(true));
|
||||
|
||||
const result = await service.isCipherRestricted(cardCipher);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for non-restricted cipher type", async () => {
|
||||
(restrictedItemTypesService.isCipherRestricted$ as jest.Mock).mockReturnValue(of(false));
|
||||
|
||||
const result = await service.isCipherRestricted(loginCipher);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when no restrictions exist", async () => {
|
||||
(restrictedItemTypesService.isCipherRestricted$ as jest.Mock).mockReturnValue(of(false));
|
||||
|
||||
const result = await service.isCipherRestricted(cardCipher);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false for organization cipher when organization is in allowViewOrgIds", async () => {
|
||||
(restrictedItemTypesService.isCipherRestricted$ as jest.Mock).mockReturnValue(of(false));
|
||||
|
||||
const result = await service.isCipherRestricted(cardCipher);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import {
|
||||
RestrictedCipherType,
|
||||
RestrictedItemTypesService,
|
||||
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||
|
||||
export class CliRestrictedItemTypesService {
|
||||
constructor(private restrictedItemTypesService: RestrictedItemTypesService) {}
|
||||
|
||||
/**
|
||||
* Gets all restricted cipher types for the current user.
|
||||
*
|
||||
* @returns Promise resolving to array of restricted cipher types with allowed organization IDs
|
||||
*/
|
||||
async getRestrictedTypes(): Promise<RestrictedCipherType[]> {
|
||||
return firstValueFrom(this.restrictedItemTypesService.restricted$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out restricted cipher types from an array of ciphers.
|
||||
*
|
||||
* @param ciphers - Array of ciphers to filter
|
||||
* @returns Promise resolving to filtered array with restricted ciphers removed
|
||||
*/
|
||||
async filterRestrictedCiphers(ciphers: CipherView[]): Promise<CipherView[]> {
|
||||
const restrictions = await this.getRestrictedTypes();
|
||||
|
||||
return ciphers.filter(
|
||||
(cipher) => !this.restrictedItemTypesService.isCipherRestricted(cipher, restrictions),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific cipher type is restricted for the user.
|
||||
*
|
||||
* @param cipherType - The cipher type to check
|
||||
* @returns Promise resolving to true if the cipher type is restricted, false otherwise
|
||||
*/
|
||||
async isCipherRestricted(cipher: Cipher | CipherView): Promise<boolean> {
|
||||
return firstValueFrom(this.restrictedItemTypesService.isCipherRestricted$(cipher));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user