From d77f77cea97dd1c6cc9d8a5d3ad5b6a440d2a22b Mon Sep 17 00:00:00 2001 From: Andrew Jorgensen Date: Mon, 17 Apr 2023 15:54:03 -0400 Subject: [PATCH] [PM-1803] Fail on unsupported export format (#5197) * Fail on unsupported export format Issue #5194: https://github.com/bitwarden/clients/issues/5194 The cli previously would take any value for the export format and default to unencrypted json if it wasn't a supported format. This behavior is a little dangerous because if for instance typed "json_encrypted" instead of "encrypted_json" and naively saved the file you might be surprised to learn the payload was not actually encrypted even though the command completed successfully. This change adds a guard clause when converting the string value passed in via `--format` into the type `ExportFormat` to ensure that the format provided is one of the supported types. * Move isSupportedExportFormat to private method --- apps/cli/src/commands/export.command.ts | 17 ++++++++++++++++- libs/common/src/abstractions/export.service.ts | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/cli/src/commands/export.command.ts b/apps/cli/src/commands/export.command.ts index 103a3e49e0..c41d1aad69 100644 --- a/apps/cli/src/commands/export.command.ts +++ b/apps/cli/src/commands/export.command.ts @@ -1,7 +1,11 @@ import * as program from "commander"; import * as inquirer from "inquirer"; -import { ExportFormat, ExportService } from "@bitwarden/common/abstractions/export.service"; +import { + ExportFormat, + ExportService, + EXPORT_FORMATS, +} from "@bitwarden/common/abstractions/export.service"; 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"; @@ -23,6 +27,13 @@ export class ExportCommand { } 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."); @@ -94,4 +105,8 @@ export class ExportCommand { } return null; } + + private isSupportedExportFormat(format: string): format is ExportFormat { + return EXPORT_FORMATS.includes(format as ExportFormat); + } } diff --git a/libs/common/src/abstractions/export.service.ts b/libs/common/src/abstractions/export.service.ts index 8d158f747a..92ed7fec69 100644 --- a/libs/common/src/abstractions/export.service.ts +++ b/libs/common/src/abstractions/export.service.ts @@ -1,7 +1,7 @@ import { EventView } from "../models/view/event.view"; -export type ExportFormat = "csv" | "json" | "encrypted_json"; - +export const EXPORT_FORMATS = ["csv", "json", "encrypted_json"] as const; +export type ExportFormat = (typeof EXPORT_FORMATS)[number]; export abstract class ExportService { getExport: (format?: ExportFormat, organizationId?: string) => Promise; getPasswordProtectedExport: (password: string, organizationId?: string) => Promise;