passbolt-browser-extension 5.3.2 → 5.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -1
- package/README.md +2 -2
- package/RELEASE_NOTES.md +8 -30
- package/crowdin.yml +1 -0
- package/package.json +4 -3
- package/src/all/_locales/cs/messages.json +10 -0
- package/src/all/background_page/controller/InformMenuController/InformMenuController.js +3 -3
- package/src/all/background_page/controller/auth/redirectPostLoginController.js +57 -0
- package/src/all/background_page/controller/auth/redirectPostLoginController.test.js +82 -0
- package/src/all/background_page/controller/auth/redirectToAdminWorkspaceController.js +50 -0
- package/src/all/background_page/controller/auth/redirectToAdminWorkspaceController.test.js +45 -0
- package/src/all/background_page/controller/comment/createCommentController.js +3 -3
- package/src/all/background_page/controller/comment/createCommentController.test.js +5 -5
- package/src/all/background_page/controller/comment/deleteCommentController.js +3 -3
- package/src/all/background_page/controller/comment/deleteCommentController.test.js +3 -3
- package/src/all/background_page/controller/comment/getCommentsByRessourceIdController.js +3 -3
- package/src/all/background_page/controller/comment/getCommentsByRessourceidController.test.js +2 -2
- package/src/all/background_page/controller/import/importResourcesFileController.test.js +23 -23
- package/src/all/background_page/controller/metadata/enableEncryptedMetadataForExistingInstanceController.js +54 -0
- package/src/all/background_page/controller/metadata/enableEncryptedMetadataForExistingInstanceController.test.js +54 -0
- package/src/all/background_page/controller/metadata/enableMetadataSetupSettingsController.js +54 -0
- package/src/all/background_page/controller/metadata/enableMetadataSetupSettingsController.test.js +64 -0
- package/src/all/background_page/controller/metadata/findAllNonDeletedMetadataKeysController.js +2 -3
- package/src/all/background_page/controller/metadata/findMetadataGettingStartedSettingsController.js +50 -0
- package/src/all/background_page/controller/metadata/findMetadataGettingStartedSettingsController.test.js +33 -0
- package/src/all/background_page/controller/metadata/findMetadataSetupSettingsController.js +50 -0
- package/src/all/background_page/controller/metadata/findMetadataSetupSettingsController.test.js +42 -0
- package/src/all/background_page/controller/metadata/keepCleartextMetadataForExistingInstanceController.js +51 -0
- package/src/all/background_page/controller/metadata/keepCleartextMetadataForExistingInstanceController.test.js +47 -0
- package/src/all/background_page/controller/permission/FindAcoPermissionsForDisplayController.js +1 -0
- package/src/all/background_page/controller/quickaccess/consumeInProgressCreationResourceController.js +53 -0
- package/src/all/background_page/controller/quickaccess/consumeInProgressCreationResourceController.test.js +40 -0
- package/src/all/background_page/controller/quickaccess/prepareResourceController.js +64 -0
- package/src/all/background_page/controller/quickaccess/prepareResourceController.test.js +73 -0
- package/src/all/background_page/controller/resource/resourceDeleteController.js +67 -0
- package/src/all/background_page/controller/resource/resourceDeleteController.test.js +114 -0
- package/src/all/background_page/controller/resourceLocalStorage/resourceUpdateLocalStorageController.js +1 -1
- package/src/all/background_page/controller/resourceLocalStorage/resourceUpdateLocalStorageController.test.js +5 -1
- package/src/all/background_page/controller/setup/signInSetupController.js +0 -10
- package/src/all/background_page/controller/setup/signInSetupController.test.js +11 -12
- package/src/all/background_page/controller/sso/saveSsoSettingsAsDraftController.test.data.js +1 -0
- package/src/all/background_page/controller/webIntegration/webIntegrationController.js +1 -1
- package/src/all/background_page/event/appEvents.js +47 -0
- package/src/all/background_page/event/authEvents.js +4 -8
- package/src/all/background_page/event/informMenuEvents.js +31 -0
- package/src/all/background_page/event/quickAccessEvents.js +18 -23
- package/src/all/background_page/event/recoverEvents.js +12 -0
- package/src/all/background_page/event/resourceEvents.js +4 -11
- package/src/all/background_page/event/setupEvents.js +55 -0
- package/src/all/background_page/model/comment/{commentModel.js → commentService.js} +6 -2
- package/src/all/background_page/model/comment/commentService.test.js +98 -0
- package/src/all/background_page/model/entity/actionLog/actionLogsCollection.js +3 -3
- package/src/all/background_page/model/entity/actionLog/permissionsUpdatedActionLogEntity.js +4 -0
- package/src/all/background_page/model/entity/import/importResourcesFileEntity.test.data.js +3 -3
- package/src/all/background_page/model/entity/organizationSettings/organizationSettingsEntity.test.data.js +4 -0
- package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionEntity.test.data.js +23 -0
- package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionEntity.test.js +18 -33
- package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionsCollection.js +71 -2
- package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionsCollection.test.js +204 -0
- package/src/all/background_page/model/entity/permission/permissionsCollection.js +78 -0
- package/src/all/background_page/model/entity/permission/permissionsCollection.test.js +139 -7
- package/src/all/background_page/model/entity/plaintext/plaintextEntity.js +9 -0
- package/src/all/background_page/model/entity/resource/external/externalResourceEntity.js +65 -8
- package/src/all/background_page/model/entity/resource/external/externalResourceEntity.test.data.js +5 -4
- package/src/all/background_page/model/entity/resource/external/externalResourceEntity.test.js +72 -16
- package/src/all/background_page/model/entity/resource/external/externalResourcesCollection.test.js +2 -1
- package/src/all/background_page/model/entity/totp/externalTotpEntity.js +2 -2
- package/src/all/background_page/model/entity/totp/totpEntity.test.js +1 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csv1PasswordRowComposer.test.js +2 -2
- package/src/all/background_page/model/export/resources/csvRowComposer/csv1passwordRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvBitWardenRowComposer.js +9 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvBitWardenRowComposer.test.js +6 -4
- package/src/all/background_page/model/export/resources/csvRowComposer/csvChromiumRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvChromiumRowComposer.test.js +3 -2
- package/src/all/background_page/model/export/resources/csvRowComposer/csvDashlaneRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvDashlaneRowComposer.test.js +2 -3
- package/src/all/background_page/model/export/resources/csvRowComposer/csvKdbxRowComposer.js +3 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvKdbxRowComposer.test.js +6 -4
- package/src/all/background_page/model/export/resources/csvRowComposer/csvLastPassRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvLastPassRowComposer.test.js +2 -3
- package/src/all/background_page/model/export/resources/csvRowComposer/csvLogMeOnceRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvLogMeOnceRowComposer.test.js +2 -3
- package/src/all/background_page/model/export/resources/csvRowComposer/csvMozillaPlatformRowComposer.js +6 -2
- package/src/all/background_page/model/export/resources/csvRowComposer/csvMozillaPlatformRowComposer.test.js +2 -2
- package/src/all/background_page/model/export/resources/csvRowComposer/csvNordpassRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvNordpassRowComposer.test.js +2 -2
- package/src/all/background_page/model/export/resources/csvRowComposer/csvSafariRowComposer.js +5 -1
- package/src/all/background_page/model/export/resources/csvRowComposer/csvSafariRowComposer.test.js +2 -2
- package/src/all/background_page/model/export/resources/resourcesKdbxExporter.js +44 -2
- package/src/all/background_page/model/export/resources/resourcesKdbxExporter.test.js +24 -3
- package/src/all/background_page/model/import/resources/csvRowParser/abstractCsvRowParser.js +1 -1
- package/src/all/background_page/model/import/resources/csvRowParser/csv1PasswordRowParser.js +5 -3
- package/src/all/background_page/model/import/resources/csvRowParser/csv1PasswordRowParser.test.js +3 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvBitWardenRowParser.js +22 -3
- package/src/all/background_page/model/import/resources/csvRowParser/csvBitWardenRowParser.test.js +92 -4
- package/src/all/background_page/model/import/resources/csvRowParser/csvChromiumRowParser.js +4 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvChromiumRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvDashlaneRowParser.js +4 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvDashlaneRowParser.test.js +3 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvKdbxRowParser.js +5 -3
- package/src/all/background_page/model/import/resources/csvRowParser/csvKdbxRowParser.test.js +4 -4
- package/src/all/background_page/model/import/resources/csvRowParser/csvLastPassRowParser.js +4 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvLastPassRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvLogMeOnceRowParser.js +5 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvLogMeOnceRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvMozillaPlatformRowParser.js +5 -3
- package/src/all/background_page/model/import/resources/csvRowParser/csvMozillaPlatformRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvNordpassRowParser.js +4 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvNordpassRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvSafariRowParser.js +4 -2
- package/src/all/background_page/model/import/resources/csvRowParser/csvSafariRowParser.test.js +2 -2
- package/src/all/background_page/model/import/resources/kdbx/kdbx-custom-fields-with-uris.kdbx +0 -0
- package/src/all/background_page/model/import/resources/kdbx/kdbx-multiple-uris-with-33-entries.kdbx +0 -0
- package/src/all/background_page/model/import/resources/kdbx/kdbx-multiple-uris.kdbx +0 -0
- package/src/all/background_page/model/import/resources/kdbx/kdbx-with-protected-custom-fields.kdbx +0 -0
- package/src/all/background_page/model/import/resources/resourcesCsvImportParser.test.js +1 -1
- package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.js +124 -41
- package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.test.js +133 -1
- package/src/all/background_page/model/import/resourcesImportParser.test.js +0 -1
- package/src/all/background_page/model/resource/resourceModel.js +0 -68
- package/src/all/background_page/service/api/comment/commentApiService.test.js +1 -1
- package/src/all/background_page/service/api/metadata/metadataSetupSettingsApiService.js +40 -0
- package/src/all/background_page/service/api/metadata/metadataSetupSettingsApiService.test.js +54 -0
- package/src/all/background_page/service/api/setup/setupService.js +2 -2
- package/src/all/background_page/service/api/setup/setupService.test.js +132 -0
- package/src/all/background_page/service/local_storage/resourceLocalStorage.js +25 -1
- package/src/all/background_page/service/local_storage/resourceLocalStorage.test.js +54 -0
- package/src/all/background_page/service/metadata/configureMetadataSettingsService.js +100 -0
- package/src/all/background_page/service/metadata/configureMetadataSettingsService.test.js +265 -0
- package/src/all/background_page/service/metadata/createMetadataKeyService.js +1 -1
- package/src/all/background_page/service/metadata/decryptMetadataPrivateKeysService.js +3 -19
- package/src/all/background_page/service/metadata/decryptMetadataService.js +5 -3
- package/src/all/background_page/service/metadata/decryptMetadataService.test.js +31 -24
- package/src/all/background_page/service/metadata/encryptMetadataService.js +2 -18
- package/src/all/background_page/service/metadata/findAndUpdateMetadataKeysSessionStorageService.js +5 -2
- package/src/all/background_page/service/metadata/findAndUpdateMetadataKeysSessionStorageService.test.js +4 -6
- package/src/all/background_page/service/metadata/findMetadataKeysService.js +8 -12
- package/src/all/background_page/service/metadata/findMetadataKeysService.test.js +21 -47
- package/src/all/background_page/service/metadata/findMetadataSetupSettingsService.js +45 -0
- package/src/all/background_page/service/metadata/findMetadataSetupSettingsService.test.js +68 -0
- package/src/all/background_page/service/metadata/generateMetadataKeyService.js +1 -1
- package/src/all/background_page/service/metadata/verifyOrTrustMetadataKeyService.test.js +16 -0
- package/src/all/background_page/service/passphrase/getPassphraseService.js +13 -0
- package/src/all/background_page/service/permission/findPermissionsService.js +3 -1
- package/src/all/background_page/service/resource/delete/deleteResourceService.js +60 -0
- package/src/all/background_page/service/resource/delete/deleteResourceService.test.js +75 -0
- package/src/all/background_page/service/resource/export/exportResourcesService.js +22 -0
- package/src/all/background_page/service/resource/export/exportResourcesService.test.js +48 -1
- package/src/all/background_page/service/resource/import/ImportResourcesService.js +34 -3
- package/src/all/background_page/service/resource/import/ImportResourcesService.test.js +55 -13
- package/src/all/background_page/service/sessionKey/decryptSessionKeysBundlesService.js +2 -18
- package/src/all/background_page/service/sessionKey/encryptSessionKeysBundlesService.js +1 -17
- package/src/all/locales/cs-CZ/common.json +130 -0
- package/src/all/locales/de-DE/common.json +11 -5
- package/src/all/locales/en-UK/common.json +6 -0
- package/src/all/locales/es-ES/common.json +6 -0
- package/src/all/locales/fr-FR/common.json +6 -0
- package/src/all/locales/it-IT/common.json +6 -0
- package/src/all/locales/ja-JP/common.json +6 -0
- package/src/all/locales/ko-KR/common.json +6 -0
- package/src/all/locales/lt-LT/common.json +6 -0
- package/src/all/locales/nl-NL/common.json +6 -0
- package/src/all/locales/pl-PL/common.json +6 -0
- package/src/all/locales/pt-BR/common.json +6 -0
- package/src/all/locales/ro-RO/common.json +6 -0
- package/src/all/locales/ru-RU/common.json +6 -0
- package/src/all/locales/sl-SI/common.json +6 -0
- package/src/all/locales/sv-SE/common.json +6 -0
- package/src/all/locales/uk-UA/common.json +6 -0
- package/src/chrome/manifest.json +1 -1
- package/src/chrome-mv3/manifest.json +1 -1
- package/src/firefox/manifest.json +1 -1
- package/src/safari/manifest.json +1 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Passbolt ~ Open source password manager for teams
|
|
3
|
+
* Copyright (c) Passbolt SA (https://www.passbolt.com)
|
|
4
|
+
*
|
|
5
|
+
* Licensed under GNU Affero General Public License version 3 of the or any later version.
|
|
6
|
+
* For full copyright and license information, please see the LICENSE.txt
|
|
7
|
+
* Redistributions of files must retain the above copyright notice.
|
|
8
|
+
*
|
|
9
|
+
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
|
|
10
|
+
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
|
|
11
|
+
* @link https://www.passbolt.com Passbolt(tm)
|
|
12
|
+
* @since 5.4.0
|
|
13
|
+
*/
|
|
14
|
+
import AccountEntity from "../../model/entity/account/accountEntity";
|
|
15
|
+
import BuildApiClientOptionsService from "../account/buildApiClientOptionsService";
|
|
16
|
+
import ConfigureMetadataSettingsService from "./configureMetadataSettingsService";
|
|
17
|
+
import MetadataTypesSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataTypesSettingsEntity";
|
|
18
|
+
import MetadataKeysSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity";
|
|
19
|
+
import ExternalGpgKeyPairEntity from "passbolt-styleguide/src/shared/models/entity/gpgkey/external/externalGpgKeyPairEntity";
|
|
20
|
+
import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
|
|
21
|
+
import MetadataGettingStartedSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataGettingStartedSettingsEntity";
|
|
22
|
+
import {defaultMetadataGettingStartedSettingsDto, enableMetadataGettingStartedSettingsDto} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataGettingStartedSettingsEntity.test.data";
|
|
23
|
+
|
|
24
|
+
describe("ConfigureMetadataSettingsService", () => {
|
|
25
|
+
describe("::enableEncryptedMetadataForNewInstance", () => {
|
|
26
|
+
it("should orchestrate all the necessary service in order to activate the encryption of metadata", async() => {
|
|
27
|
+
expect.assertions(8);
|
|
28
|
+
|
|
29
|
+
const passphrase = "ada@passbolt.com";
|
|
30
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
31
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
32
|
+
|
|
33
|
+
const expectedKeySettings = MetadataKeysSettingsEntity.createFromDefault();
|
|
34
|
+
const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV5Default();
|
|
35
|
+
|
|
36
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
37
|
+
jest.spyOn(orchestrator.generateMetadataKeyService, "generateKey");
|
|
38
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
39
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
|
|
40
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
|
|
41
|
+
|
|
42
|
+
await orchestrator.enableEncryptedMetadataForNewInstance(passphrase);
|
|
43
|
+
|
|
44
|
+
expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledWith(passphrase);
|
|
46
|
+
|
|
47
|
+
expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledTimes(1);
|
|
48
|
+
expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledWith(expect.any(ExternalGpgKeyPairEntity), passphrase);
|
|
49
|
+
|
|
50
|
+
expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledWith(expectedKeySettings);
|
|
52
|
+
|
|
53
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
|
|
54
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key generation", async() => {
|
|
58
|
+
expect.assertions(1);
|
|
59
|
+
|
|
60
|
+
const passphrase = "ada@passbolt.com";
|
|
61
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
62
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
63
|
+
|
|
64
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
65
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
66
|
+
|
|
67
|
+
await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key save", async() => {
|
|
71
|
+
expect.assertions(1);
|
|
72
|
+
|
|
73
|
+
const passphrase = "ada@passbolt.com";
|
|
74
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
75
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
76
|
+
|
|
77
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
78
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
79
|
+
|
|
80
|
+
await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the key settings", async() => {
|
|
84
|
+
expect.assertions(1);
|
|
85
|
+
|
|
86
|
+
const passphrase = "ada@passbolt.com";
|
|
87
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
88
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
89
|
+
|
|
90
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
91
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
92
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
93
|
+
|
|
94
|
+
await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
|
|
98
|
+
expect.assertions(1);
|
|
99
|
+
|
|
100
|
+
const passphrase = "ada@passbolt.com";
|
|
101
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
102
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
103
|
+
|
|
104
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
105
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
106
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
|
|
107
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
108
|
+
|
|
109
|
+
await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("::enableEncryptedMetadataForExistingInstance", () => {
|
|
114
|
+
it("should orchestrate all the necessary service in order to activate the encryption of metadata", async() => {
|
|
115
|
+
expect.assertions(8);
|
|
116
|
+
|
|
117
|
+
const passphrase = "ada@passbolt.com";
|
|
118
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
119
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
120
|
+
|
|
121
|
+
const expectedKeySettings = MetadataKeysSettingsEntity.createFromDefault();
|
|
122
|
+
const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV5Default({
|
|
123
|
+
allow_v4_v5_upgrade: true
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
127
|
+
jest.spyOn(orchestrator.generateMetadataKeyService, "generateKey");
|
|
128
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
129
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
|
|
130
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
|
|
131
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
132
|
+
|
|
133
|
+
await orchestrator.enableEncryptedMetadataForExistingInstance(passphrase);
|
|
134
|
+
|
|
135
|
+
expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledTimes(1);
|
|
136
|
+
expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledWith(passphrase);
|
|
137
|
+
|
|
138
|
+
expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledTimes(1);
|
|
139
|
+
expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledWith(expect.any(ExternalGpgKeyPairEntity), passphrase);
|
|
140
|
+
|
|
141
|
+
expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledTimes(1);
|
|
142
|
+
expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledWith(expectedKeySettings);
|
|
143
|
+
|
|
144
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
|
|
145
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key generation", async() => {
|
|
149
|
+
expect.assertions(1);
|
|
150
|
+
|
|
151
|
+
const passphrase = "ada@passbolt.com";
|
|
152
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
153
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
154
|
+
|
|
155
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
156
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
157
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
158
|
+
|
|
159
|
+
await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key save", async() => {
|
|
163
|
+
expect.assertions(1);
|
|
164
|
+
|
|
165
|
+
const passphrase = "ada@passbolt.com";
|
|
166
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
167
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
168
|
+
|
|
169
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
170
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
171
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
172
|
+
|
|
173
|
+
await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the key settings", async() => {
|
|
177
|
+
expect.assertions(1);
|
|
178
|
+
|
|
179
|
+
const passphrase = "ada@passbolt.com";
|
|
180
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
181
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
182
|
+
|
|
183
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
184
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
185
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
186
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
187
|
+
|
|
188
|
+
await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
|
|
192
|
+
expect.assertions(1);
|
|
193
|
+
|
|
194
|
+
const passphrase = "ada@passbolt.com";
|
|
195
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
196
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
197
|
+
|
|
198
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
199
|
+
jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
|
|
200
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
|
|
201
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
202
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
203
|
+
|
|
204
|
+
await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should not proceed if a strategy has already been defined", async() => {
|
|
208
|
+
expect.assertions(1);
|
|
209
|
+
|
|
210
|
+
const passphrase = "ada@passbolt.com";
|
|
211
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
212
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
213
|
+
|
|
214
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
215
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(defaultMetadataGettingStartedSettingsDto()));
|
|
216
|
+
|
|
217
|
+
await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe("::keepCleartextMetadataForExistingInstance", () => {
|
|
222
|
+
it("should orchestrate all the necessary service in order to deactivate the encryption of metadata", async() => {
|
|
223
|
+
expect.assertions(2);
|
|
224
|
+
|
|
225
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
226
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
227
|
+
|
|
228
|
+
const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV4Default();
|
|
229
|
+
|
|
230
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
231
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
|
|
232
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
233
|
+
|
|
234
|
+
await orchestrator.keepCleartextMetadataForExistingInstance();
|
|
235
|
+
|
|
236
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
|
|
237
|
+
expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
|
|
241
|
+
expect.assertions(1);
|
|
242
|
+
|
|
243
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
244
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
245
|
+
|
|
246
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
247
|
+
jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
|
|
248
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
|
|
249
|
+
|
|
250
|
+
await expect(() => orchestrator.keepCleartextMetadataForExistingInstance()).rejects.toThrowError();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
|
|
254
|
+
expect.assertions(1);
|
|
255
|
+
|
|
256
|
+
const account = new AccountEntity(defaultAccountDto());
|
|
257
|
+
const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
258
|
+
|
|
259
|
+
const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
|
|
260
|
+
jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(defaultMetadataGettingStartedSettingsDto()));
|
|
261
|
+
|
|
262
|
+
await expect(() => orchestrator.keepCleartextMetadataForExistingInstance()).rejects.toThrowError();
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -49,7 +49,7 @@ export default class CreateMetadataKeyService {
|
|
|
49
49
|
* Note: the service does not handle yet the zero knowledge, the key will be encrypted for the API.
|
|
50
50
|
* @param {ExternalGpgKeyPairEntity} metadataKeyPair The metadata key pair.
|
|
51
51
|
* @param {string} passphrase The user passphrase.
|
|
52
|
-
* @
|
|
52
|
+
* @returns {Promise<MetadataKeyEntity>}
|
|
53
53
|
* @throws {TypeError} if metadataKeyPair argument is not of the expected type
|
|
54
54
|
* @throws {TypeError} if passphrase argument is not a string
|
|
55
55
|
*/
|
|
@@ -17,7 +17,6 @@ import MetadataPrivateKeyEntity from "passbolt-styleguide/src/shared/models/enti
|
|
|
17
17
|
import MetadataPrivateKeyDataEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataPrivateKeyDataEntity";
|
|
18
18
|
import MetadataPrivateKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataPrivateKeysCollection";
|
|
19
19
|
import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
|
|
20
|
-
import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
|
|
21
20
|
import {assertType} from '../../utils/assertions';
|
|
22
21
|
import DecryptPrivateKeyService from '../crypto/decryptPrivateKeyService';
|
|
23
22
|
import DecryptMessageService from '../crypto/decryptMessageService';
|
|
@@ -53,7 +52,7 @@ class DecryptMetadataPrivateKeysService {
|
|
|
53
52
|
|
|
54
53
|
const message = await OpenpgpAssertion.readMessageOrFail(metadataPrivateKeyEntity.data);
|
|
55
54
|
|
|
56
|
-
passphrase = passphrase || await
|
|
55
|
+
passphrase = passphrase || await PassphraseStorageService.getOrFail();
|
|
57
56
|
|
|
58
57
|
const userDecryptedPrivateArmoredKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
|
|
59
58
|
const userPublicKey = await OpenpgpAssertion.readKeyOrFail(this.account.userPublicArmoredKey);
|
|
@@ -88,7 +87,7 @@ class DecryptMetadataPrivateKeysService {
|
|
|
88
87
|
async decryptAll(metadataPrivateKeysCollection, passphrase = null) {
|
|
89
88
|
assertType(metadataPrivateKeysCollection, MetadataPrivateKeysCollection, "The given collection is not of the type MetadataPrivateKeysCollection");
|
|
90
89
|
|
|
91
|
-
passphrase = passphrase || await
|
|
90
|
+
passphrase = passphrase || await PassphraseStorageService.getOrFail();
|
|
92
91
|
|
|
93
92
|
const items = metadataPrivateKeysCollection.items;
|
|
94
93
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -119,26 +118,11 @@ class DecryptMetadataPrivateKeysService {
|
|
|
119
118
|
if (!metadataPrivateKeysCollection || !metadataPrivateKeysCollection.length || !metadataKeysCollection?.hasEncryptedKeys()) {
|
|
120
119
|
continue;
|
|
121
120
|
}
|
|
122
|
-
passphrase = passphrase || await
|
|
121
|
+
passphrase = passphrase || await PassphraseStorageService.getOrFail();
|
|
123
122
|
await this.decryptAll(metadataPrivateKeysCollection, passphrase);
|
|
124
123
|
}
|
|
125
124
|
}
|
|
126
125
|
|
|
127
|
-
/**
|
|
128
|
-
* Retrieve the user passphrase from the session storage or fail.
|
|
129
|
-
*
|
|
130
|
-
* @returns {Promise<string>}
|
|
131
|
-
* @throws {UserPassphraseRequiredError} if the `passphrase` cannot be retrieved.
|
|
132
|
-
* @private
|
|
133
|
-
*/
|
|
134
|
-
async getPassphraseFromSessionStorageOrFail() {
|
|
135
|
-
const passphrase = await PassphraseStorageService.get();
|
|
136
|
-
if (!passphrase) {
|
|
137
|
-
throw new UserPassphraseRequiredError();
|
|
138
|
-
}
|
|
139
|
-
return passphrase;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
126
|
/**
|
|
143
127
|
* Verify the metadata private key entity fingerprint is equal to the armored key fingerprint.
|
|
144
128
|
* @param {MetadataPrivateKeyEntity} metadataPrivateKeyEntity the metadata private key entity to decrypt.
|
|
@@ -87,12 +87,13 @@ class DecryptMetadataService {
|
|
|
87
87
|
|
|
88
88
|
try {
|
|
89
89
|
sessionKeys = await this.getOrFindSessionKeysService.getOrFindAllByForeignModelAndForeignIds("Resource", collection.ids, passphrase);
|
|
90
|
-
for (
|
|
90
|
+
for (let i = sessionKeys.items.length - 1; i >= 0; i--) {
|
|
91
|
+
const sessionKey = sessionKeys.items[i];
|
|
91
92
|
try {
|
|
92
93
|
const entity = collection.getFirst("id", sessionKey.foreignId);
|
|
93
94
|
await this.decryptMetadataWithSessionKey(entity, sessionKey.sessionKey);
|
|
94
95
|
} catch (error) {
|
|
95
|
-
sessionKeys.
|
|
96
|
+
sessionKeys.items.splice(i, 1);
|
|
96
97
|
console.debug(`Metadata of the entity "${sessionKey.foreignModel}:${sessionKey.foreignId}" cannot be decrypted with session key.`, {cause: error});
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -267,7 +268,8 @@ class DecryptMetadataService {
|
|
|
267
268
|
return {
|
|
268
269
|
foreign_model: "Resource",
|
|
269
270
|
foreign_id: entity.id,
|
|
270
|
-
session_key: sessionKeyString
|
|
271
|
+
session_key: sessionKeyString,
|
|
272
|
+
modified: entity.modified
|
|
271
273
|
};
|
|
272
274
|
}
|
|
273
275
|
|
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
import SessionKeysCollection from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeysCollection";
|
|
32
32
|
import {metadata} from "passbolt-styleguide/test/fixture/encryptedMetadata/metadata";
|
|
33
33
|
import {defaultSessionKeyDto} from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeyEntity.test.data";
|
|
34
|
-
import SessionKeyEntity from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeyEntity";
|
|
35
34
|
import ResourceEntity from "../../model/entity/resource/resourceEntity";
|
|
36
35
|
import {defaultResourceDto} from "passbolt-styleguide/src/shared/models/entity/resource/resourceEntity.test.data";
|
|
37
36
|
import EntityValidationError from "passbolt-styleguide/src/shared/models/entity/abstract/entityValidationError";
|
|
@@ -396,8 +395,8 @@ describe("DecryptMetadataService", () => {
|
|
|
396
395
|
await expect(service.decryptAllFromForeignModels(collection, pgpKeys.ada.passphrase, {ignoreDecryptionError: true})).resolves.toBeUndefined();
|
|
397
396
|
});
|
|
398
397
|
|
|
399
|
-
it("should
|
|
400
|
-
expect.assertions(
|
|
398
|
+
it("should not update the session storage with the session keys when discovering a new session key if not specifically requested", async() => {
|
|
399
|
+
expect.assertions(1);
|
|
401
400
|
|
|
402
401
|
const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
|
|
403
402
|
const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
|
|
@@ -405,29 +404,24 @@ describe("DecryptMetadataService", () => {
|
|
|
405
404
|
metadata_key_id: metadataKeysDtos[0].id
|
|
406
405
|
});
|
|
407
406
|
const collection = new ResourcesCollection(collectionDto);
|
|
408
|
-
const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
|
|
409
|
-
const sessionKeysCount = collection.length;
|
|
410
|
-
const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: sessionKeysCount});
|
|
411
407
|
|
|
412
|
-
//invalid session key
|
|
413
|
-
sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
|
|
414
|
-
const invalidSessionKeyEntity = new SessionKeyEntity(sessionKeysDtos[3]);
|
|
415
408
|
|
|
409
|
+
const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
|
|
410
|
+
const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
|
|
411
|
+
sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
|
|
416
412
|
const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
|
|
417
413
|
|
|
418
|
-
jest.spyOn(
|
|
414
|
+
jest.spyOn(service.saveSessionKeysService, "save");
|
|
419
415
|
jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
|
|
420
416
|
jest.spyOn(service.getOrFindSessionKeysService, "getOrFindAllByForeignModelAndForeignIds").mockImplementation(() => sessionKeys);
|
|
421
417
|
|
|
422
418
|
await service.decryptAllFromForeignModels(collection);
|
|
423
419
|
|
|
424
|
-
expect(
|
|
425
|
-
expect(sessionKeys.remove).toHaveBeenCalledWith(invalidSessionKeyEntity);
|
|
426
|
-
expect(sessionKeys.length).toStrictEqual(sessionKeysCount - 1);
|
|
420
|
+
expect(service.saveSessionKeysService.save).not.toHaveBeenCalled();
|
|
427
421
|
});
|
|
428
422
|
|
|
429
|
-
it("should
|
|
430
|
-
expect.assertions(
|
|
423
|
+
it("should update the session storage with the session keys when a new session key is discovered if the option `updateSessionKeys` is passed", async() => {
|
|
424
|
+
expect.assertions(3);
|
|
431
425
|
|
|
432
426
|
const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
|
|
433
427
|
const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
|
|
@@ -436,23 +430,28 @@ describe("DecryptMetadataService", () => {
|
|
|
436
430
|
});
|
|
437
431
|
const collection = new ResourcesCollection(collectionDto);
|
|
438
432
|
|
|
439
|
-
|
|
440
433
|
const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
|
|
441
434
|
const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
|
|
442
|
-
|
|
435
|
+
const sessionKeyDiscovered = sessionKeysDtos[3];
|
|
436
|
+
sessionKeysDtos.splice(3, 1);
|
|
443
437
|
const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
|
|
438
|
+
sessionKeyDiscovered.modified = collection.resources[3].modified;
|
|
439
|
+
const expectedSessionKeysDto = [...sessionKeysDtos, sessionKeyDiscovered];
|
|
444
440
|
|
|
445
441
|
jest.spyOn(service.saveSessionKeysService, "save");
|
|
446
442
|
jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
|
|
447
443
|
jest.spyOn(service.getOrFindSessionKeysService, "getOrFindAllByForeignModelAndForeignIds").mockImplementation(() => sessionKeys);
|
|
448
444
|
|
|
449
|
-
await service.decryptAllFromForeignModels(collection);
|
|
445
|
+
await service.decryptAllFromForeignModels(collection, null, {updateSessionKeys: true});
|
|
450
446
|
|
|
451
|
-
|
|
447
|
+
const [[savedSessionKeys, passphraseArg]] = service.saveSessionKeysService.save.mock.calls;
|
|
448
|
+
expect(service.saveSessionKeysService.save).toHaveBeenCalledTimes(1);
|
|
449
|
+
expect(savedSessionKeys.toDto()).toEqual(expectedSessionKeysDto);
|
|
450
|
+
expect(passphraseArg).toBe(null);
|
|
452
451
|
});
|
|
453
452
|
|
|
454
|
-
it("should
|
|
455
|
-
expect.assertions(
|
|
453
|
+
it("should remove invalid session key and add newly discovered to the list of session keys to save", async() => {
|
|
454
|
+
expect.assertions(3);
|
|
456
455
|
|
|
457
456
|
const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
|
|
458
457
|
const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
|
|
@@ -461,11 +460,17 @@ describe("DecryptMetadataService", () => {
|
|
|
461
460
|
});
|
|
462
461
|
const collection = new ResourcesCollection(collectionDto);
|
|
463
462
|
|
|
464
|
-
|
|
465
463
|
const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
|
|
466
464
|
const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
|
|
467
|
-
|
|
465
|
+
const sessionKeyDiscovered = sessionKeysDtos[3]; // Copy the working session key.
|
|
466
|
+
sessionKeysDtos[3] = JSON.parse(JSON.stringify(sessionKeysDtos[3]));
|
|
467
|
+
sessionKeysDtos[3].session_key = "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"; // Replace session key with a non working one
|
|
468
468
|
const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
|
|
469
|
+
// Expected sessions keys arry.
|
|
470
|
+
sessionKeyDiscovered.modified = collection.resources[3].modified;
|
|
471
|
+
const expectedSessionKeysDto = JSON.parse(JSON.stringify(sessionKeysDtos));
|
|
472
|
+
expectedSessionKeysDto.splice(3, 1);
|
|
473
|
+
expectedSessionKeysDto.push(sessionKeyDiscovered);
|
|
469
474
|
|
|
470
475
|
jest.spyOn(service.saveSessionKeysService, "save");
|
|
471
476
|
jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
|
|
@@ -473,8 +478,10 @@ describe("DecryptMetadataService", () => {
|
|
|
473
478
|
|
|
474
479
|
await service.decryptAllFromForeignModels(collection, null, {updateSessionKeys: true});
|
|
475
480
|
|
|
481
|
+
const [[savedSessionKeys, passphraseArg]] = service.saveSessionKeysService.save.mock.calls;
|
|
476
482
|
expect(service.saveSessionKeysService.save).toHaveBeenCalledTimes(1);
|
|
477
|
-
expect(
|
|
483
|
+
expect(savedSessionKeys.toDto()).toEqual(expectedSessionKeysDto);
|
|
484
|
+
expect(passphraseArg).toBe(null);
|
|
478
485
|
});
|
|
479
486
|
});
|
|
480
487
|
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
* @since 4.10.0
|
|
13
13
|
*/
|
|
14
14
|
import PassphraseStorageService from '../session_storage/passphraseStorageService';
|
|
15
|
-
import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
|
|
16
15
|
import GetOrFindMetadataKeysService from "./getOrFindMetadataKeysService";
|
|
17
16
|
import EncryptMessageService from "../crypto/encryptMessageService";
|
|
18
17
|
import {OpenpgpAssertion} from "../../utils/openpgp/openpgpAssertions";
|
|
@@ -70,7 +69,7 @@ class EncryptMetadataService {
|
|
|
70
69
|
// Prevent future issue if an encrypted metadata is stored without object_type, this will fail the decryption validation of the entity
|
|
71
70
|
this.assertValidMetadataObjectType(entity);
|
|
72
71
|
|
|
73
|
-
passphrase = passphrase || await
|
|
72
|
+
passphrase = passphrase || await PassphraseStorageService.getOrFail();
|
|
74
73
|
const userPrivateKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
|
|
75
74
|
const serializedMetadata = JSON.stringify(entity.metadata.toDto(entity.metadata.constructor.DEFAULT_CONTAIN));
|
|
76
75
|
|
|
@@ -116,7 +115,7 @@ class EncryptMetadataService {
|
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
const canUsePersonalKeys = await this.allowUsageOfPersonalKeys();
|
|
119
|
-
passphrase = passphrase || await
|
|
118
|
+
passphrase = passphrase || await PassphraseStorageService.getOrFail();
|
|
120
119
|
|
|
121
120
|
const userDecryptedPrivateKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
|
|
122
121
|
|
|
@@ -222,21 +221,6 @@ class EncryptMetadataService {
|
|
|
222
221
|
return {metadataKeyId, metadataPublicKey, metadataPrivateKey};
|
|
223
222
|
}
|
|
224
223
|
|
|
225
|
-
/**
|
|
226
|
-
* Retrieve the user passphrase from the local storage or fail.
|
|
227
|
-
*
|
|
228
|
-
* @returns {Promise<string>}
|
|
229
|
-
* @throws {UserPassphraseRequiredError} if the `passphrase` is not set and cannot be retrieved.
|
|
230
|
-
* @private
|
|
231
|
-
*/
|
|
232
|
-
async getPassphraseFromLocalStorageOrFail() {
|
|
233
|
-
const passphrase = await PassphraseStorageService.get();
|
|
234
|
-
if (!passphrase) {
|
|
235
|
-
throw new UserPassphraseRequiredError();
|
|
236
|
-
}
|
|
237
|
-
return passphrase;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
224
|
/**
|
|
241
225
|
* Allow usage of personal keys
|
|
242
226
|
* @returns {Promise<boolean>}
|
package/src/all/background_page/service/metadata/findAndUpdateMetadataKeysSessionStorageService.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import FindMetadataKeysService from "./findMetadataKeysService";
|
|
15
15
|
import MetadataKeysSessionStorage from "../session_storage/metadataKeysSessionStorage";
|
|
16
16
|
import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
|
|
17
|
+
import DecryptMetadataPrivateKeysService from "./decryptMetadataPrivateKeysService";
|
|
17
18
|
|
|
18
19
|
const FIND_AND_UPDATE_METADATA_KEYS_SS_LOCK_PREFIX = "FIND_AND_UPDATE_METADATA_KEYS_SS_LOCK-";
|
|
19
20
|
|
|
@@ -28,8 +29,9 @@ export default class FindAndUpdateMetadataKeysSessionStorageService {
|
|
|
28
29
|
*/
|
|
29
30
|
constructor(account, apiClientOptions) {
|
|
30
31
|
this.account = account;
|
|
31
|
-
this.findMetadataKeysService = new FindMetadataKeysService(apiClientOptions
|
|
32
|
+
this.findMetadataKeysService = new FindMetadataKeysService(apiClientOptions);
|
|
32
33
|
this.metadataKeysSessionStorage = new MetadataKeysSessionStorage(account);
|
|
34
|
+
this.decryptMetadataPrivateKeysService = new DecryptMetadataPrivateKeysService(account);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -51,7 +53,8 @@ export default class FindAndUpdateMetadataKeysSessionStorageService {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
// Lock is granted, retrieve the metadata keys and update the session storage.
|
|
54
|
-
const metadataKeys = await this.findMetadataKeysService.findAllForSessionStorage(
|
|
56
|
+
const metadataKeys = await this.findMetadataKeysService.findAllForSessionStorage();
|
|
57
|
+
await this.decryptMetadataPrivateKeysService.decryptAllFromMetadataKeysCollection(metadataKeys, passphrase);
|
|
55
58
|
await this.metadataKeysSessionStorage.set(metadataKeys);
|
|
56
59
|
return metadataKeys;
|
|
57
60
|
});
|
|
@@ -16,9 +16,6 @@ import AccountEntity from "../../model/entity/account/accountEntity";
|
|
|
16
16
|
import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
|
|
17
17
|
import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
|
|
18
18
|
import FindAndUpdateMetadataKeysSessionStorageService from "./findAndUpdateMetadataKeysSessionStorageService";
|
|
19
|
-
import {
|
|
20
|
-
defaultMetadataKeysDtos
|
|
21
|
-
} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection.test.data";
|
|
22
19
|
import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
|
|
23
20
|
import PassphraseStorageService from "../session_storage/passphraseStorageService";
|
|
24
21
|
import {pgpKeys} from "passbolt-styleguide/test/fixture/pgpKeys/keys";
|
|
@@ -49,13 +46,15 @@ describe("FindAndUpdateMetadataKeysSessionStorageService", () => {
|
|
|
49
46
|
describe("::findAndUpdateAll", () => {
|
|
50
47
|
it("should throw an error if the user passphrase is not set and is required", async() => {
|
|
51
48
|
expect.assertions(1);
|
|
52
|
-
const
|
|
49
|
+
const id = uuidv4();
|
|
50
|
+
const metadataPrivateKeysDto = [defaultMetadataPrivateKeyDto({metadata_key_id: id, data: pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage})];
|
|
51
|
+
const metadataKeysDto = [defaultMetadataKeyDto({id: id, metadata_private_keys: metadataPrivateKeysDto, fingerprint: "c0dce0aaea4d8cce961c26bddfb6e74e598f025c"})];
|
|
53
52
|
jest.spyOn(findAndUpdateKeysSessionStorageService.findMetadataKeysService.metadataKeysApiService, "findAll").mockImplementation(() => metadataKeysDto);
|
|
54
53
|
|
|
55
54
|
await expect(() => findAndUpdateKeysSessionStorageService.findAndUpdateAll()).rejects.toThrow(UserPassphraseRequiredError);
|
|
56
55
|
});
|
|
57
56
|
|
|
58
|
-
it("retrieves the metadata keys from the API and store them into the session storage using the passphrase from the session storage.", async() => {
|
|
57
|
+
it("retrieves the metadata keys from the API and store them into the session storage and decrypt them using the passphrase from the session storage.", async() => {
|
|
59
58
|
expect.assertions(7);
|
|
60
59
|
|
|
61
60
|
const id = uuidv4();
|
|
@@ -97,7 +96,6 @@ describe("FindAndUpdateMetadataKeysSessionStorageService", () => {
|
|
|
97
96
|
expect(PassphraseStorageService.get).not.toHaveBeenCalled();
|
|
98
97
|
});
|
|
99
98
|
|
|
100
|
-
|
|
101
99
|
it("overrides session storage with a second update call.", async() => {
|
|
102
100
|
expect.assertions(2);
|
|
103
101
|
|