passbolt-browser-extension 4.6.2 → 4.7.0-alpha.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/.gitlab-ci/jobs/build.yml +3 -3
- package/.gitlab-ci/jobs/publish.yml +10 -0
- package/.gitlab-ci/jobs/test.yml +4 -4
- package/.gitlab-ci/scripts/bin/publish_npm.sh +24 -0
- package/.gitlab-ci/scripts/lib/version-check.sh +16 -0
- package/.gitlab-ci.yml +2 -2
- package/doc/worker-port-lfecycle.md +19 -0
- package/package.json +5 -4
- package/src/all/background_page/controller/account/updatePrivateKeyController.js +2 -1
- package/src/all/background_page/controller/accountRecovery/accountRecoveryValidatePublicKeyController.js +3 -2
- package/src/all/background_page/controller/accountRecovery/accountRecoveryValidatePublicKeyController.test.js +1 -1
- package/src/all/background_page/controller/accountRecovery/recoverAccountController.js +2 -0
- package/src/all/background_page/controller/accountRecovery/reviewRequestController.test.js +1 -1
- package/src/all/background_page/controller/auth/authCheckStatus.test.data.js +28 -0
- package/src/all/background_page/controller/auth/authCheckStatusController.js +19 -5
- package/src/all/background_page/controller/auth/authCheckStatusController.test.js +94 -0
- package/src/all/background_page/controller/auth/authIsMfaRequiredController.js +17 -9
- package/src/all/background_page/controller/auth/authIsMfaRequiredController.test.js +54 -0
- package/src/all/background_page/controller/auth/authLoginController.js +20 -8
- package/src/all/background_page/controller/auth/authLoginController.test.js +46 -29
- package/src/all/background_page/controller/auth/authVerifyServerKeyController.js +40 -25
- package/src/all/background_page/controller/auth/authVerifyServerKeyController.test.js +64 -11
- package/src/all/background_page/controller/auth/getServerKeyController.js +54 -0
- package/src/all/background_page/controller/auth/replaceServerKeyController.js +59 -0
- package/src/all/background_page/controller/informCallToActionController/informCallToActionController.js +3 -22
- package/src/all/background_page/controller/recover/importRecoverPrivateKeyController.js +8 -6
- package/src/all/background_page/controller/recover/importRecoverPrivateKeyController.test.js +11 -29
- package/src/all/background_page/controller/recover/startRecoverController.js +3 -3
- package/src/all/background_page/controller/setup/importSetupPrivateKeyController.js +6 -6
- package/src/all/background_page/controller/setup/importSetupPrivateKeyController.test.js +13 -30
- package/src/all/background_page/controller/setup/signInSetupController.js +13 -3
- package/src/all/background_page/controller/setup/signInSetupController.test.js +13 -6
- package/src/all/background_page/controller/setup/startSetupController.js +3 -3
- package/src/all/background_page/controller/sso/ssoAuthenticationController.js +13 -3
- package/src/all/background_page/controller/sso/ssoAuthenticationController.test.js +34 -27
- package/src/all/background_page/controller/{toolbarController.js → toolbarService.js} +8 -58
- package/src/all/background_page/controller/{toolbarController.test.js → toolbarService.test.js} +20 -51
- package/src/all/background_page/controller/userPassphrasePolicies/saveUserPassphrasePoliciesController.test.js +2 -2
- package/src/all/background_page/event/appBootstrapEvents.js +10 -8
- package/src/all/background_page/event/appEvents.js +0 -3
- package/src/all/background_page/event/authEvents.js +10 -45
- package/src/all/background_page/event/informCallToActionEvents.js +4 -8
- package/src/all/background_page/event/recoverEvents.js +1 -1
- package/src/all/background_page/event/secretEvents.js +0 -13
- package/src/all/background_page/event/setupEvents.js +1 -1
- package/src/all/background_page/index.js +29 -26
- package/src/all/background_page/model/auth/authModel.js +5 -98
- package/src/all/background_page/model/auth/authModel.test.js +8 -9
- package/src/all/background_page/model/entity/account/accountEntity.test.data.js +3 -4
- package/src/all/background_page/model/entity/worker/workerEntity.js +20 -3
- package/src/all/background_page/model/gpgAuthHeader.test.data.js +88 -0
- package/src/all/background_page/model/user.js +0 -11
- package/src/all/background_page/pagemod/appBootstrapPagemod.js +5 -6
- package/src/all/background_page/pagemod/appBootstrapPagemod.test.js +4 -3
- package/src/all/background_page/pagemod/appPagemod.js +4 -3
- package/src/all/background_page/pagemod/appPagemod.test.js +3 -3
- package/src/all/background_page/pagemod/pagemodManager.test.js +3 -2
- package/src/all/background_page/sdk/port/portManager.js +1 -1
- package/src/all/background_page/service/accountRecovery/validateOrganizationPublicKeyService.js +97 -0
- package/src/all/background_page/service/{api/accountRecovery/accountRecoveryOrganizationPolicyService.test.data.js → accountRecovery/validateOrganizationPublicKeyService.test.data.js} +1 -1
- package/src/all/background_page/service/accountRecovery/validateOrganizationPublicKeyService.test.js +69 -0
- package/src/all/background_page/service/alarm/globalAlarmService.js +38 -0
- package/src/all/background_page/service/api/accountRecovery/accountRecoveryOrganizationPolicyService.js +0 -75
- package/src/all/background_page/service/api/auth/authLoginService.js +82 -0
- package/src/all/background_page/service/api/auth/authLoginService.test.js +104 -0
- package/src/all/background_page/service/api/auth/authVerifyServerKeyService.js +79 -0
- package/src/all/background_page/service/api/auth/authVerifyServerKeyService.test.js +74 -0
- package/src/all/background_page/service/auth/authVerifyLoginChallengeService.js +49 -0
- package/src/all/background_page/service/auth/authVerifyLoginChallengeService.test.js +59 -0
- package/src/all/background_page/service/auth/authVerifyServerChallengeService.js +53 -0
- package/src/all/background_page/service/auth/authVerifyServerChallengeService.test.js +71 -0
- package/src/all/background_page/service/auth/checkAuthStatusService.js +52 -0
- package/src/all/background_page/service/auth/checkAuthStatusService.test.js +123 -0
- package/src/all/background_page/service/auth/decryptUserAuthTokenService.js +55 -0
- package/src/all/background_page/service/auth/decryptUserAuthTokenService.test.data.js +19 -0
- package/src/all/background_page/service/auth/decryptUserAuthTokenService.test.js +79 -0
- package/src/all/background_page/service/auth/postLoginService.js +40 -0
- package/src/all/background_page/service/auth/postLoginService.test.js +96 -0
- package/src/all/background_page/service/auth/postLogoutService.js +45 -0
- package/src/all/background_page/service/auth/postLogoutService.test.js +104 -0
- package/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js +28 -34
- package/src/all/background_page/service/auth/startLoopAuthSessionCheckService.test.js +28 -39
- package/src/all/background_page/service/authenticationStatusService.js +71 -0
- package/src/all/background_page/service/authenticationStatusService.test.js +58 -0
- package/src/all/background_page/service/cache/resourceInProgressCache.service.js +5 -42
- package/src/all/background_page/service/cache/resourceInProgressCache.service.test.js +8 -8
- package/src/all/background_page/service/extension/onExtensionUpdateAvailableService.js +86 -0
- package/src/all/background_page/service/extension/onExtensionUpdateAvailableService.test.js +171 -0
- package/src/all/background_page/service/localStorage/localStorageService.js +2 -0
- package/src/all/background_page/service/local_storage/AccountLocalStorage.test.js +3 -1
- package/src/all/background_page/service/local_storage/authStatusLocalStorage.js +17 -21
- package/src/all/background_page/service/passphrase/getPassphraseService.js +5 -1
- package/src/all/background_page/service/sessionStorage/userMeSessionStorageService.test.js +10 -3
- package/src/all/background_page/service/sessionStorage/workersSessionStorage.js +11 -0
- package/src/all/background_page/service/sessionStorage/workersSessionStorage.test.js +3 -2
- package/src/all/background_page/service/session_storage/keepSessionAliveService.js +82 -0
- package/src/all/background_page/service/session_storage/keepSessionAliveService.test.js +138 -0
- package/src/all/background_page/service/session_storage/passphraseStorageService.js +27 -106
- package/src/all/background_page/service/session_storage/passphraseStorageService.test.js +24 -64
- package/src/all/background_page/service/systemRequirementService/systemRequirementService.js +4 -3
- package/src/all/background_page/service/tab/tabService.js +59 -16
- package/src/all/background_page/service/tab/tabService.test.js +114 -49
- package/src/all/background_page/service/worker/workerService.js +79 -69
- package/src/all/background_page/service/worker/workerService.test.js +103 -43
- package/src/all/background_page/utils/promise/promiseTimeoutService.js +3 -39
- package/src/all/background_page/utils/promise/promiseTimeoutService.test.js +19 -27
- package/src/all/contentScripts/js/app/BrowserIntegration.js +7 -0
- package/src/all/webAccessibleResources/js/app/App.js +7 -0
- package/src/all/webAccessibleResources/js/lib/port.js +16 -1
- package/src/all/webAccessibleResources/js/lib/port.test.js +20 -0
- package/src/chrome/manifest.json +1 -1
- package/src/chrome-mv3/index.js +14 -8
- package/src/chrome-mv3/manifest.json +1 -1
- package/src/firefox/manifest.json +1 -1
- package/src/safari/manifest.json +1 -1
- package/test/fixtures/pgpKeys/keys.js +5 -0
- package/test/mocks/mockAlarms.js +134 -4
- package/test/mocks/mockApiResponse.js +11 -0
- package/test/mocks/mockExtension.js +4 -1
- package/test/mocks/mockWebExtensionPolyfill.js +1 -0
- package/src/all/background_page/controller/auth/authIsAuthenticatedController.js +0 -44
- package/src/all/background_page/controller/auth/authenticationEventController.js +0 -67
- package/src/all/background_page/controller/extension/onExtensionUpdateAvailableController.js +0 -56
- package/src/all/background_page/controller/extension/onExtensionUpdateAvailableController.test.js +0 -76
- package/src/all/background_page/model/gpgauth.js +0 -347
- package/src/all/background_page/service/api/accountRecovery/accountRecoveryOrganizationPolicyService.test.js +0 -59
- package/src/all/background_page/service/api/auth/authService.js +0 -161
- package/src/all/background_page/service/api/auth/authService.test.js +0 -103
- package/src/all/background_page/service/auth.js +0 -78
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
build:
|
|
2
2
|
stage: build
|
|
3
|
-
image: node:18
|
|
3
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:18
|
|
4
4
|
extends: .rules
|
|
5
5
|
artifacts:
|
|
6
6
|
when: always
|
|
@@ -22,7 +22,7 @@ build:
|
|
|
22
22
|
|
|
23
23
|
build_mv3:
|
|
24
24
|
stage: build
|
|
25
|
-
image: node:18
|
|
25
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:18
|
|
26
26
|
extends: .rules
|
|
27
27
|
artifacts:
|
|
28
28
|
when: always
|
|
@@ -39,4 +39,4 @@ build_mv3:
|
|
|
39
39
|
echo "Sending slack build notification"
|
|
40
40
|
echo "================================"
|
|
41
41
|
bash ./.gitlab-ci/scripts/bin/slack-status-messages.sh ":jigsaw: A new wild MV3 browser extension appeared! $CI_COMMIT_TAG" "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID/artifacts/browse/dist/"
|
|
42
|
-
fi
|
|
42
|
+
fi
|
|
@@ -36,3 +36,13 @@ publish-edge:
|
|
|
36
36
|
echo "Sending slack build notification"
|
|
37
37
|
echo "================================"
|
|
38
38
|
bash ./.gitlab-ci/scripts/bin/slack-status-messages.sh ":rocket: passbolt-edge-extension $CI_COMMIT_TAG has been published!" "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID"
|
|
39
|
+
|
|
40
|
+
publish-to-npmjs:
|
|
41
|
+
stage: publish
|
|
42
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:18
|
|
43
|
+
rules:
|
|
44
|
+
- if: "$CI_COMMIT_TAG"
|
|
45
|
+
script:
|
|
46
|
+
- |
|
|
47
|
+
bash .gitlab-ci/scripts/bin/publish_npm.sh
|
|
48
|
+
bash ./.gitlab-ci/scripts/bin/slack-status-messages.sh ":rocket: passbolt-browser-extension $CI_COMMIT_TAG has been published in https://www.npmjs.com/package/passbolt-browser-extension" "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID"
|
package/.gitlab-ci/jobs/test.yml
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
tester:
|
|
2
2
|
stage: test
|
|
3
|
-
image: node:18
|
|
3
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:18
|
|
4
4
|
coverage: /Lines\s* [:] ([\d\.]+)%/
|
|
5
5
|
extends: .rules
|
|
6
6
|
script:
|
|
7
7
|
- npm ci
|
|
8
|
-
- npm run test:coverage
|
|
8
|
+
- npm run test:ci:coverage
|
|
9
9
|
artifacts:
|
|
10
10
|
when: always
|
|
11
11
|
reports:
|
|
@@ -17,7 +17,7 @@ tester:
|
|
|
17
17
|
|
|
18
18
|
linter:
|
|
19
19
|
stage: test
|
|
20
|
-
image: node:18
|
|
20
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:18
|
|
21
21
|
extends: .rules
|
|
22
22
|
script:
|
|
23
23
|
- npm ci
|
|
@@ -29,4 +29,4 @@ audit:
|
|
|
29
29
|
image: node:18
|
|
30
30
|
extends: .rules
|
|
31
31
|
script:
|
|
32
|
-
- npm audit
|
|
32
|
+
- npm audit
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# shellcheck disable=SC1091
|
|
4
|
+
|
|
5
|
+
set -eu
|
|
6
|
+
|
|
7
|
+
CI_SCRIPTS_DIR=$(dirname "$0")/..
|
|
8
|
+
|
|
9
|
+
# shellcheck source=.gitlab-ci/scripts/lib/version-check.sh
|
|
10
|
+
source "$CI_SCRIPTS_DIR"/lib/version-check.sh
|
|
11
|
+
|
|
12
|
+
echo //registry.npmjs.org/:_authToken="$NPM_PUBLISH_TOKEN" > .npmrc
|
|
13
|
+
echo email="$NPM_PUBLISH_EMAIL" >> .npmrc
|
|
14
|
+
echo always-auth=true >> .npmrc
|
|
15
|
+
|
|
16
|
+
if is_release_candidate "$CI_COMMIT_TAG"; then
|
|
17
|
+
npm publish --tag next
|
|
18
|
+
elif is_release_alpha "$CI_COMMIT_TAG"; then
|
|
19
|
+
npm publish --tag alpha
|
|
20
|
+
elif is_release_beta "$CI_COMMIT_TAG"; then
|
|
21
|
+
npm publish --tag beta
|
|
22
|
+
else
|
|
23
|
+
npm publish
|
|
24
|
+
fi
|
|
@@ -13,6 +13,22 @@ function is_release_candidate () {
|
|
|
13
13
|
return 0
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function is_release_alpha () {
|
|
17
|
+
local version=$1
|
|
18
|
+
if [[ ! $version =~ [0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+ ]];then
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
return 0
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function is_release_beta () {
|
|
25
|
+
local version=$1
|
|
26
|
+
if [[ ! $version =~ [0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+ ]];then
|
|
27
|
+
return 1
|
|
28
|
+
fi
|
|
29
|
+
return 0
|
|
30
|
+
}
|
|
31
|
+
|
|
16
32
|
function validate_config_version_and_api_tag () {
|
|
17
33
|
local version_file="$1"
|
|
18
34
|
local version
|
package/.gitlab-ci.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
image: debian:stable-slim
|
|
1
|
+
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/debian:stable-slim
|
|
2
2
|
|
|
3
3
|
stages:
|
|
4
4
|
- test
|
|
@@ -18,4 +18,4 @@ include:
|
|
|
18
18
|
- local: "/.gitlab-ci/jobs/test.yml"
|
|
19
19
|
- local: "/.gitlab-ci/jobs/review.yml"
|
|
20
20
|
- local: "/.gitlab-ci/jobs/publish.yml"
|
|
21
|
-
- local: ".gitlab-ci/jobs/release.yml"
|
|
21
|
+
- local: ".gitlab-ci/jobs/release.yml"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
```mermaid
|
|
2
|
+
stateDiagram
|
|
3
|
+
classDef badBadEvent fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow
|
|
4
|
+
|
|
5
|
+
[*] --> awaiting_connection: SW navigation url matching
|
|
6
|
+
|
|
7
|
+
awaiting_connection --> connected: CC opening port
|
|
8
|
+
connected --> disconnected: SW stopped
|
|
9
|
+
disconnected --> reconnecting: SW navigation url same origin
|
|
10
|
+
disconnected --> connected: CC reopening port
|
|
11
|
+
reconnecting --> connected: SW requesting CC port opening ||\nCC reopening port (following a user interaction)
|
|
12
|
+
|
|
13
|
+
awaiting_connection --> [*]: SW tab removed || \n SW navigation url diff origin
|
|
14
|
+
connected --> [*]: SW tab removed || \n SW navigation url diff origin
|
|
15
|
+
disconnected --> [*]: SW tab removed || \n SW navigation url diff origin
|
|
16
|
+
reconnecting --> [*]: SW tab removed || \n Cannot reconnect port || \n SW navigation url diff origin
|
|
17
|
+
|
|
18
|
+
class reconnecting badBadEvent
|
|
19
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "passbolt-browser-extension",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0-alpha.1",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"copyright": "Copyright 2022 Passbolt SA",
|
|
6
6
|
"description": "Passbolt web extension for the open source password manager for teams",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"locutus": "~2.0.9",
|
|
22
22
|
"openpgp": "^5.11.1",
|
|
23
23
|
"papaparse": "^5.2.0",
|
|
24
|
-
"passbolt-styleguide": "^4.
|
|
24
|
+
"passbolt-styleguide": "^4.7.0-alpha-4",
|
|
25
25
|
"react": "17.0.2",
|
|
26
26
|
"react-dom": "17.0.2",
|
|
27
27
|
"secrets-passbolt": "github:passbolt/secrets.js#v2.0.1",
|
|
@@ -109,7 +109,8 @@
|
|
|
109
109
|
"lint:eslint-fix": "eslint -c .eslintrc.json --ext js --ext jsx --fix src",
|
|
110
110
|
"i18n:externalize": "i18next -c ./i18next-parser.config.js",
|
|
111
111
|
"test": "npm run test:unit",
|
|
112
|
-
"test:unit": "jest --no-cache ./src/all/ ./src/chrome-mv3/
|
|
113
|
-
"test:coverage": "jest --no-cache ./src/all/ ./src/chrome-mv3/ --
|
|
112
|
+
"test:unit": "jest --no-cache ./src/all/ ./src/chrome-mv3/",
|
|
113
|
+
"test:coverage": "jest --no-cache ./src/all/ ./src/chrome-mv3/ --coverage",
|
|
114
|
+
"test:ci:coverage": "npm run test:coverage -- --runInBand"
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -19,6 +19,7 @@ import SsoDataStorage from "../../service/indexedDB_storage/ssoDataStorage";
|
|
|
19
19
|
import SsoKitServerPartModel from "../../model/sso/ssoKitServerPartModel";
|
|
20
20
|
import PassboltApiFetchError from "passbolt-styleguide/src/shared/lib/Error/PassboltApiFetchError";
|
|
21
21
|
import GenerateSsoKitService from "../../service/sso/generateSsoKitService";
|
|
22
|
+
import KeepSessionAliveService from "../../service/session_storage/keepSessionAliveService";
|
|
22
23
|
|
|
23
24
|
const RECOVERY_KIT_FILENAME = "passbolt-recovery-kit.asc";
|
|
24
25
|
|
|
@@ -72,7 +73,7 @@ class UpdatePrivateKeyController {
|
|
|
72
73
|
}
|
|
73
74
|
await this.accountModel.updatePrivateKey(userPrivateArmoredKey);
|
|
74
75
|
await PassphraseStorageService.flushPassphrase();
|
|
75
|
-
if (
|
|
76
|
+
if (KeepSessionAliveService.isStarted()) {
|
|
76
77
|
await PassphraseStorageService.set(newPassphrase);
|
|
77
78
|
}
|
|
78
79
|
await FileService.saveFile(RECOVERY_KIT_FILENAME, userPrivateArmoredKey, "text/plain", this.worker.tab.id);
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
* @since 3.6.0
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import AccountRecoveryOrganizationPolicyService from "../../service/api/accountRecovery/accountRecoveryOrganizationPolicyService";
|
|
16
15
|
import AccountRecoveryModel from "../../model/accountRecovery/accountRecoveryModel";
|
|
16
|
+
import ValidateOrganizationPublicKeyService from "../../service/accountRecovery/validateOrganizationPublicKeyService";
|
|
17
17
|
|
|
18
18
|
class AccountRecoveryValidatePublicKeyController {
|
|
19
19
|
constructor(worker, requestId, apiClientOptions) {
|
|
20
20
|
this.worker = worker;
|
|
21
21
|
this.requestId = requestId;
|
|
22
22
|
this.accountRecoveryModel = new AccountRecoveryModel(apiClientOptions);
|
|
23
|
+
this.validateOrganizationPublicKeyService = new ValidateOrganizationPublicKeyService(apiClientOptions);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -46,7 +47,7 @@ class AccountRecoveryValidatePublicKeyController {
|
|
|
46
47
|
*/
|
|
47
48
|
async exec(publicKeyToValidate) {
|
|
48
49
|
const organizationPolicy = await this.accountRecoveryModel.findOrganizationPolicy();
|
|
49
|
-
await
|
|
50
|
+
await this.validateOrganizationPublicKeyService.validatePublicKey(publicKeyToValidate, organizationPolicy.armoredKey);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -63,7 +63,7 @@ describe("AccountRecoveryValidatePublicKeyController", () => {
|
|
|
63
63
|
{key: pgpKeys.account_recovery_organization_alternative.public, expectedError: new Error("The key is already being used, the organization recovery key must be a new one.")},
|
|
64
64
|
{key: pgpKeys.betty.public, expectedError: new Error("The key is the current organization recovery key, you must provide a new one.")},
|
|
65
65
|
]).describe("Should throw an error when the key cannot be validated", scenario => {
|
|
66
|
-
it(`Should throw an error
|
|
66
|
+
it(`Should throw an error with the scenario: ${scenario.expectedError.message}`, async() => {
|
|
67
67
|
expect.assertions(1);
|
|
68
68
|
mockFetch();
|
|
69
69
|
|
|
@@ -147,6 +147,7 @@ class RecoverAccountController {
|
|
|
147
147
|
OpenpgpAssertion.assertPrivateKey(recoveredPrivateKey);
|
|
148
148
|
this.account.userPrivateArmoredKey = recoveredPrivateKey.armor();
|
|
149
149
|
this.account.userPublicArmoredKey = recoveredPrivateKey.toPublic().armor();
|
|
150
|
+
this.account.userKeyFingerprint = recoveredPrivateKey.getFingerprint().toUpperCase();
|
|
150
151
|
await this.setupModel.completeRecover(this.account);
|
|
151
152
|
}
|
|
152
153
|
|
|
@@ -178,6 +179,7 @@ class RecoverAccountController {
|
|
|
178
179
|
_updateWorkerAccount(account) {
|
|
179
180
|
this.account.userPublicArmoredKey = account.userPublicArmoredKey;
|
|
180
181
|
this.account.userPrivateArmoredKey = account.userPrivateArmoredKey;
|
|
182
|
+
this.account.userKeyFingerprint = account.userKeyFingerprint;
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
/**
|
|
@@ -243,7 +243,7 @@ describe("ReviewRequestController", () => {
|
|
|
243
243
|
|
|
244
244
|
it("Should assert the public key of the user making the account recovery is found.", async() => {
|
|
245
245
|
expect.assertions(1);
|
|
246
|
-
await MockExtension.withConfiguredAccount();
|
|
246
|
+
await MockExtension.withConfiguredAccount(pgpKeys.betty);
|
|
247
247
|
// Mock API fetch account recovery organization policy response.
|
|
248
248
|
fetch.doMockOnce(() => mockApiResponse(enabledAccountRecoveryOrganizationPolicyDto()));
|
|
249
249
|
// Mock API get account recovery request.
|
|
@@ -0,0 +1,28 @@
|
|
|
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 4.7.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const userLoggedOutAuthStatus = () => ({
|
|
16
|
+
isAuthenticated: false,
|
|
17
|
+
isMfaRequired: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const userLoggedInAuthStatus = () => ({
|
|
21
|
+
isAuthenticated: true,
|
|
22
|
+
isMfaRequired: false,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const userRequireMfaAuthStatus = () => ({
|
|
26
|
+
isAuthenticated: true,
|
|
27
|
+
isMfaRequired: true,
|
|
28
|
+
});
|
|
@@ -11,24 +11,38 @@
|
|
|
11
11
|
* @link https://www.passbolt.com Passbolt(tm)
|
|
12
12
|
* @since 2.11.0
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
14
|
+
import CheckAuthStatusService from "../../service/auth/checkAuthStatusService";
|
|
15
15
|
|
|
16
16
|
class AuthCheckStatusController {
|
|
17
17
|
constructor(worker, requestId) {
|
|
18
18
|
this.worker = worker;
|
|
19
19
|
this.requestId = requestId;
|
|
20
|
-
this.
|
|
20
|
+
this.checkAuthStatusService = new CheckAuthStatusService();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Controller executor.
|
|
25
|
+
* @param {boolean} [flushCache = true] should the cache be flushed before
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
28
|
+
async _exec(flushCache = true) {
|
|
24
29
|
try {
|
|
25
|
-
const
|
|
26
|
-
this.worker.port.emit(this.requestId, 'SUCCESS',
|
|
30
|
+
const authStatus = await this.exec(flushCache);
|
|
31
|
+
this.worker.port.emit(this.requestId, 'SUCCESS', authStatus);
|
|
27
32
|
} catch (error) {
|
|
28
33
|
console.error(error);
|
|
29
34
|
this.worker.port.emit(this.requestId, 'ERROR', error);
|
|
30
35
|
}
|
|
31
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Controller executor.
|
|
40
|
+
* @param {boolean} flushCache should the cache be flushed before
|
|
41
|
+
* @returns {Promise<{isAuthenticated: {bool}, isMfaRequired: {bool}}>}
|
|
42
|
+
*/
|
|
43
|
+
async exec(flushCache) {
|
|
44
|
+
return await this.checkAuthStatusService.checkAuthStatus(flushCache);
|
|
45
|
+
}
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
export default AuthCheckStatusController;
|
|
@@ -0,0 +1,94 @@
|
|
|
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 4.7.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import MfaAuthenticationRequiredError from "../../error/mfaAuthenticationRequiredError";
|
|
16
|
+
import AuthenticationStatusService from "../../service/authenticationStatusService";
|
|
17
|
+
import AuthStatusLocalStorage from "../../service/local_storage/authStatusLocalStorage";
|
|
18
|
+
import AuthCheckStatusController from "./authCheckStatusController";
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("AuthCheckStatusController", () => {
|
|
25
|
+
it("should return the auth status matching the unauthanticated state", async() => {
|
|
26
|
+
expect.assertions(3);
|
|
27
|
+
jest.spyOn(AuthStatusLocalStorage, "get").mockImplementation(() => undefined);
|
|
28
|
+
jest.spyOn(AuthStatusLocalStorage, "flush");
|
|
29
|
+
jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => false);
|
|
30
|
+
|
|
31
|
+
const controller = new AuthCheckStatusController();
|
|
32
|
+
const authStatus = await controller.exec(true);
|
|
33
|
+
|
|
34
|
+
expect(AuthStatusLocalStorage.get).not.toHaveBeenCalled();
|
|
35
|
+
expect(AuthStatusLocalStorage.flush).not.toHaveBeenCalled();
|
|
36
|
+
expect(authStatus).toStrictEqual({
|
|
37
|
+
isAuthenticated: false,
|
|
38
|
+
isMfaRequired: false,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("expects the user to be fully authenticated", async() => {
|
|
43
|
+
expect.assertions(3);
|
|
44
|
+
jest.spyOn(AuthStatusLocalStorage, "get").mockImplementation(() => undefined);
|
|
45
|
+
jest.spyOn(AuthStatusLocalStorage, "flush");
|
|
46
|
+
jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => true);
|
|
47
|
+
|
|
48
|
+
const controller = new AuthCheckStatusController();
|
|
49
|
+
const authStatus = await controller.exec(true);
|
|
50
|
+
|
|
51
|
+
expect(AuthStatusLocalStorage.get).not.toHaveBeenCalled();
|
|
52
|
+
expect(AuthStatusLocalStorage.flush).not.toHaveBeenCalled();
|
|
53
|
+
expect(authStatus).toStrictEqual({
|
|
54
|
+
isAuthenticated: true,
|
|
55
|
+
isMfaRequired: false,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("expects the user to require MFA authentication", async() => {
|
|
60
|
+
expect.assertions(3);
|
|
61
|
+
jest.spyOn(AuthStatusLocalStorage, "get").mockImplementation(() => undefined);
|
|
62
|
+
jest.spyOn(AuthStatusLocalStorage, "flush");
|
|
63
|
+
jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => { throw new MfaAuthenticationRequiredError(); });
|
|
64
|
+
|
|
65
|
+
const controller = new AuthCheckStatusController();
|
|
66
|
+
const authStatus = await controller.exec(true);
|
|
67
|
+
|
|
68
|
+
expect(AuthStatusLocalStorage.get).not.toHaveBeenCalled();
|
|
69
|
+
expect(AuthStatusLocalStorage.flush).not.toHaveBeenCalled();
|
|
70
|
+
expect(authStatus).toStrictEqual({
|
|
71
|
+
isAuthenticated: true,
|
|
72
|
+
isMfaRequired: true,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should return the auth status from the local storage", async() => {
|
|
77
|
+
expect.assertions(4);
|
|
78
|
+
const expectedAuthStatus = {
|
|
79
|
+
isAuthenticated: false,
|
|
80
|
+
isMfaRequired: false,
|
|
81
|
+
};
|
|
82
|
+
jest.spyOn(AuthStatusLocalStorage, "get").mockImplementation(() => expectedAuthStatus);
|
|
83
|
+
jest.spyOn(AuthStatusLocalStorage, "flush");
|
|
84
|
+
jest.spyOn(AuthenticationStatusService, "isAuthenticated");
|
|
85
|
+
|
|
86
|
+
const controller = new AuthCheckStatusController();
|
|
87
|
+
const authStatus = await controller.exec(false);
|
|
88
|
+
|
|
89
|
+
expect(AuthStatusLocalStorage.get).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(AuthStatusLocalStorage.flush).not.toHaveBeenCalled();
|
|
91
|
+
expect(AuthenticationStatusService.isAuthenticated).not.toHaveBeenCalled();
|
|
92
|
+
expect(authStatus).toStrictEqual(expectedAuthStatus);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -11,27 +11,35 @@
|
|
|
11
11
|
* @link https://www.passbolt.com Passbolt(tm)
|
|
12
12
|
* @since 2.11.0
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
14
|
+
import CheckAuthStatusService from "../../service/auth/checkAuthStatusService";
|
|
15
15
|
|
|
16
16
|
class AuthIsMfaRequiredController {
|
|
17
17
|
constructor(worker, requestId) {
|
|
18
18
|
this.worker = worker;
|
|
19
19
|
this.requestId = requestId;
|
|
20
|
-
this.
|
|
20
|
+
this.checkAuthStatusService = new CheckAuthStatusService();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Execute the controller.
|
|
25
|
+
*/
|
|
26
|
+
async _exec() {
|
|
24
27
|
try {
|
|
25
|
-
const isMfaRequired = await this.
|
|
26
|
-
|
|
27
|
-
this.worker.port.emit(this.requestId, 'SUCCESS', true);
|
|
28
|
-
} else {
|
|
29
|
-
this.worker.port.emit(this.requestId, 'SUCCESS', false);
|
|
30
|
-
}
|
|
28
|
+
const isMfaRequired = await this.exec();
|
|
29
|
+
this.worker.port.emit(this.requestId, 'SUCCESS', isMfaRequired);
|
|
31
30
|
} catch (error) {
|
|
32
31
|
this.worker.port.emit(this.requestId, 'ERROR', error);
|
|
33
32
|
}
|
|
34
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if the current user needs to answer the MFA challenge to finish sign in
|
|
37
|
+
* @returns {Promise<boolean>}
|
|
38
|
+
*/
|
|
39
|
+
async exec() {
|
|
40
|
+
const authStatus = await this.checkAuthStatusService.checkAuthStatus(true);
|
|
41
|
+
return authStatus.isMfaRequired;
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
export default AuthIsMfaRequiredController;
|
|
@@ -0,0 +1,54 @@
|
|
|
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 4.7.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {userLoggedInAuthStatus, userLoggedOutAuthStatus, userRequireMfaAuthStatus} from "./authCheckStatus.test.data";
|
|
16
|
+
import AuthIsMfaRequiredController from "./authIsMfaRequiredController";
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("AuthIsMfaRequiredController", () => {
|
|
23
|
+
it("should return true if the user needs to authenticate with MFA", async() => {
|
|
24
|
+
expect.assertions(1);
|
|
25
|
+
|
|
26
|
+
const controller = new AuthIsMfaRequiredController();
|
|
27
|
+
jest.spyOn(controller.checkAuthStatusService, "checkAuthStatus").mockImplementation(async() => userRequireMfaAuthStatus());
|
|
28
|
+
|
|
29
|
+
const isMfaRequired = await controller.exec();
|
|
30
|
+
expect(isMfaRequired).toStrictEqual(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should return false if the user does not need to authenticate with MFA", async() => {
|
|
34
|
+
expect.assertions(1);
|
|
35
|
+
|
|
36
|
+
const controller = new AuthIsMfaRequiredController();
|
|
37
|
+
jest.spyOn(controller.checkAuthStatusService, "checkAuthStatus").mockImplementation(async() => userLoggedInAuthStatus());
|
|
38
|
+
|
|
39
|
+
const isMfaRequired = await controller.exec();
|
|
40
|
+
expect(isMfaRequired).toStrictEqual(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should return the MFA status part of the authentication status", async() => {
|
|
44
|
+
expect.assertions(1);
|
|
45
|
+
|
|
46
|
+
const controller = new AuthIsMfaRequiredController();
|
|
47
|
+
|
|
48
|
+
const authStatus = userLoggedOutAuthStatus();
|
|
49
|
+
jest.spyOn(controller.checkAuthStatusService, "checkAuthStatus").mockImplementation(async() => authStatus);
|
|
50
|
+
|
|
51
|
+
const isMfaRequired = await controller.exec();
|
|
52
|
+
expect(isMfaRequired).toStrictEqual(authStatus.isMfaRequired);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
* @link https://www.passbolt.com Passbolt(tm)
|
|
12
12
|
* @since 3.9.0
|
|
13
13
|
*/
|
|
14
|
-
import AuthModel from "../../model/auth/authModel";
|
|
15
14
|
import UserAlreadyLoggedInError from "../../error/userAlreadyLoggedInError";
|
|
16
15
|
import Keyring from "../../model/keyring";
|
|
17
16
|
import CheckPassphraseService from "../../service/crypto/checkPassphraseService";
|
|
18
17
|
import UpdateSsoCredentialsService from "../../service/account/updateSsoCredentialsService";
|
|
19
18
|
import UserRememberMeLatestChoiceLocalStorage from "../../service/local_storage/userRememberMeLatestChoiceLocalStorage";
|
|
20
19
|
import UserRememberMeLatestChoiceEntity from "../../model/entity/rememberMe/userRememberMeLatestChoiceEntity";
|
|
20
|
+
import PassphraseStorageService from "../../service/session_storage/passphraseStorageService";
|
|
21
|
+
import PostLoginService from "../../service/auth/postLoginService";
|
|
22
|
+
import AuthVerifyLoginChallengeService from "../../service/auth/authVerifyLoginChallengeService";
|
|
23
|
+
import KeepSessionAliveService from "../../service/session_storage/keepSessionAliveService";
|
|
21
24
|
|
|
22
25
|
class AuthLoginController {
|
|
23
26
|
/**
|
|
@@ -31,7 +34,7 @@ class AuthLoginController {
|
|
|
31
34
|
this.worker = worker;
|
|
32
35
|
this.requestId = requestId;
|
|
33
36
|
this.account = account;
|
|
34
|
-
this.
|
|
37
|
+
this.authVerifyLoginChallengeService = new AuthVerifyLoginChallengeService(apiClientOptions);
|
|
35
38
|
this.updateSsoCredentialsService = new UpdateSsoCredentialsService(apiClientOptions);
|
|
36
39
|
this.checkPassphraseService = new CheckPassphraseService(new Keyring());
|
|
37
40
|
this.userRememberMeLatestChoiceLocalStorage = new UserRememberMeLatestChoiceLocalStorage(account);
|
|
@@ -40,9 +43,9 @@ class AuthLoginController {
|
|
|
40
43
|
/**
|
|
41
44
|
* Wrapper of exec function to run it with worker.
|
|
42
45
|
*
|
|
43
|
-
* @param {uuid} requestId The request identifier
|
|
44
46
|
* @param {string} passphrase The passphrase to decryt the private key
|
|
45
|
-
* @param {boolean}
|
|
47
|
+
* @param {boolean} remember whether to remember the passphrase or not
|
|
48
|
+
* @param {boolean} shouldRefreshCurrentTab should refresh the current tab
|
|
46
49
|
* @return {Promise<void>}
|
|
47
50
|
*/
|
|
48
51
|
async _exec(passphrase, remember, shouldRefreshCurrentTab = false) {
|
|
@@ -59,11 +62,9 @@ class AuthLoginController {
|
|
|
59
62
|
* Attemps to sign in the current user.
|
|
60
63
|
*
|
|
61
64
|
* @param {string} passphrase The passphrase to decryt the private key
|
|
62
|
-
* @param {
|
|
65
|
+
* @param {boolean} rememberMe whether to remember the passphrase
|
|
63
66
|
* @param {boolean} shouldRefreshCurrentTab Should the controller calls for a refresh of the current running tab, default false
|
|
64
67
|
* (bool) false|undefined if should not remember
|
|
65
|
-
* (integer) -1 if should remember for the session
|
|
66
|
-
* (integer) duration in seconds to specify a specific duration
|
|
67
68
|
* @return {Promise<void>}
|
|
68
69
|
*/
|
|
69
70
|
async exec(passphrase, rememberMe, shouldRefreshCurrentTab) {
|
|
@@ -93,7 +94,18 @@ class AuthLoginController {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
try {
|
|
96
|
-
await this.
|
|
97
|
+
await this.authVerifyLoginChallengeService.verifyAndValidateLoginChallenge(this.account.userKeyFingerprint, this.account.userPrivateArmoredKey, passphrase);
|
|
98
|
+
/*
|
|
99
|
+
* Post login operations
|
|
100
|
+
* MFA may not be complete yet, so no need to preload things here
|
|
101
|
+
*/
|
|
102
|
+
if (rememberMe) {
|
|
103
|
+
await Promise.all([
|
|
104
|
+
PassphraseStorageService.set(passphrase, -1),
|
|
105
|
+
KeepSessionAliveService.start(),
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
await PostLoginService.exec();
|
|
97
109
|
await this.registerRememberMeOption(rememberMe);
|
|
98
110
|
} catch (error) {
|
|
99
111
|
if (!(error instanceof UserAlreadyLoggedInError)) {
|