1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-11 14:04:03 +00:00

Merge branch 'main' into tools/pm-919/cli-send-get-file

This commit is contained in:
voommen-livefront
2025-04-02 10:21:14 -05:00
703 changed files with 14410 additions and 13045 deletions

View File

@@ -5,7 +5,7 @@ import * as http from "http";
import { OptionValues } from "commander";
import * as inquirer from "inquirer";
import Separator from "inquirer/lib/objects/separator";
import { firstValueFrom, map } from "rxjs";
import { firstValueFrom, map, switchMap } from "rxjs";
import {
LoginStrategyServiceAbstraction,
@@ -29,6 +29,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { ClientType } from "@bitwarden/common/enums";
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
@@ -555,7 +556,10 @@ export class LoginCommand {
);
const enforcedPolicyOptions = await firstValueFrom(
this.policyService.masterPasswordPolicyOptions$(),
this.accountService.activeAccount$.pipe(
getUserId,
switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId)),
),
);
// Verify master password meets policy requirements

View File

@@ -24,4 +24,7 @@ export class CliBiometricsService extends BiometricsService {
}
async setShouldAutopromptNow(value: boolean): Promise<void> {}
async canEnableBiometricUnlock(): Promise<boolean> {
return false;
}
}

View File

@@ -14,7 +14,6 @@ import {
AbstractStorageService,
StorageUpdate,
} from "@bitwarden/common/platform/abstractions/storage.service";
import { sequentialize } from "@bitwarden/common/platform/misc/sequentialize";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { NodeUtils } from "@bitwarden/node/node-utils";
@@ -44,7 +43,6 @@ export class LowdbStorageService implements AbstractStorageService {
this.updates$ = this.updatesSubject.asObservable();
}
@sequentialize(() => "lowdbStorageInit")
async init() {
if (this.ready) {
return;

View File

@@ -28,8 +28,8 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service";
import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service";
import { DefaultPolicyService } from "@bitwarden/common/admin-console/services/policy/default-policy.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 { ProviderApiService } from "@bitwarden/common/admin-console/services/provider/provider-api.service";
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@@ -238,7 +238,7 @@ export class ServiceContainer {
cryptoFunctionService: NodeCryptoFunctionService;
encryptService: EncryptServiceImplementation;
authService: AuthService;
policyService: PolicyService;
policyService: DefaultPolicyService;
policyApiService: PolicyApiServiceAbstraction;
logService: ConsoleLogService;
sendService: SendService;
@@ -285,6 +285,7 @@ export class ServiceContainer {
ssoUrlService: SsoUrlService;
masterPasswordApiService: MasterPasswordApiServiceAbstraction;
sendDownloadService: SendDownloadService;
bulkEncryptService: FallbackBulkEncryptService;
constructor() {
let p = null;
@@ -316,6 +317,7 @@ export class ServiceContainer {
this.logService,
true,
);
this.bulkEncryptService = new FallbackBulkEncryptService(this.encryptService);
this.storageService = new LowdbStorageService(this.logService, null, p, false, true);
this.secureStorageService = new NodeEnvSecureStorageService(
this.storageService,
@@ -438,9 +440,7 @@ export class ServiceContainer {
this.kdfConfigService,
this.keyGenerationService,
this.logService,
this.masterPasswordService,
this.stateProvider,
this.stateService,
);
this.keyService = new KeyService(
@@ -471,7 +471,7 @@ export class ServiceContainer {
this.ssoUrlService = new SsoUrlService();
this.organizationService = new DefaultOrganizationService(this.stateProvider);
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.policyService = new DefaultPolicyService(this.stateProvider, this.organizationService);
this.vaultTimeoutSettingsService = new DefaultVaultTimeoutSettingsService(
this.accountService,
@@ -562,7 +562,11 @@ export class ServiceContainer {
this.providerService = new ProviderService(this.stateProvider);
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
this.policyApiService = new PolicyApiService(
this.policyService,
this.apiService,
this.accountService,
);
this.keyConnectorService = new KeyConnectorService(
this.accountService,
@@ -674,6 +678,7 @@ export class ServiceContainer {
this.autofillSettingsService = new AutofillSettingsService(
this.stateProvider,
this.policyService,
this.accountService,
);
this.cipherService = new CipherService(
@@ -685,7 +690,7 @@ export class ServiceContainer {
this.stateService,
this.autofillSettingsService,
this.encryptService,
new FallbackBulkEncryptService(this.encryptService),
this.bulkEncryptService,
this.cipherFileUploadService,
this.configService,
this.stateProvider,
@@ -797,6 +802,7 @@ export class ServiceContainer {
this.cryptoFunctionService,
this.kdfConfigService,
this.accountService,
this.apiService,
);
this.organizationExportService = new OrganizationVaultExportService(
@@ -893,6 +899,12 @@ export class ServiceContainer {
await this.sdkLoadService.loadAndInit();
await this.storageService.init();
await this.stateService.init();
this.configService.serverConfig$.subscribe((newConfig) => {
if (newConfig != null) {
this.encryptService.onServerConfigChange(newConfig);
this.bulkEncryptService.onServerConfigChange(newConfig);
}
});
this.containerService.attachToGlobal(global);
await this.i18nService.init();
this.twoFactorService.init();

View File

@@ -2,16 +2,23 @@
// @ts-strict-ignore
import { OptionValues } from "commander";
import * as inquirer from "inquirer";
import { firstValueFrom, switchMap } from "rxjs";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { EventType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import {
ExportFormat,
EXPORT_FORMATS,
VaultExportServiceAbstraction,
ExportedVault,
ExportedVaultAsBlob,
} from "@bitwarden/vault-export-core";
import { Response } from "../models/response";
@@ -22,13 +29,19 @@ export class ExportCommand {
private exportService: VaultExportServiceAbstraction,
private policyService: PolicyService,
private eventCollectionService: EventCollectionService,
private accountService: AccountService,
private configService: ConfigService,
) {}
async run(options: OptionValues): Promise<Response> {
if (
options.organizationid == null &&
(await this.policyService.policyAppliesToUser(PolicyType.DisablePersonalVaultExport))
) {
const policyApplies$ = this.accountService.activeAccount$.pipe(
getUserId,
switchMap((userId) =>
this.policyService.policyAppliesToUser$(PolicyType.DisablePersonalVaultExport, userId),
),
);
if (options.organizationid == null && (await firstValueFrom(policyApplies$))) {
return Response.badRequest(
"One or more organization policies prevents you from exporting your personal vault.",
);
@@ -42,6 +55,13 @@ export class ExportCommand {
const format =
password && options.format == "json" ? "encrypted_json" : (options.format ?? "csv");
if (
format == "zip" &&
!(await this.configService.getFeatureFlag(FeatureFlag.ExportAttachments))
) {
return Response.badRequest("Exporting attachments is not supported in this environment.");
}
if (!this.isSupportedExportFormat(format)) {
return Response.badRequest(
`'${format}' is not a supported export format. Supported formats: ${EXPORT_FORMATS.join(
@@ -54,7 +74,7 @@ export class ExportCommand {
return Response.error("`" + options.organizationid + "` is not a GUID.");
}
let exportContent: string = null;
let exportContent: ExportedVault = null;
try {
if (format === "encrypted_json") {
password = await this.promptPassword(password);
@@ -78,34 +98,28 @@ export class ExportCommand {
} catch (e) {
return Response.error(e);
}
return await this.saveFile(exportContent, options, format);
return await this.saveFile(exportContent, options);
}
private async saveFile(
exportContent: string,
options: OptionValues,
format: ExportFormat,
): Promise<Response> {
private async saveFile(exportContent: ExportedVault, options: OptionValues): Promise<Response> {
try {
const fileName = this.getFileName(format, options.organizationid != null ? "org" : null);
return await CliUtils.saveResultToFile(exportContent, options.output, fileName);
if (exportContent.type === "application/zip") {
exportContent = exportContent as ExportedVaultAsBlob;
const arrayBuffer = await exportContent.data.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
return await CliUtils.saveResultToFile(buffer, options.output, exportContent.fileName);
}
return await CliUtils.saveResultToFile(
exportContent.data,
options.output,
exportContent.fileName,
);
} catch (e) {
return Response.error(e.toString());
}
}
private getFileName(format: ExportFormat, prefix?: string) {
if (format === "encrypted_json") {
if (prefix == null) {
prefix = "encrypted";
} else {
prefix = "encrypted_" + prefix;
}
format = "json";
}
return this.exportService.getFileName(prefix, format);
}
private async promptPassword(password: string | boolean) {
// boolean => flag set with no value, we need to prompt for password
// string => flag set with value, use this value for password

View File

@@ -501,6 +501,8 @@ export class VaultProgram extends BaseProgram {
this.serviceContainer.exportService,
this.serviceContainer.policyService,
this.serviceContainer.eventCollectionService,
this.serviceContainer.accountService,
this.serviceContainer.configService,
);
const response = await command.run(options);
this.processResponse(response);