passbolt-browser-extension 5.2.0 → 5.3.2
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 +79 -1
- package/Gruntfile.js +1 -1
- package/RELEASE_NOTES.md +27 -71
- package/doc/browser-extension-class-diagram.md +9 -0
- package/package.json +5 -5
- package/src/all/_locales/sl/messages.json +2 -2
- package/src/all/background_page/controller/clipboard/cancelClipboardContentFlushController.js +51 -0
- package/src/all/background_page/controller/clipboard/cancelClipboardContentFlushController.test.js +46 -0
- package/src/all/background_page/controller/clipboard/copyTemporarilyToClipboardController.js +53 -0
- package/src/all/background_page/controller/clipboard/copyTemporarilyToClipboardController.test.js +47 -0
- package/src/all/background_page/controller/clipboard/{clipboardController.js → copyToClipboardController.js} +8 -8
- package/src/all/background_page/controller/clipboard/copyToClipboardController.test.js +47 -0
- package/src/all/background_page/controller/extension/getExtensionVersionController.test.js +1 -1
- package/src/all/background_page/controller/metadata/getOrFindMetadataKeysSettingsController.js +53 -0
- package/src/all/background_page/controller/metadata/getOrFindMetadataKeysSettingsController.test.js +106 -0
- package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.js +70 -0
- package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.test.js +78 -0
- package/src/all/background_page/controller/share/shareOneFolderController.test.js +2 -1
- package/src/all/background_page/controller/share/shareResourcesController.test.js +1 -1
- package/src/all/background_page/controller/user/deleteDryRunUserController.js +73 -0
- package/src/all/background_page/controller/user/deleteDryRunUserController.test.js +129 -0
- package/src/all/background_page/controller/user/deleteUserController.js +76 -0
- package/src/all/background_page/controller/user/deleteUserController.test.js +141 -0
- package/src/all/background_page/event/actionLogEvents.js +5 -12
- package/src/all/background_page/event/appEvents.js +33 -0
- package/src/all/background_page/event/findAllForActionLogController.js +58 -0
- package/src/all/background_page/event/findAllForActionLogController.test.js +43 -0
- package/src/all/background_page/event/quickAccessEvents.js +32 -0
- package/src/all/background_page/event/resourceEvents.js +11 -0
- package/src/all/background_page/event/userEvents.js +7 -20
- package/src/all/background_page/event/webIntegrationEvents.js +11 -0
- package/src/all/background_page/model/actionLog/{actionLogModel.js → findActionLogService.js} +25 -5
- package/src/all/background_page/model/actionLog/findActionLogService.test.js +61 -0
- package/src/all/background_page/model/comment/commentModel.js +5 -5
- package/src/all/background_page/model/entity/actionLog/actionLogsCollection.test.data.js +18 -0
- package/src/all/background_page/model/entity/actionLog/defaultActionLogEntity.test.data.js +34 -0
- package/src/all/background_page/model/entity/resource/resourcesCollection.js +25 -0
- package/src/all/background_page/model/entity/resource/resourcesCollection.test.js +34 -0
- package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.test.js +0 -1
- package/src/all/background_page/model/user/userModel.js +0 -60
- package/src/all/background_page/pagemod/appPagemod.js +0 -2
- package/src/all/background_page/pagemod/appPagemod.test.js +2 -6
- package/src/all/background_page/service/alarm/globalAlarmService.js +2 -0
- package/src/all/background_page/service/api/actionLog/{actionLogService.js → actionLogApiService.js} +5 -4
- package/src/all/background_page/service/api/actionLog/actionLogApiService.test.js +55 -0
- package/src/all/background_page/service/api/comment/{commentService.js → commentApiService.js} +6 -7
- package/src/all/background_page/service/api/comment/commentApiService.test.js +122 -0
- package/src/all/background_page/service/api/resource/resourceService.js +1 -0
- package/src/all/background_page/service/auth/postLogoutService.js +2 -0
- package/src/all/background_page/service/auth/postLogoutService.test.js +4 -1
- package/src/all/background_page/service/browser/browserService.js +22 -0
- package/src/all/background_page/service/clipboard/clipboardProviderService.js +40 -0
- package/src/all/background_page/service/clipboard/clipboardProviderService.test.js +61 -0
- package/src/all/background_page/service/clipboard/copyToClipboardService.js +123 -0
- package/src/all/background_page/service/clipboard/copyToClipboardService.test.js +174 -0
- package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.js +52 -1
- package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.test.js +100 -0
- package/src/all/background_page/service/resource/findResourcesService.js +53 -19
- package/src/all/background_page/service/resource/findResourcesService.test.js +191 -0
- package/src/all/background_page/service/resourceType/updateResourceTypesService.test.js +1 -1
- package/src/all/background_page/service/share/shareResourceService.test.js +1 -1
- package/src/all/background_page/service/user/deleteUserService.js +97 -0
- package/src/all/background_page/service/user/deleteUserService.test.js +178 -0
- package/src/all/locales/de-DE/common.json +2 -2
- package/src/all/locales/es-ES/common.json +2 -2
- package/src/all/locales/fr-FR/common.json +5 -5
- package/src/all/locales/it-IT/common.json +2 -2
- package/src/all/locales/ja-JP/common.json +2 -2
- package/src/all/locales/ko-KR/common.json +2 -2
- package/src/all/locales/lt-LT/common.json +2 -2
- package/src/all/locales/nl-NL/common.json +2 -2
- package/src/all/locales/pl-PL/common.json +5 -5
- package/src/all/locales/pt-BR/common.json +2 -2
- package/src/all/locales/ro-RO/common.json +2 -2
- package/src/all/locales/ru-RU/common.json +2 -2
- package/src/all/locales/sl-SI/common.json +33 -33
- package/src/all/locales/sv-SE/common.json +2 -2
- package/src/all/locales/uk-UA/common.json +3 -3
- package/src/chrome/manifest.json +1 -1
- package/src/chrome/polyfill/clipboard/edgeBackgroundPageClipboardService.js +31 -0
- package/src/chrome/polyfill/clipboard/edgeBackgroundPageClipboardService.test.js +51 -0
- package/src/chrome-mv3/index.js +3 -3
- package/src/chrome-mv3/manifest.json +1 -1
- package/src/chrome-mv3/offscreens/{fetch.html → offscreen.html} +1 -1
- package/src/chrome-mv3/offscreens/{fetch.js → offscreen.js} +2 -2
- package/src/chrome-mv3/offscreens/service/clipboard/writeClipobardOffscreenService.js +54 -0
- package/src/chrome-mv3/offscreens/service/clipboard/writeClipobardOffscreenService.test.js +56 -0
- package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.js +36 -44
- package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.test.data.js +0 -1
- package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.test.js +90 -120
- package/src/chrome-mv3/offscreens/service/offscreen/handleOffscreenRequestService.js +85 -0
- package/src/chrome-mv3/offscreens/service/offscreen/handleOffscreenRequestService.test.js +99 -0
- package/src/chrome-mv3/polyfill/clipboardOffscreenPolyfill.js +19 -0
- package/src/chrome-mv3/serviceWorker/service/clipboard/requestClipboardOffscreenService.js +51 -0
- package/src/chrome-mv3/serviceWorker/service/clipboard/requestClipboardOffscreenService.test.js +70 -0
- package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.js +25 -0
- package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.test.data.js +21 -0
- package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.test.js +33 -0
- package/src/chrome-mv3/serviceWorker/service/network/requestFetchOffscreenService.js +25 -50
- package/src/chrome-mv3/serviceWorker/service/network/requestFetchOffscreenService.test.js +16 -39
- package/src/chrome-mv3/serviceWorker/service/network/responseFetchOffscreenService.js +14 -45
- package/src/chrome-mv3/serviceWorker/service/network/responseFetchOffscreenService.test.js +5 -37
- package/src/chrome-mv3/serviceWorker/service/offscreen/createOffscreenDocumentService.js +43 -0
- package/src/chrome-mv3/serviceWorker/service/offscreen/createOffscreenDocumentService.test.js +48 -0
- package/src/chrome-mv3/serviceWorker/service/offscreen/handleOffscreenResponseService.js +119 -0
- package/src/chrome-mv3/serviceWorker/service/offscreen/handleOffscreenResponseService.test.js +159 -0
- package/src/firefox/manifest.json +1 -1
- package/src/safari/manifest.json +1 -1
- package/test/jest.setup.js +4 -0
- package/test/mocks/mockNavigatorClipboard.js +40 -0
- package/test/mocks/mockWebExtensionPolyfill.js +2 -1
- package/{webpack-offscreens.fetch.config.js → webpack-offscreens.config.js} +1 -1
- package/webpack.service-worker.config.js +1 -0
- package/src/all/background_page/controller/clipboard/clipboardController.test.js +0 -68
- package/src/all/background_page/event/clipboardEvents.js +0 -28
|
@@ -0,0 +1,34 @@
|
|
|
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 {v4 as uuidv4} from "uuid";
|
|
15
|
+
|
|
16
|
+
export const defaultData = {
|
|
17
|
+
"id": uuidv4(),
|
|
18
|
+
"action_log_id": uuidv4(),
|
|
19
|
+
"type": "Resources.created",
|
|
20
|
+
"creator": {
|
|
21
|
+
"id": uuidv4(),
|
|
22
|
+
"username": "ada@passbolt.com",
|
|
23
|
+
"profile": {
|
|
24
|
+
"first_name": "Ada",
|
|
25
|
+
"last_name": "Lovelace",
|
|
26
|
+
"avatar": {
|
|
27
|
+
"url": {
|
|
28
|
+
"medium": "img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.a99472d5.png",
|
|
29
|
+
"small": "img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.65a0ba70.png"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -336,6 +336,31 @@ class ResourcesCollection extends EntityV2Collection {
|
|
|
336
336
|
return result;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Update the current resource collection with the given collection.
|
|
341
|
+
* If an element already exists, it is replaced, otherwise, it's added.
|
|
342
|
+
* Note: mutation of the original collection does not trigger collection validation (schema or build rules).
|
|
343
|
+
* @param {ResourcesCollection} resourcesCollection
|
|
344
|
+
*/
|
|
345
|
+
updateWithCollection(resourcesCollection) {
|
|
346
|
+
assertType(resourcesCollection, ResourcesCollection);
|
|
347
|
+
|
|
348
|
+
const resourceMapByIdWithIndex = this.items.reduce((result, resource, currentIndex) => {
|
|
349
|
+
result[resource.id] = currentIndex;
|
|
350
|
+
return result;
|
|
351
|
+
}, {});
|
|
352
|
+
|
|
353
|
+
for (let i = 0; i < resourcesCollection.length; i++) {
|
|
354
|
+
const resource = resourcesCollection.items[i];
|
|
355
|
+
const mappedResourceIndex = resourceMapByIdWithIndex[resource.id];
|
|
356
|
+
if (typeof mappedResourceIndex === "undefined") {
|
|
357
|
+
this.push(resource, {validate: false});
|
|
358
|
+
} else {
|
|
359
|
+
this._items[mappedResourceIndex] = resource;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
339
364
|
/*
|
|
340
365
|
* ==================================================
|
|
341
366
|
* Static getters
|
|
@@ -446,4 +446,38 @@ describe("ResourcesCollection", () => {
|
|
|
446
446
|
expect(() => collection.setDecryptedMetadataFromCollection("test")).toThrow('The `resourcesCollection` parameter should be a ResourcesCollection.');
|
|
447
447
|
});
|
|
448
448
|
});
|
|
449
|
+
|
|
450
|
+
describe("::updateWithCollection", () => {
|
|
451
|
+
it("should update the existing resources and add the new ones", () => {
|
|
452
|
+
expect.assertions(5);
|
|
453
|
+
const resource1 = defaultResourceDto();
|
|
454
|
+
const resource2 = defaultResourceDto();
|
|
455
|
+
const collection = new ResourcesCollection([resource1, resource2]);
|
|
456
|
+
|
|
457
|
+
const updatedResource2 = {
|
|
458
|
+
...resource2,
|
|
459
|
+
metadata: defaultResourceMetadataDto({
|
|
460
|
+
name: "UPDATE - RESOURCE",
|
|
461
|
+
}),
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
const resource3 = defaultResourceDto();
|
|
465
|
+
const collectionForUpdate = new ResourcesCollection([resource3, updatedResource2]);
|
|
466
|
+
|
|
467
|
+
collection.updateWithCollection(collectionForUpdate);
|
|
468
|
+
|
|
469
|
+
expect(collection).toHaveLength(3);
|
|
470
|
+
expect(collection.items[0].id).toStrictEqual(resource1.id);
|
|
471
|
+
expect(collection.items[1].id).toStrictEqual(resource2.id);
|
|
472
|
+
expect(collection.items[1].metadata.name).toStrictEqual(updatedResource2.metadata.name);
|
|
473
|
+
expect(collection.items[2].id).toStrictEqual(resource3.id);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it("should assert its parameters", () => {
|
|
477
|
+
expect.assertions(1);
|
|
478
|
+
const collection = new ResourcesCollection([]);
|
|
479
|
+
|
|
480
|
+
expect(() => collection.updateWithCollection("test")).toThrow();
|
|
481
|
+
});
|
|
482
|
+
});
|
|
449
483
|
});
|
|
@@ -371,7 +371,6 @@ describe("ResourcesKdbxImportParser", () => {
|
|
|
371
371
|
const importEntity = new ImportResourcesFileEntity(importDto);
|
|
372
372
|
const parser = new ResourcesKdbxImportParser(importEntity, resourceTypesCollection, metadataTypesSettings);
|
|
373
373
|
await parser.parseImport();
|
|
374
|
-
console.log(importEntity);
|
|
375
374
|
|
|
376
375
|
// Assert resources
|
|
377
376
|
expect(importEntity.importResources.items).toHaveLength(2);
|
|
@@ -12,12 +12,9 @@
|
|
|
12
12
|
* @since 3.0.0
|
|
13
13
|
*/
|
|
14
14
|
import UserLocalStorage from "../../service/local_storage/userLocalStorage";
|
|
15
|
-
import DeleteDryRunError from "../../error/deleteDryRunError";
|
|
16
15
|
import UserService from "../../service/api/user/userService";
|
|
17
|
-
import UserDeleteTransferEntity from "../entity/user/transfer/userDeleteTransferEntity";
|
|
18
16
|
import UserEntity from "../entity/user/userEntity";
|
|
19
17
|
import UsersCollection from "../entity/user/usersCollection";
|
|
20
|
-
import PassboltApiFetchError from "passbolt-styleguide/src/shared/lib/Error/PassboltApiFetchError";
|
|
21
18
|
import Validator from "validator";
|
|
22
19
|
import RoleEntity from "passbolt-styleguide/src/shared/models/entity/role/roleEntity";
|
|
23
20
|
import UserMeSessionStorageService from "../../service/sessionStorage/userMeSessionStorageService";
|
|
@@ -208,63 +205,6 @@ class UserModel {
|
|
|
208
205
|
return new UserEntity(userDto, {ignoreInvalidEntity});
|
|
209
206
|
}
|
|
210
207
|
|
|
211
|
-
/**
|
|
212
|
-
* Check if a user can be deleted
|
|
213
|
-
*
|
|
214
|
-
* A user can not be deleted if:
|
|
215
|
-
* - they are the only owner of a shared resource
|
|
216
|
-
* - they are the only group manager of a group that owns a shared resource
|
|
217
|
-
* In such case ownership transfer is required.
|
|
218
|
-
*
|
|
219
|
-
* @param {string} userId The user id
|
|
220
|
-
* @param {UserDeleteTransferEntity} [transfer] optional ownership transfer information if needed
|
|
221
|
-
* @returns {Promise<void>}
|
|
222
|
-
* @throws {DeleteDryRunError} if some permissions must be transferred
|
|
223
|
-
* @public
|
|
224
|
-
*/
|
|
225
|
-
async deleteDryRun(userId, transfer) {
|
|
226
|
-
try {
|
|
227
|
-
const deleteData = (transfer && transfer instanceof UserDeleteTransferEntity) ? transfer.toDto() : {};
|
|
228
|
-
await this.userService.delete(userId, deleteData, true);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
if (error instanceof PassboltApiFetchError && error.data.code === 400 && error.data.body.errors) {
|
|
231
|
-
/*
|
|
232
|
-
* recast generic 400 error into a delete dry run error
|
|
233
|
-
* allowing validation of the returned entities and reuse down the line to transfer permissions
|
|
234
|
-
*/
|
|
235
|
-
throw new DeleteDryRunError(error.message, error.data.body.errors);
|
|
236
|
-
}
|
|
237
|
-
throw error;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Delete a user and transfer ownership if needed
|
|
243
|
-
*
|
|
244
|
-
* @param {string} userId The user id
|
|
245
|
-
* @param {UserDeleteTransferEntity} [transfer] optional ownership transfer information if needed
|
|
246
|
-
* @returns {Promise<void>}
|
|
247
|
-
* @public
|
|
248
|
-
*/
|
|
249
|
-
async delete(userId, transfer) {
|
|
250
|
-
try {
|
|
251
|
-
const deleteData = (transfer && transfer instanceof UserDeleteTransferEntity) ? transfer.toDto() : {};
|
|
252
|
-
await this.userService.delete(userId, deleteData);
|
|
253
|
-
} catch (error) {
|
|
254
|
-
if (error instanceof PassboltApiFetchError && error.data.code === 400 && error.data.body.errors) {
|
|
255
|
-
/*
|
|
256
|
-
* recast generic 400 error into a delete dry run error
|
|
257
|
-
* allowing validation of the returned entities and reuse down the line to transfer permissions
|
|
258
|
-
*/
|
|
259
|
-
throw new DeleteDryRunError(error.message, error.data.body.errors);
|
|
260
|
-
}
|
|
261
|
-
throw error;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Update local storage
|
|
265
|
-
await UserLocalStorage.delete(userId);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
208
|
/**
|
|
269
209
|
* Request help when a user lost its credentials.
|
|
270
210
|
* @param {AbstractAccountEntity} account The account the credentials have been lost for.
|
|
@@ -39,7 +39,6 @@ import {LocaleEvents} from "../event/localeEvents";
|
|
|
39
39
|
import {MobileEvents} from "../event/mobileEvents";
|
|
40
40
|
import {PownedPasswordEvents} from '../event/pownedPasswordEvents';
|
|
41
41
|
import {MfaEvents} from "../event/mfaEvents";
|
|
42
|
-
import {ClipboardEvents} from "../event/clipboardEvents";
|
|
43
42
|
import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService";
|
|
44
43
|
import {RememberMeEvents} from "../event/rememberMeEvents";
|
|
45
44
|
import CheckAuthStatusService from "../service/auth/checkAuthStatusService";
|
|
@@ -87,7 +86,6 @@ class App extends Pagemod {
|
|
|
87
86
|
MobileEvents,
|
|
88
87
|
PownedPasswordEvents,
|
|
89
88
|
MfaEvents,
|
|
90
|
-
ClipboardEvents,
|
|
91
89
|
RememberMeEvents,
|
|
92
90
|
PermissionEvents,
|
|
93
91
|
AccountEvents
|
|
@@ -38,7 +38,6 @@ import {ThemeEvents} from "../event/themeEvents";
|
|
|
38
38
|
import {MobileEvents} from "../event/mobileEvents";
|
|
39
39
|
import {PownedPasswordEvents} from '../event/pownedPasswordEvents';
|
|
40
40
|
import {MfaEvents} from "../event/mfaEvents";
|
|
41
|
-
import {ClipboardEvents} from "../event/clipboardEvents";
|
|
42
41
|
import {v4 as uuid} from "uuid";
|
|
43
42
|
import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService";
|
|
44
43
|
import {enableFetchMocks} from "jest-fetch-mock";
|
|
@@ -75,13 +74,12 @@ jest.spyOn(LocaleEvents, "listen").mockImplementation(jest.fn());
|
|
|
75
74
|
jest.spyOn(MobileEvents, "listen").mockImplementation(jest.fn());
|
|
76
75
|
jest.spyOn(PownedPasswordEvents, "listen").mockImplementation(jest.fn());
|
|
77
76
|
jest.spyOn(MfaEvents, "listen").mockImplementation(jest.fn());
|
|
78
|
-
jest.spyOn(ClipboardEvents, "listen").mockImplementation(jest.fn());
|
|
79
77
|
jest.spyOn(RememberMeEvents, "listen").mockImplementation(jest.fn());
|
|
80
78
|
jest.spyOn(PermissionEvents, "listen").mockImplementation(jest.fn());
|
|
81
79
|
jest.spyOn(AccountEvents, "listen").mockImplementation(jest.fn());
|
|
82
80
|
|
|
83
81
|
describe("App", () => {
|
|
84
|
-
beforeEach(
|
|
82
|
+
beforeEach(() => {
|
|
85
83
|
jest.resetModules();
|
|
86
84
|
jest.clearAllMocks();
|
|
87
85
|
enableFetchMocks();
|
|
@@ -89,7 +87,7 @@ describe("App", () => {
|
|
|
89
87
|
|
|
90
88
|
describe("App::attachEvents", () => {
|
|
91
89
|
it("Should attach events", async() => {
|
|
92
|
-
expect.assertions(
|
|
90
|
+
expect.assertions(33);
|
|
93
91
|
// data mocked
|
|
94
92
|
const port = {
|
|
95
93
|
_port: {
|
|
@@ -137,7 +135,6 @@ describe("App", () => {
|
|
|
137
135
|
expect(MobileEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
138
136
|
expect(PownedPasswordEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
139
137
|
expect(MfaEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
140
|
-
expect(ClipboardEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
141
138
|
expect(RememberMeEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
142
139
|
expect(PermissionEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
143
140
|
expect(AccountEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount);
|
|
@@ -168,7 +165,6 @@ describe("App", () => {
|
|
|
168
165
|
MobileEvents,
|
|
169
166
|
PownedPasswordEvents,
|
|
170
167
|
MfaEvents,
|
|
171
|
-
ClipboardEvents,
|
|
172
168
|
RememberMeEvents,
|
|
173
169
|
PermissionEvents,
|
|
174
170
|
AccountEvents
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import StartLoopAuthSessionCheckService from "../auth/startLoopAuthSessionCheckService";
|
|
16
|
+
import CopyToClipboardService from "../clipboard/copyToClipboardService";
|
|
16
17
|
import KeepSessionAliveService from "../session_storage/keepSessionAliveService";
|
|
17
18
|
import PassphraseStorageService from "../session_storage/passphraseStorageService";
|
|
18
19
|
|
|
@@ -20,6 +21,7 @@ const topLevelAlarmMapping = {
|
|
|
20
21
|
[StartLoopAuthSessionCheckService.ALARM_NAME]: StartLoopAuthSessionCheckService.handleAuthStatusCheckAlarm,
|
|
21
22
|
[PassphraseStorageService.ALARM_NAME]: PassphraseStorageService.handleFlushEvent,
|
|
22
23
|
[KeepSessionAliveService.ALARM_NAME]: KeepSessionAliveService.handleKeepSessionAlive,
|
|
24
|
+
[CopyToClipboardService.ALARM_NAME]: CopyToClipboardService.handleClipboardTemporaryContentFlushEvent,
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
/**
|
package/src/all/background_page/service/api/actionLog/{actionLogService.js → actionLogApiService.js}
RENAMED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @link https://www.passbolt.com Passbolt(tm)
|
|
12
12
|
*/
|
|
13
13
|
import AbstractActionLogEntity from "../../../model/entity/actionLog/abstractActionLogEntity";
|
|
14
|
+
import {assertUuid, assertNonEmptyString, assertNumber} from "../../../utils/assertions";
|
|
14
15
|
import AbstractService from "../abstract/abstractService";
|
|
15
16
|
|
|
16
17
|
const RESOURCE_SERVICE_RESOURCE_NAME = 'actionlog';
|
|
@@ -76,7 +77,9 @@ class ActionLogService extends AbstractService {
|
|
|
76
77
|
*/
|
|
77
78
|
async findAllFor(foreignModel, foreignId, page, limit) {
|
|
78
79
|
this.assertValidForeignModel(foreignModel);
|
|
79
|
-
|
|
80
|
+
assertNumber(page);
|
|
81
|
+
assertNumber(limit);
|
|
82
|
+
assertUuid(foreignId);
|
|
80
83
|
if (!page || typeof page !== 'number') {
|
|
81
84
|
throw new TypeError(`ActionLog page should be a valid integer.`);
|
|
82
85
|
}
|
|
@@ -102,9 +105,7 @@ class ActionLogService extends AbstractService {
|
|
|
102
105
|
* @public
|
|
103
106
|
*/
|
|
104
107
|
assertValidForeignModel(foreignModel) {
|
|
105
|
-
|
|
106
|
-
throw new TypeError(`ActionLog foreign model should be a valid string.`);
|
|
107
|
-
}
|
|
108
|
+
assertNonEmptyString(foreignModel, 'ActionLog foreign model should be a valid string.');
|
|
108
109
|
if (!AbstractActionLogEntity.ALLOWED_FOREIGN_MODELS.includes(foreignModel)) {
|
|
109
110
|
throw new TypeError(`ActionLog foreign model ${foreignModel} in not in the list of supported models.`);
|
|
110
111
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
|
|
15
|
+
import {enableFetchMocks} from "jest-fetch-mock";
|
|
16
|
+
import {v4 as uuidv4} from "uuid";
|
|
17
|
+
import {mockApiResponse} from '../../../../../../test/mocks/mockApiResponse';
|
|
18
|
+
import ActionLogApiService from "./actionLogApiService";
|
|
19
|
+
import AccountEntity from "../../../model/entity/account/accountEntity";
|
|
20
|
+
import {defaultAccountDto} from "../../../model/entity/account/accountEntity.test.data";
|
|
21
|
+
import BuildApiClientOptionsService from "../../account/buildApiClientOptionsService";
|
|
22
|
+
import {defaultActionLogsCollection} from "../../../model/entity/actionLog/actionLogsCollection.test.data";
|
|
23
|
+
|
|
24
|
+
describe("ActionLogService", () => {
|
|
25
|
+
let apiClientOptions, account;
|
|
26
|
+
beforeEach(async() => {
|
|
27
|
+
enableFetchMocks();
|
|
28
|
+
fetch.resetMocks();
|
|
29
|
+
account = new AccountEntity(defaultAccountDto());
|
|
30
|
+
apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('::findAllFor', () => {
|
|
34
|
+
it("Retrieves all action logs for a foreign model", async() => {
|
|
35
|
+
expect.assertions(2);
|
|
36
|
+
|
|
37
|
+
const apiResponse = [defaultActionLogsCollection];
|
|
38
|
+
fetch.doMockOnceIf(/actionlog\/resource/, () => mockApiResponse(apiResponse));
|
|
39
|
+
|
|
40
|
+
const service = new ActionLogApiService(apiClientOptions, account);
|
|
41
|
+
const result = await service.findAllFor("Resource", uuidv4(), 1, 5);
|
|
42
|
+
|
|
43
|
+
expect(result).toBeInstanceOf(Array);
|
|
44
|
+
expect(result).toHaveLength(apiResponse.length);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("throws API error if the API encountered an issue", async() => {
|
|
48
|
+
expect.assertions(1);
|
|
49
|
+
|
|
50
|
+
const service = new ActionLogApiService(apiClientOptions, account);
|
|
51
|
+
|
|
52
|
+
await expect(() => service.findAllFor("Resource", uuidv4())).rejects.toThrow(TypeError);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
package/src/all/background_page/service/api/comment/{commentService.js → commentApiService.js}
RENAMED
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
* @since 3.0.0
|
|
13
13
|
*/
|
|
14
14
|
import CommentEntity from "../../../model/entity/comment/commentEntity";
|
|
15
|
+
import {assertNonEmptyString} from "../../../utils/assertions";
|
|
15
16
|
import AbstractService from "../abstract/abstractService";
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
const COMMENT_SERVICE_RESOURCE_NAME = 'comments';
|
|
19
20
|
|
|
20
|
-
class
|
|
21
|
+
class CommentApiService extends AbstractService {
|
|
21
22
|
/**
|
|
22
23
|
* Constructor
|
|
23
24
|
*
|
|
@@ -25,7 +26,7 @@ class CommentService extends AbstractService {
|
|
|
25
26
|
* @public
|
|
26
27
|
*/
|
|
27
28
|
constructor(apiClientOptions) {
|
|
28
|
-
super(apiClientOptions,
|
|
29
|
+
super(apiClientOptions, CommentApiService.RESOURCE_NAME);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -61,7 +62,7 @@ class CommentService extends AbstractService {
|
|
|
61
62
|
this.assertValidId(foreignId);
|
|
62
63
|
this.assertValidForeignModel(foreignModel);
|
|
63
64
|
|
|
64
|
-
contains = contains ? this.formatContainOptions(contains,
|
|
65
|
+
contains = contains ? this.formatContainOptions(contains, CommentApiService.getSupportedContainOptions()) : null;
|
|
65
66
|
const urlOptions = {...contains};
|
|
66
67
|
|
|
67
68
|
const url = this.apiClient.buildUrl(`${this.apiClient.baseUrl}/${foreignModel.toLowerCase()}/${foreignId}`, urlOptions || {});
|
|
@@ -122,13 +123,11 @@ class CommentService extends AbstractService {
|
|
|
122
123
|
* @public
|
|
123
124
|
*/
|
|
124
125
|
assertValidForeignModel(foreignModel) {
|
|
125
|
-
|
|
126
|
-
throw new TypeError(`Comment foreign model should be a valid string.`);
|
|
127
|
-
}
|
|
126
|
+
assertNonEmptyString(foreignModel, `Comment foreign model should be a valid string.`);
|
|
128
127
|
if (!CommentEntity.ALLOWED_FOREIGN_MODELS.includes(foreignModel)) {
|
|
129
128
|
throw new TypeError(`Comment foreign model ${foreignModel} in not in the list of supported models.`);
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
export default
|
|
133
|
+
export default CommentApiService;
|
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
|
|
15
|
+
import {enableFetchMocks} from "jest-fetch-mock";
|
|
16
|
+
import {v4 as uuidv4} from "uuid";
|
|
17
|
+
import {mockApiResponse} from '../../../../../../test/mocks/mockApiResponse';
|
|
18
|
+
import CommentApiService from "./commentApiService";
|
|
19
|
+
import AccountEntity from "../../../model/entity/account/accountEntity";
|
|
20
|
+
import {defaultAccountDto} from "../../../model/entity/account/accountEntity.test.data";
|
|
21
|
+
import BuildApiClientOptionsService from "../../account/buildApiClientOptionsService";
|
|
22
|
+
import {defaultCommentCollectionDto} from "passbolt-styleguide/src/shared/models/entity/comment/commentEntityCollection.test.data";
|
|
23
|
+
import {defaultCommentDto} from "passbolt-styleguide/src/shared/models/entity/comment/commentEntity.test.data";
|
|
24
|
+
import PassboltServiceUnavailableError from "passbolt-styleguide/src/shared/lib/Error/PassboltServiceUnavailableError";
|
|
25
|
+
import CommentEntity from "../../../model/entity/comment/commentEntity";
|
|
26
|
+
import {mockApiResponseError} from "../../../../../../test/mocks/mockApiResponse";
|
|
27
|
+
|
|
28
|
+
describe.only("ActionLogService", () => {
|
|
29
|
+
let apiClientOptions, account;
|
|
30
|
+
beforeEach(async() => {
|
|
31
|
+
enableFetchMocks();
|
|
32
|
+
fetch.resetMocks();
|
|
33
|
+
account = new AccountEntity(defaultAccountDto());
|
|
34
|
+
apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('::findAll', () => {
|
|
38
|
+
it("retrieves the comments from API", async() => {
|
|
39
|
+
expect.assertions(2);
|
|
40
|
+
|
|
41
|
+
const commentsCollection = [defaultCommentCollectionDto()];
|
|
42
|
+
fetch.doMockOnceIf(/comments\/resource/, () => mockApiResponse(commentsCollection));
|
|
43
|
+
|
|
44
|
+
const service = new CommentApiService(apiClientOptions, account);
|
|
45
|
+
const resultDto = await service.findAll('Resource', uuidv4(), {creator: true});
|
|
46
|
+
|
|
47
|
+
expect(resultDto).toBeInstanceOf(Array);
|
|
48
|
+
expect(resultDto).toHaveLength(commentsCollection.length);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("throws API error if the API encountered an issue", async() => {
|
|
52
|
+
expect.assertions(1);
|
|
53
|
+
fetch.doMockOnceIf(/comments\/resource/, () => mockApiResponseError(500, "Something wrong happened!"));
|
|
54
|
+
|
|
55
|
+
const service = new CommentApiService(apiClientOptions);
|
|
56
|
+
|
|
57
|
+
await expect(() => service.findAll('Resource')).rejects.toThrow(TypeError);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("throws service unavailable error if an error occurred but not from the API (by instance cloudflare)", async() => {
|
|
61
|
+
expect.assertions(1);
|
|
62
|
+
fetch.doMockOnceIf(/comments\/resource/, () => { throw new Error("Service unavailable"); });
|
|
63
|
+
|
|
64
|
+
const service = new CommentApiService(apiClientOptions);
|
|
65
|
+
|
|
66
|
+
await expect(() => service.findAll('Resource', uuidv4(), {creator: true})).rejects.toThrow(PassboltServiceUnavailableError);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('::create', () => {
|
|
71
|
+
it("Create a comment", async() => {
|
|
72
|
+
expect.assertions(2);
|
|
73
|
+
|
|
74
|
+
const commentDto = defaultCommentDto({}, {withCreator: false, withModifier: false});
|
|
75
|
+
|
|
76
|
+
const payload = new CommentEntity(commentDto);
|
|
77
|
+
let reqPayload;
|
|
78
|
+
fetch.doMockOnceIf(/comments\/resource/, async req => {
|
|
79
|
+
expect(req.method).toEqual("POST");
|
|
80
|
+
reqPayload = await req.json();
|
|
81
|
+
return mockApiResponse(defaultCommentDto({...reqPayload, id: commentDto.id}));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const service = new CommentApiService(apiClientOptions);
|
|
85
|
+
const resultDto = await service.create(payload._props);
|
|
86
|
+
|
|
87
|
+
expect(resultDto).toEqual(expect.objectContaining(commentDto));
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("throws an error if input is invalid ", async() => {
|
|
91
|
+
expect.assertions(1);
|
|
92
|
+
|
|
93
|
+
const service = new CommentApiService(apiClientOptions);
|
|
94
|
+
|
|
95
|
+
await expect(() => service.create(42, {withCreator: false, withModifier: false})).rejects.toThrow(TypeError);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
describe('::delete', () => {
|
|
101
|
+
it("Delete a comment", async() => {
|
|
102
|
+
expect.assertions(1);
|
|
103
|
+
|
|
104
|
+
const deleteCommentId = uuidv4();
|
|
105
|
+
fetch.doMockOnceIf(new RegExp(`/comments\/${deleteCommentId}\.json`), async req => {
|
|
106
|
+
expect(req.method).toEqual("DELETE");
|
|
107
|
+
return mockApiResponse({});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const service = new CommentApiService(apiClientOptions);
|
|
111
|
+
await service.delete(deleteCommentId);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("throws an invalid parameter error if the id parameter is not valid", async() => {
|
|
115
|
+
expect.assertions(1);
|
|
116
|
+
|
|
117
|
+
const service = new CommentApiService(apiClientOptions);
|
|
118
|
+
|
|
119
|
+
await expect(() => service.delete(42)).rejects.toThrow(Error);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -19,6 +19,7 @@ import resourceInProgressCacheService from "../cache/resourceInProgressCache.ser
|
|
|
19
19
|
import OnExtensionUpdateAvailableService from "../extension/onExtensionUpdateAvailableService";
|
|
20
20
|
import InformCallToActionPagemod from "../../pagemod/informCallToActionPagemod";
|
|
21
21
|
import WorkerService from "../worker/workerService";
|
|
22
|
+
import CopyToClipboardService from "../clipboard/copyToClipboardService";
|
|
22
23
|
class PostLogoutService {
|
|
23
24
|
/**
|
|
24
25
|
* Execute all processes after a logout
|
|
@@ -27,6 +28,7 @@ class PostLogoutService {
|
|
|
27
28
|
static async exec() {
|
|
28
29
|
await PostLogoutService.sendLogoutEventForWorkers();
|
|
29
30
|
await LocalStorageService.flush();
|
|
31
|
+
await (new CopyToClipboardService()).flushTemporaryContentIfAny();
|
|
30
32
|
await StartLoopAuthSessionCheckService.clearAlarm();
|
|
31
33
|
toolbarService.handleUserLoggedOut();
|
|
32
34
|
resourceInProgressCacheService.reset();
|
|
@@ -26,6 +26,7 @@ import StartLoopAuthSessionCheckService from "./startLoopAuthSessionCheckService
|
|
|
26
26
|
import resourceInProgressCacheService from "../cache/resourceInProgressCache.service";
|
|
27
27
|
import OnExtensionUpdateAvailableService from "../extension/onExtensionUpdateAvailableService";
|
|
28
28
|
import toolbarService from "../toolbar/toolbarService";
|
|
29
|
+
import CopyToClipboardService from "../clipboard/copyToClipboardService";
|
|
29
30
|
|
|
30
31
|
describe("PostLogoutService", () => {
|
|
31
32
|
beforeEach(() => {
|
|
@@ -84,11 +85,12 @@ describe("PostLogoutService", () => {
|
|
|
84
85
|
});
|
|
85
86
|
|
|
86
87
|
it("Should call all services that needs to run processes on logout", async() => {
|
|
87
|
-
expect.assertions(
|
|
88
|
+
expect.assertions(6);
|
|
88
89
|
jest.spyOn(PortManager, "isPortExist").mockImplementation(() => false);
|
|
89
90
|
jest.spyOn(LocalStorageService, "flush");
|
|
90
91
|
jest.spyOn(toolbarService, "handleUserLoggedOut");
|
|
91
92
|
jest.spyOn(StartLoopAuthSessionCheckService, "clearAlarm");
|
|
93
|
+
jest.spyOn(CopyToClipboardService.prototype, "flushTemporaryContentIfAny");
|
|
92
94
|
jest.spyOn(resourceInProgressCacheService, "reset");
|
|
93
95
|
jest.spyOn(OnExtensionUpdateAvailableService, "handleUserLoggedOut");
|
|
94
96
|
|
|
@@ -99,6 +101,7 @@ describe("PostLogoutService", () => {
|
|
|
99
101
|
expect(StartLoopAuthSessionCheckService.clearAlarm).toHaveBeenCalledTimes(1);
|
|
100
102
|
expect(resourceInProgressCacheService.reset).toHaveBeenCalledTimes(1);
|
|
101
103
|
expect(OnExtensionUpdateAvailableService.handleUserLoggedOut).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect(CopyToClipboardService.prototype.flushTemporaryContentIfAny).toHaveBeenCalledTimes(1);
|
|
102
105
|
});
|
|
103
106
|
});
|
|
104
107
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
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.3.2
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The service aims to help get browser information.
|
|
17
|
+
*/
|
|
18
|
+
export default class BrowserService {
|
|
19
|
+
static isFirefox() {
|
|
20
|
+
return browser.runtime.getURL("/").startsWith("moz-extension://");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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.3.2
|
|
13
|
+
*/
|
|
14
|
+
import EdgeBackgroundPageClipboardService from "../../../../chrome/polyfill/clipboard/edgeBackgroundPageClipboardService";
|
|
15
|
+
import BrowserService from "../browser/browserService";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The service retrieves the appropriate clipboard provider for the current environment: Edge, Chrome, or Firefox.
|
|
19
|
+
*/
|
|
20
|
+
export default class ClipboardProviderService {
|
|
21
|
+
/**
|
|
22
|
+
* Returns a clipboard API that works for the currently used browser.
|
|
23
|
+
* @returns {Clipboard}
|
|
24
|
+
*/
|
|
25
|
+
static getClipboard() {
|
|
26
|
+
//is Chrome with MV3?
|
|
27
|
+
if (typeof customNavigatorClipboard !== "undefined") {
|
|
28
|
+
// eslint-disable-next-line no-undef
|
|
29
|
+
return customNavigatorClipboard;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const isMV2 = chrome.runtime.getManifest().manifest_version === 2;
|
|
33
|
+
if (!BrowserService.isFirefox() && isMV2) {
|
|
34
|
+
//it's not firefox and it's MV2 => it's most probably Edge then
|
|
35
|
+
return EdgeBackgroundPageClipboardService;
|
|
36
|
+
}
|
|
37
|
+
//by default we provide the default clipboard
|
|
38
|
+
return navigator.clipboard;
|
|
39
|
+
}
|
|
40
|
+
}
|