UNPKG

passbolt-styleguide

Version:

Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.

378 lines (282 loc) 14 kB
/** * Passbolt ~ Open source password manager for teams * Copyright (c) Passbolt SA (https://www.passbolt.com) * * Licensed under GNU Affero General Public License version 3 of the or any later version. * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com) * @license https://opensource.org/licenses/AGPL-3.0 AGPL License * @link https://www.passbolt.com Passbolt(tm) * @since 4.10.0 */ import EntitySchema from "../abstract/entitySchema"; import MetadataKeyEntity from "./metadataKeyEntity"; import { defaultMetadataKeyDto } from "./metadataKeyEntity.test.data"; import MetadataKeysCollection from "./metadataKeysCollection"; import { defaultDecryptedSharedMetadataKeysDtos, defaultMetadataKeysDtos, defaultMinimalMetadataKeysDtos, } from "./metadataKeysCollection.test.data"; import { defaultMetadataPrivateKeyDataDto } from "./metadataPrivateKeyDataEntity.test.data"; import { decryptedMetadataPrivateKeyDto, defaultMetadataPrivateKeyDto } from "./metadataPrivateKeyEntity.test.data"; import { pgpKeys } from "../../../../../test/fixture/pgpKeys/keys"; import { v4 as uuidv4 } from "uuid"; import EntityValidationError from "../abstract/entityValidationError"; import CollectionValidationError from "../abstract/collectionValidationError"; describe("MetadataKeysCollection", () => { describe("::getSchema", () => { it("schema must validate", () => { EntitySchema.validateSchema(MetadataKeysCollection.name, MetadataKeysCollection.getSchema()); }); }); describe("::constructor", () => { it("works with empty data", () => { expect.assertions(1); const collection = new MetadataKeysCollection([]); expect(collection).toHaveLength(0); }); it("works if valid minimal DTO is provided", () => { expect.assertions(3); const dtos = defaultMinimalMetadataKeysDtos(); const collection = new MetadataKeysCollection(dtos); expect(collection).toHaveLength(2); expect(collection.items[0]._props.fingerprint).toEqual(dtos[0].fingerprint); expect(collection.items[1]._props.fingerprint).toEqual(dtos[1].fingerprint); }); it("works if valid complete DTOs are provided", () => { expect.assertions(3); const dtos = defaultMetadataKeysDtos(); const collection = new MetadataKeysCollection(dtos); expect(collection).toHaveLength(2); expect(collection.items[0]._props.id).toEqual(dtos[0].id); expect(collection.items[1]._props.id).toEqual(dtos[1].id); }); it("works if valid complete entities are provided", () => { expect.assertions(3); const dtos = defaultMetadataKeysDtos(); const entity1 = new MetadataKeyEntity(dtos[0]); const entity2 = new MetadataKeyEntity(dtos[1]); const collection = new MetadataKeysCollection([entity1, entity2]); expect(collection).toHaveLength(2); expect(collection.items[0]._props.id).toEqual(entity1._props.id); expect(collection.items[1]._props.id).toEqual(entity2._props.id); }); it("should throw if the collection schema does not validate", () => { expect.assertions(1); expect(() => new MetadataKeysCollection({})).toThrowEntityValidationError("items"); }); it("should throw if one of data item does not validate the unique id build rule", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(); dtos[1].id = dtos[0].id; expect(() => new MetadataKeysCollection(dtos)).toThrowCollectionValidationError("1.id.unique"); }); it("should, with enabling the ignore invalid option, ignore items which do not validate the unique id build rule", () => { expect.assertions(2); const dtos = defaultMetadataKeysDtos(); dtos[1].id = dtos[0].id; const collection = new MetadataKeysCollection(dtos, { ignoreInvalidEntity: true }); expect(collection.items).toHaveLength(1); expect(collection.items[0]._props.id).toEqual(dtos[0].id); }); it("should throw if one of data item does not validate the collection entity schema", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(2, { fingerprint: "abcd".repeat(10) }); expect(() => new MetadataKeysCollection(dtos)).toThrowCollectionValidationError("1.fingerprint.unique"); }); it("should, with enabling the ignore invalid option, ignore items which do not validate their schema", () => { expect.assertions(2); const dtos = defaultMetadataKeysDtos(2, { fingerprint: "abcd".repeat(10) }); const collection = new MetadataKeysCollection(dtos, { ignoreInvalidEntity: true }); expect(collection.items).toHaveLength(1); expect(collection.items[0]._props.id).toEqual(dtos[0].id); }); it("should not throw if the collection has many items without metadata_key_id", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(4); delete dtos[0].metadata_key_id; delete dtos[3].metadata_key_id; const collection = new MetadataKeysCollection(dtos); expect(collection).toHaveLength(4); }); }); describe("::getFirstByLatestCreated", () => { it("should return the sole element in the list", () => { expect.assertions(1); const dtos = [defaultMetadataKeyDto({})]; const collection = new MetadataKeysCollection(dtos); expect(collection.getFirstByLatestCreated()._props.id).toStrictEqual(dtos[0].id); }); it("should return the latest created key from the collection", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(4); dtos[0].created = "2024-10-01T12:10:00+00:00"; dtos[1].created = "2024-10-05T12:10:00+00:00"; dtos[2].created = "2024-10-03T12:10:00+00:00"; dtos[3].created = "2024-10-04T12:10:00+00:00"; const collection = new MetadataKeysCollection(dtos); expect(collection.getFirstByLatestCreated()._props.id).toStrictEqual(dtos[1].id); }); it("should ignore the key with null creation date if there are other keys with a date set", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(4); delete dtos[0].created; dtos[1].created = "2024-10-05T12:10:00+00:00"; dtos[2].created = "2024-10-03T12:10:00+00:00"; dtos[3].created = "2024-10-04T12:10:00+00:00"; const collection = new MetadataKeysCollection(dtos); expect(collection.getFirstByLatestCreated()._props.id).toStrictEqual(dtos[1].id); }); it("should return the last key in the list if no creation date is available", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(4); delete dtos[0].created; delete dtos[1].created; delete dtos[2].created; delete dtos[3].created; const collection = new MetadataKeysCollection(dtos); expect(collection.getFirstByLatestCreated()._props.id).toStrictEqual(dtos[3].id); }); it("should return null if no key is in the collection", () => { expect.assertions(1); const collection = new MetadataKeysCollection([]); expect(collection.getFirstByLatestCreated()).toBeNull(); }); }); describe("::hasDecryptedKeys", () => { it("should return false if the collection has not metadata private keys", () => { expect.assertions(1); const dtos = [defaultMetadataKeyDto()]; const collection = new MetadataKeysCollection(dtos); expect(collection.hasDecryptedKeys()).toStrictEqual(false); }); it("should return true if none of the items has an encrypted metadata private key", () => { expect.assertions(1); const metadataKeyDto = defaultMetadataKeyDto(); const keyData = defaultMetadataPrivateKeyDataDto(); metadataKeyDto.metadata_private_keys = [ defaultMetadataPrivateKeyDto({ metadata_key_id: metadataKeyDto.id, data: keyData }), ]; const dtos = [metadataKeyDto]; const collection = new MetadataKeysCollection(dtos); expect(collection.hasDecryptedKeys()).toStrictEqual(true); }); it("should return false if none of the items has an encrypted metadata private key", () => { expect.assertions(1); const collection = new MetadataKeysCollection(defaultMetadataKeysDtos({}, { withMetadataPrivateKeys: true })); expect(collection.hasDecryptedKeys()).toStrictEqual(false); }); }); describe("::hasEncryptedKeys", () => { it("should return false if the collection has not metadata private keys", () => { expect.assertions(1); const dtos = [defaultMetadataKeyDto()]; const collection = new MetadataKeysCollection(dtos); expect(collection.hasEncryptedKeys()).toStrictEqual(false); }); it("should return false if none of the items has an encrypted metadata private key", () => { expect.assertions(1); const dtos = defaultMetadataKeysDtos(); const collection = new MetadataKeysCollection(dtos); expect(collection.hasEncryptedKeys()).toStrictEqual(false); }); it("should return true if one of the items has an encrypted metadata private key", () => { expect.assertions(1); const dtos = defaultDecryptedSharedMetadataKeysDtos(); dtos[0].metadata_private_keys[0].data = pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage; const collection = new MetadataKeysCollection(dtos); expect(collection.hasEncryptedKeys()).toStrictEqual(true); }); }); describe("::filterOutMissingMetadataPrivateKeys", () => { it("should filter out metadata key having no metadata private keys", () => { expect.assertions(1); const dtos = [defaultMetadataKeyDto()]; const collection = new MetadataKeysCollection(dtos); collection.filterOutMissingMetadataPrivateKeys(); expect(collection.length).toStrictEqual(0); }); it("should not filter out metadata key having a metadata private keys", () => { expect.assertions(1); const dtos = [defaultMetadataKeyDto({}, { withMetadataPrivateKeys: true })]; const collection = new MetadataKeysCollection(dtos); collection.filterOutMissingMetadataPrivateKeys(); expect(collection.length).toStrictEqual(1); }); it("should filter out only metadata keys having no metadata private keys", () => { expect.assertions(1); const dtos = [ defaultMetadataKeyDto(), defaultMetadataKeyDto({}, { withMetadataPrivateKeys: true }), defaultMetadataKeyDto(), defaultMetadataKeyDto({}, { withMetadataPrivateKeys: true }), ]; const collection = new MetadataKeysCollection(dtos); collection.filterOutMissingMetadataPrivateKeys(); expect(collection.length).toStrictEqual(2); }); }); describe("::pushMany", () => { it("[performance] should ensure performance adding large dataset remains effective.", async () => { const count = 10_000; const dtos = defaultMetadataKeysDtos(count); const start = performance.now(); const collection = new MetadataKeysCollection(dtos); const time = performance.now() - start; expect(collection).toHaveLength(count); expect(time).toBeLessThan(10_000); }); }); describe("::assertFingerprintsPublicAndPrivateKeysMatch", () => { it("should return if private key is not decrypted", () => { expect.assertions(1); const metadataKeyDto = defaultMetadataKeyDto({}, { withMetadataPrivateKeys: true }); const collection = new MetadataKeysCollection([metadataKeyDto]); expect(() => collection.assertFingerprintsPublicAndPrivateKeysMatch()).not.toThrow(); }); it("should return if no private keys are set", () => { expect.assertions(1); const metadataKeyDto = defaultMetadataKeyDto({}); const collection = new MetadataKeysCollection([metadataKeyDto]); expect(() => collection.assertFingerprintsPublicAndPrivateKeysMatch()).not.toThrow(); }); it("should throw an error if fingerprint does not match between public key and private keys", () => { expect.assertions(2); const metadataKeyId = uuidv4(); const metadataKeyDto = defaultMetadataKeyDto({ id: metadataKeyId, fingerprint: "1039097B2E1D31979FF662502714A820FAEF4FF3", metadata_private_keys: [decryptedMetadataPrivateKeyDto({ metadata_key_id: metadataKeyId })], }); const collection = new MetadataKeysCollection([metadataKeyDto]); try { collection.assertFingerprintsPublicAndPrivateKeysMatch(); } catch (error) { const entityValidationError = new EntityValidationError(); entityValidationError.addError( "metadata_private_keys.0.fingerprint", "fingerprint_match", "The fingerprint of the metadata private key does not match the fingerprint of the metadata public key", ); const collectionValidationError = new CollectionValidationError(); collectionValidationError.addItemValidationError(0, entityValidationError); expect(error).toBeInstanceOf(CollectionValidationError); expect(error).toEqual(collectionValidationError); } }); it("should succeed if fingerprint match between public key and private keys", () => { expect.assertions(1); const metadataKeyId = uuidv4(); const metadataKeyDto = defaultMetadataKeyDto({ id: metadataKeyId, fingerprint: pgpKeys.metadataKey.fingerprint, metadata_private_keys: [decryptedMetadataPrivateKeyDto({ metadata_key_id: metadataKeyId })], }); const collection = new MetadataKeysCollection([metadataKeyDto]); expect(() => collection.assertFingerprintsPublicAndPrivateKeysMatch()).not.toThrow(); }); }); });