mirror of
https://github.com/bitwarden/web
synced 2025-12-06 00:03:28 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
165944624a | ||
|
|
11b96728f2 | ||
|
|
62e22ff149 | ||
|
|
09968a18d0 | ||
|
|
cc59d08a69 | ||
|
|
ac45ac2eca | ||
|
|
95c0e211c7 | ||
|
|
fed8990a6a | ||
|
|
b8431f0101 | ||
|
|
af47e25ead | ||
|
|
a315370e5d | ||
|
|
5a64b22190 | ||
|
|
4b05bc981c | ||
|
|
00f0dc3499 |
97
.github/workflows/build.yml
vendored
97
.github/workflows/build.yml
vendored
@@ -5,13 +5,16 @@ on:
|
||||
branches-ignore:
|
||||
- 'l10n_master'
|
||||
- 'gh-pages'
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
cloc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up cloc
|
||||
run: |
|
||||
@@ -25,13 +28,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g npm@7
|
||||
node-version: '10.x'
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
@@ -42,15 +41,18 @@ jobs:
|
||||
docker --version
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GITHUB_EVENT: ${{ github.event_name }}
|
||||
|
||||
- name: Login to Azure
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
id: retrieve-secrets
|
||||
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
|
||||
with:
|
||||
@@ -60,15 +62,15 @@ jobs:
|
||||
dct-delegate-2-repo-passphrase,
|
||||
dct-delegate-2-key"
|
||||
|
||||
- name: Log into Docker
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
- name: Log into docker
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
run: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ steps.retrieve-secrets.outputs.docker-username }}
|
||||
DOCKER_PASSWORD: ${{ steps.retrieve-secrets.outputs.docker-password }}
|
||||
|
||||
- name: Setup Docker Trust
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
run: |
|
||||
mkdir -p ~/.docker/trust/private
|
||||
|
||||
@@ -78,7 +80,7 @@ jobs:
|
||||
DCT_DELEGATE_KEY: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-key }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Restore
|
||||
run: dotnet tool restore
|
||||
@@ -91,7 +93,7 @@ jobs:
|
||||
npm install
|
||||
npm run dist:selfhost
|
||||
|
||||
echo -e "\nBuilding Docker image"
|
||||
echo -e "\nBuilding docker image"
|
||||
docker --version
|
||||
docker build -t bitwarden/web .
|
||||
|
||||
@@ -100,11 +102,22 @@ jobs:
|
||||
run: docker tag bitwarden/web bitwarden/web:rc
|
||||
|
||||
- name: Tag dev
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: docker tag bitwarden/web bitwarden/web:dev
|
||||
|
||||
- name: List Docker images
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
- name: Tag beta
|
||||
if: github.event_name == 'release'
|
||||
run: docker tag bitwarden/web bitwarden/web:beta
|
||||
|
||||
- name: Tag version
|
||||
if: github.event_name == 'release'
|
||||
run: docker tag bitwarden/web bitwarden/web:$($env:RELEASE_TAG_NAME.trimStart('v'))
|
||||
shell: pwsh
|
||||
env:
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: List docker images
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
run: docker images
|
||||
|
||||
- name: Push rc images
|
||||
@@ -115,51 +128,71 @@ jobs:
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Push dev images
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: docker push bitwarden/web:dev
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Log out of Docker
|
||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc'
|
||||
- name: Push beta images
|
||||
if: github.event_name == 'release'
|
||||
run: docker push bitwarden/web:beta
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Push latest images
|
||||
if: github.event_name == 'release'
|
||||
run: docker push bitwarden/web:latest
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Push version images
|
||||
if: github.event_name == 'release'
|
||||
run: docker push bitwarden/web:$($env:RELEASE_TAG_NAME.trimStart('v'))
|
||||
shell: pwsh
|
||||
env:
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Log out of docker
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
run: docker logout
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Set up NuGet
|
||||
uses: nuget/setup-nuget@04b0c2b8d1b97922f67eca497d7cf0bf17b8ffe1
|
||||
uses: nuget/setup-nuget@v1
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@c26a08ba26249b81327e26f6ef381897b6a8754d
|
||||
uses: microsoft/setup-msbuild@v1
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g npm@7
|
||||
node-version: '10.x'
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
nuget help | grep Version
|
||||
nuget help
|
||||
msbuild -version
|
||||
dotnet --info
|
||||
node --version
|
||||
npm --version
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
Write-Output "GitHub ref: $env:GITHUB_REF"
|
||||
Write-Output "GitHub event: $env:GITHUB_EVENT"
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GITHUB_EVENT: ${{ github.event_name }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
70
.github/workflows/deploy.yml
vendored
70
.github/workflows/deploy.yml
vendored
@@ -1,70 +0,0 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_version:
|
||||
description: "Release Tag Version <vX.X.X>"
|
||||
required: true
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy Web Vault
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||
with:
|
||||
ref: gh-pages
|
||||
|
||||
- name: Get release version
|
||||
id: release-version
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo "::set-output name=version::${{ github.event.release.tag_name }}"
|
||||
else
|
||||
echo "::set-output name=version::${{ github.event.inputs.release_version }}"
|
||||
fi
|
||||
|
||||
- name: Create deploy branch
|
||||
run: |
|
||||
git switch -c deploy-${{ steps.release-version.outputs.version }}
|
||||
git push -u origin deploy-${{ steps.release-version.outputs.version }}
|
||||
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||
with:
|
||||
ref: rc
|
||||
|
||||
- name: setup git config
|
||||
run: |
|
||||
git config user.name = "GitHub Action Bot"
|
||||
git config user.email = "<>"
|
||||
|
||||
- name: Install and Build
|
||||
run: |
|
||||
npm ci
|
||||
npm run dist
|
||||
|
||||
- name: Deploy GitHub Pages
|
||||
uses: crazy-max/ghaction-github-pages@db4476a01402e1a7ce05f41832040eef16d14925 # v2.5.0
|
||||
with:
|
||||
target_branch: deploy-${{ steps.release-version.outputs.version }}
|
||||
build_dir: build
|
||||
keep_history: true
|
||||
commit_message: "Staging deploy ${{ steps.release-version.outputs.version }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create Deploy PR
|
||||
run: |
|
||||
gh pr create --title "Deploy $VERSION" --body "Deploying $VERSION" --base gh-pages --head "$PR_BRANCH"
|
||||
env:
|
||||
VERSION: ${{ steps.release-version.outputs.version }}
|
||||
PR_BRANCH: deploy-${{ steps.release-version.outputs.version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
157
.github/workflows/release.yml
vendored
157
.github/workflows/release.yml
vendored
@@ -1,157 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag_name_input:
|
||||
description: "Release Tag Name <X.X.X>"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
release_upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
release_version: ${{ steps.create_tags.outputs.package_version }}
|
||||
tag_version: ${{ steps.create_tags.outputs.tag_version }}
|
||||
steps:
|
||||
- name: Branch check
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" != "refs/heads/rc" ]]; then
|
||||
echo "==================================="
|
||||
echo "[!] Can only release from rc branch"
|
||||
echo "==================================="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # 2.3.4
|
||||
|
||||
- name: Create Release Vars
|
||||
id: create_tags
|
||||
run: |
|
||||
case "${RELEASE_TAG_NAME_INPUT:0:1}" in
|
||||
v)
|
||||
echo "RELEASE_NAME=${RELEASE_TAG_NAME_INPUT:1}" >> $GITHUB_ENV
|
||||
echo "RELEASE_TAG_NAME=$RELEASE_TAG_NAME_INPUT" >> $GITHUB_ENV
|
||||
echo "::set-output name=package_version::${RELEASE_TAG_NAME_INPUT:1}"
|
||||
echo "::set-output name=tag_version::$RELEASE_TAG_NAME_INPUT"
|
||||
;;
|
||||
[0-9])
|
||||
echo "RELEASE_NAME=$RELEASE_TAG_NAME_INPUT" >> $GITHUB_ENV
|
||||
echo "RELEASE_TAG_NAME=v$RELEASE_TAG_NAME_INPUT" >> $GITHUB_ENV
|
||||
echo "::set-output name=package_version::$RELEASE_TAG_NAME_INPUT"
|
||||
echo "::set-output name=tag_version::v$RELEASE_TAG_NAME_INPUT"
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
env:
|
||||
RELEASE_TAG_NAME_INPUT: ${{ github.event.inputs.release_tag_name_input }}
|
||||
|
||||
- name: Create Draft Release
|
||||
id: create_release
|
||||
uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # 1.1.4 - Repo Archived
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ env.RELEASE_TAG_NAME }}
|
||||
release_name: Version ${{ env.RELEASE_NAME }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
env:
|
||||
RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||
steps:
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g npm@7
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
whoami
|
||||
node --version
|
||||
npm --version
|
||||
gulp --version
|
||||
docker --version
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Login to Azure
|
||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
secrets: "docker-password,
|
||||
docker-username,
|
||||
dct-delegate-2-repo-passphrase,
|
||||
dct-delegate-2-key"
|
||||
|
||||
- name: Log into Docker
|
||||
run: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ steps.retrieve-secrets.outputs.docker-username }}
|
||||
DOCKER_PASSWORD: ${{ steps.retrieve-secrets.outputs.docker-password }}
|
||||
|
||||
- name: Setup Docker Trust
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release' || github.ref == 'refs/heads/rc'
|
||||
run: |
|
||||
mkdir -p ~/.docker/trust/private
|
||||
|
||||
echo "$DCT_DELEGATE_KEY" > ~/.docker/trust/private/$DCT_DELEGATION_KEY_ID.key
|
||||
env:
|
||||
DCT_DELEGATION_KEY_ID: "c9bde8ec820701516491e5e03d3a6354e7bd66d05fa3df2b0062f68b116dc59c"
|
||||
DCT_DELEGATE_KEY: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-key }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Restore
|
||||
run: dotnet tool restore
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
echo -e "# Building Web\n"
|
||||
echo "Building app"
|
||||
echo "npm version $(npm --version)"
|
||||
npm install
|
||||
npm run dist:selfhost
|
||||
|
||||
echo -e "\nBuilding Docker image"
|
||||
docker --version
|
||||
docker build -t bitwarden/web .
|
||||
|
||||
- name: Tag version
|
||||
run: docker tag bitwarden/web bitwarden/web:$RELEASE_VERSION
|
||||
|
||||
- name: List Docker images
|
||||
run: docker images
|
||||
|
||||
- name: Push latest images
|
||||
run: docker push bitwarden/web:latest
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Push version images
|
||||
run: docker push bitwarden/web:$RELEASE_VERSION
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.retrieve-secrets.outputs.dct-delegate-2-repo-passphrase }}
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
@@ -23,8 +23,7 @@
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org) v14.17 or greater
|
||||
- NPM v7
|
||||
- [Node.js](https://nodejs.org) v8.11 or greater
|
||||
|
||||
### Run the app
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ mkhomedir_helper $USERNAME
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
cp /etc/bitwarden/web/app-id.json /app/app-id.json
|
||||
cp /etc/bitwarden/web/assetlinks.json /app/assetlinks.json
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
chown -R $USERNAME:$GROUPNAME /bitwarden_server
|
||||
|
||||
|
||||
2
jslib
2
jslib
Submodule jslib updated: 6f428e11c4...f6d91e2d92
26555
package-lock.json
generated
26555
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
120
package.json
120
package.json
@@ -1,28 +1,28 @@
|
||||
{
|
||||
"name": "bitwarden-web",
|
||||
"version": "2.21.1",
|
||||
"version": "2.20.1",
|
||||
"license": "GPL-3.0",
|
||||
"repository": "https://github.com/bitwarden/web",
|
||||
"scripts": {
|
||||
"sub:init": "git submodule update --init --recursive",
|
||||
"sub:update": "git submodule update --remote",
|
||||
"sub:pull": "git submodule foreach git pull origin master",
|
||||
"preinstall": "npm run sub:init",
|
||||
"postinstall": "npm run sub:init",
|
||||
"symlink:win": "rm -rf ./jslib && cmd /c mklink /J .\\jslib ..\\jslib",
|
||||
"symlink:mac": "npm run symlink:lin",
|
||||
"symlink:lin": "rm -rf ./jslib && ln -s ../jslib ./jslib",
|
||||
"build": "gulp prebuild && webpack",
|
||||
"build:watch": "gulp prebuild && webpack serve",
|
||||
"build:watch": "gulp prebuild && webpack-dev-server",
|
||||
"build:dev": "gulp prebuild && cross-env ENV=development webpack",
|
||||
"build:dev:watch": "gulp prebuild && cross-env ENV=development webpack serve",
|
||||
"build:dev:watch": "gulp prebuild && cross-env ENV=development webpack-dev-server",
|
||||
"build:qa": "gulp prebuild && cross-env NODE_ENV=production ENV=qa webpack",
|
||||
"build:qa:watch": "gulp prebuild && cross-env NODE_ENV=production ENV=qa webpack serve",
|
||||
"build:qa:watch": "gulp prebuild && cross-env NODE_ENV=production ENV=qa webpack-dev-server",
|
||||
"build:prod": "gulp prebuild && cross-env NODE_ENV=production ENV=production webpack",
|
||||
"build:prod:watch": "gulp prebuild && cross-env NODE_ENV=production ENV=production webpack serve",
|
||||
"build:selfhost": "gulp prebuild && cross-env SELF_HOST=true webpack serve",
|
||||
"build:selfhost:watch": "gulp prebuild && cross-env SELF_HOST=true webpack serve",
|
||||
"build:prod:watch": "gulp prebuild && cross-env NODE_ENV=production ENV=production webpack-dev-server",
|
||||
"build:selfhost": "gulp prebuild && cross-env SELF_HOST=true webpack-dev-server",
|
||||
"build:selfhost:watch": "gulp prebuild && cross-env SELF_HOST=true webpack-dev-server",
|
||||
"build:selfhost:prod": "gulp prebuild && cross-env SELF_HOST=true NODE_ENV=production webpack",
|
||||
"build:selfhost:prod:watch": "gulp prebuild && cross-env SELF_HOST=true NODE_ENV=production webpack serve",
|
||||
"build:selfhost:prod:watch": "gulp prebuild && cross-env SELF_HOST=true NODE_ENV=production webpack-dev-server",
|
||||
"clean:l10n": "git push origin --delete l10n_master",
|
||||
"dist": "npm run build:prod && gulp postdist",
|
||||
"dist:selfhost": "npm run build:selfhost:prod && gulp postdist",
|
||||
@@ -32,58 +32,76 @@
|
||||
"lint:fix": "tslint 'src/**/*.ts' --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/compiler-cli": "^11.2.11",
|
||||
"@ngtools/webpack": "^11.2.10",
|
||||
"@types/duo_web_sdk": "^2.7.0",
|
||||
"@angular/compiler-cli": "^9.1.12",
|
||||
"@ngtools/webpack": "^9.1.12",
|
||||
"@types/jquery": "^3.5.5",
|
||||
"@types/node": "^14.17.2",
|
||||
"@types/lunr": "^2.3.3",
|
||||
"@types/node": "^10.17.28",
|
||||
"@types/node-forge": "^0.9.7",
|
||||
"@types/papaparse": "^5.2.0",
|
||||
"@types/webcrypto": "^0.0.28",
|
||||
"@types/webpack": "^4.4.27",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^6.4.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^5.2.3",
|
||||
"del": "^6.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"gh-pages": "^3.1.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-google-webfonts": "^4.0.0",
|
||||
"html-loader": "^1.3.2",
|
||||
"html-webpack-plugin": "^4.5.1",
|
||||
"mini-css-extract-plugin": "^1.5.0",
|
||||
"sass": "^1.32.10",
|
||||
"sass-loader": "^10.1.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"tapable": "^1.1.3",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"ts-loader": "^8.1.0",
|
||||
"@types/webpack": "^4.4.11",
|
||||
"@types/zxcvbn": "^4.4.0",
|
||||
"angular2-template-loader": "^0.6.2",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^1.0.0",
|
||||
"del": "^3.0.0",
|
||||
"file-loader": "^2.0.0",
|
||||
"gh-pages": "^1.2.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-google-webfonts": "^2.0.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"node-sass": "^4.13.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "^0.23.0",
|
||||
"terser-webpack-plugin": "^1.2.3",
|
||||
"ts-loader": "^7.0.5",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-loader": "^3.5.4",
|
||||
"typescript": "4.1.5",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^4.6.0",
|
||||
"webpack-dev-server": "^3.11.2"
|
||||
"typescript": "3.8.3",
|
||||
"webpack": "^4.29.0",
|
||||
"webpack-cli": "^3.2.1",
|
||||
"webpack-dev-server": "^3.1.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bitwarden/jslib-angular": "file:jslib/angular",
|
||||
"@bitwarden/jslib-common": "file:jslib/common",
|
||||
"angular2-toaster": "11.0.1",
|
||||
"bootstrap": "4.6.0",
|
||||
"braintree-web-drop-in": "1.30.1",
|
||||
"@angular/animations": "9.1.12",
|
||||
"@angular/cdk": "9.2.4",
|
||||
"@angular/common": "9.1.12",
|
||||
"@angular/compiler": "9.1.12",
|
||||
"@angular/core": "9.1.12",
|
||||
"@angular/forms": "9.1.12",
|
||||
"@angular/platform-browser": "9.1.12",
|
||||
"@angular/platform-browser-dynamic": "9.1.12",
|
||||
"@angular/router": "9.1.12",
|
||||
"@microsoft/signalr": "3.1.13",
|
||||
"@microsoft/signalr-protocol-msgpack": "3.1.13",
|
||||
"angular2-toaster": "8.0.0",
|
||||
"big-integer": "1.6.48",
|
||||
"bootstrap": "4.3.1",
|
||||
"braintree-web-drop-in": "1.13.0",
|
||||
"browser-hrtime": "^1.1.8",
|
||||
"core-js": "^3.11.0",
|
||||
"core-js": "2.6.2",
|
||||
"date-input-polyfill": "^2.14.0",
|
||||
"duo_web_sdk": "git+https://github.com/duosecurity/duo_web_sdk.git#5f9a1a8598d2cda494c4f5ee0e38b31474abfee9",
|
||||
"duo_web_sdk": "git+https://github.com/duosecurity/duo_web_sdk.git#410a9186cc34663c4913b17d6528067cd3331f1d",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.6.0",
|
||||
"popper.js": "1.16.1",
|
||||
"lunr": "2.3.3",
|
||||
"ngx-infinite-scroll": "7.0.1",
|
||||
"node-forge": "0.10.0",
|
||||
"papaparse": "5.2.0",
|
||||
"popper.js": "1.14.4",
|
||||
"qrious": "4.0.2",
|
||||
"sweetalert2": "^10.16.6",
|
||||
"webcrypto-shim": "0.1.7",
|
||||
"whatwg-fetch": "3.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "~14",
|
||||
"npm": "~7"
|
||||
"rxjs": "6.6.2",
|
||||
"sweetalert2": "10.15.4",
|
||||
"tslib": "^2.0.1",
|
||||
"web-animations-js": "2.3.1",
|
||||
"webcrypto-shim": "0.1.4",
|
||||
"whatwg-fetch": "3.0.0",
|
||||
"zone.js": "0.10.3",
|
||||
"zxcvbn": "4.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import {
|
||||
ToasterService,
|
||||
} from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { EmergencyAccessAcceptRequest } from 'jslib-common/models/request/emergencyAccessAcceptRequest';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { EmergencyAccessAcceptRequest } from 'jslib/models/request/emergencyAccessAcceptRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-accept-emergency',
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
Component,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ActivatedRoute,
|
||||
Router,
|
||||
@@ -13,18 +12,12 @@ import {
|
||||
ToasterService,
|
||||
} from 'angular2-toaster';
|
||||
|
||||
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 { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { OrganizationUserAcceptRequest } from 'jslib-common/models/request/organizationUserAcceptRequest';
|
||||
import { OrganizationUserResetPasswordEnrollmentRequest } from 'jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Policy } from 'jslib-common/models/domain/policy';
|
||||
import { OrganizationUserAcceptRequest } from 'jslib/models/request/organizationUserAcceptRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-accept-organization',
|
||||
@@ -40,8 +33,7 @@ export class AcceptOrganizationComponent implements OnInit {
|
||||
constructor(private router: Router, private toasterService: ToasterService,
|
||||
private i18nService: I18nService, private route: ActivatedRoute,
|
||||
private apiService: ApiService, private userService: UserService,
|
||||
private stateService: StateService, private cryptoService: CryptoService,
|
||||
private policyService: PolicyService) { }
|
||||
private stateService: StateService) { }
|
||||
|
||||
ngOnInit() {
|
||||
let fired = false;
|
||||
@@ -59,36 +51,8 @@ export class AcceptOrganizationComponent implements OnInit {
|
||||
const request = new OrganizationUserAcceptRequest();
|
||||
request.token = qParams.token;
|
||||
try {
|
||||
if (await this.performResetPasswordAutoEnroll(qParams)) {
|
||||
this.actionPromise = this.apiService.postOrganizationUserAccept(qParams.organizationId,
|
||||
qParams.organizationUserId, request).then(() => {
|
||||
// Retrieve Public Key
|
||||
return this.apiService.getOrganizationKeys(qParams.organizationId);
|
||||
}).then(async response => {
|
||||
if (response == null) {
|
||||
throw new Error(this.i18nService.t('resetPasswordOrgKeysError'));
|
||||
}
|
||||
|
||||
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
||||
|
||||
// RSA Encrypt user's encKey.key with organization public key
|
||||
const encKey = await this.cryptoService.getEncKey();
|
||||
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
|
||||
|
||||
// Create request and execute enrollment
|
||||
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
|
||||
|
||||
// Get User Id
|
||||
const userId = await this.userService.getUserId();
|
||||
|
||||
return this.apiService.putOrganizationUserResetPasswordEnrollment(qParams.organizationId, userId, resetRequest);
|
||||
});
|
||||
} else {
|
||||
this.actionPromise = this.apiService.postOrganizationUserAccept(qParams.organizationId,
|
||||
qParams.organizationUserId, request);
|
||||
}
|
||||
|
||||
this.actionPromise = this.apiService.postOrganizationUserAccept(qParams.organizationId,
|
||||
qParams.organizationUserId, request);
|
||||
await this.actionPromise;
|
||||
const toast: Toast = {
|
||||
type: 'success',
|
||||
@@ -128,21 +92,4 @@ export class AcceptOrganizationComponent implements OnInit {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
private async performResetPasswordAutoEnroll(qParams: any): Promise<boolean> {
|
||||
let policyList: Policy[] = null;
|
||||
try {
|
||||
const policies = await this.apiService.getPoliciesByToken(qParams.organizationId, qParams.token,
|
||||
qParams.email, qParams.organizationUserId);
|
||||
policyList = this.policyService.mapPoliciesFromToken(policies);
|
||||
} catch { }
|
||||
|
||||
if (policyList != null) {
|
||||
const result = this.policyService.getResetPasswordPolicyOptions(policyList, qParams.organizationId);
|
||||
// Return true if policy enabled and auto-enroll enabled
|
||||
return result[1] && result[0].autoEnrollEnabled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Component } 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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { HintComponent as BaseHintComponent } from 'jslib-angular/components/hint.component';
|
||||
import { HintComponent as BaseHintComponent } from 'jslib/angular/components/hint.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hint',
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
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 { MessagingService } from 'jslib-common/abstractions/messaging.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';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
import { RouterService } from '../services/router.service';
|
||||
|
||||
import { LockComponent as BaseLockComponent } from 'jslib-angular/components/lock.component';
|
||||
import { LockComponent as BaseLockComponent } from 'jslib/angular/components/lock.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-lock',
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
<p class="lead text-center mx-4 mb-4">{{'loginOrCreateNewAccount' | i18n}}</p>
|
||||
<div class="card d-block">
|
||||
<div class="card-body">
|
||||
<app-callout type="warning" title="{{'resetPasswordPolicyAutoEnroll' | i18n}}"
|
||||
*ngIf="showResetPasswordAutoEnrollWarning">
|
||||
{{'resetPasswordAutoEnrollInviteWarning' | i18n}}
|
||||
</app-callout>
|
||||
<div class="form-group">
|
||||
<label for="email">{{'emailAddress' | i18n}}</label>
|
||||
<input id="email" class="form-control" type="text" name="Email" [(ngModel)]="email" required
|
||||
|
||||
@@ -4,35 +4,27 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
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 { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.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';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from 'jslib-angular/components/login.component';
|
||||
|
||||
import { Policy } from 'jslib-common/models/domain/policy';
|
||||
import { LoginComponent as BaseLoginComponent } from 'jslib/angular/components/login.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: 'login.component.html',
|
||||
})
|
||||
export class LoginComponent extends BaseLoginComponent {
|
||||
|
||||
showResetPasswordAutoEnrollWarning = false;
|
||||
|
||||
constructor(authService: AuthService, router: Router,
|
||||
i18nService: I18nService, private route: ActivatedRoute,
|
||||
storageService: StorageService, stateService: StateService,
|
||||
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService,
|
||||
passwordGenerationService: PasswordGenerationService, cryptoFunctionService: CryptoFunctionService,
|
||||
private apiService: ApiService, private policyService: PolicyService) {
|
||||
passwordGenerationService: PasswordGenerationService, cryptoFunctionService: CryptoFunctionService) {
|
||||
super(authService, router,
|
||||
platformUtilsService, i18nService,
|
||||
stateService, environmentService,
|
||||
@@ -57,22 +49,6 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
queryParamsSub.unsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
const invite = await this.stateService.get<any>('orgInvitation');
|
||||
if (invite != null) {
|
||||
let policyList: Policy[] = null;
|
||||
try {
|
||||
const policies = await this.apiService.getPoliciesByToken(invite.organizationId, invite.token,
|
||||
invite.email, invite.organizationUserId);
|
||||
policyList = this.policyService.mapPoliciesFromToken(policies);
|
||||
} catch { }
|
||||
|
||||
if (policyList != null) {
|
||||
const result = this.policyService.getResetPasswordPolicyOptions(policyList, invite.organizationId);
|
||||
// Set to true if policy enabled and auto-enroll enabled
|
||||
this.showResetPasswordAutoEnrollWarning = result[1] && result[0].autoEnrollEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async goAfterLogIn() {
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { DeleteRecoverRequest } from 'jslib-common/models/request/deleteRecoverRequest';
|
||||
import { DeleteRecoverRequest } from 'jslib/models/request/deleteRecoverRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-recover-delete',
|
||||
|
||||
@@ -3,12 +3,12 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { TwoFactorRecoveryRequest } from 'jslib-common/models/request/twoFactorRecoveryRequest';
|
||||
import { TwoFactorRecoveryRequest } from 'jslib/models/request/twoFactorRecoveryRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-recover-two-factor',
|
||||
|
||||
@@ -4,22 +4,22 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.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 { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
|
||||
import { RegisterComponent as BaseRegisterComponent } from 'jslib-angular/components/register.component';
|
||||
import { RegisterComponent as BaseRegisterComponent } from 'jslib/angular/components/register.component';
|
||||
|
||||
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
|
||||
import { Policy } from 'jslib-common/models/domain/policy';
|
||||
import { MasterPasswordPolicyOptions } from 'jslib/models/domain/masterPasswordPolicyOptions';
|
||||
import { Policy } from 'jslib/models/domain/policy';
|
||||
|
||||
import { PolicyData } from 'jslib-common/models/data/policyData';
|
||||
import { ReferenceEventRequest } from 'jslib-common/models/request/referenceEventRequest';
|
||||
import { PolicyData } from 'jslib/models/data/policyData';
|
||||
import { ReferenceEventRequest } from 'jslib/models/request/referenceEventRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
|
||||
@@ -4,19 +4,19 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
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 { 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 { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import {
|
||||
SetPasswordComponent as BaseSetPasswordComponent,
|
||||
} from 'jslib-angular/components/set-password.component';
|
||||
} from 'jslib/angular/components/set-password.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-set-password',
|
||||
|
||||
@@ -4,16 +4,16 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
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 { I18nService } from 'jslib-common/abstractions/i18n.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';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { SsoComponent as BaseSsoComponent } from 'jslib-angular/components/sso.component';
|
||||
import { SsoComponent as BaseSsoComponent } from 'jslib/angular/components/sso.component';
|
||||
|
||||
const IdentifierStorageKey = 'ssoOrgIdentifier';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="twoStepOptionsTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="twoStepOptionsTitle">{{'twoStepOptions' | i18n}}</h2>
|
||||
@@ -7,19 +7,17 @@
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="#" appStopClick *ngFor="let p of providers" (click)="choose(p)"
|
||||
class="list-group-item list-group-item-action">
|
||||
<img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="pull-right">
|
||||
<h3>{{p.name}}</h3>
|
||||
{{p.description}}
|
||||
</a>
|
||||
<a href="#" appStopClick class="list-group-item list-group-item-action" (click)="recover()">
|
||||
<h3>{{'recoveryCodeTitle' | i18n}}</h3>
|
||||
{{'recoveryCodeDesc' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="#" appStopClick *ngFor="let p of providers" (click)="choose(p)"
|
||||
class="list-group-item list-group-item-action">
|
||||
<img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="pull-right">
|
||||
<h3>{{p.name}}</h3>
|
||||
{{p.description}}
|
||||
</a>
|
||||
<a href="#" appStopClick class="list-group-item list-group-item-action" (click)="recover()">
|
||||
<h3>{{'recoveryCodeTitle' | i18n}}</h3>
|
||||
{{'recoveryCodeDesc' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import {
|
||||
TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent,
|
||||
} from 'jslib-angular/components/two-factor-options.component';
|
||||
} from 'jslib/angular/components/two-factor-options.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-two-factor-options',
|
||||
|
||||
@@ -14,17 +14,17 @@ import { TwoFactorOptionsComponent } from './two-factor-options.component';
|
||||
|
||||
import { ModalComponent } from '../modal.component';
|
||||
|
||||
import { TwoFactorProviderType } from 'jslib-common/enums/twoFactorProviderType';
|
||||
import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib-angular/components/two-factor.component';
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib/angular/components/two-factor.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-two-factor',
|
||||
|
||||
@@ -9,11 +9,11 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { VerifyEmailRequest } from 'jslib-common/models/request/verifyEmailRequest';
|
||||
import { VerifyEmailRequest } from 'jslib/models/request/verifyEmailRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-verify-email-token',
|
||||
|
||||
@@ -9,10 +9,10 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { VerifyDeleteRecoverRequest } from 'jslib-common/models/request/verifyDeleteRecoverRequest';
|
||||
import { VerifyDeleteRecoverRequest } from 'jslib/models/request/verifyDeleteRecoverRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-verify-recover-delete',
|
||||
|
||||
@@ -88,11 +88,11 @@ import { VaultComponent } from './vault/vault.component';
|
||||
import { OrganizationGuardService } from './services/organization-guard.service';
|
||||
import { OrganizationTypeGuardService } from './services/organization-type-guard.service';
|
||||
|
||||
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
|
||||
import { LockGuardService } from 'jslib-angular/services/lock-guard.service';
|
||||
import { UnauthGuardService } from 'jslib-angular/services/unauth-guard.service';
|
||||
import { AuthGuardService } from 'jslib/angular/services/auth-guard.service';
|
||||
import { LockGuardService } from 'jslib/angular/services/lock-guard.service';
|
||||
import { UnauthGuardService } from 'jslib/angular/services/unauth-guard.service';
|
||||
|
||||
import { Permissions } from 'jslib-common/enums/permissions';
|
||||
import { Permissions } from 'jslib/enums/permissions';
|
||||
|
||||
import { EmergencyAccessViewComponent } from './settings/emergency-access-view.component';
|
||||
import { EmergencyAccessComponent } from './settings/emergency-access.component';
|
||||
@@ -200,12 +200,12 @@ const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: EmergencyAccessComponent,
|
||||
data: { titleId: 'emergencyAccess' },
|
||||
data: { titleId: 'emergencyAccess'},
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: EmergencyAccessViewComponent,
|
||||
data: { titleId: 'emergencyAccess' },
|
||||
data: { titleId: 'emergencyAccess'},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -390,7 +390,7 @@ const routes: Routes = [
|
||||
canActivate: [OrganizationTypeGuardService],
|
||||
data: {
|
||||
titleId: 'people',
|
||||
permissions: [Permissions.ManageUsers, Permissions.ManageUsersPassword],
|
||||
permissions: [Permissions.ManageUsers],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as jq from 'jquery';
|
||||
import Swal from 'sweetalert2';
|
||||
import Swal from 'sweetalert2/dist/sweetalert2.js';
|
||||
|
||||
import {
|
||||
BodyOutputType,
|
||||
@@ -21,30 +21,30 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.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 { NotificationsService } from 'jslib-common/abstractions/notifications.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 { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
import { SettingsService } from 'jslib-common/abstractions/settings.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
||||
import { TokenService } from 'jslib-common/abstractions/token.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { EventService } from 'jslib/abstractions/event.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { NotificationsService } from 'jslib/abstractions/notifications.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { SettingsService } from 'jslib/abstractions/settings.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { TokenService } from 'jslib/abstractions/token.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
import { RouterService } from './services/router.service';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'core-js';
|
||||
|
||||
import { ToasterModule } from 'angular2-toaster';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
|
||||
@@ -38,9 +40,6 @@ import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||
import { VerifyEmailTokenComponent } from './accounts/verify-email-token.component';
|
||||
import { VerifyRecoverDeleteComponent } from './accounts/verify-recover-delete.component';
|
||||
|
||||
import { BulkConfirmComponent as OrgBulkConfirmComponent } from './organizations/manage/bulk/bulk-confirm.component';
|
||||
import { BulkRemoveComponent as OrgBulkRemoveComponent } from './organizations/manage/bulk/bulk-remove.component';
|
||||
import { BulkStatusComponent as OrgBulkStatusComponent } from './organizations/manage/bulk/bulk-status.component';
|
||||
import {
|
||||
CollectionAddEditComponent as OrgCollectionAddEditComponent,
|
||||
} from './organizations/manage/collection-add-edit.component';
|
||||
@@ -54,7 +53,6 @@ import { ManageComponent as OrgManageComponent } from './organizations/manage/ma
|
||||
import { PeopleComponent as OrgPeopleComponent } from './organizations/manage/people.component';
|
||||
import { PoliciesComponent as OrgPoliciesComponent } from './organizations/manage/policies.component';
|
||||
import { PolicyEditComponent as OrgPolicyEditComponent } from './organizations/manage/policy-edit.component';
|
||||
import { ResetPasswordComponent as OrgResetPasswordComponent } from './organizations/manage/reset-password.component';
|
||||
import { UserAddEditComponent as OrgUserAddEditComponent } from './organizations/manage/user-add-edit.component';
|
||||
import { UserConfirmComponent as OrgUserConfirmComponent } from './organizations/manage/user-confirm.component';
|
||||
import { UserGroupsComponent as OrgUserGroupsComponent } from './organizations/manage/user-groups.component';
|
||||
@@ -171,47 +169,40 @@ import { SendInfoComponent } from './vault/send-info.component';
|
||||
import { ShareComponent } from './vault/share.component';
|
||||
import { VaultComponent } from './vault/vault.component';
|
||||
|
||||
import { CalloutComponent } from 'jslib-angular/components/callout.component';
|
||||
import { IconComponent } from 'jslib-angular/components/icon.component';
|
||||
import { CalloutComponent } from 'jslib/angular/components/callout.component';
|
||||
import { IconComponent } from 'jslib/angular/components/icon.component';
|
||||
|
||||
import { A11yTitleDirective } from 'jslib-angular/directives/a11y-title.directive';
|
||||
import { ApiActionDirective } from 'jslib-angular/directives/api-action.directive';
|
||||
import { AutofocusDirective } from 'jslib-angular/directives/autofocus.directive';
|
||||
import { BlurClickDirective } from 'jslib-angular/directives/blur-click.directive';
|
||||
import { BoxRowDirective } from 'jslib-angular/directives/box-row.directive';
|
||||
import { FallbackSrcDirective } from 'jslib-angular/directives/fallback-src.directive';
|
||||
import { InputVerbatimDirective } from 'jslib-angular/directives/input-verbatim.directive';
|
||||
import { SelectCopyDirective } from 'jslib-angular/directives/select-copy.directive';
|
||||
import { StopClickDirective } from 'jslib-angular/directives/stop-click.directive';
|
||||
import { StopPropDirective } from 'jslib-angular/directives/stop-prop.directive';
|
||||
import { TrueFalseValueDirective } from 'jslib-angular/directives/true-false-value.directive';
|
||||
import { A11yTitleDirective } from 'jslib/angular/directives/a11y-title.directive';
|
||||
import { ApiActionDirective } from 'jslib/angular/directives/api-action.directive';
|
||||
import { AutofocusDirective } from 'jslib/angular/directives/autofocus.directive';
|
||||
import { BlurClickDirective } from 'jslib/angular/directives/blur-click.directive';
|
||||
import { BoxRowDirective } from 'jslib/angular/directives/box-row.directive';
|
||||
import { FallbackSrcDirective } from 'jslib/angular/directives/fallback-src.directive';
|
||||
import { InputVerbatimDirective } from 'jslib/angular/directives/input-verbatim.directive';
|
||||
import { SelectCopyDirective } from 'jslib/angular/directives/select-copy.directive';
|
||||
import { StopClickDirective } from 'jslib/angular/directives/stop-click.directive';
|
||||
import { StopPropDirective } from 'jslib/angular/directives/stop-prop.directive';
|
||||
import { TrueFalseValueDirective } from 'jslib/angular/directives/true-false-value.directive';
|
||||
|
||||
import { ColorPasswordPipe } from 'jslib-angular/pipes/color-password.pipe';
|
||||
import { I18nPipe } from 'jslib-angular/pipes/i18n.pipe';
|
||||
import { SearchCiphersPipe } from 'jslib-angular/pipes/search-ciphers.pipe';
|
||||
import { SearchPipe } from 'jslib-angular/pipes/search.pipe';
|
||||
import { ColorPasswordPipe } from 'jslib/angular/pipes/color-password.pipe';
|
||||
import { I18nPipe } from 'jslib/angular/pipes/i18n.pipe';
|
||||
import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
import { SearchPipe } from 'jslib/angular/pipes/search.pipe';
|
||||
|
||||
import {
|
||||
DatePipe,
|
||||
registerLocaleData,
|
||||
} from '@angular/common';
|
||||
import localeBg from '@angular/common/locales/bg';
|
||||
import localeCa from '@angular/common/locales/ca';
|
||||
import localeCs from '@angular/common/locales/cs';
|
||||
import localeDa from '@angular/common/locales/da';
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import localeEl from '@angular/common/locales/el';
|
||||
import localeEnGb from '@angular/common/locales/en-GB';
|
||||
import localeEnIn from '@angular/common/locales/en-IN';
|
||||
import localeEo from '@angular/common/locales/eo';
|
||||
import localeEs from '@angular/common/locales/es';
|
||||
import localeEt from '@angular/common/locales/et';
|
||||
import localeFi from '@angular/common/locales/fi';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeHe from '@angular/common/locales/he';
|
||||
import localeHr from '@angular/common/locales/hr';
|
||||
import localeHu from '@angular/common/locales/hu';
|
||||
import localeId from '@angular/common/locales/id';
|
||||
import localeIt from '@angular/common/locales/it';
|
||||
import localeJa from '@angular/common/locales/ja';
|
||||
import localeKo from '@angular/common/locales/ko';
|
||||
@@ -222,33 +213,23 @@ import localeNl from '@angular/common/locales/nl';
|
||||
import localePl from '@angular/common/locales/pl';
|
||||
import localePtBr from '@angular/common/locales/pt';
|
||||
import localePtPt from '@angular/common/locales/pt-PT';
|
||||
import localeRo from '@angular/common/locales/ro';
|
||||
import localeRu from '@angular/common/locales/ru';
|
||||
import localeSk from '@angular/common/locales/sk';
|
||||
import localeSr from '@angular/common/locales/sr';
|
||||
import localeSv from '@angular/common/locales/sv';
|
||||
import localeTr from '@angular/common/locales/tr';
|
||||
import localeUk from '@angular/common/locales/uk';
|
||||
import localeZhCn from '@angular/common/locales/zh-Hans';
|
||||
import localeZhTw from '@angular/common/locales/zh-Hant';
|
||||
|
||||
registerLocaleData(localeCa, 'ca');
|
||||
registerLocaleData(localeCs, 'cs');
|
||||
registerLocaleData(localeBg, 'bg');
|
||||
registerLocaleData(localeDa, 'da');
|
||||
registerLocaleData(localeDe, 'de');
|
||||
registerLocaleData(localeEl, 'el');
|
||||
registerLocaleData(localeEnGb, 'en-GB');
|
||||
registerLocaleData(localeEnIn, 'en-IN');
|
||||
registerLocaleData(localeEs, 'es');
|
||||
registerLocaleData(localeEt, 'et');
|
||||
registerLocaleData(localeEo, 'eo');
|
||||
registerLocaleData(localeFi, 'fi');
|
||||
registerLocaleData(localeFr, 'fr');
|
||||
registerLocaleData(localeHe, 'he');
|
||||
registerLocaleData(localeHr, 'hr');
|
||||
registerLocaleData(localeHu, 'hu');
|
||||
registerLocaleData(localeId, 'id');
|
||||
registerLocaleData(localeIt, 'it');
|
||||
registerLocaleData(localeJa, 'ja');
|
||||
registerLocaleData(localeKo, 'ko');
|
||||
@@ -259,12 +240,9 @@ registerLocaleData(localeNl, 'nl');
|
||||
registerLocaleData(localePl, 'pl');
|
||||
registerLocaleData(localePtBr, 'pt-BR');
|
||||
registerLocaleData(localePtPt, 'pt-PT');
|
||||
registerLocaleData(localeRo, 'ro');
|
||||
registerLocaleData(localeRu, 'ru');
|
||||
registerLocaleData(localeSk, 'sk');
|
||||
registerLocaleData(localeSr, 'sr');
|
||||
registerLocaleData(localeSv, 'sv');
|
||||
registerLocaleData(localeTr, 'tr');
|
||||
registerLocaleData(localeUk, 'uk');
|
||||
registerLocaleData(localeZhCn, 'zh-CN');
|
||||
registerLocaleData(localeZhTw, 'zh-TW');
|
||||
@@ -352,9 +330,6 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
OrganizationPlansComponent,
|
||||
OrganizationSubscriptionComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgBulkStatusComponent,
|
||||
OrgBulkConfirmComponent,
|
||||
OrgBulkRemoveComponent,
|
||||
OrgCiphersComponent,
|
||||
OrgCollectionAddEditComponent,
|
||||
OrgCollectionsComponent,
|
||||
@@ -373,7 +348,6 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
OrgPeopleComponent,
|
||||
OrgPolicyEditComponent,
|
||||
OrgPoliciesComponent,
|
||||
OrgResetPasswordComponent,
|
||||
OrgReusedPasswordsReportComponent,
|
||||
OrgSettingComponent,
|
||||
OrgToolsComponent,
|
||||
@@ -455,16 +429,12 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
ModalComponent,
|
||||
OrgAddEditComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgBulkStatusComponent,
|
||||
OrgBulkConfirmComponent,
|
||||
OrgBulkRemoveComponent,
|
||||
OrgCollectionAddEditComponent,
|
||||
OrgCollectionsComponent,
|
||||
OrgEntityEventsComponent,
|
||||
OrgEntityUsersComponent,
|
||||
OrgGroupAddEditComponent,
|
||||
OrgPolicyEditComponent,
|
||||
OrgResetPasswordComponent,
|
||||
OrgUserAddEditComponent,
|
||||
OrgUserConfirmComponent,
|
||||
OrgUserGroupsComponent,
|
||||
@@ -481,7 +451,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
TwoFactorYubiKeyComponent,
|
||||
UpdateKeyComponent,
|
||||
],
|
||||
providers: [DatePipe, SearchPipe],
|
||||
providers: [DatePipe],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
} 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 { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-avatar',
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
OnChanges,
|
||||
} from '@angular/core';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-strength',
|
||||
|
||||
12
src/app/dummy.module.ts
Normal file
12
src/app/dummy.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { ModalComponent } from 'jslib/angular/components/modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
declarations: [
|
||||
ModalComponent,
|
||||
],
|
||||
})
|
||||
export class DummyModule {
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-frontend-layout',
|
||||
|
||||
@@ -3,9 +3,9 @@ import {
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { TokenService } from 'jslib-common/abstractions/token.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { TokenService } from 'jslib/abstractions/token.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
|
||||
@@ -7,14 +7,14 @@ import {
|
||||
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
|
||||
const BroadcasterSubscriptionId = 'OrganizationLayoutComponent';
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ModalComponent as BaseModalComponent } from 'jslib-angular/components/modal.component';
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { ModalComponent as BaseModalComponent } from 'jslib/angular/components/modal.component';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-modal',
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="bulkTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="bulkTitle">
|
||||
{{'confirmUsers' | i18n}}
|
||||
</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-body text-center" *ngIf="loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
{{'loading' | i18n}}
|
||||
</div>
|
||||
<app-callout type="danger" *ngIf="filteredUsers.length <= 0">
|
||||
{{'noSelectedUsersApplicable' | i18n}}
|
||||
</app-callout>
|
||||
<app-callout type="error" *ngIf="error">
|
||||
{{error}}
|
||||
</app-callout>
|
||||
<ng-container *ngIf="!loading && !done">
|
||||
<p>
|
||||
{{'fingerprintEnsureIntegrityVerify' | i18n}}
|
||||
<a href="https://help.bitwarden.com/article/fingerprint-phrase/" target="_blank" rel="noopener">
|
||||
{{'learnMore' | i18n}}</a>
|
||||
</p>
|
||||
<table class="table table-hover table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
<th>{{'fingerprint' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of filteredUsers">
|
||||
<td width="30">
|
||||
<app-avatar [data]="user.name || user.email" [email]="user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<small class="text-muted d-block" *ngIf="user.name">{{user.name}}</small>
|
||||
</td>
|
||||
<td>
|
||||
{{fingerprints.get(user.id)}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngFor="let user of excludedUsers">
|
||||
<td width="30">
|
||||
<app-avatar [data]="user.name || user.email" [email]="user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<small class="text-muted d-block" *ngIf="user.name">{{user.name}}</small>
|
||||
</td>
|
||||
<td>
|
||||
{{'bulkFilteredMessage' | i18n}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!loading && done">
|
||||
<table class="table table-hover table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
<th>{{'status' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of filteredUsers">
|
||||
<td width="30">
|
||||
<app-avatar [data]="user.name || user.email" [email]="user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<small class="text-muted d-block" *ngIf="user.name">{{user.name}}</small>
|
||||
</td>
|
||||
<td *ngIf="statuses.has(user.id)">
|
||||
{{statuses.get(user.id)}}
|
||||
</td>
|
||||
<td *ngIf="!statuses.has(user.id)">
|
||||
{{'bulkFilteredMessage' | i18n}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit" *ngIf="!done" [disabled]="loading" (click)="submit()">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'confirm' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,95 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
} 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 { OrganizationUserBulkConfirmRequest } from 'jslib-common/models/request/organizationUserBulkConfirmRequest';
|
||||
import { OrganizationUserBulkRequest } from 'jslib-common/models/request/organizationUserBulkRequest';
|
||||
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib-common/models/response/organizationUserResponse';
|
||||
|
||||
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bulk-confirm',
|
||||
templateUrl: 'bulk-confirm.component.html',
|
||||
})
|
||||
export class BulkConfirmComponent implements OnInit {
|
||||
|
||||
@Input() organizationId: string;
|
||||
@Input() users: OrganizationUserUserDetailsResponse[];
|
||||
|
||||
excludedUsers: OrganizationUserUserDetailsResponse[];
|
||||
filteredUsers: OrganizationUserUserDetailsResponse[];
|
||||
publicKeys: Map<string, Uint8Array> = new Map();
|
||||
fingerprints: Map<string, string> = new Map();
|
||||
statuses: Map<string, string> = new Map();
|
||||
|
||||
loading: boolean = true;
|
||||
done: boolean = false;
|
||||
error: string;
|
||||
|
||||
constructor(private cryptoService: CryptoService, private apiService: ApiService,
|
||||
private i18nService: I18nService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.excludedUsers = this.users.filter(user => user.status !== OrganizationUserStatusType.Accepted);
|
||||
this.filteredUsers = this.users.filter(user => user.status === OrganizationUserStatusType.Accepted);
|
||||
|
||||
if (this.filteredUsers.length <= 0) {
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
const request = new OrganizationUserBulkRequest(this.filteredUsers.map(user => user.id));
|
||||
const response = await this.apiService.postOrganizationUsersPublicKey(this.organizationId, request);
|
||||
|
||||
for (const entry of response.data) {
|
||||
const publicKey = Utils.fromB64ToArray(entry.key);
|
||||
const fingerprint = await this.cryptoService.getFingerprint(entry.userId, publicKey.buffer);
|
||||
if (fingerprint != null) {
|
||||
this.publicKeys.set(entry.id, publicKey);
|
||||
this.fingerprints.set(entry.id, fingerprint.join('-'));
|
||||
}
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const userIdsWithKeys: any[] = [];
|
||||
for (const user of this.filteredUsers) {
|
||||
const publicKey = this.publicKeys.get(user.id);
|
||||
if (publicKey == null) {
|
||||
continue;
|
||||
}
|
||||
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||
userIdsWithKeys.push({
|
||||
id: user.id,
|
||||
key: key.encryptedString,
|
||||
});
|
||||
}
|
||||
const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys);
|
||||
const response = await this.apiService.postOrganizationUserBulkConfirm(this.organizationId, request);
|
||||
|
||||
response.data.forEach(entry => {
|
||||
const error = entry.error !== '' ? entry.error : this.i18nService.t('bulkConfirmMessage');
|
||||
this.statuses.set(entry.id, error);
|
||||
});
|
||||
|
||||
this.done = true;
|
||||
} catch (e) {
|
||||
this.error = e.message;
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="bulkTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="bulkTitle">
|
||||
{{'removeUsers' | i18n}}
|
||||
</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-body text-center" *ngIf="loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
{{'loading' | i18n}}
|
||||
</div>
|
||||
<app-callout type="danger" *ngIf="users.length <= 0">
|
||||
{{'noSelectedUsersApplicable' | i18n}}
|
||||
</app-callout>
|
||||
<app-callout type="error" *ngIf="error">
|
||||
{{error}}
|
||||
</app-callout>
|
||||
<ng-container *ngIf="!loading && !done">
|
||||
<app-callout type="warning" *ngIf="users.length > 0 && !error">
|
||||
{{'removeUsersWarning' | i18n}}
|
||||
</app-callout>
|
||||
<table class="table table-hover table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of users">
|
||||
<td width="30">
|
||||
<app-avatar [data]="user.name || user.email" [email]="user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<small class="text-muted d-block" *ngIf="user.name">{{user.name}}</small>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!loading && done">
|
||||
<table class="table table-hover table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
<th>{{'status' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of users">
|
||||
<td width="30">
|
||||
<app-avatar [data]="user.name || user.email" [email]="user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<small class="text-muted d-block" *ngIf="user.name">{{user.name}}</small>
|
||||
</td>
|
||||
<td *ngIf="statuses.has(user.id)">
|
||||
{{statuses.get(user.id)}}
|
||||
</td>
|
||||
<td *ngIf="!statuses.has(user.id)">
|
||||
{{'bulkFilteredMessage' | i18n}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit" *ngIf="!done && users.length > 0" [disabled]="loading" (click)="submit()">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'removeUsers' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { OrganizationUserBulkRequest } from 'jslib-common/models/request/organizationUserBulkRequest';
|
||||
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib-common/models/response/organizationUserResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bulk-remove',
|
||||
templateUrl: 'bulk-remove.component.html',
|
||||
})
|
||||
export class BulkRemoveComponent {
|
||||
|
||||
@Input() organizationId: string;
|
||||
@Input() users: OrganizationUserUserDetailsResponse[];
|
||||
|
||||
statuses: Map<string, string> = new Map();
|
||||
|
||||
loading: boolean = false;
|
||||
done: boolean = false;
|
||||
error: string;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService) { }
|
||||
|
||||
async submit() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const request = new OrganizationUserBulkRequest(this.users.map(user => user.id));
|
||||
const response = await this.apiService.deleteManyOrganizationUsers(this.organizationId, request);
|
||||
|
||||
response.data.forEach(entry => {
|
||||
const error = entry.error !== '' ? entry.error : this.i18nService.t('bulkRemovedMessage');
|
||||
this.statuses.set(entry.id, error);
|
||||
});
|
||||
this.done = true;
|
||||
} catch (e) {
|
||||
this.error = e.message;
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="bulkTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="bulkTitle">
|
||||
{{'bulkConfirmStatus' | i18n}}
|
||||
</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-body text-center" *ngIf="loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
{{'loading' | i18n}}
|
||||
</div>
|
||||
<table class="table table-hover table-list" *ngIf="!loading">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
<th>{{'status' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let item of users">
|
||||
<td width="30">
|
||||
<app-avatar [data]="item.user.name || item.user.email" [email]="item.user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{item.user.email}}
|
||||
<small class="text-muted d-block" *ngIf="item.user.name">{{item.user.name}}</small>
|
||||
</td>
|
||||
<td class="text-danger" *ngIf="item.error">
|
||||
{{item.message}}
|
||||
</td>
|
||||
<td *ngIf="!item.error">
|
||||
{{item.message}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,20 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib-common/models/response/organizationUserResponse';
|
||||
|
||||
type BulkStatusEntry = {
|
||||
user: OrganizationUserUserDetailsResponse,
|
||||
error: boolean,
|
||||
message: string,
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-bulk-status',
|
||||
templateUrl: 'bulk-status.component.html',
|
||||
})
|
||||
export class BulkStatusComponent {
|
||||
|
||||
users: BulkStatusEntry[];
|
||||
loading: boolean = false;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="collectionAddEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="collectionAddEditTitle">{{title}}</h2>
|
||||
|
||||
@@ -8,19 +8,19 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { EncString } from 'jslib-common/models/domain/encString';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
import { CollectionRequest } from 'jslib-common/models/request/collectionRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib-common/models/request/selectionReadOnlyRequest';
|
||||
import { GroupResponse } from 'jslib-common/models/response/groupResponse';
|
||||
import { EncString } from 'jslib/models/domain/encString';
|
||||
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
|
||||
import { CollectionRequest } from 'jslib/models/request/collectionRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib/models/request/selectionReadOnlyRequest';
|
||||
import { GroupResponse } from 'jslib/models/response/groupResponse';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-collection-add-edit',
|
||||
|
||||
@@ -9,21 +9,21 @@ import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { CollectionData } from 'jslib-common/models/data/collectionData';
|
||||
import { Collection } from 'jslib-common/models/domain/collection';
|
||||
import { CollectionData } from 'jslib/models/data/collectionData';
|
||||
import { Collection } from 'jslib/models/domain/collection';
|
||||
import {
|
||||
CollectionDetailsResponse,
|
||||
CollectionResponse,
|
||||
} from 'jslib-common/models/response/collectionResponse';
|
||||
import { ListResponse } from 'jslib-common/models/response/listResponse';
|
||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
||||
} from 'jslib/models/response/collectionResponse';
|
||||
import { ListResponse } from 'jslib/models/response/listResponse';
|
||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
import { CollectionAddEditComponent } from './collection-add-edit.component';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="eventLogsTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="eventLogsTitle">
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { EventService } from '../../services/event.service';
|
||||
|
||||
import { EventResponse } from 'jslib-common/models/response/eventResponse';
|
||||
import { ListResponse } from 'jslib-common/models/response/listResponse';
|
||||
import { EventResponse } from 'jslib/models/response/eventResponse';
|
||||
import { ListResponse } from 'jslib/models/response/listResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-entity-events',
|
||||
@@ -94,9 +94,9 @@ export class EntityEventsComponent implements OnInit {
|
||||
} catch { }
|
||||
|
||||
this.continuationToken = response.continuationToken;
|
||||
const events = await Promise.all(response.data.map(async r => {
|
||||
const events = response.data.map(r => {
|
||||
const userId = r.actingUserId == null ? r.userId : r.actingUserId;
|
||||
const eventInfo = await this.eventService.getEventInfo(r);
|
||||
const eventInfo = this.eventService.getEventInfo(r);
|
||||
const user = this.showUser && userId != null && this.orgUsersUserIdMap.has(userId) ?
|
||||
this.orgUsersUserIdMap.get(userId) : null;
|
||||
return {
|
||||
@@ -110,7 +110,7 @@ export class EntityEventsComponent implements OnInit {
|
||||
ip: r.ipAddress,
|
||||
type: r.type,
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
||||
if (!clearExisting && this.events != null && this.events.length > 0) {
|
||||
this.events = this.events.concat(events);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="userAccessTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="userAccessTitle">
|
||||
|
||||
@@ -8,15 +8,15 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from 'jslib-common/enums/organizationUserType';
|
||||
import { SelectionReadOnlyRequest } from 'jslib-common/models/request/selectionReadOnlyRequest';
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib-common/models/response/organizationUserResponse';
|
||||
import { OrganizationUserStatusType } from 'jslib/enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from 'jslib/enums/organizationUserType';
|
||||
import { SelectionReadOnlyRequest } from 'jslib/models/request/selectionReadOnlyRequest';
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib/models/response/organizationUserResponse';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-entity-users',
|
||||
|
||||
@@ -4,29 +4,17 @@
|
||||
<div class="form-inline">
|
||||
<label class="sr-only" for="start">{{'startDate' | i18n}}</label>
|
||||
<input type="datetime-local" class="form-control form-control-sm" id="start"
|
||||
placeholder="{{'startDate' | i18n}}" [(ngModel)]="start" placeholder="YYYY-MM-DDTHH:MM"
|
||||
(change)="dirtyDates = true">
|
||||
placeholder="{{'startDate' | i18n}}" [(ngModel)]="start" placeholder="YYYY-MM-DDTHH:MM">
|
||||
<span class="mx-2">-</span>
|
||||
<label class="sr-only" for="end">{{'endDate' | i18n}}</label>
|
||||
<input type="datetime-local" class="form-control form-control-sm" id="end"
|
||||
placeholder="{{'endDate' | i18n}}" [(ngModel)]="end" placeholder="YYYY-MM-DDTHH:MM"
|
||||
(change)="dirtyDates = true">
|
||||
placeholder="{{'endDate' | i18n}}" [(ngModel)]="end" placeholder="YYYY-MM-DDTHH:MM">
|
||||
</div>
|
||||
<form #refreshForm [appApiAction]="refreshPromise" class="d-inline">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ml-3" (click)="loadEvents(true)"
|
||||
[disabled]="loaded && refreshForm.loading">
|
||||
<i class="fa fa-refresh fa-fw" aria-hidden="true" [ngClass]="{'fa-spin': loaded && refreshForm.loading}"></i>
|
||||
{{'refresh' | i18n}}
|
||||
</button>
|
||||
</form>
|
||||
<form #exportForm [appApiAction]="exportPromise" class="d-inline">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary btn-submit manual ml-3"
|
||||
[ngClass]="{loading:exportForm.loading}" (click)="exportEvents()"
|
||||
[disabled]="loaded && exportForm.loading || dirtyDates">
|
||||
<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>
|
||||
<span>{{'export' | i18n}}</span>
|
||||
</button>
|
||||
</form>
|
||||
<button #refreshBtn [appApiAction]="refreshPromise" type="button" class="btn btn-sm btn-outline-primary ml-3"
|
||||
(click)="loadEvents(true)" [disabled]="loaded && refreshBtn.loading">
|
||||
<i class="fa fa-refresh fa-fw" aria-hidden="true" [ngClass]="{'fa-spin': loaded && refreshBtn.loading}"></i>
|
||||
{{'refresh' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="!loaded">
|
||||
|
||||
@@ -6,18 +6,15 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { ExportService } from 'jslib-common/abstractions/export.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
|
||||
import { EventResponse } from 'jslib-common/models/response/eventResponse';
|
||||
import { ListResponse } from 'jslib-common/models/response/listResponse';
|
||||
import { EventView } from 'jslib-common/models/view/eventView';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { EventService } from '../../services/event.service';
|
||||
|
||||
import { EventResponse } from 'jslib/models/response/eventResponse';
|
||||
import { ListResponse } from 'jslib/models/response/listResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-events',
|
||||
templateUrl: 'events.component.html',
|
||||
@@ -26,21 +23,19 @@ export class EventsComponent implements OnInit {
|
||||
loading = true;
|
||||
loaded = false;
|
||||
organizationId: string;
|
||||
events: EventView[];
|
||||
events: any[];
|
||||
start: string;
|
||||
end: string;
|
||||
dirtyDates: boolean = true;
|
||||
continuationToken: string;
|
||||
refreshPromise: Promise<any>;
|
||||
exportPromise: Promise<any>;
|
||||
morePromise: Promise<any>;
|
||||
|
||||
private orgUsersUserIdMap = new Map<string, any>();
|
||||
private orgUsersIdMap = new Map<string, any>();
|
||||
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute, private eventService: EventService,
|
||||
private i18nService: I18nService, private toasterService: ToasterService, private userService: UserService,
|
||||
private exportService: ExportService, private platformUtilsService: PlatformUtilsService,
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute,
|
||||
private eventService: EventService, private i18nService: I18nService,
|
||||
private toasterService: ToasterService, private userService: UserService,
|
||||
private router: Router) { }
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -69,91 +64,41 @@ export class EventsComponent implements OnInit {
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
async exportEvents() {
|
||||
if (this.appApiPromiseUnfulfilled() || this.dirtyDates) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
const dates = this.parseDates();
|
||||
if (dates == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.exportPromise = this.export(dates[0], dates[1]);
|
||||
|
||||
await this.exportPromise;
|
||||
} catch { }
|
||||
|
||||
this.exportPromise = null;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async loadEvents(clearExisting: boolean) {
|
||||
if (this.appApiPromiseUnfulfilled()) {
|
||||
if (this.refreshPromise != null || this.morePromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dates = this.parseDates();
|
||||
if (dates == null) {
|
||||
let dates: string[] = null;
|
||||
try {
|
||||
dates = this.eventService.formatDateFilters(this.start, this.end);
|
||||
} catch (e) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidDateRange'));
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
let events: EventView[] = [];
|
||||
let response: ListResponse<EventResponse>;
|
||||
try {
|
||||
const promise = this.loadAndParseEvents(dates[0], dates[1], clearExisting ? null : this.continuationToken);
|
||||
const promise = this.apiService.getEventsOrganization(this.organizationId, dates[0], dates[1],
|
||||
clearExisting ? null : this.continuationToken);
|
||||
if (clearExisting) {
|
||||
this.refreshPromise = promise;
|
||||
} else {
|
||||
this.morePromise = promise;
|
||||
}
|
||||
const result = await promise;
|
||||
this.continuationToken = result.continuationToken;
|
||||
events = result.events;
|
||||
response = await promise;
|
||||
} catch { }
|
||||
|
||||
if (!clearExisting && this.events != null && this.events.length > 0) {
|
||||
this.events = this.events.concat(events);
|
||||
} else {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
this.dirtyDates = false;
|
||||
this.loading = false;
|
||||
this.morePromise = null;
|
||||
this.refreshPromise = null;
|
||||
}
|
||||
|
||||
private async export(start: string, end: string) {
|
||||
let continuationToken = this.continuationToken;
|
||||
let events = [].concat(this.events);
|
||||
|
||||
while (continuationToken != null) {
|
||||
const result = await this.loadAndParseEvents(start, end, continuationToken);
|
||||
continuationToken = result.continuationToken;
|
||||
events = events.concat(result.events);
|
||||
}
|
||||
|
||||
const data = await this.exportService.getEventExport(events);
|
||||
const fileName = this.exportService.getFileName('org-events', 'csv');
|
||||
this.platformUtilsService.saveFile(window, data, { type: 'text/plain' }, fileName);
|
||||
}
|
||||
|
||||
private async loadAndParseEvents(startDate: string, endDate: string, continuationToken: string) {
|
||||
const response = await this.apiService.getEventsOrganization(this.organizationId, startDate, endDate,
|
||||
continuationToken);
|
||||
|
||||
const events = await Promise.all(response.data.map(async r => {
|
||||
this.continuationToken = response.continuationToken;
|
||||
const events = response.data.map(r => {
|
||||
const userId = r.actingUserId == null ? r.userId : r.actingUserId;
|
||||
const eventInfo = await this.eventService.getEventInfo(r);
|
||||
const eventInfo = this.eventService.getEventInfo(r);
|
||||
const user = userId != null && this.orgUsersUserIdMap.has(userId) ?
|
||||
this.orgUsersUserIdMap.get(userId) : null;
|
||||
return new EventView({
|
||||
return {
|
||||
message: eventInfo.message,
|
||||
humanReadableMessage: eventInfo.humanReadableMessage,
|
||||
appIcon: eventInfo.appIcon,
|
||||
appName: eventInfo.appName,
|
||||
userId: userId,
|
||||
@@ -162,24 +107,17 @@ export class EventsComponent implements OnInit {
|
||||
date: r.date,
|
||||
ip: r.ipAddress,
|
||||
type: r.type,
|
||||
});
|
||||
}));
|
||||
return { continuationToken: response.continuationToken, events: events };
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
private parseDates() {
|
||||
let dates: string[] = null;
|
||||
try {
|
||||
dates = this.eventService.formatDateFilters(this.start, this.end);
|
||||
} catch (e) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidDateRange'));
|
||||
return null;
|
||||
if (!clearExisting && this.events != null && this.events.length > 0) {
|
||||
this.events = this.events.concat(events);
|
||||
} else {
|
||||
this.events = events;
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
private appApiPromiseUnfulfilled() {
|
||||
return this.refreshPromise != null || this.morePromise != null || this.exportPromise != null;
|
||||
this.loading = false;
|
||||
this.morePromise = null;
|
||||
this.refreshPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="groupAddEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="groupAddEditTitle">{{title}}</h2>
|
||||
|
||||
@@ -8,17 +8,17 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { CollectionData } from 'jslib-common/models/data/collectionData';
|
||||
import { Collection } from 'jslib-common/models/domain/collection';
|
||||
import { GroupRequest } from 'jslib-common/models/request/groupRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib-common/models/request/selectionReadOnlyRequest';
|
||||
import { CollectionDetailsResponse } from 'jslib-common/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
||||
import { CollectionData } from 'jslib/models/data/collectionData';
|
||||
import { Collection } from 'jslib/models/domain/collection';
|
||||
import { GroupRequest } from 'jslib/models/request/groupRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib/models/request/selectionReadOnlyRequest';
|
||||
import { CollectionDetailsResponse } from 'jslib/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||
|
||||
@Component({
|
||||
selector: 'app-group-add-edit',
|
||||
|
||||
@@ -12,15 +12,15 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { GroupResponse } from 'jslib-common/models/response/groupResponse';
|
||||
import { GroupResponse } from 'jslib/models/response/groupResponse';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
import { EntityUsersComponent } from './entity-users.component';
|
||||
|
||||
@@ -4,9 +4,9 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-manage',
|
||||
|
||||
@@ -25,36 +25,6 @@
|
||||
<input type="search" class="form-control form-control-sm" id="search" placeholder="{{'search' | i18n}}"
|
||||
[(ngModel)]="searchText">
|
||||
</div>
|
||||
<div class="dropdown ml-3" appListDropdown>
|
||||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" id="bulkActionsButton"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" appA11yTitle="{{'options' | i18n}}">
|
||||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="bulkActionsButton">
|
||||
<button class="dropdown-item" appStopClick (click)="bulkReinvite()">
|
||||
<i class="fa fa-fw fa-envelope-o" aria-hidden="true"></i>
|
||||
{{'reinviteSelected' | i18n}}
|
||||
</button>
|
||||
<button class="dropdown-item text-success" appStopClick (click)="bulkConfirm()"
|
||||
*ngIf="showBulkConfirmUsers">
|
||||
<i class="fa fa-fw fa-check" aria-hidden="true"></i>
|
||||
{{'confirmSelected' | i18n}}
|
||||
</button>
|
||||
<button class="dropdown-item text-danger" appStopClick (click)="bulkRemove()">
|
||||
<i class="fa fa-fw fa-remove" aria-hidden="true"></i>
|
||||
{{'remove' | i18n}}
|
||||
</button>
|
||||
<div class="dropdown-divider"></div>
|
||||
<button class="dropdown-item" appStopClick (click)="selectAll(true)">
|
||||
<i class="fa fa-fw fa-check-square-o" aria-hidden="true"></i>
|
||||
{{'selectAll' | i18n}}
|
||||
</button>
|
||||
<button class="dropdown-item" appStopClick (click)="selectAll(false)">
|
||||
<i class="fa fa-fw fa-minus-square-o" aria-hidden="true"></i>
|
||||
{{'unselectAll' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ml-3" (click)="invite()">
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
||||
{{'inviteUser' | i18n}}
|
||||
@@ -76,9 +46,6 @@
|
||||
[infiniteScrollDisabled]="!isPaging()" (scrolled)="loadMore()">
|
||||
<tbody>
|
||||
<tr *ngFor="let u of searchedUsers">
|
||||
<td (click)="checkUser(u)" class="table-list-checkbox">
|
||||
<input type="checkbox" [(ngModel)]="u.checked" appStopProp>
|
||||
</td>
|
||||
<td width="30">
|
||||
<app-avatar [data]="u.name || u.email" [email]="u.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
@@ -96,10 +63,6 @@
|
||||
<i class="fa fa-lock" title="{{'userUsingTwoStep' | i18n}}" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'userUsingTwoStep' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="showEnrolledStatus(u)">
|
||||
<i class="fa fa-key" title="{{'enrolledPasswordReset' | i18n}}" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'enrolledPasswordReset' | i18n}}</span>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td>
|
||||
<span *ngIf="u.type === organizationUserType.Owner">{{'owner' | i18n}}</span>
|
||||
@@ -135,11 +98,6 @@
|
||||
<i class="fa fa-fw fa-file-text-o" aria-hidden="true"></i>
|
||||
{{'eventLogs' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="resetPassword(u)"
|
||||
*ngIf="allowResetPassword(u)">
|
||||
<i class="fa fa-fw fa-key" aria-hidden="true"></i>
|
||||
{{'resetPassword' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="remove(u)">
|
||||
<i class="fa fa-fw fa-remove" aria-hidden="true"></i>
|
||||
{{'remove' | i18n}}
|
||||
@@ -156,7 +114,3 @@
|
||||
<ng-template #groupsTemplate></ng-template>
|
||||
<ng-template #eventsTemplate></ng-template>
|
||||
<ng-template #confirmTemplate></ng-template>
|
||||
<ng-template #resetPasswordTemplate></ng-template>
|
||||
<ng-template #bulkStatusTemplate></ng-template>
|
||||
<ng-template #bulkConfirmTemplate></ng-template>
|
||||
<ng-template #bulkRemoveTemplate></ng-template>
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ActivatedRoute,
|
||||
Router,
|
||||
@@ -13,47 +12,32 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ValidationService } from 'jslib-angular/services/validation.service';
|
||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
import { ValidationService } from 'jslib/angular/services/validation.service';
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.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 { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { OrganizationKeysRequest } from 'jslib-common/models/request/organizationKeysRequest';
|
||||
import { OrganizationUserBulkRequest } from 'jslib-common/models/request/organizationUserBulkRequest';
|
||||
import { OrganizationUserConfirmRequest } from 'jslib-common/models/request/organizationUserConfirmRequest';
|
||||
import { OrganizationUserConfirmRequest } from 'jslib/models/request/organizationUserConfirmRequest';
|
||||
|
||||
import { ListResponse } from 'jslib-common/models/response/listResponse';
|
||||
import { OrganizationUserBulkResponse } from 'jslib-common/models/response/organizationUserBulkResponse';
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib-common/models/response/organizationUserResponse';
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib/models/response/organizationUserResponse';
|
||||
|
||||
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from 'jslib-common/enums/organizationUserType';
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
import { OrganizationUserStatusType } from 'jslib/enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from 'jslib/enums/organizationUserType';
|
||||
|
||||
import { SearchPipe } from 'jslib-angular/pipes/search.pipe';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
import { BulkConfirmComponent } from './bulk/bulk-confirm.component';
|
||||
import { BulkRemoveComponent } from './bulk/bulk-remove.component';
|
||||
import { BulkStatusComponent } from './bulk/bulk-status.component';
|
||||
import { EntityEventsComponent } from './entity-events.component';
|
||||
import { ResetPasswordComponent } from './reset-password.component';
|
||||
import { UserAddEditComponent } from './user-add-edit.component';
|
||||
import { UserConfirmComponent } from './user-confirm.component';
|
||||
import { UserGroupsComponent } from './user-groups.component';
|
||||
|
||||
const MaxCheckedCount = 500;
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-people',
|
||||
templateUrl: 'people.component.html',
|
||||
@@ -63,10 +47,6 @@ export class PeopleComponent implements OnInit {
|
||||
@ViewChild('groupsTemplate', { read: ViewContainerRef, static: true }) groupsModalRef: ViewContainerRef;
|
||||
@ViewChild('eventsTemplate', { read: ViewContainerRef, static: true }) eventsModalRef: ViewContainerRef;
|
||||
@ViewChild('confirmTemplate', { read: ViewContainerRef, static: true }) confirmModalRef: ViewContainerRef;
|
||||
@ViewChild('resetPasswordTemplate', { read: ViewContainerRef, static: true }) resetPasswordModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkStatusTemplate', { read: ViewContainerRef, static: true }) bulkStatusModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkConfirmTemplate', { read: ViewContainerRef, static: true }) bulkConfirmModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkRemoveTemplate', { read: ViewContainerRef, static: true }) bulkRemoveModalRef: ViewContainerRef;
|
||||
|
||||
loading = true;
|
||||
organizationId: string;
|
||||
@@ -80,11 +60,6 @@ export class PeopleComponent implements OnInit {
|
||||
actionPromise: Promise<any>;
|
||||
accessEvents = false;
|
||||
accessGroups = false;
|
||||
canResetPassword = false; // User permission (admin/custom)
|
||||
orgUseResetPassword = false; // Org plan ability
|
||||
orgHasKeys = false; // Org public/private keys
|
||||
orgResetPasswordPolicyEnabled = false;
|
||||
callingUserType: OrganizationUserType = null;
|
||||
|
||||
protected didScroll = false;
|
||||
protected pageSize = 100;
|
||||
@@ -98,8 +73,7 @@ export class PeopleComponent implements OnInit {
|
||||
private platformUtilsService: PlatformUtilsService, private toasterService: ToasterService,
|
||||
private cryptoService: CryptoService, private userService: UserService, private router: Router,
|
||||
private storageService: StorageService, private searchService: SearchService,
|
||||
private validationService: ValidationService, private policyService: PolicyService,
|
||||
private searchPipe: SearchPipe, private syncService: SyncService) { }
|
||||
private validationService: ValidationService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.route.parent.parent.params.subscribe(async params => {
|
||||
@@ -111,25 +85,6 @@ export class PeopleComponent implements OnInit {
|
||||
}
|
||||
this.accessEvents = organization.useEvents;
|
||||
this.accessGroups = organization.useGroups;
|
||||
this.canResetPassword = organization.canManageUsersPassword;
|
||||
this.orgUseResetPassword = organization.useResetPassword;
|
||||
this.callingUserType = organization.type;
|
||||
this.orgHasKeys = organization.hasPublicAndPrivateKeys;
|
||||
|
||||
// Backfill pub/priv key if necessary
|
||||
if (this.canResetPassword && !this.orgHasKeys) {
|
||||
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
|
||||
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
const response = await this.apiService.postOrganizationKeys(this.organizationId, request);
|
||||
if (response != null) {
|
||||
this.orgHasKeys = response.publicKey != null && response.privateKey != null;
|
||||
await this.syncService.fullSync(true); // Replace oganizations with new data
|
||||
} else {
|
||||
throw new Error(this.i18nService.t('resetPasswordOrgKeysError'));
|
||||
}
|
||||
}
|
||||
|
||||
await this.load();
|
||||
|
||||
const queryParamsSub = this.route.queryParams.subscribe(async qParams => {
|
||||
@@ -160,38 +115,9 @@ export class PeopleComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
this.filter(this.status);
|
||||
const policies = await this.policyService.getAll(PolicyType.ResetPassword);
|
||||
this.orgResetPasswordPolicyEnabled = policies.some(p => p.organizationId === this.organizationId && p.enabled);
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
allowResetPassword(orgUser: OrganizationUserUserDetailsResponse): boolean {
|
||||
// Hierarchy check
|
||||
let callingUserHasPermission = false;
|
||||
|
||||
switch (this.callingUserType) {
|
||||
case OrganizationUserType.Owner:
|
||||
callingUserHasPermission = true;
|
||||
break;
|
||||
case OrganizationUserType.Admin:
|
||||
callingUserHasPermission = orgUser.type !== OrganizationUserType.Owner;
|
||||
break;
|
||||
case OrganizationUserType.Custom:
|
||||
callingUserHasPermission = orgUser.type !== OrganizationUserType.Owner
|
||||
&& orgUser.type !== OrganizationUserType.Admin;
|
||||
break;
|
||||
}
|
||||
|
||||
// Final
|
||||
return this.canResetPassword && callingUserHasPermission && this.orgUseResetPassword && this.orgHasKeys
|
||||
&& orgUser.resetPasswordEnrolled && this.orgResetPasswordPolicyEnabled
|
||||
&& orgUser.status === OrganizationUserStatusType.Confirmed;
|
||||
}
|
||||
|
||||
showEnrolledStatus(orgUser: OrganizationUserUserDetailsResponse): boolean {
|
||||
return this.orgUseResetPassword && orgUser.resetPasswordEnrolled && this.orgResetPasswordPolicyEnabled;
|
||||
}
|
||||
|
||||
filter(status: OrganizationUserStatusType) {
|
||||
this.status = status;
|
||||
if (this.status != null) {
|
||||
@@ -199,8 +125,6 @@ export class PeopleComponent implements OnInit {
|
||||
} else {
|
||||
this.users = this.allUsers;
|
||||
}
|
||||
// Reset checkbox selecton
|
||||
this.selectAll(false);
|
||||
this.resetPaging();
|
||||
}
|
||||
|
||||
@@ -244,10 +168,6 @@ export class PeopleComponent implements OnInit {
|
||||
this.confirmedCount > 0 && this.confirmedCount < 3 && this.acceptedCount > 0;
|
||||
}
|
||||
|
||||
get showBulkConfirmUsers(): boolean {
|
||||
return this.acceptedCount > 0;
|
||||
}
|
||||
|
||||
edit(user: OrganizationUserUserDetailsResponse) {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
@@ -309,101 +229,23 @@ export class PeopleComponent implements OnInit {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.actionPromise = this.apiService.deleteOrganizationUser(this.organizationId, user.id);
|
||||
try {
|
||||
await this.actionPromise;
|
||||
await this.apiService.deleteOrganizationUser(this.organizationId, user.id);
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('removedUserId', user.name || user.email));
|
||||
this.removeUser(user);
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
this.actionPromise = null;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
async reinvite(user: OrganizationUserUserDetailsResponse) {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.actionPromise = this.apiService.postOrganizationUserReinvite(this.organizationId, user.id);
|
||||
try {
|
||||
await this.actionPromise;
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('hasBeenReinvited', user.name || user.email));
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
await this.actionPromise;
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('hasBeenReinvited', user.name || user.email));
|
||||
this.actionPromise = null;
|
||||
}
|
||||
|
||||
async bulkRemove() {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.bulkRemoveModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show(BulkRemoveComponent, this.bulkRemoveModalRef);
|
||||
|
||||
childComponent.organizationId = this.organizationId;
|
||||
childComponent.users = this.getCheckedUsers();
|
||||
|
||||
this.modal.onClosed.subscribe(async () => {
|
||||
await this.load();
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
|
||||
async bulkReinvite() {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = this.getCheckedUsers();
|
||||
const filteredUsers = users.filter(u => u.status === OrganizationUserStatusType.Invited);
|
||||
|
||||
if (filteredUsers.length <= 0) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('noSelectedUsersApplicable'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const request = new OrganizationUserBulkRequest(filteredUsers.map(user => user.id));
|
||||
const response = this.apiService.postManyOrganizationUserReinvite(this.organizationId, request);
|
||||
this.showBulkStatus(users, filteredUsers, response, this.i18nService.t('bulkReinviteMessage'));
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
this.actionPromise = null;
|
||||
}
|
||||
|
||||
async bulkConfirm() {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.bulkConfirmModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show(BulkConfirmComponent, this.bulkConfirmModalRef);
|
||||
|
||||
childComponent.organizationId = this.organizationId;
|
||||
childComponent.users = this.getCheckedUsers();
|
||||
|
||||
this.modal.onClosed.subscribe(async () => {
|
||||
await this.load();
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
|
||||
async confirm(user: OrganizationUserUserDetailsResponse) {
|
||||
function updateUser(self: PeopleComponent) {
|
||||
user.status = OrganizationUserStatusType.Confirmed;
|
||||
@@ -516,101 +358,6 @@ export class PeopleComponent implements OnInit {
|
||||
return !searching && this.users && this.users.length > this.pageSize;
|
||||
}
|
||||
|
||||
async resetPassword(user: OrganizationUserUserDetailsResponse) {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.resetPasswordModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show<ResetPasswordComponent>(
|
||||
ResetPasswordComponent, this.resetPasswordModalRef);
|
||||
|
||||
childComponent.name = user != null ? user.name || user.email : null;
|
||||
childComponent.email = user != null ? user.email : null;
|
||||
childComponent.organizationId = this.organizationId;
|
||||
childComponent.id = user != null ? user.id : null;
|
||||
|
||||
childComponent.onPasswordReset.subscribe(() => {
|
||||
this.modal.close();
|
||||
this.load();
|
||||
});
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
|
||||
checkUser(user: OrganizationUserUserDetailsResponse, select?: boolean) {
|
||||
(user as any).checked = select == null ? !(user as any).checked : select;
|
||||
}
|
||||
|
||||
selectAll(select: boolean) {
|
||||
if (select) {
|
||||
this.selectAll(false);
|
||||
}
|
||||
|
||||
const filteredUsers = this.searchPipe.transform(this.users, this.searchText, 'name', 'email', 'id');
|
||||
|
||||
const selectCount = select && filteredUsers.length > MaxCheckedCount
|
||||
? MaxCheckedCount
|
||||
: filteredUsers.length;
|
||||
for (let i = 0; i < selectCount; i++) {
|
||||
this.checkUser(filteredUsers[i], select);
|
||||
}
|
||||
}
|
||||
|
||||
private async showBulkStatus(users: OrganizationUserUserDetailsResponse[], filteredUsers: OrganizationUserUserDetailsResponse[],
|
||||
request: Promise<ListResponse<OrganizationUserBulkResponse>>, successfullMessage: string) {
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.bulkStatusModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show<BulkStatusComponent>(
|
||||
BulkStatusComponent, this.bulkStatusModalRef);
|
||||
|
||||
childComponent.loading = true;
|
||||
|
||||
// Workaround to handle closing the modal shortly after it has been opened
|
||||
let close = false;
|
||||
this.modal.onShown.subscribe(() => {
|
||||
if (close) {
|
||||
this.modal.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await request;
|
||||
|
||||
if (this.modal) {
|
||||
const keyedErrors: any = response.data.filter(r => r.error !== '').reduce((a, x) => ({ ...a, [x.id]: x.error }), {});
|
||||
const keyedFilteredUsers: any = filteredUsers.reduce((a, x) => ({ ...a, [x.id]: x }), {});
|
||||
|
||||
childComponent.users = users.map(user => {
|
||||
let message = keyedErrors[user.id] ?? successfullMessage;
|
||||
if (!keyedFilteredUsers.hasOwnProperty(user.id)) {
|
||||
message = this.i18nService.t('bulkFilteredMessage');
|
||||
}
|
||||
|
||||
return {
|
||||
user: user,
|
||||
error: keyedErrors.hasOwnProperty(user.id),
|
||||
message: message,
|
||||
};
|
||||
});
|
||||
childComponent.loading = false;
|
||||
}
|
||||
} catch {
|
||||
close = true;
|
||||
if (this.modal) {
|
||||
this.modal.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async doConfirmation(user: OrganizationUserUserDetailsResponse, publicKey: Uint8Array) {
|
||||
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||
@@ -644,8 +391,4 @@ export class PeopleComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getCheckedUsers() {
|
||||
return this.users.filter(u => (u as any).checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
import { PolicyType } from 'jslib/enums/policyType';
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions';
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
||||
import { PolicyResponse } from 'jslib/models/response/policyResponse';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
|
||||
@@ -115,12 +115,6 @@ export class PoliciesComponent implements OnInit {
|
||||
type: PolicyType.SendOptions,
|
||||
enabled: false,
|
||||
display: true,
|
||||
}, {
|
||||
name: this.i18nService.t('resetPasswordPolicy'),
|
||||
description: this.i18nService.t('resetPasswordPolicyDescription'),
|
||||
type: PolicyType.ResetPassword,
|
||||
enabled: false,
|
||||
display: organization.useResetPassword,
|
||||
},
|
||||
];
|
||||
await this.load();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="policiesEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="policiesEditTitle">{{'editPolicy' | i18n}} - {{name}}</h2>
|
||||
@@ -38,9 +38,6 @@
|
||||
<app-callout type="warning" *ngIf="type === policyType.SendOptions">
|
||||
{{'sendOptionsExemption' | i18n}}
|
||||
</app-callout>
|
||||
<app-callout type="warning" *ngIf="type === policyType.ResetPassword">
|
||||
{{'resetPasswordPolicyWarning' | i18n}}
|
||||
</app-callout>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="enabled" [(ngModel)]="enabled"
|
||||
@@ -156,33 +153,19 @@
|
||||
<ng-container *ngIf="type === policyType.SendOptions">
|
||||
<h3 class="mt-4">{{'options' | i18n}}</h3>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="sendDisableHideEmail"
|
||||
[(ngModel)]="sendDisableHideEmail" name="SendDisableHideEmail">
|
||||
<input class="form-check-input" type="checkbox" id="sendDisableHideEmail" [(ngModel)]="sendDisableHideEmail"
|
||||
name="SendDisableHideEmail">
|
||||
<label class="form-check-label" for="sendDisableHideEmail">{{'disableHideEmail' | i18n}}</label>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="type === policyType.ResetPassword">
|
||||
<h3 class="mt-4">{{'resetPasswordPolicyAutoEnroll' | i18n}}</h3>
|
||||
<p>{{'resetPasswordPolicyAutoEnrollDescription' | i18n}}</p>
|
||||
<app-callout type="warning">
|
||||
{{'resetPasswordPolicyAutoEnrollWarning' | i18n}}
|
||||
</app-callout>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="autoEnrollEnabled"
|
||||
[(ngModel)]="resetPasswordAutoEnroll" name="AutoEnrollEnabled">
|
||||
<label class="form-check-label"
|
||||
for="autoEnrollEnabled">{{'resetPasswordPolicyAutoEnrollCheckbox' | i18n }}</label>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'save' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
||||
{{'cancel' | i18n}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary"
|
||||
data-dismiss="modal">{{'cancel' | i18n}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
import { PolicyType } from 'jslib/enums/policyType';
|
||||
|
||||
import { PolicyRequest } from 'jslib-common/models/request/policyRequest';
|
||||
import { PolicyRequest } from 'jslib/models/request/policyRequest';
|
||||
|
||||
import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
||||
import { PolicyResponse } from 'jslib/models/response/policyResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-policy-edit',
|
||||
@@ -60,9 +60,6 @@ export class PolicyEditComponent implements OnInit {
|
||||
// Send options
|
||||
sendDisableHideEmail?: boolean;
|
||||
|
||||
// Reset Password
|
||||
resetPasswordAutoEnroll?: boolean;
|
||||
|
||||
private policy: PolicyResponse;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||
@@ -119,9 +116,6 @@ export class PolicyEditComponent implements OnInit {
|
||||
case PolicyType.SendOptions:
|
||||
this.sendDisableHideEmail = this.policy.data.disableHideEmail;
|
||||
break;
|
||||
case PolicyType.ResetPassword:
|
||||
this.resetPasswordAutoEnroll = this.policy.data.autoEnrollEnabled;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -173,11 +167,6 @@ export class PolicyEditComponent implements OnInit {
|
||||
disableHideEmail: this.sendDisableHideEmail,
|
||||
};
|
||||
break;
|
||||
case PolicyType.ResetPassword:
|
||||
request.data = {
|
||||
autoEnrollEnabled: this.resetPasswordAutoEnroll,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="resetPasswordTitle">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="resetPasswordTitle">
|
||||
{{'resetPassword' | i18n}}
|
||||
<small class="text-muted" *ngIf="name">{{name}}</small>
|
||||
</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<app-callout type="warning">{{'resetPasswordLoggedOutWarning' | i18n: loggedOutWarningName}}
|
||||
</app-callout>
|
||||
<app-callout type="info" *ngIf="enforcedPolicyOptions">
|
||||
{{'resetPasswordMasterPasswordPolicyInEffect' | i18n}}
|
||||
<ul class="mb-0">
|
||||
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
|
||||
{{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
|
||||
{{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireUpper">
|
||||
{{'policyInEffectUppercase' | i18n}}</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireLower">
|
||||
{{'policyInEffectLowercase' | i18n}}</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
|
||||
{{'policyInEffectNumbers' | i18n}}</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
|
||||
{{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}</li>
|
||||
</ul>
|
||||
</app-callout>
|
||||
<div class="row">
|
||||
<div class="col form-group">
|
||||
<div class="d-flex">
|
||||
<label for="newPassword">{{'newPassword' | i18n}}</label>
|
||||
<div class="ml-auto d-flex">
|
||||
<a href="#" class="d-block mr-2 fa-icon-above-input" appStopClick
|
||||
appA11yTitle="{{'generatePassword' | i18n}}" (click)="generatePassword()">
|
||||
<i class="fa fa-lg fa-fw fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group mb-1">
|
||||
<input id="newPassword" class="form-control text-monospace" appAutofocus
|
||||
type="{{showPassword ? 'text' : 'password'}}" name="NewPassword"
|
||||
[(ngModel)]="newPassword" required appInputVerbatim autocomplete="new-password"
|
||||
(input)="updatePasswordStrength()">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary"
|
||||
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
|
||||
<i class="fa fa-lg" aria-hidden="true"
|
||||
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary"
|
||||
appA11yTitle="{{'copyPassword' | i18n}}" (click)="copy(newPassword)">
|
||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<app-password-strength [score]="masterPasswordScore" [showText]="true">
|
||||
</app-password-strength>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'save' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'cancel' |
|
||||
i18n}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,191 +0,0 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} 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 { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
|
||||
import { EncString } from 'jslib-common/models/domain/encString';
|
||||
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
import { OrganizationUserResetPasswordRequest } from 'jslib-common/models/request/organizationUserResetPasswordRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-reset-password',
|
||||
templateUrl: 'reset-password.component.html',
|
||||
})
|
||||
export class ResetPasswordComponent implements OnInit {
|
||||
@Input() name: string;
|
||||
@Input() email: string;
|
||||
@Input() id: string;
|
||||
@Input() organizationId: string;
|
||||
@Output() onPasswordReset = new EventEmitter();
|
||||
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
newPassword: string = null;
|
||||
showPassword: boolean = false;
|
||||
masterPasswordScore: number;
|
||||
formPromise: Promise<any>;
|
||||
private newPasswordStrengthTimeout: any;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService, private passwordGenerationService: PasswordGenerationService,
|
||||
private policyService: PolicyService, private cryptoService: CryptoService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
// Get Enforced Policy Options
|
||||
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
|
||||
}
|
||||
|
||||
get loggedOutWarningName() {
|
||||
return this.name != null ? this.name : this.i18nService.t('thisUser');
|
||||
}
|
||||
|
||||
getPasswordScoreAlertDisplay() {
|
||||
if (this.enforcedPolicyOptions == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let str: string;
|
||||
switch (this.enforcedPolicyOptions.minComplexity) {
|
||||
case 4:
|
||||
str = this.i18nService.t('strong');
|
||||
break;
|
||||
case 3:
|
||||
str = this.i18nService.t('good');
|
||||
break;
|
||||
default:
|
||||
str = this.i18nService.t('weak');
|
||||
break;
|
||||
}
|
||||
return str + ' (' + this.enforcedPolicyOptions.minComplexity + ')';
|
||||
}
|
||||
|
||||
async generatePassword() {
|
||||
const options = (await this.passwordGenerationService.getOptions())[0];
|
||||
this.newPassword = await this.passwordGenerationService.generatePassword(options);
|
||||
this.updatePasswordStrength();
|
||||
}
|
||||
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById('newPassword').focus();
|
||||
}
|
||||
|
||||
copy(value: string) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.platformUtilsService.copyToClipboard(value, { window: window });
|
||||
this.platformUtilsService.showToast('info', null,
|
||||
this.i18nService.t('valueCopied', this.i18nService.t('password')));
|
||||
}
|
||||
|
||||
async submit() {
|
||||
// Validation
|
||||
if (this.newPassword == null || this.newPassword === '') {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPassRequired'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.newPassword.length < 8) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPassLength'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.enforcedPolicyOptions != null &&
|
||||
!this.policyService.evaluateMasterPassword(this.masterPasswordScore, this.newPassword,
|
||||
this.enforcedPolicyOptions)) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPasswordPolicyRequirementsNotMet'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.masterPasswordScore < 3) {
|
||||
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
|
||||
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
|
||||
'warning');
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get user Information (kdf type, kdf iterations, resetPasswordKey, private key) and change password
|
||||
try {
|
||||
this.formPromise = this.apiService.getOrganizationUserResetPasswordDetails(this.organizationId, this.id)
|
||||
.then(async response => {
|
||||
if (response == null) {
|
||||
throw new Error(this.i18nService.t('resetPasswordDetailsError'));
|
||||
}
|
||||
|
||||
const kdfType = response.kdf;
|
||||
const kdfIterations = response.kdfIterations;
|
||||
const resetPasswordKey = response.resetPasswordKey;
|
||||
const encryptedPrivateKey = response.encryptedPrivateKey;
|
||||
|
||||
// Decrypt Organization's encrypted Private Key with org key
|
||||
const orgSymKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const decPrivateKey = await this.cryptoService.decryptToBytes(new EncString(encryptedPrivateKey), orgSymKey);
|
||||
|
||||
// Decrypt User's Reset Password Key to get EncKey
|
||||
const decValue = await this.cryptoService.rsaDecrypt(resetPasswordKey, decPrivateKey);
|
||||
const userEncKey = new SymmetricCryptoKey(decValue);
|
||||
|
||||
// Create new key and hash new password
|
||||
const newKey = await this.cryptoService.makeKey(this.newPassword, this.email.trim().toLowerCase(),
|
||||
kdfType, kdfIterations);
|
||||
const newPasswordHash = await this.cryptoService.hashPassword(this.newPassword, newKey);
|
||||
|
||||
// Create new encKey for the User
|
||||
const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey);
|
||||
|
||||
// Create request
|
||||
const request = new OrganizationUserResetPasswordRequest();
|
||||
request.key = newEncKey[1].encryptedString;
|
||||
request.newMasterPasswordHash = newPasswordHash;
|
||||
|
||||
// Change user's password
|
||||
return this.apiService.putOrganizationUserResetPassword(this.organizationId, this.id, request);
|
||||
});
|
||||
|
||||
await this.formPromise;
|
||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('resetPasswordSuccess'));
|
||||
this.onPasswordReset.emit();
|
||||
} catch { }
|
||||
}
|
||||
|
||||
updatePasswordStrength() {
|
||||
if (this.newPasswordStrengthTimeout != null) {
|
||||
clearTimeout(this.newPasswordStrengthTimeout);
|
||||
}
|
||||
this.newPasswordStrengthTimeout = setTimeout(() => {
|
||||
const strengthResult = this.passwordGenerationService.passwordStrength(this.newPassword,
|
||||
this.getPasswordStrengthUserInput());
|
||||
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
||||
}, 300);
|
||||
}
|
||||
|
||||
private getPasswordStrengthUserInput() {
|
||||
let userInput: string[] = [];
|
||||
const atPosition = this.email.indexOf('@');
|
||||
if (atPosition > -1) {
|
||||
userInput = userInput.concat(this.email.substr(0, atPosition).trim().toLowerCase().split(/[^A-Za-z0-9]/));
|
||||
}
|
||||
if (this.name != null && this.name !== '') {
|
||||
userInput = userInput.concat(this.name.trim().toLowerCase().split(' '));
|
||||
}
|
||||
return userInput;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="userAddEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="userAddEditTitle">
|
||||
@@ -172,8 +172,7 @@
|
||||
<div class="form-group mb-0">
|
||||
<div class="form-check mt-1 form-check-block">
|
||||
<input class="form-check-input" type="checkbox" name="manageUsers"
|
||||
id="manageUsers" [(ngModel)]="permissions.manageUsers"
|
||||
(change)="handleDependentPermissions()">
|
||||
id="manageUsers" [(ngModel)]="permissions.manageUsers">
|
||||
<label class="form-check-label font-weight-normal" for="manageUsers">
|
||||
{{'manageUsers' | i18n}}
|
||||
</label>
|
||||
@@ -182,8 +181,7 @@
|
||||
<div class="form-group mb-0">
|
||||
<div class="form-check mt-1 form-check-block">
|
||||
<input class="form-check-input" type="checkbox" name="manageResetPassword"
|
||||
id="manageResetPassword" [(ngModel)]="permissions.manageResetPassword"
|
||||
(change)="handleDependentPermissions()">
|
||||
id="manageResetPassword" [(ngModel)]="permissions.manageResetPassword">
|
||||
<label class="form-check-label font-weight-normal" for="manageResetPassword">
|
||||
{{'manageResetPassword' | i18n}}
|
||||
</label>
|
||||
|
||||
@@ -8,21 +8,21 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { CollectionData } from 'jslib-common/models/data/collectionData';
|
||||
import { Collection } from 'jslib-common/models/domain/collection';
|
||||
import { OrganizationUserInviteRequest } from 'jslib-common/models/request/organizationUserInviteRequest';
|
||||
import { OrganizationUserUpdateRequest } from 'jslib-common/models/request/organizationUserUpdateRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib-common/models/request/selectionReadOnlyRequest';
|
||||
import { CollectionDetailsResponse } from 'jslib-common/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
||||
import { CollectionData } from 'jslib/models/data/collectionData';
|
||||
import { Collection } from 'jslib/models/domain/collection';
|
||||
import { OrganizationUserInviteRequest } from 'jslib/models/request/organizationUserInviteRequest';
|
||||
import { OrganizationUserUpdateRequest } from 'jslib/models/request/organizationUserUpdateRequest';
|
||||
import { SelectionReadOnlyRequest } from 'jslib/models/request/selectionReadOnlyRequest';
|
||||
import { CollectionDetailsResponse } from 'jslib/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||
|
||||
import { OrganizationUserType } from 'jslib-common/enums/organizationUserType';
|
||||
import { PermissionsApi } from 'jslib-common/models/api/permissionsApi';
|
||||
import { OrganizationUserType } from 'jslib/enums/organizationUserType';
|
||||
import { PermissionsApi } from 'jslib/models/api/permissionsApi';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-add-edit',
|
||||
@@ -143,15 +143,6 @@ export class UserAddEditComponent implements OnInit {
|
||||
return p;
|
||||
}
|
||||
|
||||
handleDependentPermissions() {
|
||||
// Manage Password Reset must have Manage Users enabled
|
||||
if (this.permissions.manageResetPassword && !this.permissions.manageUsers) {
|
||||
this.permissions.manageUsers = true;
|
||||
(document.getElementById('manageUsers') as HTMLInputElement).checked = true;
|
||||
this.platformUtilsService.showToast('info', null, this.i18nService.t('resetPasswordManageUsers'));
|
||||
}
|
||||
}
|
||||
|
||||
async submit() {
|
||||
let collections: SelectionReadOnlyRequest[] = null;
|
||||
if (this.access !== 'all') {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="confirmUserTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="confirmUserTitle">
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-confirm',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="groupAccessTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="groupAccessTitle">
|
||||
|
||||
@@ -8,13 +8,13 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { OrganizationUserUpdateGroupsRequest } from 'jslib-common/models/request/organizationUserUpdateGroupsRequest';
|
||||
import { GroupResponse } from 'jslib-common/models/response/groupResponse';
|
||||
import { OrganizationUserUpdateGroupsRequest } from 'jslib/models/request/organizationUserUpdateGroupsRequest';
|
||||
import { GroupResponse } from 'jslib/models/response/groupResponse';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-groups',
|
||||
|
||||
@@ -4,28 +4,22 @@ import {
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
|
||||
import { OrganizationKeysRequest } from 'jslib-common/models/request/organizationKeysRequest';
|
||||
import { OrganizationUpdateRequest } from 'jslib-common/models/request/organizationUpdateRequest';
|
||||
|
||||
import { OrganizationResponse } from 'jslib-common/models/response/organizationResponse';
|
||||
import { OrganizationUpdateRequest } from 'jslib/models/request/organizationUpdateRequest';
|
||||
import { OrganizationResponse } from 'jslib/models/response/organizationResponse';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
|
||||
import { ApiKeyComponent } from '../../settings/api-key.component';
|
||||
import { PurgeVaultComponent } from '../../settings/purge-vault.component';
|
||||
import { TaxInfoComponent } from '../../settings/tax-info.component';
|
||||
|
||||
import { DeleteOrganizationComponent } from './delete-organization.component';
|
||||
|
||||
@Component({
|
||||
@@ -52,8 +46,7 @@ export class AccountComponent {
|
||||
constructor(private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private apiService: ApiService, private i18nService: I18nService,
|
||||
private toasterService: ToasterService, private route: ActivatedRoute,
|
||||
private syncService: SyncService, private platformUtilsService: PlatformUtilsService,
|
||||
private cryptoService: CryptoService) { }
|
||||
private syncService: SyncService, private platformUtilsService: PlatformUtilsService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||
@@ -74,14 +67,6 @@ export class AccountComponent {
|
||||
request.businessName = this.org.businessName;
|
||||
request.billingEmail = this.org.billingEmail;
|
||||
request.identifier = this.org.identifier;
|
||||
|
||||
// Backfill pub/priv key if necessary
|
||||
if (!this.org.hasPublicAndPrivateKeys) {
|
||||
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
|
||||
request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
}
|
||||
|
||||
this.formPromise = this.apiService.putOrganization(this.organizationId, request).then(() => {
|
||||
return this.syncService.fullSync(true);
|
||||
});
|
||||
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { SeatRequest } from 'jslib-common/models/request/seatRequest';
|
||||
import { SeatRequest } from 'jslib/models/request/seatRequest';
|
||||
|
||||
import { PaymentComponent } from '../../settings/payment.component';
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { PlanType } from 'jslib-common/enums/planType';
|
||||
import { ProductType } from 'jslib-common/enums/productType';
|
||||
import { PlanType } from 'jslib/enums/planType';
|
||||
import { ProductType } from 'jslib/enums/productType';
|
||||
|
||||
@Component({
|
||||
selector: 'app-change-plan',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="deleteOrganizationTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="deleteOrganizationTitle">{{'deleteOrganization' | i18n}}</h2>
|
||||
|
||||
@@ -3,11 +3,11 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
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 { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { PasswordVerificationRequest } from 'jslib-common/models/request/passwordVerificationRequest';
|
||||
import { PasswordVerificationRequest } from 'jslib/models/request/passwordVerificationRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-delete-organization',
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-download-license',
|
||||
|
||||
@@ -6,9 +6,9 @@ import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { UserBillingComponent } from '../../settings/user-billing.component';
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { OrganizationSubscriptionResponse } from 'jslib-common/models/response/organizationSubscriptionResponse';
|
||||
import { OrganizationSubscriptionResponse } from 'jslib/models/response/organizationSubscriptionResponse';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { PlanType } from 'jslib-common/enums/planType';
|
||||
import { PlanType } from 'jslib/enums/planType';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-subscription',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-settings',
|
||||
|
||||
@@ -4,12 +4,12 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { TwoFactorProviderType } from 'jslib-common/enums/twoFactorProviderType';
|
||||
import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType';
|
||||
|
||||
import { TwoFactorDuoComponent } from '../../settings/two-factor-duo.component';
|
||||
import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from '../../settings/two-factor-setup.component';
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { EventService } from 'jslib/abstractions/event.service';
|
||||
import { ExportService } from 'jslib/abstractions/export.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { ExportComponent as BaseExportComponent } from '../../tools/export.component';
|
||||
|
||||
import { EventType } from 'jslib-common/enums/eventType';
|
||||
import { EventType } from 'jslib/enums/eventType';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-export',
|
||||
|
||||
@@ -4,17 +4,17 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { AuditService } from 'jslib-common/abstractions/audit.service';
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { AuditService } from 'jslib/abstractions/audit.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import {
|
||||
ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent,
|
||||
} from '../../tools/exposed-passwords-report.component';
|
||||
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
@Component({
|
||||
selector: 'app-exposed-passwords-report',
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { ImportService } from 'jslib-common/abstractions/import.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { ImportService } from 'jslib/abstractions/import.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { ImportComponent as BaseImportComponent } from '../../tools/import.component';
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import {
|
||||
InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent,
|
||||
} from '../../tools/inactive-two-factor-report.component';
|
||||
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
@Component({
|
||||
selector: 'app-inactive-two-factor-report',
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
import {
|
||||
ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-tools',
|
||||
|
||||
@@ -4,15 +4,15 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import {
|
||||
UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent,
|
||||
} from '../../tools/unsecured-websites-report.component';
|
||||
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
@Component({
|
||||
selector: 'app-unsecured-websites-report',
|
||||
|
||||
@@ -4,14 +4,14 @@ import {
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
import {
|
||||
WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent,
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { AuditService } from 'jslib-common/abstractions/audit.service';
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
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 { 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 { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { TotpService } from 'jslib-common/abstractions/totp.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuditService } from 'jslib/abstractions/audit.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { EventService } from 'jslib/abstractions/event.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { TotpService } from 'jslib/abstractions/totp.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { CipherData } from 'jslib-common/models/data/cipherData';
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CipherCreateRequest } from 'jslib-common/models/request/cipherCreateRequest';
|
||||
import { CipherRequest } from 'jslib-common/models/request/cipherRequest';
|
||||
import { CipherData } from 'jslib/models/data/cipherData';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
import { CipherCreateRequest } from 'jslib/models/request/cipherCreateRequest';
|
||||
import { CipherRequest } from 'jslib/models/request/cipherRequest';
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from '../../vault/add-edit.component';
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { CipherData } from 'jslib-common/models/data/cipherData';
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CipherData } from 'jslib/models/data/cipherData';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
|
||||
import { AttachmentView } from 'jslib-common/models/view/attachmentView';
|
||||
import { AttachmentView } from 'jslib/models/view/attachmentView';
|
||||
|
||||
import { AttachmentsComponent as BaseAttachmentsComponent } from '../../vault/attachments.component';
|
||||
|
||||
|
||||
@@ -6,18 +6,17 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
import { TotpService } from 'jslib-common/abstractions/totp.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { EventService } from 'jslib/abstractions/event.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { TotpService } from 'jslib/abstractions/totp.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
import { CiphersComponent as BaseCiphersComponent } from '../../vault/ciphers.component';
|
||||
|
||||
@@ -35,19 +34,18 @@ export class CiphersComponent extends BaseCiphersComponent {
|
||||
|
||||
constructor(searchService: SearchService, toasterService: ToasterService, i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService, cipherService: CipherService,
|
||||
private apiService: ApiService, eventService: EventService, totpService: TotpService,
|
||||
userService: UserService, passwordRepromptService: PasswordRepromptService) {
|
||||
private apiService: ApiService, eventService: EventService, totpService: TotpService, userService: UserService) {
|
||||
super(searchService, toasterService, i18nService, platformUtilsService, cipherService,
|
||||
eventService, totpService, userService, passwordRepromptService);
|
||||
eventService, totpService, userService);
|
||||
}
|
||||
|
||||
async load(filter: (cipher: CipherView) => boolean = null) {
|
||||
if (this.organization.canManageAllCollections) {
|
||||
this.accessEvents = this.organization.useEvents;
|
||||
this.allCiphers = await this.cipherService.getAllFromApiForOrganization(this.organization.id);
|
||||
} else {
|
||||
this.allCiphers = (await this.cipherService.getAllDecrypted()).filter(c => c.organizationId === this.organization.id);
|
||||
if (!this.organization.canManageAllCollections) {
|
||||
await super.load(filter, this.deleted);
|
||||
return;
|
||||
}
|
||||
this.accessEvents = this.organization.useEvents;
|
||||
this.allCiphers = await this.cipherService.getAllFromApiForOrganization(this.organization.id);
|
||||
await this.searchService.indexCiphers(this.organization.id, this.allCiphers);
|
||||
await this.applyFilter(filter);
|
||||
this.loaded = true;
|
||||
@@ -63,7 +61,7 @@ export class CiphersComponent extends BaseCiphersComponent {
|
||||
}
|
||||
|
||||
async search(timeout: number = null) {
|
||||
await super.search(timeout, this.allCiphers);
|
||||
super.search(timeout, this.allCiphers);
|
||||
}
|
||||
events(c: CipherView) {
|
||||
this.onEventsClicked.emit(c);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { CipherData } from 'jslib-common/models/data/cipherData';
|
||||
import { Cipher } from 'jslib-common/models/domain/cipher';
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CipherCollectionsRequest } from 'jslib-common/models/request/cipherCollectionsRequest';
|
||||
import { CipherData } from 'jslib/models/data/cipherData';
|
||||
import { Cipher } from 'jslib/models/domain/cipher';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
import { CipherCollectionsRequest } from 'jslib/models/request/cipherCollectionsRequest';
|
||||
|
||||
import { CollectionsComponent as BaseCollectionsComponent } from '../../vault/collections.component';
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { StorageService } from 'jslib-common/abstractions/storage.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { CollectionData } from 'jslib-common/models/data/collectionData';
|
||||
import { Collection } from 'jslib-common/models/domain/collection';
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CollectionDetailsResponse } from 'jslib-common/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
||||
import { CollectionData } from 'jslib/models/data/collectionData';
|
||||
import { Collection } from 'jslib/models/domain/collection';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
import { CollectionDetailsResponse } from 'jslib/models/response/collectionResponse';
|
||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||
|
||||
import { GroupingsComponent as BaseGroupingsComponent } from '../../vault/groupings.component';
|
||||
|
||||
|
||||
@@ -13,18 +13,18 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
import { Organization } from 'jslib-common/models/domain/organization';
|
||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
import { CipherView } from 'jslib/models/view/cipherView';
|
||||
|
||||
import { CipherType } from 'jslib-common/enums/cipherType';
|
||||
import { CipherType } from 'jslib/enums/cipherType';
|
||||
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* tslint:disable */
|
||||
import 'core-js/stable';
|
||||
import 'core-js/es6';
|
||||
import 'core-js/es7/reflect';
|
||||
require('zone.js/dist/zone');
|
||||
|
||||
// IE11 fix, ref: https://github.com/angular/angular/issues/24769
|
||||
|
||||
@@ -5,24 +5,24 @@ import {
|
||||
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { SendAccess } from 'jslib-common/models/domain/sendAccess';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
import { SendAccess } from 'jslib/models/domain/sendAccess';
|
||||
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
|
||||
|
||||
import { SendAccessView } from 'jslib-common/models/view/sendAccessView';
|
||||
import { SendAccessView } from 'jslib/models/view/sendAccessView';
|
||||
|
||||
import { SendType } from 'jslib-common/enums/sendType';
|
||||
import { SendAccessRequest } from 'jslib-common/models/request/sendAccessRequest';
|
||||
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
|
||||
import { SendType } from 'jslib/enums/sendType';
|
||||
import { SendAccessRequest } from 'jslib/models/request/sendAccessRequest';
|
||||
import { ErrorResponse } from 'jslib/models/response/errorResponse';
|
||||
|
||||
import { SendAccessResponse } from 'jslib-common/models/response/sendAccessResponse';
|
||||
import { SendAccessResponse } from 'jslib/models/response/sendAccessResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-access',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="sendAddEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate
|
||||
autocomplete="off">
|
||||
<div class="modal-header">
|
||||
@@ -232,8 +232,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit manual" [ngClass]="{loading:form.loading}"
|
||||
[disabled]="form.loading || disableSend">
|
||||
<button class="btn btn-primary disabled" disabled=true *ngIf="disableSend">
|
||||
<span>{{'save' | i18n}}</span>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading" *ngIf="!disableSend">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'save' | i18n}}</span>
|
||||
</button>
|
||||
|
||||
@@ -2,15 +2,15 @@ import { DatePipe } from '@angular/common';
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.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';
|
||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { SendService } from 'jslib/abstractions/send.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from 'jslib-angular/components/send/add-edit.component';
|
||||
import { AddEditComponent as BaseAddEditComponent } from 'jslib/angular/components/send/add-edit.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-add-edit',
|
||||
@@ -25,11 +25,9 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
messagingService, policyService);
|
||||
}
|
||||
|
||||
async copyLinkToClipboard(link: string): Promise<void | boolean> {
|
||||
copyLinkToClipboard(link: string) {
|
||||
// Copy function on web depends on the modal being open or not. Since this event occurs during a transition
|
||||
// of the modal closing we need to add a small delay to make sure state of the DOM is consistent.
|
||||
return new Promise(resolve => {
|
||||
window.setTimeout(() => resolve(super.copyLinkToClipboard(link)), 500);
|
||||
});
|
||||
window.setTimeout(() => super.copyLinkToClipboard(link), 500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,23 @@ import {
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import { SendView } from 'jslib-common/models/view/sendView';
|
||||
import { SendView } from 'jslib/models/view/sendView';
|
||||
|
||||
import { SendComponent as BaseSendComponent } from 'jslib-angular/components/send/send.component';
|
||||
import { SendComponent as BaseSendComponent } from 'jslib/angular/components/send/send.component';
|
||||
|
||||
import { AddEditComponent } from './add-edit.component';
|
||||
|
||||
import { ModalComponent } from '../modal.component';
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.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';
|
||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||
import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { SendService } from 'jslib/abstractions/send.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
const BroadcasterSubscriptionId = 'SendComponent';
|
||||
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { DeviceType } from 'jslib-common/enums/deviceType';
|
||||
import { EventType } from 'jslib-common/enums/eventType';
|
||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||
|
||||
import { EventResponse } from 'jslib-common/models/response/eventResponse';
|
||||
import { DeviceType } from 'jslib/enums/deviceType';
|
||||
import { EventType } from 'jslib/enums/eventType';
|
||||
|
||||
import { EventResponse } from 'jslib/models/response/eventResponse';
|
||||
|
||||
@Injectable()
|
||||
export class EventService {
|
||||
constructor(private i18nService: I18nService, private policyService: PolicyService) { }
|
||||
constructor(private i18nService: I18nService) { }
|
||||
|
||||
getDefaultDateFilters() {
|
||||
const d = new Date();
|
||||
@@ -31,184 +28,146 @@ export class EventService {
|
||||
return [start.toISOString(), end.toISOString()];
|
||||
}
|
||||
|
||||
async getEventInfo(ev: EventResponse, options = new EventOptions()): Promise<EventInfo> {
|
||||
getEventInfo(ev: EventResponse, options = new EventOptions()): EventInfo {
|
||||
const appInfo = this.getAppInfo(ev.deviceType);
|
||||
const { message, humanReadableMessage } = await this.getEventMessage(ev, options);
|
||||
return {
|
||||
message: message,
|
||||
humanReadableMessage: humanReadableMessage,
|
||||
message: this.getEventMessage(ev, options),
|
||||
appIcon: appInfo[0],
|
||||
appName: appInfo[1],
|
||||
};
|
||||
}
|
||||
|
||||
private async getEventMessage(ev: EventResponse, options: EventOptions) {
|
||||
private getEventMessage(ev: EventResponse, options: EventOptions) {
|
||||
let msg = '';
|
||||
let humanReadableMsg = '';
|
||||
switch (ev.type) {
|
||||
// User
|
||||
case EventType.User_LoggedIn:
|
||||
msg = humanReadableMsg = this.i18nService.t('loggedIn');
|
||||
msg = this.i18nService.t('loggedIn');
|
||||
break;
|
||||
case EventType.User_ChangedPassword:
|
||||
msg = humanReadableMsg = this.i18nService.t('changedPassword');
|
||||
msg = this.i18nService.t('changedPassword');
|
||||
break;
|
||||
case EventType.User_Updated2fa:
|
||||
msg = humanReadableMsg = this.i18nService.t('enabledUpdated2fa');
|
||||
msg = this.i18nService.t('enabledUpdated2fa');
|
||||
break;
|
||||
case EventType.User_Disabled2fa:
|
||||
msg = humanReadableMsg = this.i18nService.t('disabled2fa');
|
||||
msg = this.i18nService.t('disabled2fa');
|
||||
break;
|
||||
case EventType.User_Recovered2fa:
|
||||
msg = humanReadableMsg = this.i18nService.t('recovered2fa');
|
||||
msg = this.i18nService.t('recovered2fa');
|
||||
break;
|
||||
case EventType.User_FailedLogIn:
|
||||
msg = humanReadableMsg = this.i18nService.t('failedLogin');
|
||||
msg = this.i18nService.t('failedLogin');
|
||||
break;
|
||||
case EventType.User_FailedLogIn2fa:
|
||||
msg = humanReadableMsg = this.i18nService.t('failedLogin2fa');
|
||||
msg = this.i18nService.t('failedLogin2fa');
|
||||
break;
|
||||
case EventType.User_ClientExportedVault:
|
||||
msg = humanReadableMsg = this.i18nService.t('exportedVault');
|
||||
msg = this.i18nService.t('exportedVault');
|
||||
break;
|
||||
// Cipher
|
||||
case EventType.Cipher_Created:
|
||||
msg = this.i18nService.t('createdItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('createdItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_Updated:
|
||||
msg = this.i18nService.t('editedItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('editedItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_Deleted:
|
||||
msg = this.i18nService.t('permanentlyDeletedItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('permanentlyDeletedItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_SoftDeleted:
|
||||
msg = this.i18nService.t('deletedItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('deletedItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_Restored:
|
||||
msg = this.i18nService.t('restoredItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('restoredItemId', this.formatCipherId(ev, options));
|
||||
break;
|
||||
case EventType.Cipher_AttachmentCreated:
|
||||
msg = this.i18nService.t('createdAttachmentForItem', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('createdAttachmentForItem', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_AttachmentDeleted:
|
||||
msg = this.i18nService.t('deletedAttachmentForItem', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('deletedAttachmentForItem', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_Shared:
|
||||
msg = this.i18nService.t('sharedItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('sharedItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientViewed:
|
||||
msg = this.i18nService.t('viewedItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('viewedItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientToggledPasswordVisible:
|
||||
msg = this.i18nService.t('viewedPasswordItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('viewedPasswordItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientToggledHiddenFieldVisible:
|
||||
msg = this.i18nService.t('viewedHiddenFieldItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('viewedHiddenFieldItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientToggledCardCodeVisible:
|
||||
msg = this.i18nService.t('viewedSecurityCodeItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('viewedSecurityCodeItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientCopiedHiddenField:
|
||||
msg = this.i18nService.t('copiedHiddenFieldItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('copiedHiddenFieldItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientCopiedPassword:
|
||||
msg = this.i18nService.t('copiedPasswordItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('copiedPasswordItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientCopiedCardCode:
|
||||
msg = this.i18nService.t('copiedSecurityCodeItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('copiedSecurityCodeItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_ClientAutofilled:
|
||||
msg = this.i18nService.t('autofilledItemId', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('autofilledItemId', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
case EventType.Cipher_UpdatedCollections:
|
||||
msg = this.i18nService.t('editedCollectionsForItem', this.formatCipherId(ev, options));
|
||||
humanReadableMsg = this.i18nService.t('editedCollectionsForItem', this.getShortId(ev.cipherId));
|
||||
break;
|
||||
// Collection
|
||||
case EventType.Collection_Created:
|
||||
msg = this.i18nService.t('createdCollectionId', this.formatCollectionId(ev));
|
||||
humanReadableMsg = this.i18nService.t('createdCollectionId', this.getShortId(ev.collectionId));
|
||||
break;
|
||||
case EventType.Collection_Updated:
|
||||
msg = this.i18nService.t('editedCollectionId', this.formatCollectionId(ev));
|
||||
humanReadableMsg = this.i18nService.t('editedCollectionId', this.getShortId(ev.collectionId));
|
||||
break;
|
||||
case EventType.Collection_Deleted:
|
||||
msg = this.i18nService.t('deletedCollectionId', this.formatCollectionId(ev));
|
||||
humanReadableMsg = this.i18nService.t('deletedCollectionId', this.getShortId(ev.collectionId));
|
||||
break;
|
||||
// Group
|
||||
case EventType.Group_Created:
|
||||
msg = this.i18nService.t('createdGroupId', this.formatGroupId(ev));
|
||||
humanReadableMsg = this.i18nService.t('createdGroupId', this.getShortId(ev.groupId));
|
||||
break;
|
||||
case EventType.Group_Updated:
|
||||
msg = this.i18nService.t('editedGroupId', this.formatGroupId(ev));
|
||||
humanReadableMsg = this.i18nService.t('editedGroupId', this.getShortId(ev.groupId));
|
||||
break;
|
||||
case EventType.Group_Deleted:
|
||||
msg = this.i18nService.t('deletedGroupId', this.formatGroupId(ev));
|
||||
humanReadableMsg = this.i18nService.t('deletedGroupId', this.getShortId(ev.groupId));
|
||||
break;
|
||||
// Org user
|
||||
case EventType.OrganizationUser_Invited:
|
||||
msg = this.i18nService.t('invitedUserId', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('invitedUserId', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_Confirmed:
|
||||
msg = this.i18nService.t('confirmedUserId', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('confirmedUserId', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_Updated:
|
||||
msg = this.i18nService.t('editedUserId', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('editedUserId', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_Removed:
|
||||
msg = this.i18nService.t('removedUserId', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('removedUserId', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_UpdatedGroups:
|
||||
msg = this.i18nService.t('editedGroupsForUser', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('editedGroupsForUser', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_UnlinkedSso:
|
||||
msg = this.i18nService.t('unlinkedSsoUser', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('unlinkedSsoUser', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_ResetPassword_Enroll:
|
||||
msg = this.i18nService.t('eventEnrollPasswordReset', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('eventEnrollPasswordReset', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_ResetPassword_Withdraw:
|
||||
msg = this.i18nService.t('eventWithdrawPasswordReset', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('eventWithdrawPasswordReset', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
case EventType.OrganizationUser_AdminResetPassword:
|
||||
msg = this.i18nService.t('eventAdminPasswordReset', this.formatOrgUserId(ev));
|
||||
humanReadableMsg = this.i18nService.t('eventAdminPasswordReset', this.getShortId(ev.organizationUserId));
|
||||
break;
|
||||
// Org
|
||||
case EventType.Organization_Updated:
|
||||
msg = humanReadableMsg = this.i18nService.t('editedOrgSettings');
|
||||
msg = this.i18nService.t('editedOrgSettings');
|
||||
break;
|
||||
case EventType.Organization_PurgedVault:
|
||||
msg = humanReadableMsg = this.i18nService.t('purgedOrganizationVault');
|
||||
msg = this.i18nService.t('purgedOrganizationVault');
|
||||
break;
|
||||
/*
|
||||
case EventType.Organization_ClientExportedVault:
|
||||
@@ -217,25 +176,13 @@ export class EventService {
|
||||
*/
|
||||
// Policies
|
||||
case EventType.Policy_Updated:
|
||||
msg = this.i18nService.t('modifiedPolicyId', this.formatPolicyId(ev));
|
||||
|
||||
const policies = await this.policyService.getAll();
|
||||
const policy = policies.filter(p => p.id === ev.policyId)[0];
|
||||
let p1 = this.getShortId(ev.policyId);
|
||||
if (policy !== null) {
|
||||
p1 = PolicyType[policy.type];
|
||||
}
|
||||
|
||||
humanReadableMsg = this.i18nService.t('modifiedPolicyId', p1);
|
||||
msg = this.i18nService.t('modifiedPolicy', this.formatPolicyId(ev));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {
|
||||
message: msg === '' ? null : msg,
|
||||
humanReadableMessage: humanReadableMsg === '' ? null : humanReadableMsg,
|
||||
};
|
||||
return msg === '' ? null : msg;
|
||||
}
|
||||
|
||||
private getAppInfo(deviceType: DeviceType): [string, string] {
|
||||
@@ -352,7 +299,6 @@ export class EventService {
|
||||
|
||||
export class EventInfo {
|
||||
message: string;
|
||||
humanReadableMessage: string;
|
||||
appIcon: string;
|
||||
appName: string;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationGuardService implements CanActivate {
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { Permissions } from 'jslib-common/enums/permissions';
|
||||
import { Permissions } from 'jslib/enums/permissions';
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationTypeGuardService implements CanActivate {
|
||||
@@ -27,8 +27,7 @@ export class OrganizationTypeGuardService implements CanActivate {
|
||||
(permissions.indexOf(Permissions.ManageGroups) !== -1 && org.canManageGroups) ||
|
||||
(permissions.indexOf(Permissions.ManageOrganization) !== -1 && org.isOwner) ||
|
||||
(permissions.indexOf(Permissions.ManagePolicies) !== -1 && org.canManagePolicies) ||
|
||||
(permissions.indexOf(Permissions.ManageUsers) !== -1 && org.canManageUsers) ||
|
||||
(permissions.indexOf(Permissions.ManageUsersPassword) !== -1 && org.canManageUsersPassword)
|
||||
(permissions.indexOf(Permissions.ManageUsers) !== -1 && org.canManageUsers)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
@Injectable()
|
||||
export class RouterService {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user