mirror of
https://github.com/bitwarden/jslib
synced 2026-01-05 01:53:13 +00:00
Merge remote-tracking branch 'origin/master' into hotfix/bwdc-api-key-refresh
This commit is contained in:
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
## Type of change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature development
|
||||
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
||||
- [ ] Build/deploy pipeline (DevOps)
|
||||
- [ ] Other
|
||||
|
||||
## Objective
|
||||
<!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding-->
|
||||
|
||||
|
||||
|
||||
## Code changes
|
||||
<!--Explain the changes you've made to each file or major component. This should help the reviewer understand your changes-->
|
||||
<!--Also refer to any related changes or PRs in other repositories-->
|
||||
|
||||
* **file.ext:** Description of what was changed and why
|
||||
|
||||
## Testing requirements
|
||||
<!--What functionality requires testing by QA? This includes testing new behavior and regression testing-->
|
||||
|
||||
|
||||
|
||||
## Before you submit
|
||||
- [ ] I have checked for **linting** errors (`npm run lint`) (required)
|
||||
- [ ] I have added **unit tests** where it makes sense to do so (encouraged but not required)
|
||||
- [ ] This change requires a **documentation update** (notify the documentation team)
|
||||
- [ ] This change has particular **deployment requirements** (notify the DevOps team)
|
||||
54
.github/workflows/build.yml
vendored
54
.github/workflows/build.yml
vendored
@@ -1,10 +1,12 @@
|
||||
---
|
||||
name: Build
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
cloc:
|
||||
runs-on: ubuntu-latest
|
||||
name: CLOC
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
@@ -18,13 +20,14 @@ jobs:
|
||||
- name: Print lines of code
|
||||
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
||||
|
||||
build:
|
||||
|
||||
build:
|
||||
name: Build jslib
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest, ubuntu-latest]
|
||||
os: [windows-2019, macos-10.15, ubuntu-20.04]
|
||||
|
||||
steps:
|
||||
- name: Set up Node
|
||||
@@ -65,3 +68,48 @@ jobs:
|
||||
with:
|
||||
name: test-coverage
|
||||
path: coverage/
|
||||
|
||||
- name: Run Node tests
|
||||
run: npm run test:node
|
||||
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
if: always()
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- cloc
|
||||
- build
|
||||
steps:
|
||||
- name: Check if any job failed
|
||||
if: ${{ (github.ref == 'refs/heads/master') || (github.ref == 'refs/heads/rc') }}
|
||||
env:
|
||||
CLOC_STATUS: ${{ needs.cloc.result }}
|
||||
BUILD_STATUS: ${{ needs.build.result }}
|
||||
run: |
|
||||
if [ "$CLOC_STATUS" = "failure" ]; then
|
||||
exit 1
|
||||
elif [ "$BUILD_STATUS" = "failure" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Login to Azure - Prod Subscription
|
||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
||||
if: failure()
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
|
||||
if: failure()
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
secrets: "devops-alerts-slack-webhook-url"
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@e4e71685b9b239384b0f676a63c32367f59c2522 # v1.2.2
|
||||
if: failure()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
|
||||
319
angular/package-lock.json
generated
319
angular/package-lock.json
generated
@@ -9,40 +9,39 @@
|
||||
"version": "0.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@angular/animations": "^11.2.11",
|
||||
"@angular/cdk": "^11.2.10",
|
||||
"@angular/common": "^11.2.11",
|
||||
"@angular/compiler": "^11.2.11",
|
||||
"@angular/core": "^11.2.11",
|
||||
"@angular/forms": "^11.2.11",
|
||||
"@angular/platform-browser": "^11.2.11",
|
||||
"@angular/platform-browser-dynamic": "^11.2.11",
|
||||
"@angular/router": "^11.2.11",
|
||||
"@angular/animations": "^12.2.13",
|
||||
"@angular/cdk": "^12.2.13",
|
||||
"@angular/common": "^12.2.13",
|
||||
"@angular/compiler": "^12.2.13",
|
||||
"@angular/core": "^12.2.13",
|
||||
"@angular/forms": "^12.2.13",
|
||||
"@angular/platform-browser": "^12.2.13",
|
||||
"@angular/platform-browser-dynamic": "^12.2.13",
|
||||
"@angular/router": "^12.2.13",
|
||||
"@bitwarden/jslib-common": "file:../common",
|
||||
"duo_web_sdk": "git+https://github.com/duosecurity/duo_web_sdk.git",
|
||||
"rxjs": "6.6.7",
|
||||
"rxjs": "^7.4.0",
|
||||
"tldjs": "^2.3.1",
|
||||
"zone.js": "0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/duo_web_sdk": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.3.5"
|
||||
}
|
||||
},
|
||||
"../common": {
|
||||
"name": "@bitwarden/jslib-common",
|
||||
"version": "0.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@microsoft/signalr": "3.1.13",
|
||||
"@microsoft/signalr-protocol-msgpack": "3.1.13",
|
||||
"@microsoft/signalr": "5.0.10",
|
||||
"@microsoft/signalr-protocol-msgpack": "5.0.10",
|
||||
"big-integer": "1.6.48",
|
||||
"browser-hrtime": "^1.1.8",
|
||||
"lunr": "^2.3.9",
|
||||
"node-forge": "^0.10.0",
|
||||
"papaparse": "^5.3.0",
|
||||
"rxjs": "6.6.7",
|
||||
"rxjs": "^7.4.0",
|
||||
"tldjs": "^2.3.1",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
@@ -54,92 +53,111 @@
|
||||
"@types/tldjs": "^2.3.0",
|
||||
"@types/zxcvbn": "^4.4.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.3.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/animations": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.2.14.tgz",
|
||||
"integrity": "sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-12.2.14.tgz",
|
||||
"integrity": "sha512-1BR5u32auVePvXNNP96DB2008V+Ku0OGqeZQl2h4XA9xzES/Zk5WllIJZXqRmWMRBVARfXsfb0RdMty9gcaVjA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "11.2.14"
|
||||
"@angular/core": "12.2.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cdk": {
|
||||
"version": "11.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-11.2.13.tgz",
|
||||
"integrity": "sha512-FkE4iCwoLbQxLDUOjV1I7M/6hmpyb7erAjEdWgch7nGRNxF1hqX5Bqf1lvLFKPNCbx5NRI5K7YVAdIUQUR8vug==",
|
||||
"version": "12.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.2.13.tgz",
|
||||
"integrity": "sha512-zSKRhECyFqhingIeyRInIyTvYErt4gWo+x5DQr0b7YLUbU8DZSwWnG4w76Ke2s4U8T7ry1jpJBHoX/e8YBpGMg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"parse5": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^11.0.0 || ^12.0.0-0",
|
||||
"@angular/core": "^11.0.0 || ^12.0.0-0"
|
||||
"@angular/common": "^12.0.0 || ^13.0.0-0",
|
||||
"@angular/core": "^12.0.0 || ^13.0.0-0",
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/common": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-11.2.14.tgz",
|
||||
"integrity": "sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-12.2.14.tgz",
|
||||
"integrity": "sha512-ffYUYdwZETmFJw0AcWY30WsaWBhJxj/zSmFXWjgEGEGZH56zwbbNwfMZOYZ1jz4haAVxGu+TdXsOl2yMGzN7jQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "11.2.14",
|
||||
"rxjs": "^6.5.3"
|
||||
"@angular/core": "12.2.14",
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/compiler": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.2.14.tgz",
|
||||
"integrity": "sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-12.2.14.tgz",
|
||||
"integrity": "sha512-dwmZi+n66IUzRFlGWu9mjXq170ZEsaDvlNLZzaPgs6vZTa4Kt7PWvIF/Y7TMvnVv/uqNG6kOhfmOkf6rfz1Gjg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/core": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-11.2.14.tgz",
|
||||
"integrity": "sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-12.2.14.tgz",
|
||||
"integrity": "sha512-dlVk7yqUHL2R/eCmM8LsWuxhEBfzg0y1zHt0UqCuFwlCoiw+IG4HFy4OlZEUw9NUEZJSv0aDv3sWqxLkvK5vvg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rxjs": "^6.5.3",
|
||||
"zone.js": "^0.10.2 || ^0.11.3"
|
||||
"rxjs": "^6.5.3 || ^7.0.0",
|
||||
"zone.js": "~0.11.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/forms": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.2.14.tgz",
|
||||
"integrity": "sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-12.2.14.tgz",
|
||||
"integrity": "sha512-/9/gSJUBXVRVdRnzgJnALAQZYJATuGDMkFC9ms9DEMG4PMAhe9x4if1lJjN6noz5RAom3qNuVBNWaYAPUxlcBQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "11.2.14",
|
||||
"@angular/core": "11.2.14",
|
||||
"@angular/platform-browser": "11.2.14",
|
||||
"rxjs": "^6.5.3"
|
||||
"@angular/common": "12.2.14",
|
||||
"@angular/core": "12.2.14",
|
||||
"@angular/platform-browser": "12.2.14",
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/platform-browser": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.2.14.tgz",
|
||||
"integrity": "sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.2.14.tgz",
|
||||
"integrity": "sha512-fWcE2rnJ3ZCISa1oPfsIDV7FBZBoLFEdDuMXAiDYqDPKvF/E5U5nHrS+K4SlLAi094bMobtTOReNWl/Ienniyw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "11.2.14",
|
||||
"@angular/common": "11.2.14",
|
||||
"@angular/core": "11.2.14"
|
||||
"@angular/animations": "12.2.14",
|
||||
"@angular/common": "12.2.14",
|
||||
"@angular/core": "12.2.14"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@angular/animations": {
|
||||
@@ -148,31 +166,37 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/platform-browser-dynamic": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz",
|
||||
"integrity": "sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.14.tgz",
|
||||
"integrity": "sha512-0NPF7mS91Tct8rBmOLZPmnLSuS4kbLHXo6eTgrg80OC0vlzBiQwGDVW4X3KncCoX9CpevaGJCdSMc+uPNsFOUQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "11.2.14",
|
||||
"@angular/compiler": "11.2.14",
|
||||
"@angular/core": "11.2.14",
|
||||
"@angular/platform-browser": "11.2.14"
|
||||
"@angular/common": "12.2.14",
|
||||
"@angular/compiler": "12.2.14",
|
||||
"@angular/core": "12.2.14",
|
||||
"@angular/platform-browser": "12.2.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/router": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-11.2.14.tgz",
|
||||
"integrity": "sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-12.2.14.tgz",
|
||||
"integrity": "sha512-yP5grSnqBvc4vNhtYdcxDgDYIebUKs5f0xyFkUJM5030UnQ0CV45tBsSxHMkQbPZucIfOuxpRy8xy5+4GizuwQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.14.1 || >=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "11.2.14",
|
||||
"@angular/core": "11.2.14",
|
||||
"@angular/platform-browser": "11.2.14",
|
||||
"rxjs": "^6.5.3"
|
||||
"@angular/common": "12.2.14",
|
||||
"@angular/core": "12.2.14",
|
||||
"@angular/platform-browser": "12.2.14",
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bitwarden/jslib-common": {
|
||||
@@ -219,9 +243,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@@ -311,20 +335,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "6.6.7",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
||||
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
|
||||
"integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==",
|
||||
"dependencies": {
|
||||
"tslib": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=2.0.0"
|
||||
"tslib": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
|
||||
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
|
||||
},
|
||||
"node_modules/tldjs": {
|
||||
"version": "2.3.1",
|
||||
@@ -339,14 +360,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -373,83 +394,83 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.2.14.tgz",
|
||||
"integrity": "sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-12.2.14.tgz",
|
||||
"integrity": "sha512-1BR5u32auVePvXNNP96DB2008V+Ku0OGqeZQl2h4XA9xzES/Zk5WllIJZXqRmWMRBVARfXsfb0RdMty9gcaVjA==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/cdk": {
|
||||
"version": "11.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-11.2.13.tgz",
|
||||
"integrity": "sha512-FkE4iCwoLbQxLDUOjV1I7M/6hmpyb7erAjEdWgch7nGRNxF1hqX5Bqf1lvLFKPNCbx5NRI5K7YVAdIUQUR8vug==",
|
||||
"version": "12.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.2.13.tgz",
|
||||
"integrity": "sha512-zSKRhECyFqhingIeyRInIyTvYErt4gWo+x5DQr0b7YLUbU8DZSwWnG4w76Ke2s4U8T7ry1jpJBHoX/e8YBpGMg==",
|
||||
"requires": {
|
||||
"parse5": "^5.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/common": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-11.2.14.tgz",
|
||||
"integrity": "sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-12.2.14.tgz",
|
||||
"integrity": "sha512-ffYUYdwZETmFJw0AcWY30WsaWBhJxj/zSmFXWjgEGEGZH56zwbbNwfMZOYZ1jz4haAVxGu+TdXsOl2yMGzN7jQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/compiler": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.2.14.tgz",
|
||||
"integrity": "sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-12.2.14.tgz",
|
||||
"integrity": "sha512-dwmZi+n66IUzRFlGWu9mjXq170ZEsaDvlNLZzaPgs6vZTa4Kt7PWvIF/Y7TMvnVv/uqNG6kOhfmOkf6rfz1Gjg==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/core": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-11.2.14.tgz",
|
||||
"integrity": "sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-12.2.14.tgz",
|
||||
"integrity": "sha512-dlVk7yqUHL2R/eCmM8LsWuxhEBfzg0y1zHt0UqCuFwlCoiw+IG4HFy4OlZEUw9NUEZJSv0aDv3sWqxLkvK5vvg==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/forms": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.2.14.tgz",
|
||||
"integrity": "sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-12.2.14.tgz",
|
||||
"integrity": "sha512-/9/gSJUBXVRVdRnzgJnALAQZYJATuGDMkFC9ms9DEMG4PMAhe9x4if1lJjN6noz5RAom3qNuVBNWaYAPUxlcBQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/platform-browser": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.2.14.tgz",
|
||||
"integrity": "sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.2.14.tgz",
|
||||
"integrity": "sha512-fWcE2rnJ3ZCISa1oPfsIDV7FBZBoLFEdDuMXAiDYqDPKvF/E5U5nHrS+K4SlLAi094bMobtTOReNWl/Ienniyw==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/platform-browser-dynamic": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz",
|
||||
"integrity": "sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.14.tgz",
|
||||
"integrity": "sha512-0NPF7mS91Tct8rBmOLZPmnLSuS4kbLHXo6eTgrg80OC0vlzBiQwGDVW4X3KncCoX9CpevaGJCdSMc+uPNsFOUQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@angular/router": {
|
||||
"version": "11.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-11.2.14.tgz",
|
||||
"integrity": "sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA==",
|
||||
"version": "12.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-12.2.14.tgz",
|
||||
"integrity": "sha512-yP5grSnqBvc4vNhtYdcxDgDYIebUKs5f0xyFkUJM5030UnQ0CV45tBsSxHMkQbPZucIfOuxpRy8xy5+4GizuwQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@bitwarden/jslib-common": {
|
||||
"version": "file:../common",
|
||||
"requires": {
|
||||
"@microsoft/signalr": "3.1.13",
|
||||
"@microsoft/signalr-protocol-msgpack": "3.1.13",
|
||||
"@microsoft/signalr": "5.0.10",
|
||||
"@microsoft/signalr-protocol-msgpack": "5.0.10",
|
||||
"@types/lunr": "^2.3.3",
|
||||
"@types/node": "^14.17.1",
|
||||
"@types/node-forge": "^0.9.7",
|
||||
@@ -462,9 +483,9 @@
|
||||
"node-forge": "^0.10.0",
|
||||
"papaparse": "^5.3.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "6.6.7",
|
||||
"rxjs": "^7.4.0",
|
||||
"tldjs": "^2.3.1",
|
||||
"typescript": "4.1.5",
|
||||
"typescript": "4.3.5",
|
||||
"zxcvbn": "^4.4.2"
|
||||
}
|
||||
},
|
||||
@@ -507,9 +528,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@@ -581,17 +602,17 @@
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.6.7",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
||||
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
|
||||
"integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
"tslib": "~2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
|
||||
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -604,14 +625,14 @@
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
|
||||
@@ -22,21 +22,21 @@
|
||||
"devDependencies": {
|
||||
"@types/duo_web_sdk": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^11.2.11",
|
||||
"@angular/cdk": "^11.2.10",
|
||||
"@angular/common": "^11.2.11",
|
||||
"@angular/compiler": "^11.2.11",
|
||||
"@angular/core": "^11.2.11",
|
||||
"@angular/forms": "^11.2.11",
|
||||
"@angular/platform-browser": "^11.2.11",
|
||||
"@angular/platform-browser-dynamic": "^11.2.11",
|
||||
"@angular/router": "^11.2.11",
|
||||
"@angular/animations": "^12.2.13",
|
||||
"@angular/cdk": "^12.2.13",
|
||||
"@angular/common": "^12.2.13",
|
||||
"@angular/compiler": "^12.2.13",
|
||||
"@angular/core": "^12.2.13",
|
||||
"@angular/forms": "^12.2.13",
|
||||
"@angular/platform-browser": "^12.2.13",
|
||||
"@angular/platform-browser-dynamic": "^12.2.13",
|
||||
"@angular/router": "^12.2.13",
|
||||
"@bitwarden/jslib-common": "file:../common",
|
||||
"duo_web_sdk": "git+https://github.com/duosecurity/duo_web_sdk.git",
|
||||
"rxjs": "6.6.7",
|
||||
"rxjs": "^7.4.0",
|
||||
"tldjs": "^2.3.1",
|
||||
"zone.js": "0.11.4"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import {
|
||||
Directive,
|
||||
Input,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
@@ -18,13 +20,17 @@ import { CipherType } from 'jslib-common/enums/cipherType';
|
||||
import { EventType } from 'jslib-common/enums/eventType';
|
||||
import { FieldType } from 'jslib-common/enums/fieldType';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@Directive()
|
||||
export class AddEditCustomFieldsComponent {
|
||||
export class AddEditCustomFieldsComponent implements OnChanges {
|
||||
@Input() cipher: CipherView;
|
||||
@Input() thisCipherType: CipherType;
|
||||
@Input() editMode: boolean;
|
||||
|
||||
addFieldType: FieldType = FieldType.Text;
|
||||
addFieldTypeOptions: any[];
|
||||
addFieldLinkedTypeOption: any;
|
||||
linkedFieldOptions: any[] = [];
|
||||
|
||||
cipherType = CipherType;
|
||||
@@ -37,6 +43,17 @@ export class AddEditCustomFieldsComponent {
|
||||
{ name: i18nService.t('cfTypeHidden'), value: FieldType.Hidden },
|
||||
{ name: i18nService.t('cfTypeBoolean'), value: FieldType.Boolean },
|
||||
];
|
||||
this.addFieldLinkedTypeOption = { name: this.i18nService.t('cfTypeLinked'), value: FieldType.Linked };
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.thisCipherType != null) {
|
||||
this.setLinkedFieldOptions();
|
||||
|
||||
if (!changes.thisCipherType.firstChange) {
|
||||
this.resetCipherLinkedFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addField() {
|
||||
@@ -48,6 +65,10 @@ export class AddEditCustomFieldsComponent {
|
||||
f.type = this.addFieldType;
|
||||
f.newField = true;
|
||||
|
||||
if (f.type === FieldType.Linked) {
|
||||
f.linkedId = this.linkedFieldOptions[0].value;
|
||||
}
|
||||
|
||||
this.cipher.fields.push(f);
|
||||
}
|
||||
|
||||
@@ -73,4 +94,31 @@ export class AddEditCustomFieldsComponent {
|
||||
drop(event: CdkDragDrop<string[]>) {
|
||||
moveItemInArray(this.cipher.fields, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
|
||||
private setLinkedFieldOptions() {
|
||||
if (this.cipher.linkedFieldOptions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options: any = [];
|
||||
this.cipher.linkedFieldOptions.forEach((linkedFieldOption, id) =>
|
||||
options.push({ name: this.i18nService.t(linkedFieldOption.i18nKey), value: id }));
|
||||
this.linkedFieldOptions = options.sort(Utils.getSortFunction(this.i18nService, 'name'));
|
||||
}
|
||||
|
||||
private resetCipherLinkedFields() {
|
||||
if (this.cipher.fields == null || this.cipher.fields.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete any Linked custom fields if the item type does not support them
|
||||
if (this.cipher.linkedFieldOptions == null) {
|
||||
this.cipher.fields = this.cipher.fields.filter(f => f.type !== FieldType.Linked);
|
||||
return;
|
||||
}
|
||||
|
||||
this.cipher.fields
|
||||
.filter(f => f.type === FieldType.Linked)
|
||||
.forEach(f => f.linkedId = this.linkedFieldOptions[0].value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ import { CollectionService } from 'jslib-common/abstractions/collection.service'
|
||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
@@ -79,6 +81,7 @@ export class AddEditComponent implements OnInit {
|
||||
currentDate = new Date();
|
||||
allowPersonal = true;
|
||||
reprompt: boolean = false;
|
||||
canUseReprompt: boolean = true;
|
||||
|
||||
protected writeableCollections: CollectionView[];
|
||||
private previousCipherId: string;
|
||||
@@ -88,7 +91,8 @@ export class AddEditComponent implements OnInit {
|
||||
protected auditService: AuditService, protected stateService: StateService,
|
||||
protected userService: UserService, protected collectionService: CollectionService,
|
||||
protected messagingService: MessagingService, protected eventService: EventService,
|
||||
protected policyService: PolicyService) {
|
||||
protected policyService: PolicyService, protected passwordRepromptService: PasswordRepromptService,
|
||||
private logService: LogService) {
|
||||
this.typeOptions = [
|
||||
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
|
||||
{ name: i18nService.t('typeCard'), value: CipherType.Card },
|
||||
@@ -150,21 +154,29 @@ export class AddEditComponent implements OnInit {
|
||||
}
|
||||
|
||||
async init() {
|
||||
const myEmail = await this.userService.getEmail();
|
||||
this.ownershipOptions.push({ name: myEmail, value: null });
|
||||
if (this.ownershipOptions.length) {
|
||||
this.ownershipOptions = [];
|
||||
}
|
||||
if (await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership)) {
|
||||
this.allowPersonal = false;
|
||||
} else {
|
||||
const myEmail = await this.userService.getEmail();
|
||||
this.ownershipOptions.push({ name: myEmail, value: null });
|
||||
}
|
||||
|
||||
const orgs = await this.userService.getAllOrganizations();
|
||||
orgs.sort(Utils.getSortFunction(this.i18nService, 'name')).forEach(o => {
|
||||
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
|
||||
this.ownershipOptions.push({ name: o.name, value: o.id });
|
||||
}
|
||||
});
|
||||
|
||||
if (this.allowPersonal && await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership)) {
|
||||
this.allowPersonal = false;
|
||||
this.ownershipOptions.splice(0, 1);
|
||||
if (!this.allowPersonal) {
|
||||
this.organizationId = this.ownershipOptions[0].value;
|
||||
}
|
||||
|
||||
this.writeableCollections = await this.loadCollections();
|
||||
|
||||
this.canUseReprompt = await this.passwordRepromptService.enabled();
|
||||
}
|
||||
|
||||
async load() {
|
||||
@@ -280,7 +292,9 @@ export class AddEditComponent implements OnInit {
|
||||
this.onSavedCipher.emit(this.cipher);
|
||||
this.messagingService.send(this.editMode && !this.cloneMode ? 'editedCipher' : 'addedCipher');
|
||||
return true;
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -343,7 +357,9 @@ export class AddEditComponent implements OnInit {
|
||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
|
||||
this.onDeletedCipher.emit(this.cipher);
|
||||
this.messagingService.send(this.cipher.isDeleted ? 'permanentlyDeletedCipher' : 'deletedCipher');
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -366,7 +382,9 @@ export class AddEditComponent implements OnInit {
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('restoredItem'));
|
||||
this.onRestoredCipher.emit(this.cipher);
|
||||
this.messagingService.send('restoredCipher');
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
@@ -38,7 +39,7 @@ export class AttachmentsComponent implements OnInit {
|
||||
constructor(protected cipherService: CipherService, protected i18nService: I18nService,
|
||||
protected cryptoService: CryptoService, protected userService: UserService,
|
||||
protected platformUtilsService: PlatformUtilsService, protected apiService: ApiService,
|
||||
protected win: Window) { }
|
||||
protected win: Window, private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.init();
|
||||
@@ -71,7 +72,9 @@ export class AttachmentsComponent implements OnInit {
|
||||
this.cipher = await this.cipherDomain.decrypt();
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('attachmentSaved'));
|
||||
this.onUploadedAttachment.emit();
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
// reset file input
|
||||
// ref: https://stackoverflow.com/a/20552042
|
||||
@@ -100,7 +103,9 @@ export class AttachmentsComponent implements OnInit {
|
||||
if (i > -1) {
|
||||
this.cipher.attachments.splice(i, 1);
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
this.deletePromises[attachment.id] = null;
|
||||
this.onDeletedAttachment.emit();
|
||||
@@ -226,7 +231,9 @@ export class AttachmentsComponent implements OnInit {
|
||||
a.downloading = false;
|
||||
});
|
||||
await this.reuploadPromises[attachment.id];
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected loadCipher() {
|
||||
|
||||
138
angular/src/components/avatar.component.ts
Normal file
138
angular/src/components/avatar.component.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-avatar',
|
||||
template: '<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
|
||||
'[ngClass]="{\'rounded-circle\': circle}">',
|
||||
})
|
||||
export class AvatarComponent implements OnChanges, OnInit {
|
||||
@Input() data: string;
|
||||
@Input() email: string;
|
||||
@Input() size = 45;
|
||||
@Input() charCount = 2;
|
||||
@Input() textColor = '#ffffff';
|
||||
@Input() fontSize = 20;
|
||||
@Input() fontWeight = 300;
|
||||
@Input() dynamic = false;
|
||||
@Input() circle = false;
|
||||
|
||||
src: string;
|
||||
|
||||
constructor(public sanitizer: DomSanitizer, private cryptoFunctionService: CryptoFunctionService,
|
||||
private stateService: StateService) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.dynamic) {
|
||||
this.generate();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.dynamic) {
|
||||
this.generate();
|
||||
}
|
||||
}
|
||||
|
||||
private async generate() {
|
||||
const enableGravatars = await this.stateService.get<boolean>('enableGravatars');
|
||||
if (enableGravatars && this.email != null) {
|
||||
const hashBytes = await this.cryptoFunctionService.hash(this.email.toLowerCase().trim(), 'md5');
|
||||
const hash = Utils.fromBufferToHex(hashBytes).toLowerCase();
|
||||
this.src = 'https://www.gravatar.com/avatar/' + hash + '?s=' + this.size + '&r=pg&d=retro';
|
||||
} else {
|
||||
let chars: string = null;
|
||||
const upperData = this.data.toUpperCase();
|
||||
|
||||
if (this.charCount > 1) {
|
||||
chars = this.getFirstLetters(upperData, this.charCount);
|
||||
}
|
||||
if (chars == null) {
|
||||
chars = this.unicodeSafeSubstring(upperData, this.charCount);
|
||||
}
|
||||
|
||||
// If the chars contain an emoji, only show it.
|
||||
if (chars.match(Utils.regexpEmojiPresentation)) {
|
||||
chars = chars.match(Utils.regexpEmojiPresentation)[0];
|
||||
}
|
||||
|
||||
const charObj = this.getCharText(chars);
|
||||
const color = this.stringToColor(upperData);
|
||||
const svg = this.getSvg(this.size, color);
|
||||
svg.appendChild(charObj);
|
||||
const html = window.document.createElement('div').appendChild(svg).outerHTML;
|
||||
const svgHtml = window.btoa(unescape(encodeURIComponent(html)));
|
||||
this.src = 'data:image/svg+xml;base64,' + svgHtml;
|
||||
}
|
||||
}
|
||||
|
||||
private stringToColor(str: string): string {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
// tslint:disable-next-line
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
let color = '#';
|
||||
for (let i = 0; i < 3; i++) {
|
||||
// tslint:disable-next-line
|
||||
const value = (hash >> (i * 8)) & 0xFF;
|
||||
color += ('00' + value.toString(16)).substr(-2);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private getFirstLetters(data: string, count: number): string {
|
||||
const parts = data.split(' ');
|
||||
if (parts.length > 1) {
|
||||
let text = '';
|
||||
for (let i = 0; i < count; i++) {
|
||||
text += this.unicodeSafeSubstring(parts[i], 1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getSvg(size: number, color: string): HTMLElement {
|
||||
const svgTag = window.document.createElement('svg');
|
||||
svgTag.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
||||
svgTag.setAttribute('pointer-events', 'none');
|
||||
svgTag.setAttribute('width', size.toString());
|
||||
svgTag.setAttribute('height', size.toString());
|
||||
svgTag.style.backgroundColor = color;
|
||||
svgTag.style.width = size + 'px';
|
||||
svgTag.style.height = size + 'px';
|
||||
return svgTag;
|
||||
}
|
||||
|
||||
private getCharText(character: string): HTMLElement {
|
||||
const textTag = window.document.createElement('text');
|
||||
textTag.setAttribute('text-anchor', 'middle');
|
||||
textTag.setAttribute('y', '50%');
|
||||
textTag.setAttribute('x', '50%');
|
||||
textTag.setAttribute('dy', '0.35em');
|
||||
textTag.setAttribute('pointer-events', 'auto');
|
||||
textTag.setAttribute('fill', this.textColor);
|
||||
textTag.setAttribute('font-family', '"Open Sans","Helvetica Neue",Helvetica,Arial,' +
|
||||
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"');
|
||||
textTag.textContent = character;
|
||||
textTag.style.fontWeight = this.fontWeight.toString();
|
||||
textTag.style.fontSize = this.fontSize + 'px';
|
||||
return textTag;
|
||||
}
|
||||
|
||||
private unicodeSafeSubstring(str: string, count: number) {
|
||||
const characters = str.match(/./ug);
|
||||
return characters != null ? characters.slice(0, count).join('') : '';
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<div class="callout callout-{{calloutStyle}}" [ngClass]="{'clickable': clickable}" role="alert">
|
||||
<div #callout class="callout callout-{{calloutStyle}}" [ngClass]="{'clickable': clickable}"
|
||||
[attr.role]="useAlertRole ? 'alert' : null">
|
||||
<h3 class="callout-heading" *ngIf="title">
|
||||
<i class="fa {{icon}}" *ngIf="icon" aria-hidden="true"></i>
|
||||
{{title}}
|
||||
|
||||
@@ -19,6 +19,7 @@ export class CalloutComponent implements OnInit {
|
||||
@Input() clickable: boolean;
|
||||
@Input() enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
@Input() enforcedPolicyMessage: string;
|
||||
@Input() useAlertRole = false;
|
||||
|
||||
calloutStyle: string;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
@@ -30,7 +31,7 @@ export class CollectionsComponent implements OnInit {
|
||||
protected cipherDomain: Cipher;
|
||||
|
||||
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
|
||||
protected i18nService: I18nService, protected cipherService: CipherService) { }
|
||||
protected i18nService: I18nService, protected cipherService: CipherService, private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.load();
|
||||
@@ -65,7 +66,9 @@ export class CollectionsComponent implements OnInit {
|
||||
await this.formPromise;
|
||||
this.onSavedCollections.emit();
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('editedItem'));
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected loadCipher() {
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { NotificationsService } from 'jslib-common/abstractions/notifications.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
|
||||
@Directive()
|
||||
@@ -20,7 +19,6 @@ export class EnvironmentComponent {
|
||||
notificationsUrl: string;
|
||||
baseUrl: string;
|
||||
showCustom = false;
|
||||
enterpriseUrl: string;
|
||||
|
||||
constructor(protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
|
||||
protected i18nService: I18nService) {
|
||||
@@ -33,7 +31,6 @@ export class EnvironmentComponent {
|
||||
this.identityUrl = urls.identity || '';
|
||||
this.iconsUrl = urls.icons || '';
|
||||
this.notificationsUrl = urls.notifications || '';
|
||||
this.enterpriseUrl = urls.enterprise || '';
|
||||
}
|
||||
|
||||
async submit() {
|
||||
@@ -44,7 +41,6 @@ export class EnvironmentComponent {
|
||||
webVault: this.webVaultUrl,
|
||||
icons: this.iconsUrl,
|
||||
notifications: this.notificationsUrl,
|
||||
enterprise: this.enterpriseUrl,
|
||||
});
|
||||
|
||||
// re-set urls since service can change them, ex: prefixing https://
|
||||
@@ -54,7 +50,6 @@ export class EnvironmentComponent {
|
||||
this.webVaultUrl = resUrls.webVault;
|
||||
this.iconsUrl = resUrls.icons;
|
||||
this.notificationsUrl = resUrls.notifications;
|
||||
this.enterpriseUrl = resUrls.enterprise;
|
||||
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('environmentSaved'));
|
||||
this.saved();
|
||||
|
||||
@@ -4,13 +4,16 @@ import {
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
||||
import { ExportService } from 'jslib-common/abstractions/export.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
|
||||
|
||||
import { EventType } from 'jslib-common/enums/eventType';
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
@@ -20,14 +23,24 @@ export class ExportComponent implements OnInit {
|
||||
@Output() onSaved = new EventEmitter();
|
||||
|
||||
formPromise: Promise<string>;
|
||||
masterPassword: string;
|
||||
format: 'json' | 'encrypted_json' | 'csv' = 'json';
|
||||
showPassword = false;
|
||||
disabledByPolicy: boolean = false;
|
||||
|
||||
exportForm = this.fb.group({
|
||||
format: ['json'],
|
||||
secret: [''],
|
||||
});
|
||||
|
||||
formatOptions = [
|
||||
{ name: '.json', value: 'json' },
|
||||
{ name: '.csv', value: 'csv' },
|
||||
{ name: '.json (Encrypted)', value: 'encrypted_json' },
|
||||
];
|
||||
|
||||
constructor(protected cryptoService: CryptoService, protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService, protected exportService: ExportService,
|
||||
protected eventService: EventService, private policyService: PolicyService, protected win: Window) { }
|
||||
protected eventService: EventService, private policyService: PolicyService, protected win: Window,
|
||||
private logService: LogService, private userVerificationService: UserVerificationService,
|
||||
private fb: FormBuilder) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.checkExportDisabled();
|
||||
@@ -35,6 +48,9 @@ export class ExportComponent implements OnInit {
|
||||
|
||||
async checkExportDisabled() {
|
||||
this.disabledByPolicy = await this.policyService.policyAppliesToUser(PolicyType.DisablePersonalVaultExport);
|
||||
if (this.disabledByPolicy) {
|
||||
this.exportForm.disable();
|
||||
}
|
||||
}
|
||||
|
||||
get encryptedFormat() {
|
||||
@@ -47,29 +63,28 @@ export class ExportComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.masterPassword == null || this.masterPassword === '') {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidMasterPassword'));
|
||||
return;
|
||||
}
|
||||
|
||||
const acceptedWarning = await this.warningDialog();
|
||||
if (!acceptedWarning) {
|
||||
return;
|
||||
}
|
||||
|
||||
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null);
|
||||
if (passwordValid) {
|
||||
try {
|
||||
this.formPromise = this.getExportData();
|
||||
const data = await this.formPromise;
|
||||
this.downloadFile(data);
|
||||
this.saved();
|
||||
await this.collectEvent();
|
||||
} catch { }
|
||||
} else {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidMasterPassword'));
|
||||
const secret = this.exportForm.get('secret').value;
|
||||
try {
|
||||
await this.userVerificationService.verifyUser(secret);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formPromise = this.getExportData();
|
||||
const data = await this.formPromise;
|
||||
this.downloadFile(data);
|
||||
this.saved();
|
||||
await this.collectEvent();
|
||||
this.exportForm.get('secret').setValue('');
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +104,6 @@ export class ExportComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById('masterPassword').focus();
|
||||
}
|
||||
|
||||
protected saved() {
|
||||
this.onSaved.emit();
|
||||
}
|
||||
@@ -119,6 +129,10 @@ export class ExportComponent implements OnInit {
|
||||
await this.eventService.collect(EventType.User_ClientExportedVault);
|
||||
}
|
||||
|
||||
get format() {
|
||||
return this.exportForm.get('format').value;
|
||||
}
|
||||
|
||||
private downloadFile(csv: string): void {
|
||||
const fileName = this.getFileName();
|
||||
this.platformUtilsService.saveFile(this.win, csv, { type: 'text/plain' }, fileName);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
|
||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
|
||||
import { FolderView } from 'jslib-common/models/view/folderView';
|
||||
@@ -25,7 +26,7 @@ export class FolderAddEditComponent implements OnInit {
|
||||
deletePromise: Promise<any>;
|
||||
|
||||
constructor(protected folderService: FolderService, protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService) { }
|
||||
protected platformUtilsService: PlatformUtilsService, private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.init();
|
||||
@@ -46,7 +47,9 @@ export class FolderAddEditComponent implements OnInit {
|
||||
this.i18nService.t(this.editMode ? 'editedFolder' : 'addedFolder'));
|
||||
this.onSavedFolder.emit(this.folder);
|
||||
return true;
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -64,7 +67,9 @@ export class FolderAddEditComponent implements OnInit {
|
||||
await this.deletePromise;
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedFolder'));
|
||||
this.onDeletedFolder.emit(this.folder);
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PasswordHintRequest } from 'jslib-common/models/request/passwordHintReq
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
|
||||
export class HintComponent {
|
||||
@@ -14,7 +15,8 @@ export class HintComponent {
|
||||
protected onSuccessfulSubmit: () => void;
|
||||
|
||||
constructor(protected router: Router, protected i18nService: I18nService,
|
||||
protected apiService: ApiService, protected platformUtilsService: PlatformUtilsService) { }
|
||||
protected apiService: ApiService, protected platformUtilsService: PlatformUtilsService,
|
||||
private logService: LogService) { }
|
||||
|
||||
async submit() {
|
||||
if (this.email == null || this.email === '') {
|
||||
@@ -37,6 +39,8 @@ export class HintComponent {
|
||||
} else if (this.router != null) {
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,9 @@ export class IconComponent implements OnChanges {
|
||||
try {
|
||||
this.image = this.iconsUrl + '/' + Utils.getHostname(hostnameUri) + '/icon.png';
|
||||
this.fallbackImage = 'images/fa-globe.png';
|
||||
} catch (e) { }
|
||||
} catch (e) {
|
||||
// Ignore error since the fallback icon will be shown if image is null.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.image = null;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Directive, OnInit } from '@angular/core';
|
||||
import { Directive, NgZone, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
@@ -17,7 +20,7 @@ import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
import { EncString } from 'jslib-common/models/domain/encString';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
|
||||
import { PasswordVerificationRequest } from 'jslib-common/models/request/passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from 'jslib-common/models/request/secretVerificationRequest';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@@ -35,6 +38,7 @@ export class LockComponent implements OnInit {
|
||||
supportsBiometric: boolean;
|
||||
biometricLock: boolean;
|
||||
biometricText: string;
|
||||
hideInput: boolean;
|
||||
|
||||
protected successRoute: string = 'vault';
|
||||
protected onSuccessfulSubmit: () => void;
|
||||
@@ -47,7 +51,8 @@ export class LockComponent implements OnInit {
|
||||
protected userService: UserService, protected cryptoService: CryptoService,
|
||||
protected storageService: StorageService, protected vaultTimeoutService: VaultTimeoutService,
|
||||
protected environmentService: EnvironmentService, protected stateService: StateService,
|
||||
protected apiService: ApiService) { }
|
||||
protected apiService: ApiService, private logService: LogService,
|
||||
private keyConnectorService: KeyConnectorService, protected ngZone: NgZone) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.pinSet = await this.vaultTimeoutService.isPinLockSet();
|
||||
@@ -57,6 +62,13 @@ export class LockComponent implements OnInit {
|
||||
(await this.cryptoService.hasKeyStored('biometric') || !this.platformUtilsService.supportsSecureStorage());
|
||||
this.biometricText = await this.storageService.get(ConstantsService.biometricText);
|
||||
this.email = await this.userService.getEmail();
|
||||
const usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
||||
this.hideInput = usesKeyConnector && !this.pinLock;
|
||||
|
||||
// Users with key connector and without biometric or pin has no MP to unlock using
|
||||
if (usesKeyConnector && !(this.biometricLock || this.pinLock)) {
|
||||
await this.vaultTimeoutService.logOut();
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const vaultUrl = webVaultUrl === 'https://vault.bitwarden.com' ? 'https://bitwarden.com' : webVaultUrl;
|
||||
@@ -118,7 +130,7 @@ export class LockComponent implements OnInit {
|
||||
if (storedKeyHash != null) {
|
||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, key);
|
||||
} else {
|
||||
const request = new PasswordVerificationRequest();
|
||||
const request = new SecretVerificationRequest();
|
||||
const serverKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
|
||||
HashPurpose.ServerAuthorization);
|
||||
request.masterPasswordHash = serverKeyHash;
|
||||
@@ -129,7 +141,9 @@ export class LockComponent implements OnInit {
|
||||
const localKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
|
||||
HashPurpose.LocalAuthorization);
|
||||
await this.cryptoService.setKeyHash(localKeyHash);
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (passwordValid) {
|
||||
@@ -156,7 +170,7 @@ export class LockComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async unlockBiometric() {
|
||||
async unlockBiometric(): Promise<boolean> {
|
||||
if (!this.biometricLock) {
|
||||
return;
|
||||
}
|
||||
@@ -166,11 +180,18 @@ export class LockComponent implements OnInit {
|
||||
if (success) {
|
||||
await this.doContinue();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById(this.pinLock ? 'pin' : 'masterPassword').focus();
|
||||
const input = document.getElementById(this.pinLock ? 'pin' : 'masterPassword');
|
||||
if (this.ngZone.isStable) {
|
||||
input.focus();
|
||||
} else {
|
||||
this.ngZone.onStable.pipe(take(1)).subscribe(() => input.focus());
|
||||
}
|
||||
}
|
||||
|
||||
private async setKeyAndContinue(key: SymmetricCryptoKey) {
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import {
|
||||
Directive,
|
||||
Input,
|
||||
NgZone,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { AuthResult } from 'jslib-common/models/domain/authResult';
|
||||
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
@@ -49,7 +53,8 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
||||
platformUtilsService: PlatformUtilsService, i18nService: I18nService,
|
||||
protected stateService: StateService, environmentService: EnvironmentService,
|
||||
protected passwordGenerationService: PasswordGenerationService,
|
||||
protected cryptoFunctionService: CryptoFunctionService, private storageService: StorageService) {
|
||||
protected cryptoFunctionService: CryptoFunctionService, private storageService: StorageService,
|
||||
protected logService: LogService, protected ngZone: NgZone) {
|
||||
super(environmentService, i18nService, platformUtilsService);
|
||||
}
|
||||
|
||||
@@ -123,12 +128,18 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById('masterPassword').focus();
|
||||
if (this.ngZone.isStable) {
|
||||
document.getElementById('masterPassword').focus();
|
||||
} else {
|
||||
this.ngZone.onStable.pipe(take(1)).subscribe(() => document.getElementById('masterPassword').focus());
|
||||
}
|
||||
}
|
||||
|
||||
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
|
||||
|
||||
@@ -10,6 +10,11 @@ import {
|
||||
ViewContainerRef
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ConfigurableFocusTrap,
|
||||
ConfigurableFocusTrapFactory,
|
||||
} from '@angular/cdk/a11y';
|
||||
|
||||
import { ModalService } from '../../services/modal.service';
|
||||
|
||||
import { ModalRef } from './modal.ref';
|
||||
@@ -26,8 +31,11 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
||||
childComponentType: Type<any>;
|
||||
setComponentParameters: (component: any) => void;
|
||||
|
||||
private focusTrap: ConfigurableFocusTrap;
|
||||
|
||||
constructor(private modalService: ModalService, private cd: ChangeDetectorRef,
|
||||
private el: ElementRef<HTMLElement>, public modalRef: ModalRef) {}
|
||||
private el: ElementRef<HTMLElement>, private focusTrapFactory: ConfigurableFocusTrapFactory,
|
||||
public modalRef: ModalRef) { }
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.loadChildComponent(this.childComponentType);
|
||||
@@ -37,6 +45,10 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
||||
this.cd.detectChanges();
|
||||
|
||||
this.modalRef.created(this.el.nativeElement);
|
||||
this.focusTrap = this.focusTrapFactory.create(this.el.nativeElement.querySelector('.modal-dialog'));
|
||||
if (this.el.nativeElement.querySelector('[appAutoFocus]') == null) {
|
||||
this.focusTrap.focusFirstTabbableElementWhenReady();
|
||||
}
|
||||
}
|
||||
|
||||
loadChildComponent(componentType: Type<any>) {
|
||||
@@ -50,9 +62,15 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
||||
if (this.componentRef) {
|
||||
this.componentRef.destroy();
|
||||
}
|
||||
this.focusTrap.destroy();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
|
||||
getFocus() {
|
||||
const autoFocusEl = this.el.nativeElement.querySelector('[appAutoFocus]') as HTMLElement;
|
||||
autoFocusEl?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ export class ModalRef {
|
||||
onCreated: Observable<HTMLElement>; // Modal added to the DOM.
|
||||
onClose: Observable<any>; // Initiated close.
|
||||
onClosed: Observable<any>; // Modal was closed (Remove element from DOM)
|
||||
onShow: Observable<any>; // Start showing modal
|
||||
onShown: Observable<any>; // Modal is fully visible
|
||||
onShow: Observable<void>; // Start showing modal
|
||||
onShown: Observable<void>; // Modal is fully visible
|
||||
|
||||
private readonly _onCreated = new Subject<HTMLElement>();
|
||||
private readonly _onClose = new Subject<any>();
|
||||
private readonly _onClosed = new Subject<any>();
|
||||
private readonly _onShow = new Subject<any>();
|
||||
private readonly _onShown = new Subject<any>();
|
||||
private readonly _onShow = new Subject<void>();
|
||||
private readonly _onShown = new Subject<void>();
|
||||
private lastResult: any;
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Directive, OnInit } from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { TokenService } from 'jslib-common/abstractions/token.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
@Directive()
|
||||
@@ -13,7 +13,7 @@ export class PremiumComponent implements OnInit {
|
||||
refreshPromise: Promise<any>;
|
||||
|
||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
||||
protected apiService: ApiService, protected userService: UserService) { }
|
||||
protected apiService: ApiService, protected userService: UserService, private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.isPremium = await this.userService.canAccessPremium();
|
||||
@@ -25,7 +25,9 @@ export class PremiumComponent implements OnInit {
|
||||
await this.refreshPromise;
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('refreshComplete'));
|
||||
this.isPremium = await this.userService.canAccessPremium();
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async purchase() {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
@@ -39,7 +40,8 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
||||
i18nService: I18nService, protected cryptoService: CryptoService,
|
||||
protected apiService: ApiService, protected stateService: StateService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
protected passwordGenerationService: PasswordGenerationService, environmentService: EnvironmentService) {
|
||||
protected passwordGenerationService: PasswordGenerationService, environmentService: EnvironmentService,
|
||||
protected logService: LogService) {
|
||||
super(environmentService, i18nService, platformUtilsService);
|
||||
this.showTerms = !platformUtilsService.isSelfHost();
|
||||
}
|
||||
@@ -158,7 +160,9 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
||||
}
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('newAccountCreated'));
|
||||
this.router.navigate([this.successRoute], { queryParams: { email: this.email } });
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
|
||||
77
angular/src/components/remove-password.component.ts
Normal file
77
angular/src/components/remove-password.component.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
Directive,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
|
||||
@Directive()
|
||||
export class RemovePasswordComponent implements OnInit {
|
||||
|
||||
actionPromise: Promise<any>;
|
||||
continuing: boolean = false;
|
||||
leaving: boolean = false;
|
||||
|
||||
loading: boolean = true;
|
||||
organization: Organization;
|
||||
email: string;
|
||||
|
||||
constructor(private router: Router, private userService: UserService,
|
||||
private apiService: ApiService, private syncService: SyncService,
|
||||
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
|
||||
private keyConnectorService: KeyConnectorService, private storageService: StorageService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.organization = await this.keyConnectorService.getManagingOrganization();
|
||||
this.email = await this.userService.getEmail();
|
||||
await this.syncService.fullSync(false);
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async convert() {
|
||||
this.continuing = true;
|
||||
this.actionPromise = this.keyConnectorService.migrateUser();
|
||||
|
||||
try {
|
||||
await this.actionPromise;
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('removedMasterPassword'));
|
||||
await this.keyConnectorService.removeConvertAccountRequired();
|
||||
this.router.navigate(['']);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async leave() {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('leaveOrganizationConfirmation'), this.organization.name,
|
||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.leaving = true;
|
||||
this.actionPromise = this.apiService.postLeaveOrganization(this.organization.id).then(() => {
|
||||
return this.syncService.fullSync(true);
|
||||
});
|
||||
await this.actionPromise;
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('leftOrganization'));
|
||||
await this.keyConnectorService.removeConvertAccountRequired();
|
||||
this.router.navigate(['']);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { SendType } from 'jslib-common/enums/sendType';
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
@@ -57,7 +58,8 @@ export class AddEditComponent implements OnInit {
|
||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
||||
protected environmentService: EnvironmentService, protected datePipe: DatePipe,
|
||||
protected sendService: SendService, protected userService: UserService,
|
||||
protected messagingService: MessagingService, protected policyService: PolicyService) {
|
||||
protected messagingService: MessagingService, protected policyService: PolicyService,
|
||||
private logService: LogService) {
|
||||
this.typeOptions = [
|
||||
{ name: i18nService.t('sendTypeFile'), value: SendType.File },
|
||||
{ name: i18nService.t('sendTypeText'), value: SendType.Text },
|
||||
@@ -191,7 +193,9 @@ export class AddEditComponent implements OnInit {
|
||||
try {
|
||||
await this.formPromise;
|
||||
return true;
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,7 +222,9 @@ export class AddEditComponent implements OnInit {
|
||||
await this.load();
|
||||
this.onDeletedSend.emit(this.send);
|
||||
return true;
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -183,6 +183,12 @@ export class EffluxDatesComponent implements OnInit {
|
||||
return this.safariTimePresetOptions(DateField.ExpriationDate);
|
||||
}
|
||||
|
||||
private get nextWeek(): Date {
|
||||
const nextWeek = new Date();
|
||||
nextWeek.setDate(nextWeek.getDate() + 7);
|
||||
return nextWeek;
|
||||
}
|
||||
|
||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
||||
protected datePipe: DatePipe) {
|
||||
}
|
||||
@@ -244,6 +250,15 @@ export class EffluxDatesComponent implements OnInit {
|
||||
} else {
|
||||
this.selectedDeletionDatePreset.setValue(DatePreset.SevenDays);
|
||||
this.selectedExpirationDatePreset.setValue(DatePreset.Never);
|
||||
|
||||
switch (this.browserPath) {
|
||||
case BrowserPath.Safari:
|
||||
this.fallbackDeletionDate.setValue(this.nextWeek.toISOString().slice(0, 10));
|
||||
this.fallbackDeletionTime.setValue(this.safariTimePresetOptions(DateField.DeletionDate)[1].twentyFourHour);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
import { SendType } from 'jslib-common/enums/sendType';
|
||||
|
||||
@@ -12,6 +11,7 @@ import { SendView } from 'jslib-common/models/view/sendView';
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
@@ -48,7 +48,8 @@ export class SendComponent implements OnInit {
|
||||
constructor(protected sendService: SendService, protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
|
||||
protected ngZone: NgZone, protected searchService: SearchService,
|
||||
protected policyService: PolicyService, protected userService: UserService) { }
|
||||
protected policyService: PolicyService, protected userService: UserService,
|
||||
private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
|
||||
@@ -129,7 +130,9 @@ export class SendComponent implements OnInit {
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('removedPassword'));
|
||||
await this.load();
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
this.actionPromise = null;
|
||||
}
|
||||
|
||||
@@ -156,7 +159,9 @@ export class SendComponent implements OnInit {
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend'));
|
||||
await this.refresh();
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
this.actionPromise = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
Router
|
||||
} from '@angular/router';
|
||||
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
@@ -25,7 +27,6 @@ import { ChangePasswordComponent as BaseChangePasswordComponent } from './change
|
||||
|
||||
import { HashPurpose } from 'jslib-common/enums/hashPurpose';
|
||||
import { KdfType } from 'jslib-common/enums/kdfType';
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@@ -53,14 +54,10 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
await this.syncService.fullSync(true);
|
||||
this.syncLoading = false;
|
||||
|
||||
const queryParamsSub = this.route.queryParams.subscribe(async qParams => {
|
||||
this.route.queryParams.pipe(first()).subscribe(async qParams => {
|
||||
if (qParams.identifier != null) {
|
||||
this.identifier = qParams.identifier;
|
||||
}
|
||||
|
||||
if (queryParamsSub != null) {
|
||||
queryParamsSub.unsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
// Automatic Enrollment Detection
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Directive } from '@angular/core';
|
||||
import {
|
||||
Directive,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
@@ -12,14 +16,20 @@ import { Utils } from 'jslib-common/misc/utils';
|
||||
import { ModalRef } from './modal/modal.ref';
|
||||
|
||||
@Directive()
|
||||
export class SetPinComponent {
|
||||
export class SetPinComponent implements OnInit {
|
||||
|
||||
pin = '';
|
||||
showPin = false;
|
||||
masterPassOnRestart = true;
|
||||
showMasterPassOnRestart = true;
|
||||
|
||||
constructor(private modalRef: ModalRef, private cryptoService: CryptoService, private userService: UserService,
|
||||
private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService) { }
|
||||
private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService,
|
||||
private keyConnectorService: KeyConnectorService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.showMasterPassOnRestart = this.masterPassOnRestart = !await this.keyConnectorService.getUsesKeyConnector();
|
||||
}
|
||||
|
||||
toggleVisibility() {
|
||||
this.showPin = !this.showPin;
|
||||
|
||||
@@ -11,6 +11,7 @@ import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserS
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
@@ -35,7 +36,7 @@ export class ShareComponent implements OnInit {
|
||||
|
||||
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
|
||||
protected i18nService: I18nService, protected userService: UserService,
|
||||
protected cipherService: CipherService) { }
|
||||
protected cipherService: CipherService, private logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.load();
|
||||
@@ -88,7 +89,9 @@ export class ShareComponent implements OnInit {
|
||||
});
|
||||
await this.formPromise;
|
||||
return true;
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,14 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
@@ -47,17 +50,17 @@ export class SsoComponent {
|
||||
protected storageService: StorageService, protected stateService: StateService,
|
||||
protected platformUtilsService: PlatformUtilsService, protected apiService: ApiService,
|
||||
protected cryptoFunctionService: CryptoFunctionService, protected environmentService: EnvironmentService,
|
||||
protected passwordGenerationService: PasswordGenerationService) { }
|
||||
protected passwordGenerationService: PasswordGenerationService, protected logService: LogService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
const queryParamsSub = this.route.queryParams.subscribe(async qParams => {
|
||||
this.route.queryParams.pipe(first()).subscribe(async qParams => {
|
||||
if (qParams.code != null && qParams.state != null) {
|
||||
const codeVerifier = await this.storageService.get<string>(ConstantsService.ssoCodeVerifierKey);
|
||||
const state = await this.storageService.get<string>(ConstantsService.ssoStateKey);
|
||||
await this.storageService.remove(ConstantsService.ssoCodeVerifierKey);
|
||||
await this.storageService.remove(ConstantsService.ssoStateKey);
|
||||
if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
|
||||
await this.logIn(qParams.code, codeVerifier, this.getOrgIdentiferFromState(qParams.state));
|
||||
await this.logIn(qParams.code, codeVerifier, this.getOrgIdentifierFromState(qParams.state));
|
||||
}
|
||||
} else if (qParams.clientId != null && qParams.redirectUri != null && qParams.state != null &&
|
||||
qParams.codeChallenge != null) {
|
||||
@@ -66,9 +69,6 @@ export class SsoComponent {
|
||||
this.codeChallenge = qParams.codeChallenge;
|
||||
this.clientId = qParams.clientId;
|
||||
}
|
||||
if (queryParamsSub != null) {
|
||||
queryParamsSub.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ export class SsoComponent {
|
||||
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
|
||||
this.loggingIn = true;
|
||||
try {
|
||||
this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri);
|
||||
this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri, orgIdFromState);
|
||||
const response = await this.formPromise;
|
||||
if (response.twoFactor) {
|
||||
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
|
||||
@@ -181,11 +181,16 @@ export class SsoComponent {
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
if (e.message === 'Unable to reach key connector') {
|
||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('ssoKeyConnectorUnavailable'));
|
||||
}
|
||||
}
|
||||
this.loggingIn = false;
|
||||
}
|
||||
|
||||
private getOrgIdentiferFromState(state: string): string {
|
||||
private getOrgIdentifierFromState(state: string): string {
|
||||
if (state === null || state === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
85
angular/src/components/toastr.component.ts
Normal file
85
angular/src/components/toastr.component.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
animate,
|
||||
state,
|
||||
style,
|
||||
transition,
|
||||
trigger
|
||||
} from '@angular/animations';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, ToastPackage, ToastrService, TOAST_CONFIG } from 'ngx-toastr';
|
||||
|
||||
@Component({
|
||||
selector: '[toast-component2]',
|
||||
template: `
|
||||
<button *ngIf="options.closeButton" (click)="remove()" type="button" class="toast-close-button" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div class="icon">
|
||||
<i></i>
|
||||
</div>
|
||||
<div>
|
||||
<div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
|
||||
{{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
|
||||
</div>
|
||||
<div *ngIf="message && options.enableHtml" role="alertdialog" aria-live="polite"
|
||||
[class]="options.messageClass" [innerHTML]="message">
|
||||
</div>
|
||||
<div *ngIf="message && !options.enableHtml" role="alertdialog" aria-live="polite"
|
||||
[class]="options.messageClass" [attr.aria-label]="message">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="options.progressBar">
|
||||
<div class="toast-progress" [style.width]="width + '%'"></div>
|
||||
</div>
|
||||
`,
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('inactive', style({ opacity: 0 })),
|
||||
state('active', style({ opacity: 1 })),
|
||||
state('removed', style({ opacity: 0 })),
|
||||
transition(
|
||||
'inactive => active',
|
||||
animate('{{ easeTime }}ms {{ easing }}')
|
||||
),
|
||||
transition(
|
||||
'active => removed',
|
||||
animate('{{ easeTime }}ms {{ easing }}')
|
||||
),
|
||||
]),
|
||||
],
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class BitwardenToast extends BaseToast {
|
||||
constructor(protected toastrService: ToastrService, public toastPackage: ToastPackage) {
|
||||
super(toastrService, toastPackage);
|
||||
}
|
||||
}
|
||||
|
||||
export const BitwardenToastGlobalConfig: GlobalConfig = {
|
||||
...DefaultNoComponentGlobalConfig,
|
||||
toastComponent: BitwardenToast,
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [BitwardenToast],
|
||||
exports: [BitwardenToast],
|
||||
})
|
||||
export class BitwardenToastModule {
|
||||
static forRoot(config: Partial<GlobalConfig> = {}): ModuleWithProviders<BitwardenToastModule> {
|
||||
return {
|
||||
ngModule: BitwardenToastModule,
|
||||
providers: [
|
||||
{
|
||||
provide: TOAST_CONFIG,
|
||||
useValue: {
|
||||
default: BitwardenToastGlobalConfig,
|
||||
config: config,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
@@ -57,7 +58,8 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
||||
protected i18nService: I18nService, protected apiService: ApiService,
|
||||
protected platformUtilsService: PlatformUtilsService, protected win: Window,
|
||||
protected environmentService: EnvironmentService, protected stateService: StateService,
|
||||
protected storageService: StorageService, protected route: ActivatedRoute) {
|
||||
protected storageService: StorageService, protected route: ActivatedRoute,
|
||||
protected logService: LogService) {
|
||||
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
|
||||
}
|
||||
|
||||
@@ -209,14 +211,18 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
try {
|
||||
const request = new TwoFactorEmailRequest(this.authService.email, this.authService.masterPasswordHash);
|
||||
const request = new TwoFactorEmailRequest();
|
||||
request.email = this.authService.email;
|
||||
request.masterPasswordHash = this.authService.masterPasswordHash;
|
||||
this.emailPromise = this.apiService.postTwoFactorEmail(request);
|
||||
await this.emailPromise;
|
||||
if (doToast) {
|
||||
this.platformUtilsService.showToast('success', null,
|
||||
this.i18nService.t('verificationCodeEmailSent', this.twoFactorEmail));
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
this.emailPromise = null;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ import { Directive } from '@angular/core';
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
import { ChangePasswordComponent as BaseChangePasswordComponent } from './change-password.component';
|
||||
@@ -29,11 +31,17 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
|
||||
passwordGenerationService: PasswordGenerationService, policyService: PolicyService,
|
||||
cryptoService: CryptoService, userService: UserService,
|
||||
messagingService: MessagingService, private apiService: ApiService) {
|
||||
messagingService: MessagingService, private apiService: ApiService,
|
||||
private syncService: SyncService, private logService: LogService) {
|
||||
super(i18nService, cryptoService, messagingService, userService, passwordGenerationService,
|
||||
platformUtilsService, policyService);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.syncService.fullSync(true);
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
|
||||
@@ -70,7 +78,9 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey);
|
||||
|
||||
await this.performSubmitActions(newPasswordHash, newKey, newEncKey);
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
|
||||
@@ -92,6 +102,8 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
} else {
|
||||
this.messagingService.send('logout');
|
||||
}
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
angular/src/components/verify-master-password.component.html
Normal file
25
angular/src/components/verify-master-password.component.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<ng-container *ngIf="!usesKeyConnector">
|
||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
||||
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control"
|
||||
[formControl]="secret" required appAutofocus appInputVerbatim>
|
||||
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="usesKeyConnector">
|
||||
<div class="form-group">
|
||||
<label class="d-block">{{'sendVerificationCode' | i18n}}</label>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="requestOTP()" [disabled]="disableRequestOTP">
|
||||
{{'sendCode' | i18n}}
|
||||
</button>
|
||||
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
|
||||
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
|
||||
{{'codeSent' | i18n}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="verificationCode">{{'verificationCode' | i18n}}</label>
|
||||
<input id="verificationCode" type="input" name="verificationCode" class="form-control"
|
||||
[formControl]="secret" required appAutofocus appInputVerbatim>
|
||||
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
105
angular/src/components/verify-master-password.component.ts
Normal file
105
angular/src/components/verify-master-password.component.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
animate,
|
||||
style,
|
||||
transition,
|
||||
trigger,
|
||||
} from '@angular/animations';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormControl,
|
||||
NG_VALUE_ACCESSOR,
|
||||
} from '@angular/forms';
|
||||
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
|
||||
|
||||
import { VerificationType } from 'jslib-common/enums/verificationType';
|
||||
|
||||
import { Verification } from 'jslib-common/types/verification';
|
||||
|
||||
@Component({
|
||||
selector: 'app-verify-master-password',
|
||||
templateUrl: 'verify-master-password.component.html',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
multi: true,
|
||||
useExisting: VerifyMasterPasswordComponent,
|
||||
},
|
||||
],
|
||||
animations: [
|
||||
trigger('sent', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate('100ms', style({ opacity: 1 })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class VerifyMasterPasswordComponent implements ControlValueAccessor, OnInit {
|
||||
usesKeyConnector: boolean = false;
|
||||
disableRequestOTP: boolean = false;
|
||||
sentCode: boolean = false;
|
||||
|
||||
secret = new FormControl('');
|
||||
|
||||
private onChange: (value: Verification) => void;
|
||||
|
||||
constructor(private keyConnectorService: KeyConnectorService,
|
||||
private userVerificationService: UserVerificationService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
||||
this.processChanges(this.secret.value);
|
||||
|
||||
this.secret.valueChanges.subscribe(secret => this.processChanges(secret));
|
||||
}
|
||||
|
||||
async requestOTP() {
|
||||
if (this.usesKeyConnector) {
|
||||
this.disableRequestOTP = true;
|
||||
try {
|
||||
await this.userVerificationService.requestOTP();
|
||||
this.sentCode = true;
|
||||
} finally {
|
||||
this.disableRequestOTP = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeValue(obj: any): void {
|
||||
this.secret.setValue(obj);
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disableRequestOTP = isDisabled;
|
||||
if (isDisabled) {
|
||||
this.secret.disable();
|
||||
} else {
|
||||
this.secret.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private processChanges(secret: string) {
|
||||
if (this.onChange == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onChange({
|
||||
type: this.usesKeyConnector ? VerificationType.OTP : VerificationType.MasterPassword,
|
||||
secret: secret,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { TokenService } from 'jslib-common/abstractions/token.service';
|
||||
@@ -31,7 +32,6 @@ import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
|
||||
|
||||
import { AttachmentView } from 'jslib-common/models/view/attachmentView';
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { FieldView } from 'jslib-common/models/view/fieldView';
|
||||
import { LoginUriView } from 'jslib-common/models/view/loginUriView';
|
||||
|
||||
const BroadcasterSubscriptionId = 'ViewComponent';
|
||||
@@ -69,7 +69,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
protected broadcasterService: BroadcasterService, protected ngZone: NgZone,
|
||||
protected changeDetectorRef: ChangeDetectorRef, protected userService: UserService,
|
||||
protected eventService: EventService, protected apiService: ApiService,
|
||||
protected passwordRepromptService: PasswordRepromptService) { }
|
||||
protected passwordRepromptService: PasswordRepromptService, private logService: LogService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
@@ -159,7 +159,9 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
this.platformUtilsService.showToast('success', null,
|
||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
|
||||
this.onDeletedCipher.emit(this.cipher);
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -180,7 +182,9 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
await this.restoreCipher();
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('restoredItem'));
|
||||
this.onRestoredCipher.emit(this.cipher);
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
NgZone,
|
||||
} from '@angular/core';
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@Directive({
|
||||
@@ -16,11 +19,15 @@ export class AutofocusDirective {
|
||||
|
||||
private autofocus: boolean;
|
||||
|
||||
constructor(private el: ElementRef) { }
|
||||
constructor(private el: ElementRef, private ngZone: NgZone) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (!Utils.isMobileBrowser && this.autofocus) {
|
||||
this.el.nativeElement.focus();
|
||||
if (this.ngZone.isStable) {
|
||||
this.el.nativeElement.focus();
|
||||
} else {
|
||||
this.ngZone.onStable.pipe(take(1)).subscribe(() => this.el.nativeElement.focus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
@@ -13,7 +14,7 @@ import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.serv
|
||||
@Injectable()
|
||||
export class AuthGuardService implements CanActivate {
|
||||
constructor(private vaultTimeoutService: VaultTimeoutService, private userService: UserService,
|
||||
private router: Router, private messagingService: MessagingService) { }
|
||||
private router: Router, private messagingService: MessagingService, private keyConnectorService: KeyConnectorService) { }
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
||||
const isAuthed = await this.userService.isAuthenticated();
|
||||
@@ -31,6 +32,11 @@ export class AuthGuardService implements CanActivate {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!routerState.url.includes('remove-password') && await this.keyConnectorService.getConvertAccountRequired()) {
|
||||
this.router.navigate(['/remove-password']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
391
angular/src/services/jslib-services.module.ts
Normal file
391
angular/src/services/jslib-services.module.ts
Normal file
@@ -0,0 +1,391 @@
|
||||
import {
|
||||
Injector,
|
||||
LOCALE_ID,
|
||||
NgModule,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/services/api.service';
|
||||
import { AppIdService } from 'jslib-common/services/appId.service';
|
||||
import { AuditService } from 'jslib-common/services/audit.service';
|
||||
import { AuthService } from 'jslib-common/services/auth.service';
|
||||
import { CipherService } from 'jslib-common/services/cipher.service';
|
||||
import { CollectionService } from 'jslib-common/services/collection.service';
|
||||
import { ConsoleLogService } from 'jslib-common/services/consoleLog.service';
|
||||
import { CryptoService } from 'jslib-common/services/crypto.service';
|
||||
import { EnvironmentService } from 'jslib-common/services/environment.service';
|
||||
import { EventService } from 'jslib-common/services/event.service';
|
||||
import { ExportService } from 'jslib-common/services/export.service';
|
||||
import { FileUploadService } from 'jslib-common/services/fileUpload.service';
|
||||
import { FolderService } from 'jslib-common/services/folder.service';
|
||||
import { KeyConnectorService } from 'jslib-common/services/keyConnector.service';
|
||||
import { NotificationsService } from 'jslib-common/services/notifications.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/services/passwordGeneration.service';
|
||||
import { PolicyService } from 'jslib-common/services/policy.service';
|
||||
import { SearchService } from 'jslib-common/services/search.service';
|
||||
import { SendService } from 'jslib-common/services/send.service';
|
||||
import { SettingsService } from 'jslib-common/services/settings.service';
|
||||
import { StateService } from 'jslib-common/services/state.service';
|
||||
import { SyncService } from 'jslib-common/services/sync.service';
|
||||
import { TokenService } from 'jslib-common/services/token.service';
|
||||
import { TotpService } from 'jslib-common/services/totp.service';
|
||||
import { UserService } from 'jslib-common/services/user.service';
|
||||
import { UserVerificationService } from 'jslib-common/services/userVerification.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/services/vaultTimeout.service';
|
||||
import { WebCryptoFunctionService } from 'jslib-common/services/webCryptoFunction.service';
|
||||
|
||||
import { ApiService as ApiServiceAbstraction } from 'jslib-common/abstractions/api.service';
|
||||
import { AppIdService as AppIdServiceAbstraction } from 'jslib-common/abstractions/appId.service';
|
||||
import { AuditService as AuditServiceAbstraction } from 'jslib-common/abstractions/audit.service';
|
||||
import { AuthService as AuthServiceAbstraction } from 'jslib-common/abstractions/auth.service';
|
||||
import { BroadcasterService as BroadcasterServiceAbstraction } from 'jslib-common/abstractions/broadcaster.service';
|
||||
import { CipherService as CipherServiceAbstraction } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CollectionService as CollectionServiceAbstraction } from 'jslib-common/abstractions/collection.service';
|
||||
import { CryptoService as CryptoServiceAbstraction } from 'jslib-common/abstractions/crypto.service';
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { EnvironmentService as EnvironmentServiceAbstraction, Urls } from 'jslib-common/abstractions/environment.service';
|
||||
import { EventService as EventServiceAbstraction } from 'jslib-common/abstractions/event.service';
|
||||
import { ExportService as ExportServiceAbstraction } from 'jslib-common/abstractions/export.service';
|
||||
import { FileUploadService as FileUploadServiceAbstraction } from 'jslib-common/abstractions/fileUpload.service';
|
||||
import { FolderService as FolderServiceAbstraction } from 'jslib-common/abstractions/folder.service';
|
||||
import { I18nService as I18nServiceAbstraction } from 'jslib-common/abstractions/i18n.service';
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService as MessagingServiceAbstraction } from 'jslib-common/abstractions/messaging.service';
|
||||
import { NotificationsService as NotificationsServiceAbstraction } from 'jslib-common/abstractions/notifications.service';
|
||||
import {
|
||||
PasswordGenerationService as PasswordGenerationServiceAbstraction,
|
||||
} from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
|
||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService as PolicyServiceAbstraction } from 'jslib-common/abstractions/policy.service';
|
||||
import { SearchService as SearchServiceAbstraction } from 'jslib-common/abstractions/search.service';
|
||||
import { SendService as SendServiceAbstraction } from 'jslib-common/abstractions/send.service';
|
||||
import { SettingsService as SettingsServiceAbstraction } from 'jslib-common/abstractions/settings.service';
|
||||
import { StateService as StateServiceAbstraction } from 'jslib-common/abstractions/state.service';
|
||||
import { StorageService as StorageServiceAbstraction } from 'jslib-common/abstractions/storage.service';
|
||||
import { SyncService as SyncServiceAbstraction } from 'jslib-common/abstractions/sync.service';
|
||||
import { TokenService as TokenServiceAbstraction } from 'jslib-common/abstractions/token.service';
|
||||
import { TotpService as TotpServiceAbstraction } from 'jslib-common/abstractions/totp.service';
|
||||
import { UserService as UserServiceAbstraction } from 'jslib-common/abstractions/user.service';
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from 'jslib-common/abstractions/userVerification.service';
|
||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
|
||||
import { AuthGuardService } from './auth-guard.service';
|
||||
import { BroadcasterService } from './broadcaster.service';
|
||||
import { LockGuardService } from './lock-guard.service';
|
||||
import { ModalService } from './modal.service';
|
||||
import { PasswordRepromptService } from './passwordReprompt.service';
|
||||
import { UnauthGuardService } from './unauth-guard.service';
|
||||
import { ValidationService } from './validation.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
providers: [
|
||||
{ provide: 'WINDOW', useValue: window },
|
||||
{
|
||||
provide: LOCALE_ID,
|
||||
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
||||
deps: [I18nServiceAbstraction],
|
||||
},
|
||||
ValidationService,
|
||||
AuthGuardService,
|
||||
UnauthGuardService,
|
||||
LockGuardService,
|
||||
ModalService,
|
||||
{
|
||||
provide: AppIdServiceAbstraction,
|
||||
useClass: AppIdService,
|
||||
deps: [StorageServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: AuditServiceAbstraction,
|
||||
useClass: AuditService,
|
||||
deps: [CryptoFunctionServiceAbstraction, ApiServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: AuthServiceAbstraction,
|
||||
useClass: AuthService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
VaultTimeoutServiceAbstraction,
|
||||
LogService,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
KeyConnectorServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: CipherServiceAbstraction,
|
||||
useFactory: (cryptoService: CryptoServiceAbstraction, userService: UserServiceAbstraction,
|
||||
settingsService: SettingsServiceAbstraction, apiService: ApiServiceAbstraction,
|
||||
fileUploadService: FileUploadServiceAbstraction, storageService: StorageServiceAbstraction,
|
||||
i18nService: I18nServiceAbstraction, injector: Injector, logService: LogService) =>
|
||||
new CipherService(cryptoService, userService, settingsService, apiService, fileUploadService,
|
||||
storageService, i18nService, () => injector.get(SearchServiceAbstraction), logService),
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
SettingsServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
FileUploadServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
Injector, // TODO: Get rid of this circular dependency!
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: FolderServiceAbstraction,
|
||||
useClass: FolderService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
CipherServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{ provide: LogService, useFactory: () => new ConsoleLogService(false) },
|
||||
{
|
||||
provide: CollectionServiceAbstraction,
|
||||
useClass: CollectionService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: EnvironmentServiceAbstraction,
|
||||
useClass: EnvironmentService,
|
||||
deps: [StorageServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: TotpServiceAbstraction,
|
||||
useClass: TotpService,
|
||||
deps: [
|
||||
StorageServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StorageServiceAbstraction] },
|
||||
{
|
||||
provide: CryptoServiceAbstraction,
|
||||
useClass: CryptoService,
|
||||
deps: [
|
||||
StorageServiceAbstraction,
|
||||
'SECURE_STORAGE',
|
||||
CryptoFunctionServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: PasswordGenerationServiceAbstraction,
|
||||
useClass: PasswordGenerationService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
PolicyServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: ApiServiceAbstraction,
|
||||
useFactory: (tokenService: TokenServiceAbstraction, platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||
environmentService: EnvironmentServiceAbstraction, messagingService: MessagingServiceAbstraction) =>
|
||||
new ApiService(tokenService, platformUtilsService, environmentService,
|
||||
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
|
||||
deps: [
|
||||
TokenServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: FileUploadServiceAbstraction,
|
||||
useClass: FileUploadService,
|
||||
deps: [
|
||||
LogService,
|
||||
ApiServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: SyncServiceAbstraction,
|
||||
useFactory: (userService: UserServiceAbstraction, apiService: ApiServiceAbstraction,
|
||||
settingsService: SettingsServiceAbstraction, folderService: FolderServiceAbstraction,
|
||||
cipherService: CipherServiceAbstraction, cryptoService: CryptoServiceAbstraction,
|
||||
collectionService: CollectionServiceAbstraction, storageService: StorageServiceAbstraction,
|
||||
messagingService: MessagingServiceAbstraction, policyService: PolicyServiceAbstraction,
|
||||
sendService: SendServiceAbstraction, logService: LogService, tokenService: TokenService,
|
||||
keyConnectorService: KeyConnectorServiceAbstraction) => new SyncService(userService, apiService,
|
||||
settingsService, folderService, cipherService, cryptoService, collectionService, storageService,
|
||||
messagingService, policyService, sendService, logService, tokenService, keyConnectorService,
|
||||
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
|
||||
deps: [
|
||||
UserServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
SettingsServiceAbstraction,
|
||||
FolderServiceAbstraction,
|
||||
CipherServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
CollectionServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
PolicyServiceAbstraction,
|
||||
SendServiceAbstraction,
|
||||
LogService,
|
||||
TokenServiceAbstraction,
|
||||
KeyConnectorServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: UserServiceAbstraction,
|
||||
useClass: UserService,
|
||||
deps: [TokenServiceAbstraction, StorageServiceAbstraction],
|
||||
},
|
||||
{ provide: BroadcasterServiceAbstraction, useClass: BroadcasterService },
|
||||
{
|
||||
provide: SettingsServiceAbstraction,
|
||||
useClass: SettingsService,
|
||||
deps: [UserServiceAbstraction, StorageServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: VaultTimeoutServiceAbstraction,
|
||||
useFactory: (cipherService: CipherServiceAbstraction, folderService: FolderServiceAbstraction,
|
||||
collectionService: CollectionServiceAbstraction, cryptoService: CryptoServiceAbstraction,
|
||||
platformUtilsService: PlatformUtilsServiceAbstraction, storageService: StorageServiceAbstraction,
|
||||
messagingService: MessagingServiceAbstraction, searchService: SearchServiceAbstraction,
|
||||
userService: UserServiceAbstraction, tokenService: TokenServiceAbstraction,
|
||||
policyService: PolicyServiceAbstraction, keyConnectorService: KeyConnectorServiceAbstraction) =>
|
||||
new VaultTimeoutService(cipherService, folderService, collectionService, cryptoService,
|
||||
platformUtilsService, storageService, messagingService, searchService, userService, tokenService,
|
||||
policyService, keyConnectorService, null,
|
||||
async () => messagingService.send('logout', { expired: false })),
|
||||
deps: [
|
||||
CipherServiceAbstraction,
|
||||
FolderServiceAbstraction,
|
||||
CollectionServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
SearchServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
PolicyServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{ provide: StateServiceAbstraction, useClass: StateService },
|
||||
{
|
||||
provide: ExportServiceAbstraction,
|
||||
useClass: ExportService,
|
||||
deps: [
|
||||
FolderServiceAbstraction,
|
||||
CipherServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: SearchServiceAbstraction,
|
||||
useClass: SearchService,
|
||||
deps: [
|
||||
CipherServiceAbstraction,
|
||||
LogService,
|
||||
I18nServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: NotificationsServiceAbstraction,
|
||||
useFactory: (userService: UserServiceAbstraction, syncService: SyncServiceAbstraction,
|
||||
appIdService: AppIdServiceAbstraction, apiService: ApiServiceAbstraction,
|
||||
vaultTimeoutService: VaultTimeoutServiceAbstraction, environmentService: EnvironmentServiceAbstraction,
|
||||
messagingService: MessagingServiceAbstraction, logService: LogService) =>
|
||||
new NotificationsService(userService, syncService, appIdService, apiService, vaultTimeoutService,
|
||||
environmentService, async () => messagingService.send('logout', { expired: true }), logService),
|
||||
deps: [
|
||||
UserServiceAbstraction,
|
||||
SyncServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
VaultTimeoutServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: CryptoFunctionServiceAbstraction,
|
||||
useClass: WebCryptoFunctionService,
|
||||
deps: ['WINDOW', PlatformUtilsServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: EventServiceAbstraction,
|
||||
useClass: EventService,
|
||||
deps: [
|
||||
StorageServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
CipherServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: PolicyServiceAbstraction,
|
||||
useClass: PolicyService,
|
||||
deps: [
|
||||
UserServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: SendServiceAbstraction,
|
||||
useClass: SendService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
FileUploadServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: KeyConnectorServiceAbstraction,
|
||||
useClass: KeyConnectorService,
|
||||
deps: [
|
||||
StorageServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: UserVerificationServiceAbstraction,
|
||||
useClass: UserVerificationService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
||||
],
|
||||
})
|
||||
export class JslibServicesModule {
|
||||
}
|
||||
@@ -22,19 +22,32 @@ export class ModalConfig<D = any> {
|
||||
|
||||
@Injectable()
|
||||
export class ModalService {
|
||||
protected modalCount = 0;
|
||||
protected modalList: ComponentRef<DynamicModalComponent>[] = [];
|
||||
|
||||
// Lazy loaded modules are not available in componentFactoryResolver,
|
||||
// therefore modules needs to manually initialize their resolvers.
|
||||
private factoryResolvers: Map<Type<any>, ComponentFactoryResolver> = new Map();
|
||||
|
||||
constructor(private componentFactoryResolver: ComponentFactoryResolver, private applicationRef: ApplicationRef,
|
||||
private injector: Injector) {}
|
||||
private injector: Injector) {
|
||||
document.addEventListener('keyup', event => {
|
||||
if (event.key === 'Escape' && this.modalCount > 0) {
|
||||
this.topModal.instance.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get modalCount() {
|
||||
return this.modalList.length;
|
||||
}
|
||||
|
||||
private get topModal() {
|
||||
return this.modalList[this.modalCount - 1];
|
||||
}
|
||||
|
||||
async openViewRef<T>(componentType: Type<T>, viewContainerRef: ViewContainerRef,
|
||||
setComponentParameters: (component: T) => void = null): Promise<[ModalRef, T]> {
|
||||
|
||||
this.modalCount++;
|
||||
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
|
||||
modalComponentRef.instance.setComponentParameters = setComponentParameters;
|
||||
|
||||
@@ -49,7 +62,6 @@ export class ModalService {
|
||||
if (!(config?.allowMultipleModals ?? false) && this.modalCount > 0) {
|
||||
return;
|
||||
}
|
||||
this.modalCount++;
|
||||
|
||||
const [modalRef, _] = this.openInternal(componentType, config, true);
|
||||
|
||||
@@ -85,11 +97,17 @@ export class ModalService {
|
||||
this.applicationRef.detachView(componentRef.hostView);
|
||||
}
|
||||
componentRef.destroy();
|
||||
this.modalCount--;
|
||||
|
||||
this.modalList.pop();
|
||||
if (this.modalCount > 0) {
|
||||
this.topModal.instance.getFocus();
|
||||
}
|
||||
});
|
||||
|
||||
this.setupHandlers(modalRef);
|
||||
|
||||
this.modalList.push(componentRef);
|
||||
|
||||
return [modalRef, componentRef];
|
||||
}
|
||||
|
||||
@@ -100,19 +118,20 @@ export class ModalService {
|
||||
modalRef.onCreated.pipe(first()).subscribe(el => {
|
||||
document.body.classList.add('modal-open');
|
||||
|
||||
const modalEl: HTMLElement = el.querySelector('.modal');
|
||||
const dialogEl = modalEl.querySelector('.modal-dialog') as HTMLElement;
|
||||
|
||||
backdrop = document.createElement('div');
|
||||
backdrop.className = 'modal-backdrop fade';
|
||||
backdrop.style.zIndex = `${this.modalCount}040`;
|
||||
document.body.appendChild(backdrop);
|
||||
modalEl.prepend(backdrop);
|
||||
|
||||
el.querySelector('.modal-dialog').addEventListener('click', (e: Event) => {
|
||||
dialogEl.addEventListener('click', (e: Event) => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
dialogEl.style.zIndex = `${this.modalCount}050`;
|
||||
|
||||
const modalEl: HTMLElement = el.querySelector('.modal');
|
||||
modalEl.style.zIndex = `${this.modalCount}050`;
|
||||
|
||||
const modals = Array.from(el.querySelectorAll('.modal, .modal *[data-dismiss="modal"]'));
|
||||
const modals = Array.from(el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]'));
|
||||
for (const closeElement of modals) {
|
||||
closeElement.addEventListener('click', event => {
|
||||
modalRef.close();
|
||||
@@ -127,10 +146,6 @@ export class ModalService {
|
||||
if (this.modalCount === 0) {
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
if (backdrop != null) {
|
||||
document.body.removeChild(backdrop);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
|
||||
|
||||
import { PasswordRepromptComponent } from '../components/password-reprompt.component';
|
||||
@@ -9,13 +10,17 @@ import { ModalService } from './modal.service';
|
||||
export class PasswordRepromptService implements PasswordRepromptServiceAbstraction {
|
||||
protected component = PasswordRepromptComponent;
|
||||
|
||||
constructor(private modalService: ModalService) { }
|
||||
constructor(private modalService: ModalService, private keyConnectorService: KeyConnectorService) { }
|
||||
|
||||
protectedFields() {
|
||||
return ['TOTP', 'Password', 'H_Field', 'Card Number', 'Security Code'];
|
||||
}
|
||||
|
||||
async showPasswordPrompt() {
|
||||
if (!await this.enabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ref = this.modalService.open(this.component, {allowMultipleModals: true});
|
||||
|
||||
if (ref == null) {
|
||||
@@ -25,4 +30,8 @@ export class PasswordRepromptService implements PasswordRepromptServiceAbstracti
|
||||
const result = await ref.onClosedPromise();
|
||||
return result === true;
|
||||
}
|
||||
|
||||
async enabled() {
|
||||
return !await this.keyConnectorService.getUsesKeyConnector();
|
||||
}
|
||||
}
|
||||
|
||||
941
common/package-lock.json
generated
941
common/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -27,17 +27,17 @@
|
||||
"@types/tldjs": "^2.3.0",
|
||||
"@types/zxcvbn": "^4.4.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "4.1.5"
|
||||
"typescript": "4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/signalr": "3.1.13",
|
||||
"@microsoft/signalr-protocol-msgpack": "3.1.13",
|
||||
"@microsoft/signalr": "5.0.10",
|
||||
"@microsoft/signalr-protocol-msgpack": "5.0.10",
|
||||
"big-integer": "1.6.48",
|
||||
"browser-hrtime": "^1.1.8",
|
||||
"lunr": "^2.3.9",
|
||||
"node-forge": "^0.10.0",
|
||||
"papaparse": "^5.3.0",
|
||||
"rxjs": "6.6.7",
|
||||
"rxjs": "^7.4.0",
|
||||
"tldjs": "^2.3.1",
|
||||
"zxcvbn": "^4.4.2"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PolicyType } from '../enums/policyType';
|
||||
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
|
||||
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
|
||||
|
||||
import { EnvironmentUrls } from '../models/domain/environmentUrls';
|
||||
import { AttachmentRequest } from '../models/request/attachmentRequest';
|
||||
|
||||
import { BitPayInvoiceRequest } from '../models/request/bitPayInvoiceRequest';
|
||||
@@ -29,7 +30,11 @@ import { ImportCiphersRequest } from '../models/request/importCiphersRequest';
|
||||
import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest';
|
||||
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
|
||||
import { KdfRequest } from '../models/request/kdfRequest';
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
import { KeysRequest } from '../models/request/keysRequest';
|
||||
import { OrganizationSponsorshipCreateRequest } from '../models/request/organization/organizationSponsorshipCreateRequest';
|
||||
import { OrganizationSponsorshipRedeemRequest } from '../models/request/organization/organizationSponsorshipRedeemRequest';
|
||||
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
|
||||
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
|
||||
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
|
||||
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
|
||||
@@ -48,7 +53,6 @@ import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizat
|
||||
import { OrganizationUserUpdateRequest } from '../models/request/organizationUserUpdateRequest';
|
||||
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
||||
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
||||
import { PolicyRequest } from '../models/request/policyRequest';
|
||||
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||
@@ -64,6 +68,7 @@ import { ProviderUserInviteRequest } from '../models/request/provider/providerUs
|
||||
import { ProviderUserUpdateRequest } from '../models/request/provider/providerUserUpdateRequest';
|
||||
import { RegisterRequest } from '../models/request/registerRequest';
|
||||
import { SeatRequest } from '../models/request/seatRequest';
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
|
||||
import { SendAccessRequest } from '../models/request/sendAccessRequest';
|
||||
import { SendRequest } from '../models/request/sendRequest';
|
||||
@@ -114,7 +119,9 @@ import {
|
||||
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
|
||||
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
|
||||
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
|
||||
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
|
||||
import { ListResponse } from '../models/response/listResponse';
|
||||
import { OrganizationSsoResponse } from '../models/response/organization/organizationSsoResponse';
|
||||
import { OrganizationAutoEnrollStatusResponse } from '../models/response/organizationAutoEnrollStatusResponse';
|
||||
import { OrganizationKeysResponse } from '../models/response/organizationKeysResponse';
|
||||
import { OrganizationResponse } from '../models/response/organizationResponse';
|
||||
@@ -171,8 +178,9 @@ export abstract class ApiService {
|
||||
postEmail: (request: EmailRequest) => Promise<any>;
|
||||
postPassword: (request: PasswordRequest) => Promise<any>;
|
||||
setPassword: (request: SetPasswordRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: SecretVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: SecretVerificationRequest) => Promise<any>;
|
||||
getAccountRevisionDate: () => Promise<number>;
|
||||
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
|
||||
postRegister: (request: RegisterRequest) => Promise<any>;
|
||||
@@ -187,14 +195,16 @@ export abstract class ApiService {
|
||||
postAccountKeys: (request: KeysRequest) => Promise<any>;
|
||||
postAccountVerifyEmail: () => Promise<any>;
|
||||
postAccountVerifyEmailToken: (request: VerifyEmailRequest) => Promise<any>;
|
||||
postAccountVerifyPassword: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
postAccountVerifyPassword: (request: SecretVerificationRequest) => Promise<any>;
|
||||
postAccountRecoverDelete: (request: DeleteRecoverRequest) => Promise<any>;
|
||||
postAccountRecoverDeleteToken: (request: VerifyDeleteRecoverRequest) => Promise<any>;
|
||||
postAccountKdf: (request: KdfRequest) => Promise<any>;
|
||||
getEnterprisePortalSignInToken: () => Promise<string>;
|
||||
postUserApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserRotateApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
||||
postAccountRequestOTP: () => Promise<void>;
|
||||
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
||||
postConvertToKeyConnector: () => Promise<void>;
|
||||
|
||||
getFolder: (id: string) => Promise<FolderResponse>;
|
||||
postFolder: (request: FolderRequest) => Promise<FolderResponse>;
|
||||
@@ -236,7 +246,7 @@ export abstract class ApiService {
|
||||
putShareCiphers: (request: CipherBulkShareRequest) => Promise<any>;
|
||||
putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
postPurgeCiphers: (request: PasswordVerificationRequest, organizationId?: string) => Promise<any>;
|
||||
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
|
||||
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
|
||||
postImportOrganizationCiphers: (organizationId: string, request: ImportOrganizationCiphersRequest) => Promise<any>;
|
||||
putDeleteCipher: (id: string) => Promise<any>;
|
||||
@@ -325,15 +335,15 @@ export abstract class ApiService {
|
||||
|
||||
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorOrganizationProviders: (organizationId: string) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorAuthenticator: (request: PasswordVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
getTwoFactorEmail: (request: PasswordVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||
getTwoFactorDuo: (request: PasswordVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorAuthenticator: (request: SecretVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorOrganizationDuo: (organizationId: string,
|
||||
request: PasswordVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorYubiKey: (request: PasswordVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||
getTwoFactorWebAuthn: (request: PasswordVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||
getTwoFactorWebAuthnChallenge: (request: PasswordVerificationRequest) => Promise<ChallengeResponse>;
|
||||
getTwoFactorRecover: (request: PasswordVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||
request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
||||
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||
putTwoFactorAuthenticator: (
|
||||
request: UpdateTwoFactorAuthenticatorRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
||||
@@ -373,14 +383,16 @@ export abstract class ApiService {
|
||||
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
|
||||
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
|
||||
getOrganizationAutoEnrollStatus: (identifier: string) => Promise<OrganizationAutoEnrollStatusResponse>;
|
||||
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
|
||||
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
|
||||
putOrganization: (id: string, request: OrganizationUpdateRequest) => Promise<OrganizationResponse>;
|
||||
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
|
||||
postLeaveOrganization: (id: string) => Promise<any>;
|
||||
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
||||
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
||||
postOrganizationApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationRotateApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
|
||||
postOrganizationUpgrade: (id: string, request: OrganizationUpgradeRequest) => Promise<PaymentResponse>;
|
||||
postOrganizationUpdateSubscription: (id: string, request: OrganizationSubscriptionUpdateRequest) => Promise<void>;
|
||||
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
|
||||
@@ -389,7 +401,7 @@ export abstract class ApiService {
|
||||
postOrganizationVerifyBank: (id: string, request: VerifyBankRequest) => Promise<any>;
|
||||
postOrganizationCancel: (id: string) => Promise<any>;
|
||||
postOrganizationReinstate: (id: string) => Promise<any>;
|
||||
deleteOrganization: (id: string, request: PasswordVerificationRequest) => Promise<any>;
|
||||
deleteOrganization: (id: string, request: SecretVerificationRequest) => Promise<any>;
|
||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
||||
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
||||
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
|
||||
@@ -442,4 +454,15 @@ export abstract class ApiService {
|
||||
nativeFetch: (request: Request) => Promise<Response>;
|
||||
|
||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
||||
|
||||
postCreateSponsorship: (sponsorshipOrgId: string, request: OrganizationSponsorshipCreateRequest) => Promise<void>;
|
||||
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
||||
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
||||
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
|
||||
postRedeemSponsorship: (sponsorshipToken: string, request: OrganizationSponsorshipRedeemRequest) => Promise<void>;
|
||||
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
||||
|
||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
||||
postUserKeyToKeyConnector: (keyConnectorUrl: string, request: KeyConnectorUserKeyRequest) => Promise<void>;
|
||||
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export abstract class AuthService {
|
||||
selectedTwoFactorProviderType: TwoFactorProviderType;
|
||||
|
||||
logIn: (email: string, masterPassword: string, captchaToken?: string) => Promise<AuthResult>;
|
||||
logInSso: (code: string, codeVerifier: string, redirectUrl: string) => Promise<AuthResult>;
|
||||
logInSso: (code: string, codeVerifier: string, redirectUrl: string, orgId: string) => Promise<AuthResult>;
|
||||
logInApiKey: (clientId: string, clientSecret: string) => Promise<AuthResult>;
|
||||
logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
|
||||
remember?: boolean) => Promise<AuthResult>;
|
||||
|
||||
@@ -8,7 +8,7 @@ export type Urls = {
|
||||
icons?: string;
|
||||
notifications?: string;
|
||||
events?: string;
|
||||
enterprise?: string;
|
||||
keyConnector?: string;
|
||||
};
|
||||
|
||||
export type PayPalConfig = {
|
||||
@@ -21,13 +21,13 @@ export abstract class EnvironmentService {
|
||||
|
||||
hasBaseUrl: () => boolean;
|
||||
getNotificationsUrl: () => string;
|
||||
getEnterpriseUrl: () => string;
|
||||
getWebVaultUrl: () => string;
|
||||
getSendUrl: () => string;
|
||||
getIconsUrl: () => string;
|
||||
getApiUrl: () => string;
|
||||
getIdentityUrl: () => string;
|
||||
getEventsUrl: () => string;
|
||||
getKeyConnectorUrl: () => string;
|
||||
setUrlsFromStorage: () => Promise<void>;
|
||||
setUrls: (urls: any, saveSettings?: boolean) => Promise<Urls>;
|
||||
getUrls: () => Urls;
|
||||
|
||||
14
common/src/abstractions/keyConnector.service.ts
Normal file
14
common/src/abstractions/keyConnector.service.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Organization } from '../models/domain/organization';
|
||||
|
||||
export abstract class KeyConnectorService {
|
||||
getAndSetKey: (url?: string) => Promise<void>;
|
||||
getManagingOrganization: () => Promise<Organization>;
|
||||
getUsesKeyConnector: () => Promise<boolean>;
|
||||
migrateUser: () => Promise<void>;
|
||||
userNeedsMigration: () => Promise<boolean>;
|
||||
setUsesKeyConnector: (enabled: boolean) => Promise<void>;
|
||||
setConvertAccountRequired: (status: boolean) => Promise<void>;
|
||||
getConvertAccountRequired: () => Promise<boolean>;
|
||||
removeConvertAccountRequired: () => Promise<void>;
|
||||
clear: () => Promise<void>;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export abstract class PasswordRepromptService {
|
||||
protectedFields: () => string[];
|
||||
showPasswordPrompt: () => Promise<boolean>;
|
||||
enabled: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { DeviceType } from '../enums/deviceType';
|
||||
import { ThemeType } from '../enums/themeType';
|
||||
|
||||
interface ToastOptions {
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export abstract class PlatformUtilsService {
|
||||
identityClientId: string;
|
||||
@@ -19,7 +24,7 @@ export abstract class PlatformUtilsService {
|
||||
supportsWebAuthn: (win: Window) => boolean;
|
||||
supportsDuo: () => boolean;
|
||||
showToast: (type: 'error' | 'success' | 'warning' | 'info', title: string, text: string | string[],
|
||||
options?: any) => void;
|
||||
options?: ToastOptions) => void;
|
||||
showDialog: (body: string, title?: string, confirmText?: string, cancelText?: string,
|
||||
type?: string, bodyIsHtml?: boolean) => Promise<boolean>;
|
||||
isDev: () => boolean;
|
||||
@@ -28,7 +33,8 @@ export abstract class PlatformUtilsService {
|
||||
readFromClipboard: (options?: any) => Promise<string>;
|
||||
supportsBiometric: () => Promise<boolean>;
|
||||
authenticateBiometric: () => Promise<boolean>;
|
||||
getDefaultSystemTheme: () => Promise<'light' | 'dark'>;
|
||||
onDefaultSystemThemeChange: (callback: ((theme: 'light' | 'dark') => unknown)) => unknown;
|
||||
getDefaultSystemTheme: () => Promise<ThemeType.Light | ThemeType.Dark>;
|
||||
onDefaultSystemThemeChange: (callback: ((theme: ThemeType.Light | ThemeType.Dark) => unknown)) => unknown;
|
||||
getEffectiveTheme: () => Promise<ThemeType>;
|
||||
supportsSecureStorage: () => boolean;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,5 @@ export abstract class TokenService {
|
||||
getName: () => string;
|
||||
getPremium: () => boolean;
|
||||
getIssuer: () => string;
|
||||
getIsExternal: () => boolean;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OrganizationData } from '../models/data/organizationData';
|
||||
import { ProviderData } from '../models/data/providerData';
|
||||
|
||||
import { Organization } from '../models/domain/organization';
|
||||
import { Provider } from '../models/domain/provider';
|
||||
|
||||
@@ -20,6 +21,7 @@ export abstract class UserService {
|
||||
clear: () => Promise<any>;
|
||||
isAuthenticated: () => Promise<boolean>;
|
||||
canAccessPremium: () => Promise<boolean>;
|
||||
canManageSponsorships: () => Promise<boolean>;
|
||||
getOrganization: (id: string) => Promise<Organization>;
|
||||
getOrganizationByIdentifier: (identifier: string) => Promise<Organization>;
|
||||
getAllOrganizations: () => Promise<Organization[]>;
|
||||
|
||||
10
common/src/abstractions/userVerification.service.ts
Normal file
10
common/src/abstractions/userVerification.service.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
|
||||
import { Verification } from '../types/verification';
|
||||
|
||||
export abstract class UserVerificationService {
|
||||
buildRequest: <T extends SecretVerificationRequest> (verification: Verification,
|
||||
requestClass?: new () => T, alreadyHashed?: boolean) => Promise<T>;
|
||||
verifyUser: (verification: Verification) => Promise<boolean>;
|
||||
requestOTP: () => Promise<void>;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ export enum EventType {
|
||||
User_FailedLogIn2fa = 1006,
|
||||
User_ClientExportedVault = 1007,
|
||||
User_UpdatedTempPassword = 1008,
|
||||
User_MigratedKeyToKeyConnector = 1009,
|
||||
|
||||
Cipher_Created = 1100,
|
||||
Cipher_Updated = 1101,
|
||||
@@ -46,11 +47,16 @@ export enum EventType {
|
||||
OrganizationUser_ResetPassword_Withdraw = 1507,
|
||||
OrganizationUser_AdminResetPassword = 1508,
|
||||
OrganizationUser_ResetSsoLink = 1509,
|
||||
OrganizationUser_FirstSsoLogin = 1510,
|
||||
|
||||
Organization_Updated = 1600,
|
||||
Organization_PurgedVault = 1601,
|
||||
// Organization_ClientExportedVault = 1602,
|
||||
Organization_VaultAccessed = 1603,
|
||||
Organization_EnabledSso = 1604,
|
||||
Organization_DisabledSso = 1605,
|
||||
Organization_EnabledKeyConnector = 1606,
|
||||
Organization_DisabledKeyConnector = 1607,
|
||||
|
||||
Policy_Updated = 1700,
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ export enum FieldType {
|
||||
Text = 0,
|
||||
Hidden = 1,
|
||||
Boolean = 2,
|
||||
Linked = 3,
|
||||
}
|
||||
|
||||
40
common/src/enums/linkedIdType.ts
Normal file
40
common/src/enums/linkedIdType.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId;
|
||||
|
||||
// LoginView
|
||||
export enum LoginLinkedId {
|
||||
Username = 100,
|
||||
Password = 101,
|
||||
}
|
||||
|
||||
// CardView
|
||||
export enum CardLinkedId {
|
||||
CardholderName = 300,
|
||||
ExpMonth = 301,
|
||||
ExpYear = 302,
|
||||
Code = 303,
|
||||
Brand = 304,
|
||||
Number = 305,
|
||||
}
|
||||
|
||||
// IdentityView
|
||||
export enum IdentityLinkedId {
|
||||
Title = 400,
|
||||
MiddleName = 401,
|
||||
Address1 = 402,
|
||||
Address2 = 403,
|
||||
Address3 = 404,
|
||||
City = 405,
|
||||
State = 406,
|
||||
PostalCode = 407,
|
||||
Country = 408,
|
||||
Company = 409,
|
||||
Email = 410,
|
||||
Phone = 411,
|
||||
Ssn = 412,
|
||||
Username = 413,
|
||||
PassportNumber = 414,
|
||||
LicenseNumber = 415,
|
||||
FirstName = 416,
|
||||
LastName = 417,
|
||||
FullName = 418,
|
||||
}
|
||||
@@ -1,14 +1,27 @@
|
||||
export enum Permissions {
|
||||
AccessBusinessPortal,
|
||||
AccessEventLogs,
|
||||
AccessImportExport,
|
||||
AccessReports,
|
||||
/**
|
||||
* @deprecated Sep 29 2021: This permission has been split out to `createNewCollections`, `editAnyCollection`, and
|
||||
* `deleteAnyCollection`. It exists here for backwards compatibility with Server versions <= 1.43.0
|
||||
*/
|
||||
ManageAllCollections,
|
||||
/**
|
||||
* @deprecated Sep 29 2021: This permission has been split out to `editAssignedCollections` and
|
||||
* `deleteAssignedCollections`. It exists here for backwards compatibility with Server versions <= 1.43.0
|
||||
*/
|
||||
ManageAssignedCollections,
|
||||
ManageGroups,
|
||||
ManageOrganization,
|
||||
ManageOrganization ,
|
||||
ManagePolicies,
|
||||
ManageProvider,
|
||||
ManageUsers,
|
||||
ManageUsersPassword,
|
||||
CreateNewCollections,
|
||||
EditAnyCollection,
|
||||
DeleteAnyCollection,
|
||||
EditAssignedCollections,
|
||||
DeleteAssignedCollections,
|
||||
ManageSso,
|
||||
}
|
||||
|
||||
3
common/src/enums/planSponsorshipType.ts
Normal file
3
common/src/enums/planSponsorshipType.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export enum PlanSponsorshipType {
|
||||
FamiliesForEnterprise = 0,
|
||||
}
|
||||
7
common/src/enums/themeType.ts
Normal file
7
common/src/enums/themeType.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export enum ThemeType {
|
||||
System = 'system',
|
||||
Light = 'light',
|
||||
Dark = 'dark',
|
||||
Nord = 'nord',
|
||||
SolarizedDark = 'solarizedDark',
|
||||
}
|
||||
4
common/src/enums/verificationType.ts
Normal file
4
common/src/enums/verificationType.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum VerificationType {
|
||||
MasterPassword = 0,
|
||||
OTP = 1,
|
||||
}
|
||||
@@ -88,7 +88,7 @@ export abstract class BaseImporter {
|
||||
}
|
||||
|
||||
protected parseCsv(data: string, header: boolean, options: any = {}): any[] {
|
||||
const parseOptions = Object.assign({ header: header }, this.parseCsvOptions, options);
|
||||
const parseOptions: papa.ParseConfig<string> = Object.assign({ header: header }, this.parseCsvOptions, options);
|
||||
data = this.splitNewLine(data).join('\n').trim();
|
||||
const result = papa.parse(data, parseOptions);
|
||||
if (result.errors != null && result.errors.length > 0) {
|
||||
|
||||
@@ -21,7 +21,9 @@ export class PasspackCsvImporter extends BaseImporter implements Importer {
|
||||
try {
|
||||
const t = JSON.parse(tagJson);
|
||||
return this.getValueOrDefault(t.tag);
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
return null;
|
||||
}).filter((t: string) => !this.isNullOrWhitespace(t)) : null;
|
||||
|
||||
@@ -72,7 +74,9 @@ export class PasspackCsvImporter extends BaseImporter implements Importer {
|
||||
fieldsJson.extraFields.length > 0 ? fieldsJson.extraFields.map((fieldJson: string) => {
|
||||
try {
|
||||
return JSON.parse(fieldJson);
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
return null;
|
||||
}) : null;
|
||||
if (fields != null) {
|
||||
|
||||
@@ -84,7 +84,9 @@ export class PasswordBossJsonImporter extends BaseImporter implements Importer {
|
||||
const expDate = new Date(val);
|
||||
cipher.card.expYear = expDate.getFullYear().toString();
|
||||
cipher.card.expMonth = (expDate.getMonth() + 1).toString();
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
continue;
|
||||
} else if (property === 'cardType') {
|
||||
continue;
|
||||
|
||||
@@ -43,7 +43,9 @@ export class RememBearCsvImporter extends BaseImporter implements Importer {
|
||||
cipher.card.expMonth = expMonthNumber.toString();
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
try {
|
||||
const expYear = this.getValueOrDefault(value.expiryYear);
|
||||
if (expYear != null) {
|
||||
@@ -52,7 +54,9 @@ export class RememBearCsvImporter extends BaseImporter implements Importer {
|
||||
cipher.card.expYear = expYearNumber.toString();
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
|
||||
const pin = this.getValueOrDefault(value.pin);
|
||||
if (pin != null) {
|
||||
|
||||
29
common/src/importers/safariCsvImporter.ts
Normal file
29
common/src/importers/safariCsvImporter.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { BaseImporter } from './baseImporter';
|
||||
import { Importer } from './importer';
|
||||
|
||||
import { ImportResult } from '../models/domain/importResult';
|
||||
|
||||
export class SafariCsvImporter extends BaseImporter implements Importer {
|
||||
parse(data: string): Promise<ImportResult> {
|
||||
const result = new ImportResult();
|
||||
const results = this.parseCsv(data, true);
|
||||
if (results == null) {
|
||||
result.success = false;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
results.forEach(value => {
|
||||
const cipher = this.initLoginCipher();
|
||||
cipher.name = this.getValueOrDefault(value.Title, '--');
|
||||
cipher.login.username = this.getValueOrDefault(value.Username);
|
||||
cipher.login.password = this.getValueOrDefault(value.Password);
|
||||
cipher.login.uris = this.makeUriArray(value.Url);
|
||||
cipher.login.totp = this.getValueOrDefault(value.OTPAuth);
|
||||
this.cleanupCipher(cipher);
|
||||
result.ciphers.push(cipher);
|
||||
});
|
||||
|
||||
result.success = true;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,9 @@ export class TrueKeyCsvImporter extends BaseImporter implements Importer {
|
||||
const expDate = new Date(value.expiryDate);
|
||||
cipher.card.expYear = expDate.getFullYear().toString();
|
||||
cipher.card.expMonth = (expDate.getMonth() + 1).toString();
|
||||
} catch { }
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
}
|
||||
} else if (value.kind !== 'login') {
|
||||
cipher.type = CipherType.SecureNote;
|
||||
|
||||
28
common/src/misc/linkedFieldOption.decorator.ts
Normal file
28
common/src/misc/linkedFieldOption.decorator.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { ItemView } from '../models/view/itemView';
|
||||
|
||||
import { LinkedIdType } from '../enums/linkedIdType';
|
||||
|
||||
export class LinkedMetadata {
|
||||
constructor(readonly propertyKey: string, private readonly _i18nKey?: string) { }
|
||||
|
||||
get i18nKey() {
|
||||
return this._i18nKey ?? this.propertyKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A decorator used to set metadata used by Linked custom fields. Apply it to a class property or getter to make it
|
||||
* available as a Linked custom field option.
|
||||
* @param id - A unique value that is saved in the Field model. It is used to look up the decorated class property.
|
||||
* @param i18nKey - The i18n key used to describe the decorated class property in the UI. If it is null, then the name
|
||||
* of the class property will be used as the i18n key.
|
||||
*/
|
||||
export function linkedFieldOption(id: LinkedIdType, i18nKey?: string) {
|
||||
return (prototype: ItemView, propertyKey: string) => {
|
||||
if (prototype.linkedFieldOptions == null) {
|
||||
prototype.linkedFieldOptions = new Map<LinkedIdType, LinkedMetadata>();
|
||||
}
|
||||
|
||||
prototype.linkedFieldOptions.set(id, new LinkedMetadata(propertyKey, i18nKey));
|
||||
};
|
||||
}
|
||||
@@ -219,7 +219,8 @@ export class Utils {
|
||||
}
|
||||
|
||||
let httpUrl = uriString.startsWith('http://') || uriString.startsWith('https://');
|
||||
if (!httpUrl && uriString.indexOf('://') < 0 && Utils.tldEndingRegex.test(uriString)) {
|
||||
if (!httpUrl && uriString.indexOf('://') < 0 && Utils.tldEndingRegex.test(uriString) &&
|
||||
uriString.indexOf('@') < 0) {
|
||||
uriString = 'http://' + uriString;
|
||||
httpUrl = true;
|
||||
}
|
||||
@@ -238,7 +239,9 @@ export class Utils {
|
||||
|
||||
const urlDomain = tldjs != null && tldjs.getDomain != null ? tldjs.getDomain(url.hostname) : null;
|
||||
return urlDomain != null ? urlDomain : url.hostname;
|
||||
} catch (e) { }
|
||||
} catch (e) {
|
||||
// Invalid domain, try another approach below.
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -325,6 +328,10 @@ export class Utils {
|
||||
return url;
|
||||
}
|
||||
|
||||
static camelToPascalCase(s: string) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
}
|
||||
|
||||
private static validIpAddress(ipString: string): boolean {
|
||||
// tslint:disable-next-line
|
||||
const ipRegex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
@@ -363,7 +370,9 @@ export class Utils {
|
||||
anchor.href = uriString;
|
||||
return anchor as any;
|
||||
}
|
||||
} catch (e) { }
|
||||
} catch (e) {
|
||||
// Ignore error
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { BaseResponse } from '../response/baseResponse';
|
||||
|
||||
import { FieldType } from '../../enums/fieldType';
|
||||
import { LinkedIdType } from '../../enums/linkedIdType';
|
||||
|
||||
export class FieldApi extends BaseResponse {
|
||||
name: string;
|
||||
value: string;
|
||||
type: FieldType;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
@@ -15,5 +17,6 @@ export class FieldApi extends BaseResponse {
|
||||
this.type = this.getResponseProperty('Type');
|
||||
this.name = this.getResponseProperty('Name');
|
||||
this.value = this.getResponseProperty('Value');
|
||||
this.linkedId = this.getResponseProperty('linkedId');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import { BaseResponse } from '../response/baseResponse';
|
||||
|
||||
export class PermissionsApi extends BaseResponse {
|
||||
accessBusinessPortal: boolean;
|
||||
accessEventLogs: boolean;
|
||||
accessImportExport: boolean;
|
||||
accessReports: boolean;
|
||||
/**
|
||||
* @deprecated Sep 29 2021: This permission has been split out to `createNewCollections`, `editAnyCollection`, and
|
||||
* `deleteAnyCollection`. It exists here for backwards compatibility with Server versions <= 1.43.0
|
||||
*/
|
||||
manageAllCollections: boolean;
|
||||
createNewCollections: boolean;
|
||||
editAnyCollection: boolean;
|
||||
deleteAnyCollection: boolean;
|
||||
/**
|
||||
* @deprecated Sep 29 2021: This permission has been split out to `editAssignedCollections` and
|
||||
* `deleteAssignedCollections`. It exists here for backwards compatibility with Server versions <= 1.43.0
|
||||
*/
|
||||
manageAssignedCollections: boolean;
|
||||
editAssignedCollections: boolean;
|
||||
deleteAssignedCollections: boolean;
|
||||
manageCiphers: boolean;
|
||||
manageGroups: boolean;
|
||||
manageSso: boolean;
|
||||
@@ -19,12 +31,20 @@ export class PermissionsApi extends BaseResponse {
|
||||
if (data == null) {
|
||||
return this;
|
||||
}
|
||||
this.accessBusinessPortal = this.getResponseProperty('AccessBusinessPortal');
|
||||
this.accessEventLogs = this.getResponseProperty('AccessEventLogs');
|
||||
this.accessImportExport = this.getResponseProperty('AccessImportExport');
|
||||
this.accessReports = this.getResponseProperty('AccessReports');
|
||||
|
||||
// For backwards compatibility with Server <= 1.43.0
|
||||
this.manageAllCollections = this.getResponseProperty('ManageAllCollections');
|
||||
this.manageAssignedCollections = this.getResponseProperty('ManageAssignedCollections');
|
||||
|
||||
this.createNewCollections = this.getResponseProperty('CreateNewCollections');
|
||||
this.editAnyCollection = this.getResponseProperty('EditAnyCollection');
|
||||
this.deleteAnyCollection = this.getResponseProperty('DeleteAnyCollection');
|
||||
this.editAssignedCollections = this.getResponseProperty('EditAssignedCollections');
|
||||
this.deleteAssignedCollections = this.getResponseProperty('DeleteAssignedCollections');
|
||||
|
||||
this.manageCiphers = this.getResponseProperty('ManageCiphers');
|
||||
this.manageGroups = this.getResponseProperty('ManageGroups');
|
||||
this.manageSso = this.getResponseProperty('ManageSso');
|
||||
|
||||
118
common/src/models/api/ssoConfigApi.ts
Normal file
118
common/src/models/api/ssoConfigApi.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { BaseResponse } from '../response/baseResponse';
|
||||
|
||||
enum SsoType {
|
||||
OpenIdConnect = 1,
|
||||
Saml2 = 2,
|
||||
}
|
||||
|
||||
enum OpenIdConnectRedirectBehavior {
|
||||
RedirectGet = 0,
|
||||
FormPost = 1,
|
||||
}
|
||||
|
||||
enum Saml2BindingType {
|
||||
HttpRedirect = 1,
|
||||
HttpPost = 2,
|
||||
Artifact = 4,
|
||||
}
|
||||
|
||||
enum Saml2NameIdFormat {
|
||||
NotConfigured = 0,
|
||||
Unspecified = 1,
|
||||
EmailAddress = 2,
|
||||
X509SubjectName = 3,
|
||||
WindowsDomainQualifiedName = 4,
|
||||
KerberosPrincipalName = 5,
|
||||
EntityIdentifier = 6,
|
||||
Persistent = 7,
|
||||
Transient = 8,
|
||||
}
|
||||
|
||||
enum Saml2SigningBehavior {
|
||||
IfIdpWantAuthnRequestsSigned = 0,
|
||||
Always = 1,
|
||||
Never = 3,
|
||||
}
|
||||
|
||||
export class SsoConfigApi extends BaseResponse {
|
||||
configType: SsoType;
|
||||
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
// OpenId
|
||||
authority: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
metadataAddress: string;
|
||||
redirectBehavior: OpenIdConnectRedirectBehavior;
|
||||
getClaimsFromUserInfoEndpoint: boolean;
|
||||
additionalScopes: string;
|
||||
additionalUserIdClaimTypes: string;
|
||||
additionalEmailClaimTypes: string;
|
||||
additionalNameClaimTypes: string;
|
||||
acrValues: string;
|
||||
expectedReturnAcrValue: string;
|
||||
|
||||
// SAML
|
||||
spNameIdFormat: Saml2NameIdFormat;
|
||||
spOutboundSigningAlgorithm: string;
|
||||
spSigningBehavior: Saml2SigningBehavior;
|
||||
spMinIncomingSigningAlgorithm: boolean;
|
||||
spWantAssertionsSigned: boolean;
|
||||
spValidateCertificates: boolean;
|
||||
|
||||
idpEntityId: string;
|
||||
idpBindingType: Saml2BindingType;
|
||||
idpSingleSignOnServiceUrl: string;
|
||||
idpSingleLogoutServiceUrl: string;
|
||||
idpArtifactResolutionServiceUrl: string;
|
||||
idpX509PublicCert: string;
|
||||
idpOutboundSigningAlgorithm: string;
|
||||
idpAllowUnsolicitedAuthnResponse: boolean;
|
||||
idpDisableOutboundLogoutRequests: boolean;
|
||||
idpWantAuthnRequestsSigned: boolean;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.configType = this.getResponseProperty('ConfigType');
|
||||
|
||||
this.keyConnectorEnabled = this.getResponseProperty('KeyConnectorEnabled');
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
|
||||
this.authority = this.getResponseProperty('Authority');
|
||||
this.clientId = this.getResponseProperty('ClientId');
|
||||
this.clientSecret = this.getResponseProperty('ClientSecret');
|
||||
this.metadataAddress = this.getResponseProperty('MetadataAddress');
|
||||
this.redirectBehavior = this.getResponseProperty('RedirectBehavior');
|
||||
this.getClaimsFromUserInfoEndpoint = this.getResponseProperty('GetClaimsFromUserInfoEndpoint');
|
||||
this.additionalScopes = this.getResponseProperty('AdditionalScopes');
|
||||
this.additionalUserIdClaimTypes = this.getResponseProperty('AdditionalUserIdClaimTypes');
|
||||
this.additionalEmailClaimTypes = this.getResponseProperty('AdditionalEmailClaimTypes');
|
||||
this.additionalNameClaimTypes = this.getResponseProperty('AdditionalNameClaimTypes');
|
||||
this.acrValues = this.getResponseProperty('AcrValues');
|
||||
this.expectedReturnAcrValue = this.getResponseProperty('ExpectedReturnAcrValue');
|
||||
|
||||
this.spNameIdFormat = this.getResponseProperty('SpNameIdFormat');
|
||||
this.spOutboundSigningAlgorithm = this.getResponseProperty('SpOutboundSigningAlgorithm');
|
||||
this.spSigningBehavior = this.getResponseProperty('SpSigningBehavior');
|
||||
this.spMinIncomingSigningAlgorithm = this.getResponseProperty('SpMinIncomingSigningAlgorithm');
|
||||
this.spWantAssertionsSigned = this.getResponseProperty('SpWantAssertionsSigned');
|
||||
this.spValidateCertificates = this.getResponseProperty('SpValidateCertificates');
|
||||
|
||||
this.idpEntityId = this.getResponseProperty('IdpEntityId');
|
||||
this.idpBindingType = this.getResponseProperty('IdpBindingType');
|
||||
this.idpSingleSignOnServiceUrl = this.getResponseProperty('IdpSingleSignOnServiceUrl');
|
||||
this.idpSingleLogoutServiceUrl = this.getResponseProperty('IdpSingleLogoutServiceUrl');
|
||||
this.idpArtifactResolutionServiceUrl = this.getResponseProperty('IdpArtifactResolutionServiceUrl');
|
||||
this.idpX509PublicCert = this.getResponseProperty('IdpX509PublicCert');
|
||||
this.idpOutboundSigningAlgorithm = this.getResponseProperty('IdpOutboundSigningAlgorithm');
|
||||
this.idpAllowUnsolicitedAuthnResponse = this.getResponseProperty('IdpAllowUnsolicitedAuthnResponse');
|
||||
this.idpDisableOutboundLogoutRequests = this.getResponseProperty('IdpDisableOutboundLogoutRequests');
|
||||
this.idpWantAuthnRequestsSigned = this.getResponseProperty('IdpWantAuthnRequestsSigned');
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FieldType } from '../../enums/fieldType';
|
||||
import { LinkedIdType } from '../../enums/linkedIdType';
|
||||
|
||||
import { FieldApi } from '../api/fieldApi';
|
||||
|
||||
@@ -6,6 +7,7 @@ export class FieldData {
|
||||
type: FieldType;
|
||||
name: string;
|
||||
value: string;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(response?: FieldApi) {
|
||||
if (response == null) {
|
||||
@@ -14,5 +16,6 @@ export class FieldData {
|
||||
this.type = response.type;
|
||||
this.name = response.name;
|
||||
this.value = response.value;
|
||||
this.linkedId = response.linkedId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { ProfileOrganizationResponse } from '../response/profileOrganizationResp
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
export class OrganizationData {
|
||||
@@ -17,8 +19,8 @@ export class OrganizationData {
|
||||
useTotp: boolean;
|
||||
use2fa: boolean;
|
||||
useApi: boolean;
|
||||
useBusinessPortal: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
@@ -34,6 +36,11 @@ export class OrganizationData {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: ProfileOrganizationResponse) {
|
||||
this.id = response.id;
|
||||
@@ -48,8 +55,8 @@ export class OrganizationData {
|
||||
this.useTotp = response.useTotp;
|
||||
this.use2fa = response.use2fa;
|
||||
this.useApi = response.useApi;
|
||||
this.useBusinessPortal = response.useBusinessPortal;
|
||||
this.useSso = response.useSso;
|
||||
this.useKeyConnector = response.useKeyConnector;
|
||||
this.useResetPassword = response.useResetPassword;
|
||||
this.selfHost = response.selfHost;
|
||||
this.usersGetPremium = response.usersGetPremium;
|
||||
@@ -64,5 +71,10 @@ export class OrganizationData {
|
||||
this.hasPublicAndPrivateKeys = response.hasPublicAndPrivateKeys;
|
||||
this.providerId = response.providerId;
|
||||
this.providerName = response.providerName;
|
||||
this.familySponsorshipFriendlyName = response.familySponsorshipFriendlyName;
|
||||
this.familySponsorshipAvailable = response.familySponsorshipAvailable;
|
||||
this.planProductType = response.planProductType;
|
||||
this.keyConnectorEnabled = response.keyConnectorEnabled;
|
||||
this.keyConnectorUrl = response.keyConnectorUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FieldType } from '../../enums/fieldType';
|
||||
import { LinkedIdType } from '../../enums/linkedIdType';
|
||||
|
||||
import { FieldData } from '../data/fieldData';
|
||||
|
||||
@@ -12,6 +13,7 @@ export class Field extends Domain {
|
||||
name: EncString;
|
||||
value: EncString;
|
||||
type: FieldType;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(obj?: FieldData, alreadyEncrypted: boolean = false) {
|
||||
super();
|
||||
@@ -20,6 +22,7 @@ export class Field extends Domain {
|
||||
}
|
||||
|
||||
this.type = obj.type;
|
||||
this.linkedId = obj.linkedId;
|
||||
this.buildDomainModel(this, obj, {
|
||||
name: null,
|
||||
value: null,
|
||||
@@ -39,7 +42,8 @@ export class Field extends Domain {
|
||||
name: null,
|
||||
value: null,
|
||||
type: null,
|
||||
}, ['type']);
|
||||
linkedId: null,
|
||||
}, ['type', 'linkedId']);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { OrganizationData } from '../data/organizationData';
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
|
||||
@@ -18,8 +19,8 @@ export class Organization {
|
||||
useTotp: boolean;
|
||||
use2fa: boolean;
|
||||
useApi: boolean;
|
||||
useBusinessPortal: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
@@ -35,6 +36,11 @@ export class Organization {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(obj?: OrganizationData) {
|
||||
if (obj == null) {
|
||||
@@ -53,8 +59,8 @@ export class Organization {
|
||||
this.useTotp = obj.useTotp;
|
||||
this.use2fa = obj.use2fa;
|
||||
this.useApi = obj.useApi;
|
||||
this.useBusinessPortal = obj.useBusinessPortal;
|
||||
this.useSso = obj.useSso;
|
||||
this.useKeyConnector = obj.useKeyConnector;
|
||||
this.useResetPassword = obj.useResetPassword;
|
||||
this.selfHost = obj.selfHost;
|
||||
this.usersGetPremium = obj.usersGetPremium;
|
||||
@@ -70,6 +76,11 @@ export class Organization {
|
||||
this.providerId = obj.providerId;
|
||||
this.providerName = obj.providerName;
|
||||
this.isProviderUser = obj.isProviderUser;
|
||||
this.familySponsorshipFriendlyName = obj.familySponsorshipFriendlyName;
|
||||
this.familySponsorshipAvailable = obj.familySponsorshipAvailable;
|
||||
this.planProductType = obj.planProductType;
|
||||
this.keyConnectorEnabled = obj.keyConnectorEnabled;
|
||||
this.keyConnectorUrl = obj.keyConnectorUrl;
|
||||
}
|
||||
|
||||
get canAccess() {
|
||||
@@ -92,10 +103,6 @@ export class Organization {
|
||||
return this.type === OrganizationUserType.Owner || this.isProviderUser;
|
||||
}
|
||||
|
||||
get canAccessBusinessPortal() {
|
||||
return this.isAdmin || this.permissions.accessBusinessPortal;
|
||||
}
|
||||
|
||||
get canAccessEventLogs() {
|
||||
return this.isAdmin || this.permissions.accessEventLogs;
|
||||
}
|
||||
@@ -108,12 +115,32 @@ export class Organization {
|
||||
return this.isAdmin || this.permissions.accessReports;
|
||||
}
|
||||
|
||||
get canManageAllCollections() {
|
||||
return this.isAdmin || this.permissions.manageAllCollections;
|
||||
get canCreateNewCollections() {
|
||||
return this.isManager || (this.permissions.createNewCollections ?? this.permissions.manageAllCollections);
|
||||
}
|
||||
|
||||
get canManageAssignedCollections() {
|
||||
return this.isManager || this.permissions.manageAssignedCollections;
|
||||
get canEditAnyCollection() {
|
||||
return this.isAdmin || (this.permissions.editAnyCollection ?? this.permissions.manageAllCollections);
|
||||
}
|
||||
|
||||
get canDeleteAnyCollection() {
|
||||
return this.isAdmin || (this.permissions.deleteAnyCollection ?? this.permissions.manageAllCollections);
|
||||
}
|
||||
|
||||
get canViewAllCollections() {
|
||||
return this.canCreateNewCollections || this.canEditAnyCollection || this.canDeleteAnyCollection;
|
||||
}
|
||||
|
||||
get canEditAssignedCollections() {
|
||||
return this.isManager || (this.permissions.editAssignedCollections ?? this.permissions.manageAssignedCollections);
|
||||
}
|
||||
|
||||
get canDeleteAssignedCollections() {
|
||||
return this.isManager || (this.permissions.deleteAssignedCollections ?? this.permissions.manageAssignedCollections);
|
||||
}
|
||||
|
||||
get canViewAssignedCollections() {
|
||||
return this.canDeleteAssignedCollections || this.canEditAssignedCollections;
|
||||
}
|
||||
|
||||
get canManageGroups() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FieldType } from '../../enums/fieldType';
|
||||
import { LinkedIdType } from '../../enums/linkedIdType';
|
||||
|
||||
import { FieldView } from '../view/fieldView';
|
||||
|
||||
@@ -18,6 +19,7 @@ export class Field {
|
||||
view.type = req.type;
|
||||
view.value = req.value;
|
||||
view.name = req.name;
|
||||
view.linkedId = req.linkedId;
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -25,12 +27,14 @@ export class Field {
|
||||
domain.type = req.type;
|
||||
domain.value = req.value != null ? new EncString(req.value) : null;
|
||||
domain.name = req.name != null ? new EncString(req.name) : null;
|
||||
domain.linkedId = req.linkedId;
|
||||
return domain;
|
||||
}
|
||||
|
||||
name: string;
|
||||
value: string;
|
||||
type: FieldType;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(o?: FieldView | FieldDomain) {
|
||||
if (o == null) {
|
||||
@@ -45,5 +49,6 @@ export class Field {
|
||||
this.value = o.value?.encryptedString;
|
||||
}
|
||||
this.type = o.type;
|
||||
this.linkedId = o.linkedId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { KeysRequest } from '../keysRequest';
|
||||
|
||||
import { KdfType } from '../../../enums/kdfType';
|
||||
|
||||
export class SetKeyConnectorKeyRequest {
|
||||
key: string;
|
||||
keys: KeysRequest;
|
||||
kdf: KdfType;
|
||||
kdfIterations: number;
|
||||
orgIdentifier: string;
|
||||
|
||||
constructor(key: string, kdf: KdfType, kdfIterations: number, orgIdentifier: string, keys: KeysRequest) {
|
||||
this.key = key;
|
||||
this.kdf = kdf;
|
||||
this.kdfIterations = kdfIterations;
|
||||
this.orgIdentifier = orgIdentifier;
|
||||
this.keys = keys;
|
||||
}
|
||||
}
|
||||
7
common/src/models/request/account/verifyOTPRequest.ts
Normal file
7
common/src/models/request/account/verifyOTPRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class VerifyOTPRequest {
|
||||
OTP: string;
|
||||
|
||||
constructor(OTP: string) {
|
||||
this.OTP = OTP;
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,7 @@ export class CipherRequest {
|
||||
field.type = f.type;
|
||||
field.name = f.name ? f.name.encryptedString : null;
|
||||
field.value = f.value ? f.value.encryptedString : null;
|
||||
field.linkedId = f.linkedId;
|
||||
return field;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class EmailTokenRequest extends PasswordVerificationRequest {
|
||||
export class EmailTokenRequest extends SecretVerificationRequest {
|
||||
newEmail: string;
|
||||
masterPasswordHash: string;
|
||||
}
|
||||
|
||||
7
common/src/models/request/keyConnectorUserKeyRequest.ts
Normal file
7
common/src/models/request/keyConnectorUserKeyRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class KeyConnectorUserKeyRequest {
|
||||
key: string;
|
||||
|
||||
constructor(key: string) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { PlanSponsorshipType } from '../../../enums/planSponsorshipType';
|
||||
|
||||
export class OrganizationSponsorshipCreateRequest {
|
||||
sponsoredEmail: string;
|
||||
planSponsorshipType: PlanSponsorshipType;
|
||||
friendlyName: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { PlanSponsorshipType } from '../../../enums/planSponsorshipType';
|
||||
|
||||
export class OrganizationSponsorshipRedeemRequest {
|
||||
planSponsorshipType: PlanSponsorshipType;
|
||||
sponsoredOrganizationId: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { SsoConfigApi } from '../../api/ssoConfigApi';
|
||||
|
||||
export class OrganizationSsoRequest {
|
||||
enabled: boolean = false;
|
||||
data: SsoConfigApi;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class PasswordRequest extends PasswordVerificationRequest {
|
||||
export class PasswordRequest extends SecretVerificationRequest {
|
||||
newMasterPasswordHash: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export class PasswordVerificationRequest {
|
||||
masterPasswordHash: string;
|
||||
}
|
||||
4
common/src/models/request/secretVerificationRequest.ts
Normal file
4
common/src/models/request/secretVerificationRequest.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class SecretVerificationRequest {
|
||||
masterPasswordHash: string;
|
||||
otp: string;
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class TwoFactorEmailRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorEmailRequest extends SecretVerificationRequest {
|
||||
email: string;
|
||||
|
||||
constructor(email: string, masterPasswordHash: string) {
|
||||
super();
|
||||
this.masterPasswordHash = masterPasswordHash;
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
import { TwoFactorProviderType } from '../../enums/twoFactorProviderType';
|
||||
|
||||
export class TwoFactorProviderRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorProviderRequest extends SecretVerificationRequest {
|
||||
type: TwoFactorProviderType;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class TwoFactorRecoveryRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorRecoveryRequest extends SecretVerificationRequest {
|
||||
recoveryCode: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorAuthenticatorRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorAuthenticatorRequest extends SecretVerificationRequest {
|
||||
token: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorDuoRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorDuoRequest extends SecretVerificationRequest {
|
||||
integrationKey: string;
|
||||
secretKey: string;
|
||||
host: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorEmailRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorEmailRequest extends SecretVerificationRequest {
|
||||
token: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorWebAuthnDeleteRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorWebAuthnDeleteRequest extends SecretVerificationRequest {
|
||||
id: number;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorWebAuthnRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorWebAuthnRequest extends SecretVerificationRequest {
|
||||
deviceResponse: PublicKeyCredential;
|
||||
name: string;
|
||||
id: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorYubioOtpRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorYubioOtpRequest extends SecretVerificationRequest {
|
||||
key1: string;
|
||||
key2: string;
|
||||
key3: string;
|
||||
|
||||
@@ -15,6 +15,8 @@ export class IdentityTokenResponse extends BaseResponse {
|
||||
kdf: KdfType;
|
||||
kdfIterations: number;
|
||||
forcePasswordReset: boolean;
|
||||
apiUseKeyConnector: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -30,5 +32,7 @@ export class IdentityTokenResponse extends BaseResponse {
|
||||
this.kdf = this.getResponseProperty('Kdf');
|
||||
this.kdfIterations = this.getResponseProperty('KdfIterations');
|
||||
this.forcePasswordReset = this.getResponseProperty('ForcePasswordReset');
|
||||
this.apiUseKeyConnector = this.getResponseProperty('ApiUseKeyConnector');
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
}
|
||||
}
|
||||
|
||||
10
common/src/models/response/keyConnectorUserKeyResponse.ts
Normal file
10
common/src/models/response/keyConnectorUserKeyResponse.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { BaseResponse } from './baseResponse';
|
||||
|
||||
export class KeyConnectorUserKeyResponse extends BaseResponse {
|
||||
key: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.key = this.getResponseProperty('Key');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { SsoConfigApi } from '../../api/ssoConfigApi';
|
||||
import { BaseResponse } from '../baseResponse';
|
||||
|
||||
export class OrganizationSsoResponse extends BaseResponse {
|
||||
enabled: boolean;
|
||||
data: SsoConfigApi;
|
||||
urls: SsoUrls;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.enabled = this.getResponseProperty('Enabled');
|
||||
this.data = new SsoConfigApi(this.getResponseProperty('Data'));
|
||||
this.urls = new SsoUrls(this.getResponseProperty('Urls'));
|
||||
}
|
||||
}
|
||||
|
||||
class SsoUrls extends BaseResponse {
|
||||
callbackPath: string;
|
||||
signedOutCallbackPath: string;
|
||||
spEntityId: string;
|
||||
spMetadataUrl: string;
|
||||
spAcsUrl: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.callbackPath = this.getResponseProperty('CallbackPath');
|
||||
this.signedOutCallbackPath = this.getResponseProperty('SignedOutCallbackPath');
|
||||
this.spEntityId = this.getResponseProperty('SpEntityId');
|
||||
this.spMetadataUrl = this.getResponseProperty('SpMetadataUrl');
|
||||
this.spAcsUrl = this.getResponseProperty('SpAcsUrl');
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,14 @@ export class OrganizationUserUserDetailsResponse extends OrganizationUserRespons
|
||||
name: string;
|
||||
email: string;
|
||||
twoFactorEnabled: boolean;
|
||||
usesKeyConnector: boolean;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.name = this.getResponseProperty('Name');
|
||||
this.email = this.getResponseProperty('Email');
|
||||
this.twoFactorEnabled = this.getResponseProperty('TwoFactorEnabled');
|
||||
this.usesKeyConnector = this.getResponseProperty('UsesKeyConnector') ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BaseResponse } from './baseResponse';
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
export class ProfileOrganizationResponse extends BaseResponse {
|
||||
@@ -14,8 +15,8 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
useTotp: boolean;
|
||||
use2fa: boolean;
|
||||
useApi: boolean;
|
||||
useBusinessPortal: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
@@ -34,6 +35,11 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
userId: string;
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -46,8 +52,8 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
this.useTotp = this.getResponseProperty('UseTotp');
|
||||
this.use2fa = this.getResponseProperty('Use2fa');
|
||||
this.useApi = this.getResponseProperty('UseApi');
|
||||
this.useBusinessPortal = this.getResponseProperty('UseBusinessPortal');
|
||||
this.useSso = this.getResponseProperty('UseSso');
|
||||
this.useKeyConnector = this.getResponseProperty('UseKeyConnector') ?? false;
|
||||
this.useResetPassword = this.getResponseProperty('UseResetPassword');
|
||||
this.selfHost = this.getResponseProperty('SelfHost');
|
||||
this.usersGetPremium = this.getResponseProperty('UsersGetPremium');
|
||||
@@ -66,5 +72,10 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
this.userId = this.getResponseProperty('UserId');
|
||||
this.providerId = this.getResponseProperty('ProviderId');
|
||||
this.providerName = this.getResponseProperty('ProviderName');
|
||||
this.familySponsorshipFriendlyName = this.getResponseProperty('FamilySponsorshipFriendlyName');
|
||||
this.familySponsorshipAvailable = this.getResponseProperty('FamilySponsorshipAvailable');
|
||||
this.planProductType = this.getResponseProperty('PlanProductType');
|
||||
this.keyConnectorEnabled = this.getResponseProperty('KeyConnectorEnabled') ?? false;
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user