1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-13 06:43:35 +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:
SmithThe4th
2025-06-23 12:04:56 -04:00
committed by GitHub
parent 2e8c0de719
commit e291e2df0a
24 changed files with 444 additions and 113 deletions

View File

@@ -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),
);