mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[PM-328] Move exporter to tools (#5070)
* Create and register new libs/exporter Create package.json Create tsconfig Create jest.config Extend shared and root tsconfig and jest.configs Register with eslint * Migrate exportService to libs/exporter Move exportService (abstraction and impl) into libs/exporter Refactored exportService to be split into vault-export and event-export Created barrel-files for both exports Moved export.service.spec.ts into vault-export Created an export-helper, which helps build the filename (extract method refactor from ExportService) * Move components in libs/angular into tools-subfolder Moved components Updated imports in jslib-services.module and jslib.module * Register libs/exporter with browser and fix imports Move export.component into tools-subfolder * Register libs/exporter with cli and fix imports Move export.command into tools-subfolder * Register libs/exporter with desktop and fix imports Move export.component into tools-subfolder * Move export models to libs/exporter * Update web imports * Update package-lock.json * Move export models back as it would create circular dependency Reponse models in common rely on export models which are in libs/exporter, which relies on common * Fix up web for event-export * Update CODEOWNERS * Add export-models to team-tools-dev * Simplify domain import * Moving EventExport into web
This commit is contained in:
committed by
GitHub
parent
830af7b06d
commit
192bb5a7b3
115
apps/cli/src/tools/export.command.ts
Normal file
115
apps/cli/src/tools/export.command.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as program from "commander";
|
||||
import * as inquirer from "inquirer";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import {
|
||||
ExportFormat,
|
||||
EXPORT_FORMATS,
|
||||
VaultExportServiceAbstraction,
|
||||
} from "@bitwarden/exporter/vault-export";
|
||||
|
||||
import { Response } from "../models/response";
|
||||
import { CliUtils } from "../utils";
|
||||
|
||||
export class ExportCommand {
|
||||
constructor(
|
||||
private exportService: VaultExportServiceAbstraction,
|
||||
private policyService: PolicyService
|
||||
) {}
|
||||
|
||||
async run(options: program.OptionValues): Promise<Response> {
|
||||
if (
|
||||
options.organizationid == null &&
|
||||
(await this.policyService.policyAppliesToUser(PolicyType.DisablePersonalVaultExport))
|
||||
) {
|
||||
return Response.badRequest(
|
||||
"One or more organization policies prevents you from exporting your personal vault."
|
||||
);
|
||||
}
|
||||
|
||||
const format = options.format ?? "csv";
|
||||
if (!this.isSupportedExportFormat(format)) {
|
||||
return Response.badRequest(
|
||||
`'${format}' is not a supported export format. Supported formats: ${EXPORT_FORMATS.join(
|
||||
", "
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (options.organizationid != null && !Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
}
|
||||
|
||||
let exportContent: string = null;
|
||||
try {
|
||||
exportContent =
|
||||
format === "encrypted_json"
|
||||
? await this.getProtectedExport(options.password, options.organizationid)
|
||||
: await this.getUnprotectedExport(format, options.organizationid);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
return await this.saveFile(exportContent, options, format);
|
||||
}
|
||||
|
||||
private async getProtectedExport(passwordOption: string | boolean, organizationId?: string) {
|
||||
const password = await this.promptPassword(passwordOption);
|
||||
return password == null
|
||||
? await this.exportService.getExport("encrypted_json", organizationId)
|
||||
: await this.exportService.getPasswordProtectedExport(password, organizationId);
|
||||
}
|
||||
|
||||
private async getUnprotectedExport(format: ExportFormat, organizationId?: string) {
|
||||
return this.exportService.getExport(format, organizationId);
|
||||
}
|
||||
|
||||
private async saveFile(
|
||||
exportContent: string,
|
||||
options: program.OptionValues,
|
||||
format: ExportFormat
|
||||
): Promise<Response> {
|
||||
try {
|
||||
const fileName = this.getFileName(format, options.organizationid != null ? "org" : null);
|
||||
return await CliUtils.saveResultToFile(exportContent, options.output, 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
|
||||
// undefined/null/false => account protect, not password, no password needed
|
||||
if (typeof password === "string") {
|
||||
return password;
|
||||
} else if (password) {
|
||||
const answer: inquirer.Answers = await inquirer.createPromptModule({
|
||||
output: process.stderr,
|
||||
})({
|
||||
type: "password",
|
||||
name: "password",
|
||||
message: "Export file password:",
|
||||
});
|
||||
return answer.password as string;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private isSupportedExportFormat(format: string): format is ExportFormat {
|
||||
return EXPORT_FORMATS.includes(format as ExportFormat);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user