2023-03-23 11:43:27 +01:00
|
|
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
|
|
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|
|
|
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
[AC-1266] Enums filename conventions (#5140)
* refactor: update clientType enum
* refactor: update deviceType filename
* refactor: update encryptedExportType filename
* refactor: update encryptionType filename
* refactor: update eventType filename
* refactor: update fieldType filename
* refactor: update fileUploadType filename
* refactor: update hashPurpose filename
* refactor: update htmlStorageLocation filename
* refactor: update kdfType filename
* refactor: update keySuffixOptions filename
* refactor: update linkedIdType filename
* refactor: update logLevelType filename
* refactor: update nativeMessagingVersion filename
* refactor: update notificationType filename
* refactor: update productType filename
* refactor: update secureNoteType filename
* refactor: update stateVersion filename
* refactor: update storageLocation filename
* refactor: update themeType filename
* refactor: update uriMatchType filename
* fix: update kdfType classes missed in initial pass, refs AC-1266
* fix: missing import update for device-type
* refactor: add barrel file for enums and update pathed import statements, refs AC-1266
* fix: incorrect import statements for web, refs AC-1266
* fix: missed import statement updates (browser), refs AC-1266
* fix: missed import statement changes (cli), refs AC-1266
* fix: missed import statement changes (desktop), refs AC-1266
* fix: prettier, refs AC-1266
* refactor: (libs) update relative paths to use barrel file, refs AC-1266
* fix: missed find/replace import statements for SecureNoteType, refs AC-1266
* refactor: apply .enum suffix to enums folder and modify leftover relative paths, refs AC-1266
* fix: find/replace errors for native-messaging-version, refs AC-1266
2023-04-05 05:42:21 +02:00
|
|
|
import { KdfType } from "@bitwarden/common/enums";
|
2023-03-23 11:43:27 +01:00
|
|
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
|
|
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
2023-04-19 11:30:46 +02:00
|
|
|
import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/exporter/vault-export/bitwarden-password-protected-types";
|
2023-03-23 11:43:27 +01:00
|
|
|
|
|
|
|
import { ImportResult } from "../../models/import-result";
|
|
|
|
import { Importer } from "../importer";
|
2022-02-07 16:33:10 +01:00
|
|
|
|
2022-11-11 16:20:03 +01:00
|
|
|
import { BitwardenJsonImporter } from "./bitwarden-json-importer";
|
2022-02-23 04:02:07 +01:00
|
|
|
export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter implements Importer {
|
2022-02-07 16:33:10 +01:00
|
|
|
private key: SymmetricCryptoKey;
|
|
|
|
|
2023-04-06 22:41:09 +02:00
|
|
|
constructor(
|
|
|
|
cryptoService: CryptoService,
|
|
|
|
i18nService: I18nService,
|
|
|
|
private promptForPassword_callback: () => Promise<string>
|
|
|
|
) {
|
2022-02-23 04:02:07 +01:00
|
|
|
super(cryptoService, i18nService);
|
2022-02-07 16:33:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async parse(data: string): Promise<ImportResult> {
|
|
|
|
const result = new ImportResult();
|
2023-04-06 22:41:09 +02:00
|
|
|
const parsedData: BitwardenPasswordProtectedFileFormat = JSON.parse(data);
|
|
|
|
|
|
|
|
if (!parsedData) {
|
|
|
|
result.success = false;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// File is unencrypted
|
|
|
|
if (!parsedData?.encrypted) {
|
|
|
|
return await super.parse(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// File is account-encrypted
|
|
|
|
if (!parsedData?.passwordProtected) {
|
|
|
|
return await super.parse(data);
|
|
|
|
}
|
|
|
|
|
2022-02-07 16:33:10 +01:00
|
|
|
if (this.cannotParseFile(parsedData)) {
|
|
|
|
result.success = false;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-04-06 22:41:09 +02:00
|
|
|
// File is password-protected
|
|
|
|
const password = await this.promptForPassword_callback();
|
|
|
|
if (!(await this.checkPassword(parsedData, password))) {
|
2022-02-07 16:33:10 +01:00
|
|
|
result.success = false;
|
2022-08-29 16:11:44 +02:00
|
|
|
result.errorMessage = this.i18nService.t("invalidFilePassword");
|
2022-02-07 16:33:10 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const encData = new EncString(parsedData.data);
|
|
|
|
const clearTextData = await this.cryptoService.decryptToUtf8(encData, this.key);
|
2022-02-23 04:02:07 +01:00
|
|
|
return await super.parse(clearTextData);
|
2022-02-07 16:33:10 +01:00
|
|
|
}
|
|
|
|
|
2023-04-06 22:41:09 +02:00
|
|
|
private async checkPassword(
|
|
|
|
jdoc: BitwardenPasswordProtectedFileFormat,
|
|
|
|
password: string
|
|
|
|
): Promise<boolean> {
|
2022-02-07 16:33:10 +01:00
|
|
|
this.key = await this.cryptoService.makePinKey(
|
2023-04-06 22:41:09 +02:00
|
|
|
password,
|
2022-02-07 16:33:10 +01:00
|
|
|
jdoc.salt,
|
2023-03-31 13:49:07 +02:00
|
|
|
jdoc.kdfType,
|
|
|
|
new KdfConfig(jdoc.kdfIterations, jdoc.kdfMemory, jdoc.kdfParallelism)
|
2022-02-07 16:33:10 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
const encKeyValidation = new EncString(jdoc.encKeyValidation_DO_NOT_EDIT);
|
|
|
|
|
|
|
|
const encKeyValidationDecrypt = await this.cryptoService.decryptToUtf8(
|
|
|
|
encKeyValidation,
|
|
|
|
this.key
|
|
|
|
);
|
|
|
|
if (encKeyValidationDecrypt === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private cannotParseFile(jdoc: BitwardenPasswordProtectedFileFormat): boolean {
|
|
|
|
return (
|
|
|
|
!jdoc ||
|
|
|
|
!jdoc.encrypted ||
|
|
|
|
!jdoc.passwordProtected ||
|
|
|
|
!jdoc.salt ||
|
|
|
|
!jdoc.kdfIterations ||
|
|
|
|
typeof jdoc.kdfIterations !== "number" ||
|
|
|
|
jdoc.kdfType == null ||
|
|
|
|
KdfType[jdoc.kdfType] == null ||
|
|
|
|
!jdoc.encKeyValidation_DO_NOT_EDIT ||
|
|
|
|
!jdoc.data
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|