mirror of
https://github.com/bitwarden/browser.git
synced 2025-12-05 09:14:28 +01:00
Merge 0cfa59d53e into d32365fbba
This commit is contained in:
commit
10caf959c8
@ -0,0 +1,188 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { filter, firstValueFrom } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Collection } from "@bitwarden/admin-console/common";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import {
|
||||
CipherWithIdExport,
|
||||
CollectionWithIdExport,
|
||||
FolderWithIdExport,
|
||||
} from "@bitwarden/common/models/export";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { OrgKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
import {
|
||||
BitwardenEncryptedIndividualJsonExport,
|
||||
BitwardenEncryptedJsonExport,
|
||||
BitwardenEncryptedOrgJsonExport,
|
||||
BitwardenJsonExport,
|
||||
isOrgEncrypted,
|
||||
isUnencrypted,
|
||||
} from "@bitwarden/vault-export-core";
|
||||
|
||||
import { ImportResult } from "../../models/import-result";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { BitwardenJsonImporter } from "./bitwarden-json-importer";
|
||||
|
||||
export class BitwardenEncryptedJsonImporter extends BitwardenJsonImporter implements Importer {
|
||||
constructor(
|
||||
protected keyService: KeyService,
|
||||
protected encryptService: EncryptService,
|
||||
protected i18nService: I18nService,
|
||||
private cipherService: CipherService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async parse(data: string): Promise<ImportResult> {
|
||||
const results: BitwardenJsonExport = JSON.parse(data);
|
||||
if (results == null || results.items == null) {
|
||||
const result = new ImportResult();
|
||||
result.success = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isUnencrypted(results)) {
|
||||
return super.parse(data);
|
||||
}
|
||||
|
||||
return await this.parseEncrypted(results);
|
||||
}
|
||||
|
||||
private async parseEncrypted(data: BitwardenEncryptedJsonExport): Promise<ImportResult> {
|
||||
const account = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
if (data.encKeyValidation_DO_NOT_EDIT != null) {
|
||||
const orgKeys = await firstValueFrom(this.keyService.orgKeys$(account.id));
|
||||
let keyForDecryption: OrgKey | UserKey | null | undefined = orgKeys?.[this.organizationId];
|
||||
if (!keyForDecryption) {
|
||||
keyForDecryption = await firstValueFrom(this.keyService.userKey$(account.id));
|
||||
}
|
||||
|
||||
if (!keyForDecryption) {
|
||||
const result = new ImportResult();
|
||||
result.success = false;
|
||||
result.errorMessage = this.i18nService.t("importEncKeyError");
|
||||
return result;
|
||||
}
|
||||
const encKeyValidation = new EncString(data.encKeyValidation_DO_NOT_EDIT);
|
||||
try {
|
||||
await this.encryptService.decryptString(encKeyValidation, keyForDecryption);
|
||||
} catch {
|
||||
const result = new ImportResult();
|
||||
result.success = false;
|
||||
result.errorMessage = this.i18nService.t("importEncKeyError");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const result = new ImportResult();
|
||||
|
||||
let groupingsMap: Map<string, number> | null = null;
|
||||
if (isOrgEncrypted(data)) {
|
||||
groupingsMap = await this.parseEncryptedCollections(account.id, data, result);
|
||||
} else {
|
||||
groupingsMap = await this.parseEncryptedFolders(data, result);
|
||||
}
|
||||
|
||||
for (const c of data.items) {
|
||||
const cipher = CipherWithIdExport.toDomain(c);
|
||||
// reset ids in case they were set for some reason
|
||||
cipher.id = null;
|
||||
cipher.organizationId = this.organizationId;
|
||||
cipher.collectionIds = null;
|
||||
|
||||
// make sure password history is limited
|
||||
if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) {
|
||||
cipher.passwordHistory = cipher.passwordHistory.slice(0, 5);
|
||||
}
|
||||
|
||||
if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) {
|
||||
result.folderRelationships.push([result.ciphers.length, groupingsMap.get(c.folderId)]);
|
||||
} else if (this.organization && c.collectionIds != null) {
|
||||
c.collectionIds.forEach((cId) => {
|
||||
if (groupingsMap.has(cId)) {
|
||||
result.collectionRelationships.push([result.ciphers.length, groupingsMap.get(cId)]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const view = await this.cipherService.decrypt(cipher, account.id);
|
||||
this.cleanupCipher(view);
|
||||
result.ciphers.push(view);
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async parseEncryptedFolders(
|
||||
data: BitwardenEncryptedIndividualJsonExport,
|
||||
importResult: ImportResult,
|
||||
): Promise<Map<string, number>> {
|
||||
const groupingsMap = new Map<string, number>();
|
||||
|
||||
if (data.folders == null) {
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
for (const f of data.folders) {
|
||||
let folderView: FolderView;
|
||||
const folder = FolderWithIdExport.toDomain(f);
|
||||
if (folder != null) {
|
||||
folderView = await folder.decrypt();
|
||||
}
|
||||
|
||||
if (folderView != null) {
|
||||
groupingsMap.set(f.id, importResult.folders.length);
|
||||
importResult.folders.push(folderView);
|
||||
}
|
||||
}
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
private async parseEncryptedCollections(
|
||||
userId: UserId,
|
||||
data: BitwardenEncryptedOrgJsonExport,
|
||||
importResult: ImportResult,
|
||||
): Promise<Map<string, number>> {
|
||||
const groupingsMap = new Map<string, number>();
|
||||
if (data.collections == null) {
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
const orgKeys = await firstValueFrom(
|
||||
this.keyService.orgKeys$(userId).pipe(filter((orgKeys) => orgKeys != null)),
|
||||
);
|
||||
|
||||
for (const c of data.collections) {
|
||||
const collection = CollectionWithIdExport.toDomain(
|
||||
c,
|
||||
new Collection({
|
||||
id: c.id,
|
||||
name: new EncString(c.name),
|
||||
organizationId: this.organizationId,
|
||||
}),
|
||||
);
|
||||
|
||||
const orgKey = orgKeys[c.organizationId];
|
||||
const collectionView = await collection.decrypt(orgKey, this.encryptService);
|
||||
|
||||
if (collectionView != null) {
|
||||
groupingsMap.set(c.id, importResult.collections.length);
|
||||
importResult.collections.push(collectionView);
|
||||
}
|
||||
}
|
||||
return groupingsMap;
|
||||
}
|
||||
}
|
||||
@ -1,31 +1,17 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { filter, firstValueFrom } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Collection, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import {
|
||||
CipherWithIdExport,
|
||||
CollectionWithIdExport,
|
||||
FolderWithIdExport,
|
||||
} from "@bitwarden/common/models/export";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import {
|
||||
BitwardenEncryptedIndividualJsonExport,
|
||||
BitwardenEncryptedOrgJsonExport,
|
||||
BitwardenJsonExport,
|
||||
BitwardenUnEncryptedIndividualJsonExport,
|
||||
BitwardenUnEncryptedJsonExport,
|
||||
BitwardenUnEncryptedOrgJsonExport,
|
||||
isOrgUnEncrypted,
|
||||
isUnencrypted,
|
||||
} from "@bitwarden/vault-export-core";
|
||||
|
||||
import { ImportResult } from "../../models/import-result";
|
||||
@ -33,104 +19,30 @@ import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
||||
private result: ImportResult;
|
||||
|
||||
protected constructor(
|
||||
protected keyService: KeyService,
|
||||
protected encryptService: EncryptService,
|
||||
protected i18nService: I18nService,
|
||||
protected cipherService: CipherService,
|
||||
protected accountService: AccountService,
|
||||
) {
|
||||
protected constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async parse(data: string): Promise<ImportResult> {
|
||||
this.result = new ImportResult();
|
||||
const results: BitwardenJsonExport = JSON.parse(data);
|
||||
if (results == null || results.items == null) {
|
||||
this.result.success = false;
|
||||
return this.result;
|
||||
const result = new ImportResult();
|
||||
result.success = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (results.encrypted) {
|
||||
await this.parseEncrypted(results as any);
|
||||
} else {
|
||||
await this.parseDecrypted(results as any);
|
||||
if (!isUnencrypted(results)) {
|
||||
throw new Error("Data is encrypted. Use BitwardenEncryptedJsonImporter instead.");
|
||||
}
|
||||
|
||||
return this.result;
|
||||
return await this.parseDecrypted(results);
|
||||
}
|
||||
|
||||
private async parseEncrypted(
|
||||
results: BitwardenEncryptedIndividualJsonExport | BitwardenEncryptedOrgJsonExport,
|
||||
) {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
private async parseDecrypted(results: BitwardenUnEncryptedJsonExport): Promise<ImportResult> {
|
||||
const importResult = new ImportResult();
|
||||
|
||||
if (results.encKeyValidation_DO_NOT_EDIT != null) {
|
||||
const orgKeys = await firstValueFrom(this.keyService.orgKeys$(userId));
|
||||
let keyForDecryption: SymmetricCryptoKey = orgKeys?.[this.organizationId];
|
||||
if (keyForDecryption == null) {
|
||||
keyForDecryption = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
}
|
||||
const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT);
|
||||
try {
|
||||
await this.encryptService.decryptString(encKeyValidation, keyForDecryption);
|
||||
} catch {
|
||||
this.result.success = false;
|
||||
this.result.errorMessage = this.i18nService.t("importEncKeyError");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const groupingsMap = this.organization
|
||||
? await this.parseCollections(userId, results as BitwardenEncryptedOrgJsonExport)
|
||||
: await this.parseFolders(results as BitwardenEncryptedIndividualJsonExport);
|
||||
|
||||
for (const c of results.items) {
|
||||
const cipher = CipherWithIdExport.toDomain(c);
|
||||
// reset ids in case they were set for some reason
|
||||
cipher.id = null;
|
||||
cipher.organizationId = this.organizationId;
|
||||
cipher.collectionIds = null;
|
||||
|
||||
// make sure password history is limited
|
||||
if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) {
|
||||
cipher.passwordHistory = cipher.passwordHistory.slice(0, 5);
|
||||
}
|
||||
|
||||
if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) {
|
||||
this.result.folderRelationships.push([
|
||||
this.result.ciphers.length,
|
||||
groupingsMap.get(c.folderId),
|
||||
]);
|
||||
} else if (this.organization && c.collectionIds != null) {
|
||||
c.collectionIds.forEach((cId) => {
|
||||
if (groupingsMap.has(cId)) {
|
||||
this.result.collectionRelationships.push([
|
||||
this.result.ciphers.length,
|
||||
groupingsMap.get(cId),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const view = await this.cipherService.decrypt(cipher, userId);
|
||||
this.cleanupCipher(view);
|
||||
this.result.ciphers.push(view);
|
||||
}
|
||||
|
||||
this.result.success = true;
|
||||
}
|
||||
|
||||
private async parseDecrypted(
|
||||
results: BitwardenUnEncryptedIndividualJsonExport | BitwardenUnEncryptedOrgJsonExport,
|
||||
) {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
const groupingsMap = this.organization
|
||||
? await this.parseCollections(userId, results as BitwardenUnEncryptedOrgJsonExport)
|
||||
: await this.parseFolders(results as BitwardenUnEncryptedIndividualJsonExport);
|
||||
const groupingsMap = isOrgUnEncrypted(results)
|
||||
? await this.parseCollections(results, importResult)
|
||||
: await this.parseFolders(results, importResult);
|
||||
|
||||
results.items.forEach((c) => {
|
||||
const cipher = CipherWithIdExport.toView(c);
|
||||
@ -145,15 +57,15 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
||||
}
|
||||
|
||||
if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) {
|
||||
this.result.folderRelationships.push([
|
||||
this.result.ciphers.length,
|
||||
importResult.folderRelationships.push([
|
||||
importResult.ciphers.length,
|
||||
groupingsMap.get(c.folderId),
|
||||
]);
|
||||
} else if (this.organization && c.collectionIds != null) {
|
||||
c.collectionIds.forEach((cId) => {
|
||||
if (groupingsMap.has(cId)) {
|
||||
this.result.collectionRelationships.push([
|
||||
this.result.ciphers.length,
|
||||
importResult.collectionRelationships.push([
|
||||
importResult.ciphers.length,
|
||||
groupingsMap.get(cId),
|
||||
]);
|
||||
}
|
||||
@ -161,76 +73,48 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
||||
}
|
||||
|
||||
this.cleanupCipher(cipher);
|
||||
this.result.ciphers.push(cipher);
|
||||
importResult.ciphers.push(cipher);
|
||||
});
|
||||
|
||||
this.result.success = true;
|
||||
importResult.success = true;
|
||||
return importResult;
|
||||
}
|
||||
|
||||
private async parseFolders(
|
||||
data: BitwardenUnEncryptedIndividualJsonExport | BitwardenEncryptedIndividualJsonExport,
|
||||
): Promise<Map<string, number>> | null {
|
||||
data: BitwardenUnEncryptedIndividualJsonExport,
|
||||
importResult: ImportResult,
|
||||
): Promise<Map<string, number>> {
|
||||
const groupingsMap = new Map<string, number>();
|
||||
if (data.folders == null) {
|
||||
return null;
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
const groupingsMap = new Map<string, number>();
|
||||
|
||||
for (const f of data.folders) {
|
||||
let folderView: FolderView;
|
||||
if (data.encrypted) {
|
||||
const folder = FolderWithIdExport.toDomain(f);
|
||||
if (folder != null) {
|
||||
folderView = await folder.decrypt();
|
||||
}
|
||||
} else {
|
||||
folderView = FolderWithIdExport.toView(f);
|
||||
}
|
||||
|
||||
const folderView = FolderWithIdExport.toView(f);
|
||||
if (folderView != null) {
|
||||
groupingsMap.set(f.id, this.result.folders.length);
|
||||
this.result.folders.push(folderView);
|
||||
groupingsMap.set(f.id, importResult.folders.length);
|
||||
importResult.folders.push(folderView);
|
||||
}
|
||||
}
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
private async parseCollections(
|
||||
userId: UserId,
|
||||
data: BitwardenUnEncryptedOrgJsonExport | BitwardenEncryptedOrgJsonExport,
|
||||
): Promise<Map<string, number>> | null {
|
||||
data: BitwardenUnEncryptedOrgJsonExport,
|
||||
importResult: ImportResult,
|
||||
): Promise<Map<string, number>> {
|
||||
const groupingsMap = new Map<string, number>();
|
||||
if (data.collections == null) {
|
||||
return null;
|
||||
return groupingsMap;
|
||||
}
|
||||
|
||||
const orgKeys = await firstValueFrom(
|
||||
this.keyService.orgKeys$(userId).pipe(filter((orgKeys) => orgKeys != null)),
|
||||
);
|
||||
|
||||
const groupingsMap = new Map<string, number>();
|
||||
|
||||
for (const c of data.collections) {
|
||||
let collectionView: CollectionView;
|
||||
if (data.encrypted) {
|
||||
const collection = CollectionWithIdExport.toDomain(
|
||||
c,
|
||||
new Collection({
|
||||
id: c.id,
|
||||
name: new EncString(c.name),
|
||||
organizationId: this.organizationId,
|
||||
}),
|
||||
);
|
||||
|
||||
const orgKey = orgKeys[c.organizationId];
|
||||
collectionView = await collection.decrypt(orgKey, this.encryptService);
|
||||
} else {
|
||||
collectionView = CollectionWithIdExport.toView(c);
|
||||
collectionView.organizationId = null;
|
||||
}
|
||||
const collectionView = CollectionWithIdExport.toView(c);
|
||||
collectionView.organizationId = null;
|
||||
|
||||
if (collectionView != null) {
|
||||
groupingsMap.set(c.id, this.result.collections.length);
|
||||
this.result.collections.push(collectionView);
|
||||
groupingsMap.set(c.id, importResult.collections.length);
|
||||
importResult.collections.push(collectionView);
|
||||
}
|
||||
}
|
||||
return groupingsMap;
|
||||
|
||||
@ -15,6 +15,7 @@ import { UserId } from "@bitwarden/user-core";
|
||||
import { emptyAccountEncrypted } from "../spec-data/bitwarden-json/account-encrypted.json";
|
||||
import { emptyUnencryptedExport } from "../spec-data/bitwarden-json/unencrypted.json";
|
||||
|
||||
import { BitwardenEncryptedJsonImporter } from "./bitwarden-encrypted-json-importer";
|
||||
import { BitwardenJsonImporter } from "./bitwarden-json-importer";
|
||||
import { BitwardenPasswordProtectedImporter } from "./bitwarden-password-protected-importer";
|
||||
|
||||
@ -90,7 +91,7 @@ describe("BitwardenPasswordProtectedImporter", () => {
|
||||
|
||||
describe("Account encrypted", () => {
|
||||
beforeAll(() => {
|
||||
jest.spyOn(BitwardenJsonImporter.prototype, "parse");
|
||||
jest.spyOn(BitwardenEncryptedJsonImporter.prototype, "parse");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@ -111,9 +112,11 @@ describe("BitwardenPasswordProtectedImporter", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("Should call BitwardenJsonImporter", async () => {
|
||||
it("Should call BitwardenEncryptedJsonImporter", async () => {
|
||||
expect((await importer.parse(emptyAccountEncrypted)).success).toEqual(true);
|
||||
expect(BitwardenJsonImporter.prototype.parse).toHaveBeenCalledWith(emptyAccountEncrypted);
|
||||
expect(BitwardenEncryptedJsonImporter.prototype.parse).toHaveBeenCalledWith(
|
||||
emptyAccountEncrypted,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -14,14 +14,21 @@ import {
|
||||
KeyService,
|
||||
KdfType,
|
||||
} from "@bitwarden/key-management";
|
||||
import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/vault-export-core";
|
||||
import {
|
||||
BitwardenJsonExport,
|
||||
BitwardenPasswordProtectedFileFormat,
|
||||
isPasswordProtected,
|
||||
} from "@bitwarden/vault-export-core";
|
||||
|
||||
import { ImportResult } from "../../models/import-result";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { BitwardenJsonImporter } from "./bitwarden-json-importer";
|
||||
import { BitwardenEncryptedJsonImporter } from "./bitwarden-encrypted-json-importer";
|
||||
|
||||
export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter implements Importer {
|
||||
export class BitwardenPasswordProtectedImporter
|
||||
extends BitwardenEncryptedJsonImporter
|
||||
implements Importer
|
||||
{
|
||||
private key: SymmetricCryptoKey;
|
||||
|
||||
constructor(
|
||||
@ -38,20 +45,14 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
|
||||
|
||||
async parse(data: string): Promise<ImportResult> {
|
||||
const result = new ImportResult();
|
||||
const parsedData: BitwardenPasswordProtectedFileFormat = JSON.parse(data);
|
||||
const parsedData: BitwardenPasswordProtectedFileFormat | BitwardenJsonExport = 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) {
|
||||
if (!isPasswordProtected(parsedData)) {
|
||||
return await super.parse(data);
|
||||
}
|
||||
|
||||
|
||||
@ -5,42 +5,48 @@ import {
|
||||
} from "@bitwarden/common/models/export";
|
||||
|
||||
// Base
|
||||
export type BitwardenJsonExport = {
|
||||
encrypted: boolean;
|
||||
items: CipherWithIdExport[];
|
||||
};
|
||||
export type BitwardenJsonExport = BitwardenUnEncryptedJsonExport | BitwardenEncryptedJsonExport;
|
||||
|
||||
// Decrypted
|
||||
export type BitwardenUnEncryptedJsonExport = BitwardenJsonExport & {
|
||||
encrypted: false;
|
||||
};
|
||||
export type BitwardenUnEncryptedJsonExport =
|
||||
| BitwardenUnEncryptedIndividualJsonExport
|
||||
| BitwardenUnEncryptedOrgJsonExport;
|
||||
|
||||
export type BitwardenUnEncryptedIndividualJsonExport = BitwardenUnEncryptedJsonExport & {
|
||||
export type BitwardenUnEncryptedIndividualJsonExport = {
|
||||
encrypted: false;
|
||||
items: CipherWithIdExport[];
|
||||
folders: FolderWithIdExport[];
|
||||
};
|
||||
|
||||
export type BitwardenUnEncryptedOrgJsonExport = BitwardenUnEncryptedJsonExport & {
|
||||
export type BitwardenUnEncryptedOrgJsonExport = {
|
||||
encrypted: false;
|
||||
items: CipherWithIdExport[];
|
||||
collections: CollectionWithIdExport[];
|
||||
};
|
||||
|
||||
// Account-encrypted
|
||||
export type BitwardenEncryptedJsonExport = BitwardenJsonExport & {
|
||||
export type BitwardenEncryptedJsonExport =
|
||||
| BitwardenEncryptedIndividualJsonExport
|
||||
| BitwardenEncryptedOrgJsonExport;
|
||||
|
||||
export type BitwardenEncryptedIndividualJsonExport = {
|
||||
encrypted: true;
|
||||
encKeyValidation_DO_NOT_EDIT: string;
|
||||
};
|
||||
|
||||
export type BitwardenEncryptedIndividualJsonExport = BitwardenEncryptedJsonExport & {
|
||||
items: CipherWithIdExport[];
|
||||
folders: FolderWithIdExport[];
|
||||
};
|
||||
|
||||
export type BitwardenEncryptedOrgJsonExport = BitwardenEncryptedJsonExport & {
|
||||
export type BitwardenEncryptedOrgJsonExport = {
|
||||
encrypted: true;
|
||||
encKeyValidation_DO_NOT_EDIT: string;
|
||||
items: CipherWithIdExport[];
|
||||
collections: CollectionWithIdExport[];
|
||||
};
|
||||
|
||||
// Password-protected
|
||||
export type BitwardenPasswordProtectedFileFormat = {
|
||||
encrypted: boolean;
|
||||
passwordProtected: boolean;
|
||||
encrypted: true;
|
||||
passwordProtected: true;
|
||||
salt: string;
|
||||
kdfIterations: number;
|
||||
kdfMemory?: number;
|
||||
@ -49,3 +55,50 @@ export type BitwardenPasswordProtectedFileFormat = {
|
||||
encKeyValidation_DO_NOT_EDIT: string;
|
||||
data: string;
|
||||
};
|
||||
|
||||
// Unencrypted type guards
|
||||
export function isUnencrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenUnEncryptedJsonExport {
|
||||
return data != null && (data as { encrypted?: unknown }).encrypted !== true;
|
||||
}
|
||||
|
||||
export function isIndividualUnEncrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenUnEncryptedIndividualJsonExport {
|
||||
return isUnencrypted(data) && (data as { folders?: unknown }).folders != null;
|
||||
}
|
||||
|
||||
export function isOrgUnEncrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenUnEncryptedOrgJsonExport {
|
||||
return isUnencrypted(data) && (data as { collections?: unknown }).collections != null;
|
||||
}
|
||||
|
||||
// Encrypted type guards
|
||||
export function isEncrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenEncryptedJsonExport {
|
||||
return data != null && (data as { encrypted?: unknown }).encrypted === true;
|
||||
}
|
||||
export function isPasswordProtected(
|
||||
data: BitwardenPasswordProtectedFileFormat | BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenPasswordProtectedFileFormat {
|
||||
return (
|
||||
data != null &&
|
||||
(data as { encrypted?: unknown }).encrypted === true &&
|
||||
(data as { passwordProtected?: unknown }).passwordProtected === true
|
||||
);
|
||||
}
|
||||
|
||||
export function isIndividualEncrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenEncryptedIndividualJsonExport {
|
||||
return isEncrypted(data) && (data as { folders?: unknown }).folders != null;
|
||||
}
|
||||
|
||||
export function isOrgEncrypted(
|
||||
data: BitwardenJsonExport | null | undefined,
|
||||
): data is BitwardenEncryptedOrgJsonExport {
|
||||
return isEncrypted(data) && (data as { collections?: unknown }).collections != null;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user