mirror of
https://github.com/bitwarden/web
synced 2025-12-10 05:13:40 +00:00
Compare commits
2 Commits
v2.27.0
...
feature/ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5d3caba65 | ||
|
|
5a2294fb4f |
@@ -1,8 +0,0 @@
|
|||||||
**/dist
|
|
||||||
**/build
|
|
||||||
jslib
|
|
||||||
webpack.config.js
|
|
||||||
scripts/optimize.js
|
|
||||||
config.js
|
|
||||||
|
|
||||||
**/node_modules
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"browser": true
|
|
||||||
},
|
|
||||||
"extends": ["./jslib/shared/eslintrc.json"],
|
|
||||||
"rules": {
|
|
||||||
"import/order": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"alphabetize": {
|
|
||||||
"order": "asc"
|
|
||||||
},
|
|
||||||
"newlines-between": "always",
|
|
||||||
"pathGroups": [
|
|
||||||
{
|
|
||||||
"pattern": "jslib-*/**",
|
|
||||||
"group": "external",
|
|
||||||
"position": "after"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pattern": "src/**/*",
|
|
||||||
"group": "parent",
|
|
||||||
"position": "before"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"pathGroupsExcludedImportTypes": ["builtin"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
65
.github/workflows/build.yml
vendored
65
.github/workflows/build.yml
vendored
@@ -11,8 +11,6 @@ on:
|
|||||||
branches-ignore:
|
branches-ignore:
|
||||||
- "l10n_master"
|
- "l10n_master"
|
||||||
- "gh-pages"
|
- "gh-pages"
|
||||||
paths-ignore:
|
|
||||||
- '.github/workflows/**'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cloc:
|
cloc:
|
||||||
@@ -30,26 +28,6 @@ jobs:
|
|||||||
- name: Print lines of code
|
- name: Print lines of code
|
||||||
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
||||||
|
|
||||||
lint:
|
|
||||||
name: Lint
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
|
||||||
|
|
||||||
- name: Cache npm
|
|
||||||
id: npm-cache
|
|
||||||
uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6
|
|
||||||
with:
|
|
||||||
path: "~/.npm"
|
|
||||||
key: ${{ runner.os }}-npm-lint-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run linter
|
|
||||||
run: npm run lint
|
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
name: Setup
|
name: Setup
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@@ -66,9 +44,7 @@ jobs:
|
|||||||
build-oss-selfhost:
|
build-oss-selfhost:
|
||||||
name: Build OSS zip
|
name: Build OSS zip
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs:
|
needs: setup
|
||||||
- setup
|
|
||||||
- lint
|
|
||||||
env:
|
env:
|
||||||
_VERSION: ${{ needs.setup.outputs.version }}
|
_VERSION: ${{ needs.setup.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
@@ -115,9 +91,7 @@ jobs:
|
|||||||
build-cloud:
|
build-cloud:
|
||||||
name: Build Cloud zip
|
name: Build Cloud zip
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs:
|
needs: setup
|
||||||
- setup
|
|
||||||
- lint
|
|
||||||
env:
|
env:
|
||||||
_VERSION: ${{ needs.setup.outputs.version }}
|
_VERSION: ${{ needs.setup.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
@@ -164,9 +138,7 @@ jobs:
|
|||||||
build-commercial-selfhost:
|
build-commercial-selfhost:
|
||||||
name: Build SelfHost Docker image
|
name: Build SelfHost Docker image
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs:
|
needs: setup
|
||||||
- setup
|
|
||||||
- lint
|
|
||||||
env:
|
env:
|
||||||
_VERSION: ${{ needs.setup.outputs.version }}
|
_VERSION: ${{ needs.setup.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
@@ -193,7 +165,7 @@ jobs:
|
|||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
- name: Setup DCT
|
- name: Setup DCT
|
||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc'
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix'
|
||||||
id: setup-dct
|
id: setup-dct
|
||||||
uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff
|
uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff
|
||||||
with:
|
with:
|
||||||
@@ -203,6 +175,9 @@ jobs:
|
|||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet tool restore
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
@@ -237,11 +212,11 @@ jobs:
|
|||||||
run: docker tag bitwarden/web bitwarden/web:dev
|
run: docker tag bitwarden/web bitwarden/web:dev
|
||||||
|
|
||||||
- name: Tag hotfix branch
|
- name: Tag hotfix branch
|
||||||
if: github.ref == 'refs/heads/hotfix-rc'
|
if: github.ref == 'refs/heads/hotfix'
|
||||||
run: docker tag bitwarden/web bitwarden/web:hotfix-rc
|
run: docker tag bitwarden/web bitwarden/web:hotfix
|
||||||
|
|
||||||
- name: List Docker images
|
- name: List Docker images
|
||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc'
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix'
|
||||||
run: docker images
|
run: docker images
|
||||||
|
|
||||||
- name: Push rc image
|
- name: Push rc image
|
||||||
@@ -259,22 +234,19 @@ jobs:
|
|||||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||||
|
|
||||||
- name: Push hotfix image
|
- name: Push hotfix image
|
||||||
if: github.ref == 'refs/heads/hotfix-rc'
|
if: github.ref == 'refs/heads/hotfix'
|
||||||
run: docker push bitwarden/web:hotfix-rc
|
run: docker push bitwarden/web:hotfix
|
||||||
env:
|
env:
|
||||||
DOCKER_CONTENT_TRUST: 1
|
DOCKER_CONTENT_TRUST: 1
|
||||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||||
|
|
||||||
- name: Log out of Docker
|
- name: Log out of Docker
|
||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc'
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix'
|
||||||
run: docker logout
|
run: docker logout
|
||||||
|
|
||||||
build-qa:
|
build-qa:
|
||||||
name: Build Docker images for QA environment
|
name: Build Docker images for QA environment
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs:
|
|
||||||
- setup
|
|
||||||
- lint
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||||
@@ -309,6 +281,9 @@ jobs:
|
|||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet tool restore
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
@@ -392,6 +367,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
nuget help | grep Version
|
nuget help | grep Version
|
||||||
msbuild -version
|
msbuild -version
|
||||||
|
dotnet --info
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
@@ -406,6 +382,9 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run linter
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
- name: NPM build
|
- name: NPM build
|
||||||
run: npm run build:bit:cloud
|
run: npm run build:bit:cloud
|
||||||
|
|
||||||
@@ -454,7 +433,6 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- cloc
|
- cloc
|
||||||
- setup
|
- setup
|
||||||
- lint
|
|
||||||
- build-oss-selfhost
|
- build-oss-selfhost
|
||||||
- build-cloud
|
- build-cloud
|
||||||
- build-commercial-selfhost
|
- build-commercial-selfhost
|
||||||
@@ -466,7 +444,6 @@ jobs:
|
|||||||
if: ${{ (github.ref == 'refs/heads/master') || (github.ref == 'refs/heads/rc') }}
|
if: ${{ (github.ref == 'refs/heads/master') || (github.ref == 'refs/heads/rc') }}
|
||||||
env:
|
env:
|
||||||
CLOC_STATUS: ${{ needs.cloc.result }}
|
CLOC_STATUS: ${{ needs.cloc.result }}
|
||||||
LINT_STATUS: ${{ needs.lint.result }}
|
|
||||||
SETUP_STATUS: ${{ needs.setup.result }}
|
SETUP_STATUS: ${{ needs.setup.result }}
|
||||||
BUILD_OSS_SELFHOST_STATUS: ${{ needs.build-oss-selfhost.result }}
|
BUILD_OSS_SELFHOST_STATUS: ${{ needs.build-oss-selfhost.result }}
|
||||||
BUILD_CLOUD_STATUS: ${{ needs.build-cloud.result }}
|
BUILD_CLOUD_STATUS: ${{ needs.build-cloud.result }}
|
||||||
@@ -477,8 +454,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
if [ "$CLOC_STATUS" = "failure" ]; then
|
if [ "$CLOC_STATUS" = "failure" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
elif [ "$LINT_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$SETUP_STATUS" = "failure" ]; then
|
elif [ "$SETUP_STATUS" = "failure" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
elif [ "$BUILD_OSS_SELFHOST_STATUS" = "failure" ]; then
|
elif [ "$BUILD_OSS_SELFHOST_STATUS" = "failure" ]; then
|
||||||
|
|||||||
16
.github/workflows/enforce-labels.yml
vendored
16
.github/workflows/enforce-labels.yml
vendored
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enforce PR labels
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [labeled, unlabeled, opened, edited, synchronize]
|
|
||||||
jobs:
|
|
||||||
enforce-label:
|
|
||||||
name: EnforceLabel
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- name: Enforce Label
|
|
||||||
uses: yogevbd/enforce-label-action@8d1e1709b1011e6d90400a0e6cf7c0b77aa5efeb
|
|
||||||
with:
|
|
||||||
BANNED_LABELS: "hold"
|
|
||||||
BANNED_LABELS_DESCRIPTION: "PRs on hold cannot be merged"
|
|
||||||
106
.github/workflows/release.yml
vendored
106
.github/workflows/release.yml
vendored
@@ -12,7 +12,6 @@ on:
|
|||||||
options:
|
options:
|
||||||
- Initial Release
|
- Initial Release
|
||||||
- Redeploy
|
- Redeploy
|
||||||
- Dry Run
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
@@ -21,20 +20,19 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
release_version: ${{ steps.version.outputs.package }}
|
release_version: ${{ steps.version.outputs.package }}
|
||||||
tag_version: ${{ steps.version.outputs.tag }}
|
tag_version: ${{ steps.version.outputs.tag }}
|
||||||
branch_name: ${{ steps.branch.outputs.branch_name }}
|
branch-name: ${{ steps.branch.outputs.branch-name }}
|
||||||
steps:
|
steps:
|
||||||
- name: Branch check
|
- name: Branch check
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
|
||||||
run: |
|
run: |
|
||||||
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
|
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix" ]]; then
|
||||||
echo "==================================="
|
echo "==================================="
|
||||||
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
|
echo "[!] Can only release from the 'rc' or 'hotfix' branches"
|
||||||
echo "==================================="
|
echo "==================================="
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # 2.4.0
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # 2.3.4
|
||||||
|
|
||||||
- name: Check Release Version
|
- name: Check Release Version
|
||||||
id: version
|
id: version
|
||||||
@@ -57,17 +55,15 @@ jobs:
|
|||||||
id: branch
|
id: branch
|
||||||
run: |
|
run: |
|
||||||
BRANCH_NAME=$(basename ${{ github.ref }})
|
BRANCH_NAME=$(basename ${{ github.ref }})
|
||||||
echo "::set-output name=branch_name::$BRANCH_NAME"
|
echo "::set-output name=branch-name::$BRANCH_NAME"
|
||||||
|
|
||||||
|
|
||||||
self-host:
|
self-host:
|
||||||
name: Release self-host docker
|
name: Release self-host docker
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs: setup
|
needs: setup
|
||||||
env:
|
env:
|
||||||
_BRANCH_NAME: ${{ needs.setup.outputs.branch_name }}
|
_BRANCH_NAME: ${{ needs.setup.outputs.branch-name }}
|
||||||
_RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
|
_RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||||
_RELEASE_OPTION: ${{ github.event.inputs.release_type }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
@@ -75,12 +71,7 @@ jobs:
|
|||||||
docker --version
|
docker --version
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
echo "Github Release Option: $_RELEASE_OPTION"
|
|
||||||
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
|
||||||
|
|
||||||
########## DockerHub ##########
|
|
||||||
- name: Setup DCT
|
- name: Setup DCT
|
||||||
id: setup-dct
|
id: setup-dct
|
||||||
uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff
|
uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff
|
||||||
@@ -88,25 +79,21 @@ jobs:
|
|||||||
azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||||
azure-keyvault-name: "bitwarden-prod-kv"
|
azure-keyvault-name: "bitwarden-prod-kv"
|
||||||
|
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||||
|
|
||||||
- name: Pull latest selfhost image
|
- name: Pull latest selfhost image
|
||||||
run: |
|
run: docker pull bitwarden/web:$_BRANCH_NAME
|
||||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
|
||||||
docker pull bitwarden/web:latest
|
|
||||||
else
|
|
||||||
docker pull bitwarden/web:$_BRANCH_NAME
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Tag version and latest
|
- name: Tag version and latest
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
|
||||||
docker tag bitwarden/web:latest bitwarden/web:dryrun
|
|
||||||
else
|
|
||||||
docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:$_RELEASE_VERSION
|
docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:$_RELEASE_VERSION
|
||||||
docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:latest
|
docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:latest
|
||||||
fi
|
|
||||||
|
- name: List Docker images
|
||||||
|
run: docker images
|
||||||
|
|
||||||
- name: Push version and latest image
|
- name: Push version and latest image
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
|
||||||
env:
|
env:
|
||||||
DOCKER_CONTENT_TRUST: 1
|
DOCKER_CONTENT_TRUST: 1
|
||||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||||
@@ -114,43 +101,9 @@ jobs:
|
|||||||
docker push bitwarden/web:$_RELEASE_VERSION
|
docker push bitwarden/web:$_RELEASE_VERSION
|
||||||
docker push bitwarden/web:latest
|
docker push bitwarden/web:latest
|
||||||
|
|
||||||
- name: Log out of Docker and disable Docker Notary
|
|
||||||
run: |
|
|
||||||
docker logout
|
|
||||||
echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
########## ACR ##########
|
|
||||||
- name: Login to Azure - QA Subscription
|
|
||||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
|
||||||
with:
|
|
||||||
creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }}
|
|
||||||
|
|
||||||
- name: Login to Azure ACR
|
|
||||||
run: az acr login -n bitwardenqa
|
|
||||||
|
|
||||||
- name: Tag version and latest
|
|
||||||
env:
|
|
||||||
REGISTRY: bitwardenqa.azurecr.io
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
|
||||||
docker tag bitwarden/web:latest $REGISTRY/web:dryrun
|
|
||||||
else
|
|
||||||
docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web:$_RELEASE_VERSION
|
|
||||||
docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web:latest
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Push version and latest image
|
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
|
||||||
env:
|
|
||||||
REGISTRY: bitwardenqa.azurecr.io
|
|
||||||
run: |
|
|
||||||
docker push $REGISTRY/web:$_RELEASE_VERSION
|
|
||||||
docker push $REGISTRY/web:latest
|
|
||||||
|
|
||||||
- name: Log out of Docker
|
- name: Log out of Docker
|
||||||
run: docker logout
|
run: docker logout
|
||||||
|
|
||||||
|
|
||||||
ghpages-deploy:
|
ghpages-deploy:
|
||||||
name: Deploy Web Vault
|
name: Deploy Web Vault
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@@ -162,7 +115,7 @@ jobs:
|
|||||||
_TAG_VERSION: ${{ needs.setup.outputs.tag_version }}
|
_TAG_VERSION: ${{ needs.setup.outputs.tag_version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||||
with:
|
with:
|
||||||
ref: gh-pages
|
ref: gh-pages
|
||||||
|
|
||||||
@@ -172,7 +125,7 @@ jobs:
|
|||||||
git push -u origin deploy-$_TAG_VERSION
|
git push -u origin deploy-$_TAG_VERSION
|
||||||
|
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||||
|
|
||||||
- name: Setup git config
|
- name: Setup git config
|
||||||
run: |
|
run: |
|
||||||
@@ -186,7 +139,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
branch: ${{ needs.setup.outputs.branch_name }}
|
branch: ${{ needs.setup.outputs.branch-name }}
|
||||||
artifacts: web-*-cloud-COMMERCIAL.zip
|
artifacts: web-*-cloud-COMMERCIAL.zip
|
||||||
|
|
||||||
# This should result in a build directory in the current working directory
|
# This should result in a build directory in the current working directory
|
||||||
@@ -194,7 +147,7 @@ jobs:
|
|||||||
run: unzip web-*-cloud-COMMERCIAL.zip
|
run: unzip web-*-cloud-COMMERCIAL.zip
|
||||||
|
|
||||||
- name: Deploy GitHub Pages
|
- name: Deploy GitHub Pages
|
||||||
uses: crazy-max/ghaction-github-pages@a117e4aa1fb4854d021546d2abdfac95be568a3a # v2.6.0
|
uses: crazy-max/ghaction-github-pages@db4476a01402e1a7ce05f41832040eef16d14925 # v2.5.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
@@ -202,10 +155,8 @@ jobs:
|
|||||||
build_dir: build
|
build_dir: build
|
||||||
keep_history: true
|
keep_history: true
|
||||||
commit_message: "Staging deploy ${{ needs.setup.outputs.release_version }}"
|
commit_message: "Staging deploy ${{ needs.setup.outputs.release_version }}"
|
||||||
dry_run: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
|
||||||
|
|
||||||
- name: Create Deploy PR
|
- name: Create Deploy PR
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
|
||||||
env:
|
env:
|
||||||
PR_BRANCH: deploy-${{ env._TAG_VERSION }}
|
PR_BRANCH: deploy-${{ env._TAG_VERSION }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -215,7 +166,6 @@ jobs:
|
|||||||
--base gh-pages \
|
--base gh-pages \
|
||||||
--head "$PR_BRANCH"
|
--head "$PR_BRANCH"
|
||||||
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Create GitHub Release
|
name: Create GitHub Release
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@@ -229,7 +179,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
branch: ${{ needs.setup.outputs.branch_name }}
|
branch: ${{ needs.setup.outputs.branch-name }}
|
||||||
artifacts: "web-*-selfhosted-COMMERCIAL.zip,
|
artifacts: "web-*-selfhosted-COMMERCIAL.zip,
|
||||||
web-*-selfhosted-open-source.zip"
|
web-*-selfhosted-open-source.zip"
|
||||||
|
|
||||||
@@ -239,8 +189,7 @@ jobs:
|
|||||||
mv web-*-selfhosted-open-source.zip web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip
|
mv web-*-selfhosted-open-source.zip web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09
|
||||||
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01
|
|
||||||
with:
|
with:
|
||||||
name: "Version ${{ needs.setup.outputs.release_version }}"
|
name: "Version ${{ needs.setup.outputs.release_version }}"
|
||||||
commit: ${{ github.sha }}
|
commit: ${{ github.sha }}
|
||||||
@@ -250,20 +199,3 @@ jobs:
|
|||||||
web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip"
|
web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip"
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
|
|
||||||
dry-run:
|
|
||||||
name: Dry Run Cleanup
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
|
||||||
env:
|
|
||||||
_TAG_VERSION: ${{ needs.setup.outputs.tag_version }}
|
|
||||||
needs:
|
|
||||||
- setup
|
|
||||||
- release
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # 2.4.0
|
|
||||||
|
|
||||||
- name: Remove deploy branch
|
|
||||||
run: git push origin --delete deploy-$_TAG_VERSION
|
|
||||||
|
|||||||
11
.github/workflows/workflow-linter.yml
vendored
11
.github/workflows/workflow-linter.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
name: Workflow Linter
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/workflows/**
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
call-workflow:
|
|
||||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@master
|
|
||||||
0
.husky/pre-commit
Executable file → Normal file
0
.husky/pre-commit
Executable file → Normal file
@@ -1,4 +1,4 @@
|
|||||||
FROM bitwarden/server
|
FROM bitwarden/server:dev
|
||||||
|
|
||||||
LABEL com.bitwarden.product="bitwarden"
|
LABEL com.bitwarden.product="bitwarden"
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,6 @@ You can also manually adjusting your API endpoint settings by adding `config/loc
|
|||||||
|
|
||||||
Where the `urls` object is defined by the [Urls type in jslib](https://github.com/bitwarden/jslib/blob/master/common/src/abstractions/environment.service.ts).
|
Where the `urls` object is defined by the [Urls type in jslib](https://github.com/bitwarden/jslib/blob/master/common/src/abstractions/environment.service.ts).
|
||||||
|
|
||||||
## We're Hiring!
|
|
||||||
|
|
||||||
Interested in contributing in a big way? Consider joining our team! We're hiring for many positions. Please take a look at our [Careers page](https://bitwarden.com/careers/) to see what opportunities are currently open as well as what it's like to work at Bitwarden.
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.
|
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { AppComponent as BaseAppComponent } from "src/app/app.component";
|
import { AppComponent as BaseAppComponent } from "src/app/app.component";
|
||||||
|
|
||||||
import { DisablePersonalVaultExportPolicy } from "./policies/disable-personal-vault-export.component";
|
import { DisablePersonalVaultExportPolicy } from "./policies/disable-personal-vault-export.component";
|
||||||
import { MaximumVaultTimeoutPolicy } from "./policies/maximum-vault-timeout.component";
|
import { MaximumVaultTimeoutPolicy } from "./policies/maximum-vault-timeout.component";
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,17 @@ import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
|||||||
|
|
||||||
import { BitwardenToastModule } from "jslib-angular/components/toastr.component";
|
import { BitwardenToastModule } from "jslib-angular/components/toastr.component";
|
||||||
|
|
||||||
import { OssRoutingModule } from "src/app/oss-routing.module";
|
|
||||||
import { OssModule } from "src/app/oss.module";
|
|
||||||
import { ServicesModule } from "src/app/services/services.module";
|
|
||||||
import { WildcardRoutingModule } from "src/app/wildcard-routing.module";
|
|
||||||
|
|
||||||
import { AppRoutingModule } from "./app-routing.module";
|
import { AppRoutingModule } from "./app-routing.module";
|
||||||
import { AppComponent } from "./app.component";
|
import { AppComponent } from "./app.component";
|
||||||
import { OrganizationsModule } from "./organizations/organizations.module";
|
import { OrganizationsModule } from "./organizations/organizations.module";
|
||||||
import { DisablePersonalVaultExportPolicyComponent } from "./policies/disable-personal-vault-export.component";
|
import { DisablePersonalVaultExportPolicyComponent } from "./policies/disable-personal-vault-export.component";
|
||||||
import { MaximumVaultTimeoutPolicyComponent } from "./policies/maximum-vault-timeout.component";
|
import { MaximumVaultTimeoutPolicyComponent } from "./policies/maximum-vault-timeout.component";
|
||||||
|
|
||||||
|
import { OssRoutingModule } from "src/app/oss-routing.module";
|
||||||
|
import { OssModule } from "src/app/oss.module";
|
||||||
|
import { ServicesModule } from "src/app/services/services.module";
|
||||||
|
import { WildcardRoutingModule } from "src/app/wildcard-routing.module";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
OssModule,
|
OssModule,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import "bootstrap";
|
|||||||
import "jquery";
|
import "jquery";
|
||||||
import "popper.js";
|
import "popper.js";
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
require("src/scss/styles.scss");
|
require("src/scss/styles.scss");
|
||||||
|
|
||||||
import { AppModule } from "./app.module";
|
import { AppModule } from "./app.module";
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import { Directive, Input, OnInit, Self } from "@angular/core";
|
|
||||||
import { ControlValueAccessor, FormControl, NgControl, Validators } from "@angular/forms";
|
|
||||||
|
|
||||||
import { dirtyRequired } from "jslib-angular/validators/dirty.validator";
|
|
||||||
|
|
||||||
/** For use in the SSO Config Form only - will be deprecated by the Component Library */
|
|
||||||
@Directive()
|
|
||||||
export abstract class BaseCvaComponent implements ControlValueAccessor, OnInit {
|
|
||||||
get describedById() {
|
|
||||||
return this.showDescribedBy ? this.controlId + "Desc" : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get showDescribedBy() {
|
|
||||||
return this.helperText != null || this.controlDir.control.hasError("required");
|
|
||||||
}
|
|
||||||
|
|
||||||
get isRequired() {
|
|
||||||
return (
|
|
||||||
this.controlDir.control.hasValidator(Validators.required) ||
|
|
||||||
this.controlDir.control.hasValidator(dirtyRequired)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input() label: string;
|
|
||||||
@Input() controlId: string;
|
|
||||||
@Input() helperText: string;
|
|
||||||
|
|
||||||
internalControl = new FormControl("");
|
|
||||||
|
|
||||||
protected onChange: any;
|
|
||||||
protected onTouched: any;
|
|
||||||
|
|
||||||
constructor(@Self() public controlDir: NgControl) {
|
|
||||||
this.controlDir.valueAccessor = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.internalControl.valueChanges.subscribe(this.onValueChangesInternal);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBlurInternal() {
|
|
||||||
this.onTouched();
|
|
||||||
}
|
|
||||||
|
|
||||||
// CVA interfaces
|
|
||||||
writeValue(value: string) {
|
|
||||||
this.internalControl.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerOnChange(fn: any) {
|
|
||||||
this.onChange = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerOnTouched(fn: any) {
|
|
||||||
this.onTouched = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDisabledState(isDisabled: boolean) {
|
|
||||||
if (isDisabled) {
|
|
||||||
this.internalControl.disable();
|
|
||||||
} else {
|
|
||||||
this.internalControl.enable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onValueChangesInternal: any = (value: string) => this.onChange(value);
|
|
||||||
// End CVA interfaces
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<div class="form-group">
|
|
||||||
<div class="form-check">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
[attr.id]="controlId"
|
|
||||||
[attr.aria-describedby]="describedById"
|
|
||||||
[formControl]="internalControl"
|
|
||||||
(blur)="onBlurInternal()"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" [attr.for]="controlId">{{ label }}</label>
|
|
||||||
</div>
|
|
||||||
<small *ngIf="showDescribedBy" [attr.id]="describedById" class="form-text text-muted">{{
|
|
||||||
helperText
|
|
||||||
}}</small>
|
|
||||||
</div>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { Component } from "@angular/core";
|
|
||||||
|
|
||||||
import { BaseCvaComponent } from "./base-cva.component";
|
|
||||||
|
|
||||||
/** For use in the SSO Config Form only - will be deprecated by the Component Library */
|
|
||||||
@Component({
|
|
||||||
selector: "app-input-checkbox",
|
|
||||||
templateUrl: "input-checkbox.component.html",
|
|
||||||
})
|
|
||||||
export class InputCheckboxComponent extends BaseCvaComponent {}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<div class="form-group">
|
|
||||||
<label>{{ label }}</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input class="form-control" readonly [value]="controlValue" />
|
|
||||||
<div class="input-group-append" *ngIf="showLaunch">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
appA11yTitle="{{ 'launch' | i18n }}"
|
|
||||||
(click)="launchUri(controlValue)"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-lg bwi-external-link" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="input-group-append" *ngIf="showCopy">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
appA11yTitle="{{ 'copyValue' | i18n }}"
|
|
||||||
(click)="copy(controlValue)"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
|
||||||
|
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
|
||||||
|
|
||||||
/** For use in the SSO Config Form only - will be deprecated by the Component Library */
|
|
||||||
@Component({
|
|
||||||
selector: "app-input-text-readonly",
|
|
||||||
templateUrl: "input-text-readonly.component.html",
|
|
||||||
})
|
|
||||||
export class InputTextReadOnlyComponent {
|
|
||||||
@Input() controlValue: string;
|
|
||||||
@Input() label: string;
|
|
||||||
@Input() showCopy = true;
|
|
||||||
@Input() showLaunch = false;
|
|
||||||
|
|
||||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
|
||||||
|
|
||||||
copy(value: string) {
|
|
||||||
this.platformUtilsService.copyToClipboard(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
launchUri(url: string) {
|
|
||||||
this.platformUtilsService.launchUri(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<div class="form-group">
|
|
||||||
<label [attr.for]="controlId">
|
|
||||||
{{ label }}
|
|
||||||
<small *ngIf="isRequired" class="text-muted form-text d-inline"
|
|
||||||
>({{ "required" | i18n }})</small
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
[formControl]="internalControl"
|
|
||||||
class="form-control"
|
|
||||||
[attr.id]="controlId"
|
|
||||||
[attr.aria-describedby]="describedById"
|
|
||||||
[attr.aria-invalid]="controlDir.control.invalid"
|
|
||||||
(blur)="onBlurInternal()"
|
|
||||||
/>
|
|
||||||
<div *ngIf="showDescribedBy" [attr.id]="describedById">
|
|
||||||
<small
|
|
||||||
*ngIf="helperText != null && !controlDir.control.hasError(helperTextSameAsError)"
|
|
||||||
class="form-text text-muted"
|
|
||||||
>
|
|
||||||
{{ helperText }}
|
|
||||||
</small>
|
|
||||||
<small class="error-inline" *ngIf="controlDir.control.hasError('required')" role="alert">
|
|
||||||
<i class="bwi bwi-exclamation-circle" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{{ "error" | i18n }}:</span>
|
|
||||||
{{
|
|
||||||
controlDir.control.hasError(helperTextSameAsError)
|
|
||||||
? helperText
|
|
||||||
: ("fieldRequiredError" | i18n: label)
|
|
||||||
}}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { Component, Input, OnInit } from "@angular/core";
|
|
||||||
|
|
||||||
import { BaseCvaComponent } from "./base-cva.component";
|
|
||||||
|
|
||||||
/** For use in the SSO Config Form only - will be deprecated by the Component Library */
|
|
||||||
@Component({
|
|
||||||
selector: "app-input-text[label][controlId]",
|
|
||||||
templateUrl: "input-text.component.html",
|
|
||||||
})
|
|
||||||
export class InputTextComponent extends BaseCvaComponent implements OnInit {
|
|
||||||
@Input() helperTextSameAsError: string;
|
|
||||||
@Input() requiredErrorMessage: string;
|
|
||||||
@Input() stripSpaces = false;
|
|
||||||
|
|
||||||
transformValue: (value: string) => string = null;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
super.ngOnInit();
|
|
||||||
if (this.stripSpaces) {
|
|
||||||
this.transformValue = this.doStripSpaces;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writeValue(value: string) {
|
|
||||||
this.internalControl.setValue(value == null ? "" : value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onValueChangesInternal: any = (value: string) => {
|
|
||||||
let newValue = value;
|
|
||||||
if (this.transformValue != null) {
|
|
||||||
newValue = this.transformValue(value);
|
|
||||||
this.internalControl.setValue(newValue, { emitEvent: false });
|
|
||||||
}
|
|
||||||
this.onChange(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
protected onValueChangeInternal(value: string) {
|
|
||||||
let newValue = value;
|
|
||||||
if (this.transformValue != null) {
|
|
||||||
newValue = this.transformValue(value);
|
|
||||||
this.internalControl.setValue(newValue, { emitEvent: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private doStripSpaces(value: string) {
|
|
||||||
return value.replace(/ /g, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<div class="form-group">
|
|
||||||
<label [attr.for]="controlId">
|
|
||||||
{{ label }}
|
|
||||||
<small *ngIf="isRequired" class="text-muted form-text d-inline"
|
|
||||||
>({{ "required" | i18n }})</small
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
class="form-control"
|
|
||||||
[attr.id]="controlId"
|
|
||||||
[attr.aria-invalid]="controlDir.control.invalid"
|
|
||||||
[formControl]="internalControl"
|
|
||||||
(blur)="onBlurInternal()"
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of selectOptions" [ngValue]="o.value" disabled="{{ o.disabled }}">
|
|
||||||
{{ o.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
|
||||||
|
|
||||||
import { SelectOptions } from "jslib-angular/interfaces/selectOptions";
|
|
||||||
|
|
||||||
import { BaseCvaComponent } from "./base-cva.component";
|
|
||||||
|
|
||||||
/** For use in the SSO Config Form only - will be deprecated by the Component Library */
|
|
||||||
@Component({
|
|
||||||
selector: "app-select",
|
|
||||||
templateUrl: "select.component.html",
|
|
||||||
})
|
|
||||||
export class SelectComponent extends BaseCvaComponent {
|
|
||||||
@Input() selectOptions: SelectOptions[];
|
|
||||||
}
|
|
||||||
@@ -14,9 +14,10 @@
|
|||||||
<form
|
<form
|
||||||
#form
|
#form
|
||||||
(ngSubmit)="submit()"
|
(ngSubmit)="submit()"
|
||||||
[formGroup]="ssoConfigForm"
|
[formGroup]="data"
|
||||||
[appApiAction]="formPromise"
|
[appApiAction]="formPromise"
|
||||||
*ngIf="!loading"
|
*ngIf="!loading"
|
||||||
|
ngNativeValidate
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
{{ "ssoPolicyHelpStart" | i18n }}
|
{{ "ssoPolicyHelpStart" | i18n }}
|
||||||
@@ -26,14 +27,19 @@
|
|||||||
{{ "ssoPolicyHelpKeyConnector" | i18n }}
|
{{ "ssoPolicyHelpKeyConnector" | i18n }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Root form -->
|
<div class="form-group">
|
||||||
<ng-container>
|
<div class="form-check">
|
||||||
<app-input-checkbox
|
<input
|
||||||
controlId="enabled"
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="enabled"
|
||||||
[formControl]="enabled"
|
[formControl]="enabled"
|
||||||
[label]="'allowSso' | i18n"
|
name="Enabled"
|
||||||
[helperText]="'allowSsoDesc' | i18n"
|
/>
|
||||||
></app-input-checkbox>
|
<label class="form-check-label" for="enabled">{{ "allowSso" | i18n }}</label>
|
||||||
|
</div>
|
||||||
|
<small class="form-text text-muted">{{ "allowSsoDesc" | i18n }}</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ "memberDecryptionOption" | i18n }}</label>
|
<label>{{ "memberDecryptionOption" | i18n }}</label>
|
||||||
@@ -74,26 +80,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Key Connector -->
|
<ng-container *ngIf="data.value.keyConnectorEnabled">
|
||||||
<ng-container *ngIf="ssoConfigForm.get('keyConnectorEnabled').value">
|
|
||||||
<app-callout type="warning" [useAlertRole]="true">
|
<app-callout type="warning" [useAlertRole]="true">
|
||||||
{{ "keyConnectorWarning" | i18n }}
|
{{ "keyConnectorWarning" | i18n }}
|
||||||
</app-callout>
|
</app-callout>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="keyConnectorUrl">
|
<label for="keyConnectorUrl">{{ "keyConnectorUrl" | i18n }}</label>
|
||||||
{{ "keyConnectorUrl" | i18n }}
|
|
||||||
<small class="text-muted form-text d-inline">({{ "required" | i18n }})</small>
|
|
||||||
</label>
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
formControlName="keyConnectorUrl"
|
formControlName="keyConnectorUrl"
|
||||||
id="keyConnectorUrl"
|
id="keyConnectorUrl"
|
||||||
aria-describedby="keyConnectorUrlDesc"
|
required
|
||||||
(change)="haveTestedKeyConnector = false"
|
|
||||||
appInputStripSpaces
|
|
||||||
appA11yInvalid
|
|
||||||
/>
|
/>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button
|
<button
|
||||||
@@ -114,319 +113,376 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="haveTestedKeyConnector" id="keyConnectorUrlDesc" aria-live="polite">
|
<ng-container *ngIf="keyConnectorUrl.pristine && !keyConnectorUrl.pending">
|
||||||
<small
|
<div class="text-danger" *ngIf="keyConnectorUrl.hasError('invalidUrl')" role="alert">
|
||||||
class="error-inline"
|
|
||||||
*ngIf="keyConnectorUrl.hasError('invalidUrl'); else keyConnectorSuccess"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-exclamation-circle" aria-hidden="true"></i>
|
<i class="bwi bwi-exclamation-circle" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ "error" | i18n }}:</span>
|
|
||||||
{{ "keyConnectorTestFail" | i18n }}
|
{{ "keyConnectorTestFail" | i18n }}
|
||||||
</small>
|
</div>
|
||||||
<ng-template #keyConnectorSuccess>
|
<div class="text-success" *ngIf="!keyConnectorUrl.hasError('invalidUrl')" role="alert">
|
||||||
<small class="text-success">
|
|
||||||
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
|
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
|
||||||
{{ "keyConnectorTestSuccess" | i18n }}
|
{{ "keyConnectorTestSuccess" | i18n }}
|
||||||
</small>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<app-select
|
<div class="form-group">
|
||||||
controlId="type"
|
<label for="type">{{ "type" | i18n }}</label>
|
||||||
[label]="'type' | i18n"
|
<select class="form-control" id="type" formControlName="configType">
|
||||||
[selectOptions]="ssoTypeOptions"
|
<option [ngValue]="0" disabled>{{ "selectType" | i18n }}</option>
|
||||||
formControlName="configType"
|
<option [ngValue]="1">OpenID Connect</option>
|
||||||
>
|
<option [ngValue]="2">SAML 2.0</option>
|
||||||
</app-select>
|
</select>
|
||||||
</ng-container>
|
</div>
|
||||||
|
|
||||||
<!-- OIDC -->
|
<!-- OIDC -->
|
||||||
<div
|
<div *ngIf="data.value.configType == 1">
|
||||||
*ngIf="ssoConfigForm.get('configType').value === ssoType.OpenIdConnect"
|
|
||||||
[formGroup]="openIdForm"
|
|
||||||
>
|
|
||||||
<div class="config-section">
|
<div class="config-section">
|
||||||
<h2 class="secondary-header">{{ "openIdConnectConfig" | i18n }}</h2>
|
<h2>{{ "openIdConnectConfig" | i18n }}</h2>
|
||||||
|
<div class="form-group">
|
||||||
<app-input-text-readonly
|
<label>{{ "callbackPath" | i18n }}</label>
|
||||||
[label]="'callbackPath' | i18n"
|
<div class="input-group">
|
||||||
[controlValue]="callbackPath"
|
<input class="form-control" readonly [value]="callbackPath" />
|
||||||
></app-input-text-readonly>
|
<div class="input-group-append">
|
||||||
|
|
||||||
<app-input-text-readonly
|
|
||||||
[label]="'signedOutCallbackPath' | i18n"
|
|
||||||
[controlValue]="signedOutCallbackPath"
|
|
||||||
></app-input-text-readonly>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'authority' | i18n"
|
|
||||||
controlId="authority"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
formControlName="authority"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'clientId' | i18n"
|
|
||||||
controlId="clientId"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
formControlName="clientId"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'clientSecret' | i18n"
|
|
||||||
controlId="clientSecret"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
formControlName="clientSecret"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'metadataAddress' | i18n"
|
|
||||||
controlId="metadataAddress"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
[helperText]="'openIdAuthorityRequired' | i18n"
|
|
||||||
formControlName="metadataAddress"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-select
|
|
||||||
controlId="redirectBehavior"
|
|
||||||
[label]="'oidcRedirectBehavior' | i18n"
|
|
||||||
[selectOptions]="connectRedirectOptions"
|
|
||||||
formControlName="redirectBehavior"
|
|
||||||
>
|
|
||||||
</app-select>
|
|
||||||
|
|
||||||
<app-input-checkbox
|
|
||||||
controlId="getClaimsFromUserInfoEndpoint"
|
|
||||||
formControlName="getClaimsFromUserInfoEndpoint"
|
|
||||||
[label]="'getClaimsFromUserInfoEndpoint' | i18n"
|
|
||||||
></app-input-checkbox>
|
|
||||||
|
|
||||||
<!-- Optional customizations -->
|
|
||||||
<div
|
|
||||||
class="section-header d-flex flex-row align-items-center mt-3 mb-3"
|
|
||||||
(click)="toggleOpenIdCustomizations()"
|
|
||||||
>
|
|
||||||
<h3 class="mb-0 mr-2" id="customizations-header">
|
|
||||||
{{ "openIdOptionalCustomizations" | i18n }}
|
|
||||||
</h3>
|
|
||||||
<button
|
<button
|
||||||
class="mb-1 btn btn-link"
|
|
||||||
type="button"
|
type="button"
|
||||||
appStopClick
|
class="btn btn-outline-secondary"
|
||||||
role="button"
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
aria-controls="customizations"
|
(click)="copy(callbackPath)"
|
||||||
[attr.aria-expanded]="showOpenIdCustomizations"
|
|
||||||
aria-labelledby="customizations-header"
|
|
||||||
>
|
>
|
||||||
<i
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
class="bwi"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{
|
|
||||||
'bwi-angle-down': !showOpenIdCustomizations,
|
|
||||||
'bwi-chevron-up': showOpenIdCustomizations
|
|
||||||
}"
|
|
||||||
></i>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="customizations" [hidden]="!showOpenIdCustomizations">
|
</div>
|
||||||
<app-input-text
|
</div>
|
||||||
[label]="'additionalScopes' | i18n"
|
<div class="form-group">
|
||||||
controlId="additionalScopes"
|
<label>{{ "signedOutCallbackPath" | i18n }}</label>
|
||||||
[helperText]="'separateMultipleWithComma' | i18n"
|
<div class="input-group">
|
||||||
formControlName="additionalScopes"
|
<input class="form-control" readonly [value]="signedOutCallbackPath" />
|
||||||
></app-input-text>
|
<div class="input-group-append">
|
||||||
|
<button
|
||||||
<app-input-text
|
type="button"
|
||||||
[label]="'additionalUserIdClaimTypes' | i18n"
|
class="btn btn-outline-secondary"
|
||||||
controlId="additionalUserIdClaimTypes"
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
[helperText]="'separateMultipleWithComma' | i18n"
|
(click)="copy(signedOutCallbackPath)"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="authority">{{ "authority" | i18n }}</label>
|
||||||
|
<input class="form-control" formControlName="authority" id="authority" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="clientId">{{ "clientId" | i18n }}</label>
|
||||||
|
<input class="form-control" formControlName="clientId" id="clientId" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="clientSecret">{{ "clientSecret" | i18n }}</label>
|
||||||
|
<input class="form-control" formControlName="clientSecret" id="clientSecret" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="metadataAddress">{{ "metadataAddress" | i18n }}</label>
|
||||||
|
<input class="form-control" formControlName="metadataAddress" id="metadataAddress" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redirectBehavior">{{ "oidcRedirectBehavior" | i18n }}</label>
|
||||||
|
<select class="form-control" formControlName="redirectBehavior" id="redirectBehavior">
|
||||||
|
<option [ngValue]="0">Redirect GET</option>
|
||||||
|
<option [ngValue]="1">Form POST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="getClaimsFromUserInfoEndpoint"
|
||||||
|
formControlName="getClaimsFromUserInfoEndpoint"
|
||||||
|
/>
|
||||||
|
<label class="form-check-label" for="getClaimsFromUserInfoEndpoint">
|
||||||
|
{{ "getClaimsFromUserInfoEndpoint" | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="additionalScopes">{{ "additionalScopes" | i18n }}</label>
|
||||||
|
<input class="form-control" formControlName="additionalScopes" id="additionalScopes" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="additionalUserIdClaimTypes">{{ "additionalUserIdClaimTypes" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
formControlName="additionalUserIdClaimTypes"
|
formControlName="additionalUserIdClaimTypes"
|
||||||
></app-input-text>
|
id="additionalUserIdClaimTypes"
|
||||||
|
/>
|
||||||
<app-input-text
|
</div>
|
||||||
[label]="'additionalEmailClaimTypes' | i18n"
|
<div class="form-group">
|
||||||
controlId="additionalEmailClaimTypes"
|
<label for="additionalEmailClaimTypes">{{ "additionalEmailClaimTypes" | i18n }}</label>
|
||||||
[helperText]="'separateMultipleWithComma' | i18n"
|
<input
|
||||||
|
class="form-control"
|
||||||
formControlName="additionalEmailClaimTypes"
|
formControlName="additionalEmailClaimTypes"
|
||||||
></app-input-text>
|
id="additionalEmailClaimTypes"
|
||||||
|
/>
|
||||||
<app-input-text
|
</div>
|
||||||
[label]="'additionalNameClaimTypes' | i18n"
|
<div class="form-group">
|
||||||
controlId="additionalNameClaimTypes"
|
<label for="additionalNameClaimTypes">{{ "additionalNameClaimTypes" | i18n }}</label>
|
||||||
[helperText]="'separateMultipleWithComma' | i18n"
|
<input
|
||||||
|
class="form-control"
|
||||||
formControlName="additionalNameClaimTypes"
|
formControlName="additionalNameClaimTypes"
|
||||||
></app-input-text>
|
id="additionalNameClaimTypes"
|
||||||
|
/>
|
||||||
<app-input-text
|
</div>
|
||||||
[label]="'acrValues' | i18n"
|
<div class="form-group">
|
||||||
controlId="acrValues"
|
<label for="acrValues">{{ "acrValues" | i18n }}</label>
|
||||||
helperText="acr_values"
|
<input class="form-control" formControlName="acrValues" id="acrValues" />
|
||||||
formControlName="acrValues"
|
</div>
|
||||||
></app-input-text>
|
<div class="form-group">
|
||||||
|
<label for="expectedReturnAcrValue">{{ "expectedReturnAcrValue" | i18n }}</label>
|
||||||
<app-input-text
|
<input
|
||||||
[label]="'expectedReturnAcrValue' | i18n"
|
class="form-control"
|
||||||
controlId="expectedReturnAcrValue"
|
|
||||||
helperText="acr_validation"
|
|
||||||
formControlName="expectedReturnAcrValue"
|
formControlName="expectedReturnAcrValue"
|
||||||
></app-input-text>
|
id="expectedReturnAcrValue"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- SAML2 SP -->
|
<div *ngIf="data.value.configType == 2">
|
||||||
<div *ngIf="ssoConfigForm.get('configType').value === ssoType.Saml2" [formGroup]="samlForm">
|
|
||||||
<!-- SAML2 SP -->
|
<!-- SAML2 SP -->
|
||||||
<div class="config-section">
|
<div class="config-section">
|
||||||
<h2 class="secondary-header">{{ "samlSpConfig" | i18n }}</h2>
|
<h2>{{ "samlSpConfig" | i18n }}</h2>
|
||||||
|
<div class="form-group">
|
||||||
<app-input-text-readonly
|
<label>{{ "spEntityId" | i18n }}</label>
|
||||||
[label]="'spEntityId' | i18n"
|
<div class="input-group">
|
||||||
[controlValue]="spEntityId"
|
<input class="form-control" readonly [value]="spEntityId" />
|
||||||
></app-input-text-readonly>
|
<div class="input-group-append">
|
||||||
|
<button
|
||||||
<app-input-text-readonly
|
type="button"
|
||||||
[label]="'spMetadataUrl' | i18n"
|
class="btn btn-outline-secondary"
|
||||||
[controlValue]="spMetadataUrl"
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
[showLaunch]="true"
|
(click)="copy(spEntityId)"
|
||||||
></app-input-text-readonly>
|
|
||||||
|
|
||||||
<app-input-text-readonly
|
|
||||||
[label]="'spAcsUrl' | i18n"
|
|
||||||
[controlValue]="spAcsUrl"
|
|
||||||
></app-input-text-readonly>
|
|
||||||
|
|
||||||
<app-select
|
|
||||||
controlId="spNameIdFormat"
|
|
||||||
[label]="'spNameIdFormat' | i18n"
|
|
||||||
[selectOptions]="saml2NameIdFormatOptions"
|
|
||||||
formControlName="spNameIdFormat"
|
|
||||||
>
|
>
|
||||||
</app-select>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<app-select
|
</div>
|
||||||
controlId="spOutboundSigningAlgorithm"
|
</div>
|
||||||
[label]="'spOutboundSigningAlgorithm' | i18n"
|
</div>
|
||||||
[selectOptions]="samlSigningAlgorithmOptions"
|
<div class="form-group">
|
||||||
|
<label>{{ "spMetadataUrl" | i18n }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input class="form-control" readonly [value]="spMetadataUrl" />
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
appA11yTitle="{{ 'launch' | i18n }}"
|
||||||
|
(click)="launchUri(spMetadataUrl)"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-external-link" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
|
(click)="copy(spMetadataUrl)"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ "spAcsUrl" | i18n }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input class="form-control" readonly [value]="spAcsUrl" />
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
|
(click)="copy(spAcsUrl)"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spNameIdFormat">{{ "spNameIdFormat" | i18n }}</label>
|
||||||
|
<select class="form-control" formControlName="spNameIdFormat" id="spNameIdFormat">
|
||||||
|
<option value="0">Not Configured</option>
|
||||||
|
<option value="1">Unspecified</option>
|
||||||
|
<option value="2">Email Address</option>
|
||||||
|
<option value="3">X.509 Subject Name</option>
|
||||||
|
<option value="4">Windows Domain Qualified Name</option>
|
||||||
|
<option value="5">Kerberos Principal Name</option>
|
||||||
|
<option value="6">Entity Identifier</option>
|
||||||
|
<option value="7">Persistent</option>
|
||||||
|
<option value="8">Transient</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spOutboundSigningAlgorithm">{{ "spOutboundSigningAlgorithm" | i18n }}</label>
|
||||||
|
<select
|
||||||
|
class="form-control"
|
||||||
formControlName="spOutboundSigningAlgorithm"
|
formControlName="spOutboundSigningAlgorithm"
|
||||||
|
id="spOutboundSigningAlgorithm"
|
||||||
>
|
>
|
||||||
</app-select>
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{ o }}</option>
|
||||||
|
</select>
|
||||||
<app-select
|
</div>
|
||||||
controlId="spSigningBehavior"
|
<div class="form-group">
|
||||||
[label]="'spSigningBehavior' | i18n"
|
<label for="spSigningBehavior">{{ "spSigningBehavior" | i18n }}</label>
|
||||||
[selectOptions]="saml2SigningBehaviourOptions"
|
<select class="form-control" formControlName="spSigningBehavior" id="spSigningBehavior">
|
||||||
formControlName="spSigningBehavior"
|
<option value="0">If IdP Wants Authn Requests Signed</option>
|
||||||
>
|
<option value="1">Always</option>
|
||||||
</app-select>
|
<option value="3">Never</option>
|
||||||
|
</select>
|
||||||
<app-select
|
</div>
|
||||||
controlId="spMinIncomingSigningAlgorithm"
|
<div class="form-group">
|
||||||
[label]="'spMinIncomingSigningAlgorithm' | i18n"
|
<label for="spMinIncomingSigningAlgorithm">{{
|
||||||
[selectOptions]="samlSigningAlgorithmOptions"
|
"spMinIncomingSigningAlgorithm" | i18n
|
||||||
|
}}</label>
|
||||||
|
<select
|
||||||
|
class="form-control"
|
||||||
formControlName="spMinIncomingSigningAlgorithm"
|
formControlName="spMinIncomingSigningAlgorithm"
|
||||||
|
id="spMinIncomingSigningAlgorithm"
|
||||||
>
|
>
|
||||||
</app-select>
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{ o }}</option>
|
||||||
|
</select>
|
||||||
<app-input-checkbox
|
</div>
|
||||||
controlId="spWantAssertionsSigned"
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="spWantAssertionsSigned"
|
||||||
formControlName="spWantAssertionsSigned"
|
formControlName="spWantAssertionsSigned"
|
||||||
[label]="'spWantAssertionsSigned' | i18n"
|
/>
|
||||||
></app-input-checkbox>
|
<label class="form-check-label" for="spWantAssertionsSigned">
|
||||||
|
{{ "spWantAssertionsSigned" | i18n }}
|
||||||
<app-input-checkbox
|
</label>
|
||||||
controlId="spValidateCertificates"
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="spValidateCertificates"
|
||||||
formControlName="spValidateCertificates"
|
formControlName="spValidateCertificates"
|
||||||
[label]="'spValidateCertificates' | i18n"
|
/>
|
||||||
></app-input-checkbox>
|
<label class="form-check-label" for="spValidateCertificates">
|
||||||
|
{{ "spValidateCertificates" | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- SAML2 IDP -->
|
<!-- SAML2 IDP -->
|
||||||
<div class="config-section">
|
<div class="config-section">
|
||||||
<h2 class="secondary-header">{{ "samlIdpConfig" | i18n }}</h2>
|
<h2>{{ "samlIdpConfig" | i18n }}</h2>
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'idpEntityId' | i18n"
|
|
||||||
controlId="idpEntityId"
|
|
||||||
formControlName="idpEntityId"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-select
|
|
||||||
controlId="idpBindingType"
|
|
||||||
[label]="'idpBindingType' | i18n"
|
|
||||||
[selectOptions]="saml2BindingTypeOptions"
|
|
||||||
formControlName="idpBindingType"
|
|
||||||
>
|
|
||||||
</app-select>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'idpSingleSignOnServiceUrl' | i18n"
|
|
||||||
controlId="idpSingleSignOnServiceUrl"
|
|
||||||
[helperText]="'idpSingleSignOnServiceUrlRequired' | i18n"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
formControlName="idpSingleSignOnServiceUrl"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<app-input-text
|
|
||||||
[label]="'idpSingleLogoutServiceUrl' | i18n"
|
|
||||||
controlId="idpSingleLogoutServiceUrl"
|
|
||||||
[stripSpaces]="true"
|
|
||||||
formControlName="idpSingleLogoutServiceUrl"
|
|
||||||
></app-input-text>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="idpX509PublicCert">
|
<label for="idpEntityId">{{ "idpEntityId" | i18n }}</label>
|
||||||
{{ "idpX509PublicCert" | i18n }}
|
<input class="form-control" formControlName="idpEntityId" id="idpEntityId" />
|
||||||
<small class="text-muted form-text d-inline">({{ "required" | i18n }})</small>
|
</div>
|
||||||
</label>
|
<div class="form-group">
|
||||||
|
<label for="idpBindingType">{{ "idpBindingType" | i18n }}</label>
|
||||||
|
<select class="form-control" formControlName="idpBindingType" id="idpBindingType">
|
||||||
|
<option value="1">Redirect</option>
|
||||||
|
<option value="2">HTTP POST</option>
|
||||||
|
<option value="4">Artifact</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="idpSingleSignOnServiceUrl">{{ "idpSingleSignOnServiceUrl" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
formControlName="idpSingleSignOnServiceUrl"
|
||||||
|
id="idpSingleSignOnServiceUrl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="idpSingleLogoutServiceUrl">{{ "idpSingleLogoutServiceUrl" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
formControlName="idpSingleLogoutServiceUrl"
|
||||||
|
id="idpSingleLogoutServiceUrl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="idpArtifactResolutionServiceUrl">{{
|
||||||
|
"idpArtifactResolutionServiceUrl" | i18n
|
||||||
|
}}</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
formControlName="idpArtifactResolutionServiceUrl"
|
||||||
|
id="idpArtifactResolutionServiceUrl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="idpX509PublicCert">{{ "idpX509PublicCert" | i18n }}</label>
|
||||||
<textarea
|
<textarea
|
||||||
formControlName="idpX509PublicCert"
|
formControlName="idpX509PublicCert"
|
||||||
class="form-control form-control-sm text-monospace"
|
class="form-control form-control-sm text-monospace"
|
||||||
rows="6"
|
rows="6"
|
||||||
id="idpX509PublicCert"
|
id="idpX509PublicCert"
|
||||||
appA11yInvalid
|
|
||||||
aria-describedby="idpX509PublicCertDesc"
|
|
||||||
></textarea>
|
></textarea>
|
||||||
<small
|
|
||||||
id="idpX509PublicCertDesc"
|
|
||||||
class="error-inline"
|
|
||||||
role="alert"
|
|
||||||
*ngIf="samlForm.get('idpX509PublicCert').hasError('required')"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-exclamation-circle" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{{ "error" | i18n }}:</span>
|
|
||||||
{{ "fieldRequiredError" | i18n: ("idpX509PublicCert" | i18n) }}
|
|
||||||
</small>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
<app-select
|
<label for="idpOutboundSigningAlgorithm">{{ "idpOutboundSigningAlgorithm" | i18n }}</label>
|
||||||
controlId="idpOutboundSigningAlgorithm"
|
<select
|
||||||
[label]="'idpOutboundSigningAlgorithm' | i18n"
|
class="form-control"
|
||||||
[selectOptions]="samlSigningAlgorithmOptions"
|
|
||||||
formControlName="idpOutboundSigningAlgorithm"
|
formControlName="idpOutboundSigningAlgorithm"
|
||||||
|
id="idpOutboundSigningAlgorithm"
|
||||||
>
|
>
|
||||||
</app-select>
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{ o }}</option>
|
||||||
|
</select>
|
||||||
<!--TODO: Uncomment once Unsolicited IdP Response is supported-->
|
</div>
|
||||||
<!-- <app-input-checkbox
|
<div class="form-group" [hidden]="true">
|
||||||
controlId="idpAllowUnsolicitedAuthnResponse"
|
<!--TODO: Unhide once Unsolicited IdP Response is supported-->
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="idpAllowUnsolicitedAuthnResponse"
|
||||||
formControlName="idpAllowUnsolicitedAuthnResponse"
|
formControlName="idpAllowUnsolicitedAuthnResponse"
|
||||||
[label]="'idpAllowUnsolicitedAuthnResponse' | i18n"
|
/>
|
||||||
></app-input-checkbox> -->
|
<label class="form-check-label" for="idpAllowUnsolicitedAuthnResponse">
|
||||||
|
{{ "idpAllowUnsolicitedAuthnResponse" | i18n }}
|
||||||
<app-input-checkbox
|
</label>
|
||||||
controlId="idpAllowOutboundLogoutRequests"
|
</div>
|
||||||
formControlName="idpAllowOutboundLogoutRequests"
|
</div>
|
||||||
[label]="'idpAllowOutboundLogoutRequests' | i18n"
|
<div class="form-group">
|
||||||
></app-input-checkbox>
|
<div class="form-check">
|
||||||
|
<input
|
||||||
<app-input-checkbox
|
class="form-check-input"
|
||||||
controlId="idpWantAuthnRequestsSigned"
|
type="checkbox"
|
||||||
|
id="idpDisableOutboundLogoutRequests"
|
||||||
|
formControlName="idpDisableOutboundLogoutRequests"
|
||||||
|
/>
|
||||||
|
<label class="form-check-label" for="idpDisableOutboundLogoutRequests">
|
||||||
|
{{ "idpDisableOutboundLogoutRequests" | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="idpWantAuthnRequestsSigned"
|
||||||
formControlName="idpWantAuthnRequestsSigned"
|
formControlName="idpWantAuthnRequestsSigned"
|
||||||
[label]="'idpSignAuthenticationRequests' | i18n"
|
/>
|
||||||
></app-input-checkbox>
|
<label class="form-check-label" for="idpWantAuthnRequestsSigned">
|
||||||
|
{{ "idpWantAuthnRequestsSigned" | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -434,15 +490,4 @@
|
|||||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||||
<span>{{ "save" | i18n }}</span>
|
<span>{{ "save" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
<div
|
|
||||||
id="errorSummary"
|
|
||||||
class="error-summary text-danger"
|
|
||||||
*ngIf="this.getErrorCount(ssoConfigForm) as errorCount"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-exclamation-circle" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{{ "error" | i18n }}:</span>
|
|
||||||
{{
|
|
||||||
(errorCount === 1 ? "formErrorSummarySingle" : "formErrorSummaryPlural") | i18n: errorCount
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,82 +1,29 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { AbstractControl, FormBuilder, FormGroup } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { SelectOptions } from "jslib-angular/interfaces/selectOptions";
|
|
||||||
import { dirtyRequired } from "jslib-angular/validators/dirty.validator";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import {
|
|
||||||
OpenIdConnectRedirectBehavior,
|
|
||||||
Saml2BindingType,
|
|
||||||
Saml2NameIdFormat,
|
|
||||||
Saml2SigningBehavior,
|
|
||||||
SsoType,
|
|
||||||
} from "jslib-common/enums/ssoEnums";
|
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
|
||||||
import { SsoConfigApi } from "jslib-common/models/api/ssoConfigApi";
|
|
||||||
import { Organization } from "jslib-common/models/domain/organization";
|
|
||||||
import { OrganizationSsoRequest } from "jslib-common/models/request/organization/organizationSsoRequest";
|
|
||||||
import { OrganizationSsoResponse } from "jslib-common/models/response/organization/organizationSsoResponse";
|
|
||||||
import { SsoConfigView } from "jslib-common/models/view/ssoConfigView";
|
|
||||||
|
|
||||||
const defaultSigningAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
import { Organization } from "jslib-common/models/domain/organization";
|
||||||
|
|
||||||
|
import { OrganizationSsoRequest } from "jslib-common/models/request/organization/organizationSsoRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-org-manage-sso",
|
selector: "app-org-manage-sso",
|
||||||
templateUrl: "sso.component.html",
|
templateUrl: "sso.component.html",
|
||||||
})
|
})
|
||||||
export class SsoComponent implements OnInit {
|
export class SsoComponent implements OnInit {
|
||||||
readonly ssoType = SsoType;
|
samlSigningAlgorithms = [
|
||||||
|
|
||||||
readonly ssoTypeOptions: SelectOptions[] = [
|
|
||||||
{ name: this.i18nService.t("selectType"), value: SsoType.None, disabled: true },
|
|
||||||
{ name: "OpenID Connect", value: SsoType.OpenIdConnect },
|
|
||||||
{ name: "SAML 2.0", value: SsoType.Saml2 },
|
|
||||||
];
|
|
||||||
|
|
||||||
readonly samlSigningAlgorithms = [
|
|
||||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||||
"http://www.w3.org/2000/09/xmldsig#rsa-sha384",
|
"http://www.w3.org/2000/09/xmldsig#rsa-sha384",
|
||||||
"http://www.w3.org/2000/09/xmldsig#rsa-sha512",
|
"http://www.w3.org/2000/09/xmldsig#rsa-sha512",
|
||||||
"http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
"http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
||||||
];
|
];
|
||||||
|
|
||||||
readonly saml2SigningBehaviourOptions: SelectOptions[] = [
|
|
||||||
{
|
|
||||||
name: "If IdP Wants Authn Requests Signed",
|
|
||||||
value: Saml2SigningBehavior.IfIdpWantAuthnRequestsSigned,
|
|
||||||
},
|
|
||||||
{ name: "Always", value: Saml2SigningBehavior.Always },
|
|
||||||
{ name: "Never", value: Saml2SigningBehavior.Never },
|
|
||||||
];
|
|
||||||
readonly saml2BindingTypeOptions: SelectOptions[] = [
|
|
||||||
{ name: "Redirect", value: Saml2BindingType.HttpRedirect },
|
|
||||||
{ name: "HTTP POST", value: Saml2BindingType.HttpPost },
|
|
||||||
];
|
|
||||||
readonly saml2NameIdFormatOptions: SelectOptions[] = [
|
|
||||||
{ name: "Not Configured", value: Saml2NameIdFormat.NotConfigured },
|
|
||||||
{ name: "Unspecified", value: Saml2NameIdFormat.Unspecified },
|
|
||||||
{ name: "Email Address", value: Saml2NameIdFormat.EmailAddress },
|
|
||||||
{ name: "X.509 Subject Name", value: Saml2NameIdFormat.X509SubjectName },
|
|
||||||
{ name: "Windows Domain Qualified Name", value: Saml2NameIdFormat.WindowsDomainQualifiedName },
|
|
||||||
{ name: "Kerberos Principal Name", value: Saml2NameIdFormat.KerberosPrincipalName },
|
|
||||||
{ name: "Entity Identifier", value: Saml2NameIdFormat.EntityIdentifier },
|
|
||||||
{ name: "Persistent", value: Saml2NameIdFormat.Persistent },
|
|
||||||
{ name: "Transient", value: Saml2NameIdFormat.Transient },
|
|
||||||
];
|
|
||||||
|
|
||||||
readonly connectRedirectOptions: SelectOptions[] = [
|
|
||||||
{ name: "Redirect GET", value: OpenIdConnectRedirectBehavior.RedirectGet },
|
|
||||||
{ name: "Form POST", value: OpenIdConnectRedirectBehavior.FormPost },
|
|
||||||
];
|
|
||||||
|
|
||||||
showOpenIdCustomizations = false;
|
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
haveTestedKeyConnector = false;
|
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
organization: Organization;
|
organization: Organization;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
@@ -88,14 +35,18 @@ export class SsoComponent implements OnInit {
|
|||||||
spAcsUrl: string;
|
spAcsUrl: string;
|
||||||
|
|
||||||
enabled = this.formBuilder.control(false);
|
enabled = this.formBuilder.control(false);
|
||||||
|
data = this.formBuilder.group({
|
||||||
|
configType: [],
|
||||||
|
|
||||||
openIdForm = this.formBuilder.group(
|
keyConnectorEnabled: [],
|
||||||
{
|
keyConnectorUrl: [],
|
||||||
authority: ["", dirtyRequired],
|
|
||||||
clientId: ["", dirtyRequired],
|
// OpenId
|
||||||
clientSecret: ["", dirtyRequired],
|
authority: [],
|
||||||
|
clientId: [],
|
||||||
|
clientSecret: [],
|
||||||
metadataAddress: [],
|
metadataAddress: [],
|
||||||
redirectBehavior: [OpenIdConnectRedirectBehavior.RedirectGet, dirtyRequired],
|
redirectBehavior: [],
|
||||||
getClaimsFromUserInfoEndpoint: [],
|
getClaimsFromUserInfoEndpoint: [],
|
||||||
additionalScopes: [],
|
additionalScopes: [],
|
||||||
additionalUserIdClaimTypes: [],
|
additionalUserIdClaimTypes: [],
|
||||||
@@ -103,42 +54,25 @@ export class SsoComponent implements OnInit {
|
|||||||
additionalNameClaimTypes: [],
|
additionalNameClaimTypes: [],
|
||||||
acrValues: [],
|
acrValues: [],
|
||||||
expectedReturnAcrValue: [],
|
expectedReturnAcrValue: [],
|
||||||
},
|
|
||||||
{
|
|
||||||
updateOn: "blur",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
samlForm = this.formBuilder.group(
|
// SAML
|
||||||
{
|
spNameIdFormat: [],
|
||||||
spNameIdFormat: [Saml2NameIdFormat.NotConfigured],
|
spOutboundSigningAlgorithm: [],
|
||||||
spOutboundSigningAlgorithm: [defaultSigningAlgorithm],
|
spSigningBehavior: [],
|
||||||
spSigningBehavior: [Saml2SigningBehavior.IfIdpWantAuthnRequestsSigned],
|
spMinIncomingSigningAlgorithm: [],
|
||||||
spMinIncomingSigningAlgorithm: [defaultSigningAlgorithm],
|
|
||||||
spWantAssertionsSigned: [],
|
spWantAssertionsSigned: [],
|
||||||
spValidateCertificates: [],
|
spValidateCertificates: [],
|
||||||
|
|
||||||
idpEntityId: ["", dirtyRequired],
|
idpEntityId: [],
|
||||||
idpBindingType: [Saml2BindingType.HttpRedirect],
|
idpBindingType: [],
|
||||||
idpSingleSignOnServiceUrl: [],
|
idpSingleSignOnServiceUrl: [],
|
||||||
idpSingleLogoutServiceUrl: [],
|
idpSingleLogoutServiceUrl: [],
|
||||||
idpX509PublicCert: ["", dirtyRequired],
|
idpArtifactResolutionServiceUrl: [],
|
||||||
idpOutboundSigningAlgorithm: [defaultSigningAlgorithm],
|
idpX509PublicCert: [],
|
||||||
|
idpOutboundSigningAlgorithm: [],
|
||||||
idpAllowUnsolicitedAuthnResponse: [],
|
idpAllowUnsolicitedAuthnResponse: [],
|
||||||
idpAllowOutboundLogoutRequests: [true],
|
idpDisableOutboundLogoutRequests: [],
|
||||||
idpWantAuthnRequestsSigned: [],
|
idpWantAuthnRequestsSigned: [],
|
||||||
},
|
|
||||||
{
|
|
||||||
updateOn: "blur",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
ssoConfigForm = this.formBuilder.group({
|
|
||||||
configType: [SsoType.None],
|
|
||||||
keyConnectorEnabled: [false],
|
|
||||||
keyConnectorUrl: [""],
|
|
||||||
openId: this.openIdForm,
|
|
||||||
saml: this.samlForm,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -151,25 +85,6 @@ export class SsoComponent implements OnInit {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.ssoConfigForm.get("configType").valueChanges.subscribe((newType: SsoType) => {
|
|
||||||
if (newType === SsoType.OpenIdConnect) {
|
|
||||||
this.openIdForm.enable();
|
|
||||||
this.samlForm.disable();
|
|
||||||
} else if (newType === SsoType.Saml2) {
|
|
||||||
this.openIdForm.disable();
|
|
||||||
this.samlForm.enable();
|
|
||||||
} else {
|
|
||||||
this.openIdForm.disable();
|
|
||||||
this.samlForm.disable();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.samlForm
|
|
||||||
.get("spSigningBehavior")
|
|
||||||
.valueChanges.subscribe(() =>
|
|
||||||
this.samlForm.get("idpX509PublicCert").updateValueAndValidity()
|
|
||||||
);
|
|
||||||
|
|
||||||
this.route.parent.parent.params.subscribe(async (params) => {
|
this.route.parent.parent.params.subscribe(async (params) => {
|
||||||
this.organizationId = params.organizationId;
|
this.organizationId = params.organizationId;
|
||||||
await this.load();
|
await this.load();
|
||||||
@@ -179,7 +94,9 @@ export class SsoComponent implements OnInit {
|
|||||||
async load() {
|
async load() {
|
||||||
this.organization = await this.organizationService.get(this.organizationId);
|
this.organization = await this.organizationService.get(this.organizationId);
|
||||||
const ssoSettings = await this.apiService.getOrganizationSso(this.organizationId);
|
const ssoSettings = await this.apiService.getOrganizationSso(this.organizationId);
|
||||||
this.populateForm(ssoSettings);
|
|
||||||
|
this.data.patchValue(ssoSettings.data);
|
||||||
|
this.enabled.setValue(ssoSettings.enabled);
|
||||||
|
|
||||||
this.callbackPath = ssoSettings.urls.callbackPath;
|
this.callbackPath = ssoSettings.urls.callbackPath;
|
||||||
this.signedOutCallbackPath = ssoSettings.urls.signedOutCallbackPath;
|
this.signedOutCallbackPath = ssoSettings.urls.signedOutCallbackPath;
|
||||||
@@ -187,30 +104,28 @@ export class SsoComponent implements OnInit {
|
|||||||
this.spMetadataUrl = ssoSettings.urls.spMetadataUrl;
|
this.spMetadataUrl = ssoSettings.urls.spMetadataUrl;
|
||||||
this.spAcsUrl = ssoSettings.urls.spAcsUrl;
|
this.spAcsUrl = ssoSettings.urls.spAcsUrl;
|
||||||
|
|
||||||
|
this.keyConnectorUrl.markAsDirty();
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy(value: string) {
|
||||||
|
this.platformUtilsService.copyToClipboard(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
launchUri(url: string) {
|
||||||
|
this.platformUtilsService.launchUri(url);
|
||||||
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
this.validateForm(this.ssoConfigForm);
|
this.formPromise = this.postData();
|
||||||
|
|
||||||
if (this.ssoConfigForm.get("keyConnectorEnabled").value) {
|
|
||||||
await this.validateKeyConnectorUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.ssoConfigForm.valid) {
|
|
||||||
this.readOutErrors();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = new OrganizationSsoRequest();
|
|
||||||
request.enabled = this.enabled.value;
|
|
||||||
request.data = SsoConfigApi.fromView(this.ssoConfigForm.value as SsoConfigView);
|
|
||||||
|
|
||||||
this.formPromise = this.apiService.postOrganizationSso(this.organizationId, request);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.formPromise;
|
const response = await this.formPromise;
|
||||||
this.populateForm(response);
|
|
||||||
|
this.data.patchValue(response.data);
|
||||||
|
this.enabled.setValue(response.enabled);
|
||||||
|
|
||||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("ssoSettingsSaved"));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("ssoSettingsSaved"));
|
||||||
} catch {
|
} catch {
|
||||||
// Logged by appApiAction, do nothing
|
// Logged by appApiAction, do nothing
|
||||||
@@ -219,8 +134,24 @@ export class SsoComponent implements OnInit {
|
|||||||
this.formPromise = null;
|
this.formPromise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async postData() {
|
||||||
|
if (this.data.get("keyConnectorEnabled").value) {
|
||||||
|
await this.validateKeyConnectorUrl();
|
||||||
|
|
||||||
|
if (this.keyConnectorUrl.hasError("invalidUrl")) {
|
||||||
|
throw new Error(this.i18nService.t("keyConnectorTestFail"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = new OrganizationSsoRequest();
|
||||||
|
request.enabled = this.enabled.value;
|
||||||
|
request.data = this.data.value;
|
||||||
|
|
||||||
|
return this.apiService.postOrganizationSso(this.organizationId, request);
|
||||||
|
}
|
||||||
|
|
||||||
async validateKeyConnectorUrl() {
|
async validateKeyConnectorUrl() {
|
||||||
if (this.haveTestedKeyConnector) {
|
if (this.keyConnectorUrl.pristine) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,84 +166,18 @@ export class SsoComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.haveTestedKeyConnector = true;
|
this.keyConnectorUrl.markAsPristine();
|
||||||
}
|
|
||||||
|
|
||||||
toggleOpenIdCustomizations() {
|
|
||||||
this.showOpenIdCustomizations = !this.showOpenIdCustomizations;
|
|
||||||
}
|
|
||||||
|
|
||||||
getErrorCount(form: FormGroup): number {
|
|
||||||
return Object.values(form.controls).reduce((acc: number, control: AbstractControl) => {
|
|
||||||
if (control instanceof FormGroup) {
|
|
||||||
return acc + this.getErrorCount(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (control.errors == null) {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
return acc + Object.keys(control.errors).length;
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get enableTestKeyConnector() {
|
get enableTestKeyConnector() {
|
||||||
return (
|
return (
|
||||||
this.ssoConfigForm.get("keyConnectorEnabled").value &&
|
this.data.get("keyConnectorEnabled").value &&
|
||||||
!Utils.isNullOrWhitespace(this.keyConnectorUrl?.value)
|
this.keyConnectorUrl != null &&
|
||||||
|
this.keyConnectorUrl.value !== ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get keyConnectorUrl() {
|
get keyConnectorUrl() {
|
||||||
return this.ssoConfigForm.get("keyConnectorUrl");
|
return this.data.get("keyConnectorUrl");
|
||||||
}
|
|
||||||
|
|
||||||
get samlSigningAlgorithmOptions(): SelectOptions[] {
|
|
||||||
return this.samlSigningAlgorithms.map((algorithm) => ({ name: algorithm, value: algorithm }));
|
|
||||||
}
|
|
||||||
|
|
||||||
private validateForm(form: FormGroup) {
|
|
||||||
Object.values(form.controls).forEach((control: AbstractControl) => {
|
|
||||||
if (control.disabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (control instanceof FormGroup) {
|
|
||||||
this.validateForm(control);
|
|
||||||
} else {
|
|
||||||
control.markAsDirty();
|
|
||||||
control.markAsTouched();
|
|
||||||
control.updateValueAndValidity();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private populateForm(ssoSettings: OrganizationSsoResponse) {
|
|
||||||
this.enabled.setValue(ssoSettings.enabled);
|
|
||||||
if (ssoSettings.data != null) {
|
|
||||||
const ssoConfigView = new SsoConfigView(ssoSettings.data);
|
|
||||||
this.ssoConfigForm.patchValue(ssoConfigView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readOutErrors() {
|
|
||||||
const errorText = this.i18nService.t("error");
|
|
||||||
const errorCount = this.getErrorCount(this.ssoConfigForm);
|
|
||||||
const errorCountText = this.i18nService.t(
|
|
||||||
errorCount === 1 ? "formErrorSummarySingle" : "formErrorSummaryPlural",
|
|
||||||
errorCount.toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
const div = document.createElement("div");
|
|
||||||
div.className = "sr-only";
|
|
||||||
div.id = "srErrorCount";
|
|
||||||
div.setAttribute("aria-live", "polite");
|
|
||||||
div.innerText = errorText + ": " + errorCountText;
|
|
||||||
|
|
||||||
const existing = document.getElementById("srErrorCount");
|
|
||||||
if (existing != null) {
|
|
||||||
existing.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.append(div);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { NgModule } from "@angular/core";
|
|||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
||||||
|
|
||||||
import { Permissions } from "jslib-common/enums/permissions";
|
import { Permissions } from "jslib-common/enums/permissions";
|
||||||
|
|
||||||
import { OrganizationLayoutComponent } from "src/app/layouts/organization-layout.component";
|
import { OrganizationLayoutComponent } from "src/app/layouts/organization-layout.component";
|
||||||
|
|||||||
@@ -4,23 +4,11 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
|||||||
|
|
||||||
import { OssModule } from "src/app/oss.module";
|
import { OssModule } from "src/app/oss.module";
|
||||||
|
|
||||||
import { InputCheckboxComponent } from "./components/input-checkbox.component";
|
|
||||||
import { InputTextReadOnlyComponent } from "./components/input-text-readonly.component";
|
|
||||||
import { InputTextComponent } from "./components/input-text.component";
|
|
||||||
import { SelectComponent } from "./components/select.component";
|
|
||||||
import { SsoComponent } from "./manage/sso.component";
|
import { SsoComponent } from "./manage/sso.component";
|
||||||
import { OrganizationsRoutingModule } from "./organizations-routing.module";
|
import { OrganizationsRoutingModule } from "./organizations-routing.module";
|
||||||
|
|
||||||
// Form components are for use in the SSO Configuration Form only and should not be exported for use elsewhere.
|
|
||||||
// They will be deprecated by the Component Library.
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, FormsModule, ReactiveFormsModule, OssModule, OrganizationsRoutingModule],
|
imports: [CommonModule, FormsModule, ReactiveFormsModule, OssModule, OrganizationsRoutingModule],
|
||||||
declarations: [
|
declarations: [SsoComponent],
|
||||||
InputCheckboxComponent,
|
|
||||||
InputTextComponent,
|
|
||||||
InputTextReadOnlyComponent,
|
|
||||||
SelectComponent,
|
|
||||||
SsoComponent,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class OrganizationsModule {}
|
export class OrganizationsModule {}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
|
||||||
import { PolicyType } from "jslib-common/enums/policyType";
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
|
|
||||||
|
import { PolicyRequest } from "jslib-common/models/request/policyRequest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BasePolicy,
|
BasePolicy,
|
||||||
BasePolicyComponent,
|
BasePolicyComponent,
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { Component } from "@angular/core";
|
|||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
|
||||||
import { PolicyType } from "jslib-common/enums/policyType";
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
|
|
||||||
import { PolicyRequest } from "jslib-common/models/request/policyRequest";
|
import { PolicyRequest } from "jslib-common/models/request/policyRequest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
|
|
||||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
import { Organization } from "jslib-common/models/domain/organization";
|
|
||||||
import { Provider } from "jslib-common/models/domain/provider";
|
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||||
|
|
||||||
import { WebProviderService } from "../services/webProvider.service";
|
import { WebProviderService } from "../services/webProvider.service";
|
||||||
|
|
||||||
|
import { Organization } from "jslib-common/models/domain/organization";
|
||||||
|
import { Provider } from "jslib-common/models/domain/provider";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "provider-add-organization",
|
selector: "provider-add-organization",
|
||||||
templateUrl: "add-organization.component.html",
|
templateUrl: "add-organization.component.html",
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
|
||||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
@@ -11,8 +10,13 @@ import { OrganizationService } from "jslib-common/abstractions/organization.serv
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
|
|
||||||
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
|
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||||
|
|
||||||
import { PlanType } from "jslib-common/enums/planType";
|
import { PlanType } from "jslib-common/enums/planType";
|
||||||
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
||||||
|
|
||||||
import { Organization } from "jslib-common/models/domain/organization";
|
import { Organization } from "jslib-common/models/domain/organization";
|
||||||
import { ProviderOrganizationOrganizationDetailsResponse } from "jslib-common/models/response/provider/providerOrganizationResponse";
|
import { ProviderOrganizationOrganizationDetailsResponse } from "jslib-common/models/response/provider/providerOrganizationResponse";
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
|
import { BaseAcceptComponent } from "src/app/common/base.accept.component";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
|
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { ProviderUserAcceptRequest } from "jslib-common/models/request/provider/providerUserAcceptRequest";
|
import { ProviderUserAcceptRequest } from "jslib-common/models/request/provider/providerUserAcceptRequest";
|
||||||
|
|
||||||
import { BaseAcceptComponent } from "src/app/common/base.accept.component";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-accept-provider",
|
selector: "app-accept-provider",
|
||||||
templateUrl: "accept-provider.component.html",
|
templateUrl: "accept-provider.component.html",
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
import { Component, Input } from "@angular/core";
|
||||||
|
|
||||||
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
|
||||||
import { ProviderUserBulkConfirmRequest } from "jslib-common/models/request/provider/providerUserBulkConfirmRequest";
|
import { ProviderUserBulkConfirmRequest } from "jslib-common/models/request/provider/providerUserBulkConfirmRequest";
|
||||||
import { ProviderUserBulkRequest } from "jslib-common/models/request/provider/providerUserBulkRequest";
|
import { ProviderUserBulkRequest } from "jslib-common/models/request/provider/providerUserBulkRequest";
|
||||||
|
|
||||||
|
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
||||||
|
|
||||||
import { BulkConfirmComponent as OrganizationBulkConfirmComponent } from "src/app/organizations/manage/bulk/bulk-confirm.component";
|
import { BulkConfirmComponent as OrganizationBulkConfirmComponent } from "src/app/organizations/manage/bulk/bulk-confirm.component";
|
||||||
import { BulkUserDetails } from "src/app/organizations/manage/bulk/bulk-status.component";
|
import { BulkUserDetails } from "src/app/organizations/manage/bulk/bulk-status.component";
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { ExportService } from "jslib-common/abstractions/export.service";
|
import { ExportService } from "jslib-common/abstractions/export.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
|
|
||||||
|
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
||||||
|
|
||||||
import { EventResponse } from "jslib-common/models/response/eventResponse";
|
import { EventResponse } from "jslib-common/models/response/eventResponse";
|
||||||
|
|
||||||
import { BaseEventsComponent } from "src/app/common/base.events.component";
|
|
||||||
import { EventService } from "src/app/services/event.service";
|
import { EventService } from "src/app/services/event.service";
|
||||||
|
|
||||||
|
import { BaseEventsComponent } from "src/app/common/base.events.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "provider-events",
|
selector: "provider-events",
|
||||||
templateUrl: "events.component.html",
|
templateUrl: "events.component.html",
|
||||||
})
|
})
|
||||||
export class EventsComponent extends BaseEventsComponent implements OnInit {
|
export class EventsComponent extends BaseEventsComponent implements OnInit {
|
||||||
exportFileName = "provider-events";
|
exportFileName: string = "provider-events";
|
||||||
providerId: string;
|
providerId: string;
|
||||||
|
|
||||||
private providerUsersUserIdMap = new Map<string, any>();
|
private providerUsersUserIdMap = new Map<string, any>();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
|
|||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
|
|
||||||
import { Provider } from "jslib-common/models/domain/provider";
|
import { Provider } from "jslib-common/models/domain/provider";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -214,7 +214,7 @@
|
|||||||
{{ "eventLogs" | i18n }}
|
{{ "eventLogs" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="remove(u)">
|
<a class="dropdown-item text-danger" href="#" appStopClick (click)="remove(u)">
|
||||||
<i class="bwi bwi-fw bwi-close" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-remove" aria-hidden="true"></i>
|
||||||
{{ "remove" | i18n }}
|
{{ "remove" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { SearchPipe } from "jslib-angular/pipes/search.pipe";
|
|
||||||
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
|
||||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
@@ -14,18 +11,26 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
|
|||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
|
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||||
|
|
||||||
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
||||||
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
||||||
|
|
||||||
|
import { SearchPipe } from "jslib-angular/pipes/search.pipe";
|
||||||
|
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
||||||
|
|
||||||
|
import { ListResponse } from "jslib-common/models/response/listResponse";
|
||||||
|
import { ProviderUserUserDetailsResponse } from "jslib-common/models/response/provider/providerUserResponse";
|
||||||
|
|
||||||
import { ProviderUserBulkRequest } from "jslib-common/models/request/provider/providerUserBulkRequest";
|
import { ProviderUserBulkRequest } from "jslib-common/models/request/provider/providerUserBulkRequest";
|
||||||
import { ProviderUserConfirmRequest } from "jslib-common/models/request/provider/providerUserConfirmRequest";
|
import { ProviderUserConfirmRequest } from "jslib-common/models/request/provider/providerUserConfirmRequest";
|
||||||
import { ListResponse } from "jslib-common/models/response/listResponse";
|
|
||||||
import { ProviderUserBulkResponse } from "jslib-common/models/response/provider/providerUserBulkResponse";
|
import { ProviderUserBulkResponse } from "jslib-common/models/response/provider/providerUserBulkResponse";
|
||||||
import { ProviderUserUserDetailsResponse } from "jslib-common/models/response/provider/providerUserResponse";
|
|
||||||
|
|
||||||
import { BasePeopleComponent } from "src/app/common/base.people.component";
|
import { BasePeopleComponent } from "src/app/common/base.people.component";
|
||||||
import { BulkStatusComponent } from "src/app/organizations/manage/bulk/bulk-status.component";
|
import { BulkStatusComponent } from "src/app/organizations/manage/bulk/bulk-status.component";
|
||||||
import { EntityEventsComponent } from "src/app/organizations/manage/entity-events.component";
|
import { EntityEventsComponent } from "src/app/organizations/manage/entity-events.component";
|
||||||
|
|
||||||
import { BulkConfirmComponent } from "./bulk/bulk-confirm.component";
|
import { BulkConfirmComponent } from "./bulk/bulk-confirm.component";
|
||||||
import { BulkRemoveComponent } from "./bulk/bulk-remove.component";
|
import { BulkRemoveComponent } from "./bulk/bulk-remove.component";
|
||||||
import { UserAddEditComponent } from "./user-add-edit.component";
|
import { UserAddEditComponent } from "./user-add-edit.component";
|
||||||
@@ -153,13 +158,17 @@ export class PeopleComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
async events(user: ProviderUserUserDetailsResponse) {
|
async events(user: ProviderUserUserDetailsResponse) {
|
||||||
await this.modalService.openViewRef(EntityEventsComponent, this.eventsModalRef, (comp) => {
|
const [modal] = await this.modalService.openViewRef(
|
||||||
|
EntityEventsComponent,
|
||||||
|
this.eventsModalRef,
|
||||||
|
(comp) => {
|
||||||
comp.name = this.userNamePipe.transform(user);
|
comp.name = this.userNamePipe.transform(user);
|
||||||
comp.providerId = this.providerId;
|
comp.providerId = this.providerId;
|
||||||
comp.entityId = user.id;
|
comp.entityId = user.id;
|
||||||
comp.showUser = false;
|
comp.showUser = false;
|
||||||
comp.entity = "user";
|
comp.entity = "user";
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkRemove() {
|
async bulkRemove() {
|
||||||
@@ -263,14 +272,13 @@ export class PeopleComponent
|
|||||||
|
|
||||||
childComponent.users = users.map((user) => {
|
childComponent.users = users.map((user) => {
|
||||||
let message = keyedErrors[user.id] ?? successfullMessage;
|
let message = keyedErrors[user.id] ?? successfullMessage;
|
||||||
// eslint-disable-next-line
|
|
||||||
if (!keyedFilteredUsers.hasOwnProperty(user.id)) {
|
if (!keyedFilteredUsers.hasOwnProperty(user.id)) {
|
||||||
message = this.i18nService.t("bulkFilteredMessage");
|
message = this.i18nService.t("bulkFilteredMessage");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: user,
|
user: user,
|
||||||
error: keyedErrors.hasOwnProperty(user.id), // eslint-disable-line
|
error: keyedErrors.hasOwnProperty(user.id),
|
||||||
message: message,
|
message: message,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import { ApiService } from "jslib-common/abstractions/api.service";
|
|||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
|
||||||
import { PermissionsApi } from "jslib-common/models/api/permissionsApi";
|
|
||||||
import { ProviderUserInviteRequest } from "jslib-common/models/request/provider/providerUserInviteRequest";
|
import { ProviderUserInviteRequest } from "jslib-common/models/request/provider/providerUserInviteRequest";
|
||||||
|
|
||||||
|
import { PermissionsApi } from "jslib-common/models/api/permissionsApi";
|
||||||
|
|
||||||
|
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
||||||
import { ProviderUserUpdateRequest } from "jslib-common/models/request/provider/providerUserUpdateRequest";
|
import { ProviderUserUpdateRequest } from "jslib-common/models/request/provider/providerUserUpdateRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -21,7 +24,7 @@ export class UserAddEditComponent implements OnInit {
|
|||||||
@Output() onDeletedUser = new EventEmitter();
|
@Output() onDeletedUser = new EventEmitter();
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
editMode = false;
|
editMode: boolean = false;
|
||||||
title: string;
|
title: string;
|
||||||
emails: string;
|
emails: string;
|
||||||
type: ProviderUserType = ProviderUserType.ServiceUser;
|
type: ProviderUserType = ProviderUserType.ServiceUser;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
|||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
|
|
||||||
import { Provider } from "jslib-common/models/domain/provider";
|
import { Provider } from "jslib-common/models/domain/provider";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import { RouterModule, Routes } from "@angular/router";
|
|||||||
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
||||||
import { Permissions } from "jslib-common/enums/permissions";
|
import { Permissions } from "jslib-common/enums/permissions";
|
||||||
|
|
||||||
import { FrontendLayoutComponent } from "src/app/layouts/frontend-layout.component";
|
import { AddOrganizationComponent } from "./clients/add-organization.component";
|
||||||
import { ProvidersComponent } from "src/app/providers/providers.component";
|
|
||||||
|
|
||||||
import { ClientsComponent } from "./clients/clients.component";
|
import { ClientsComponent } from "./clients/clients.component";
|
||||||
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
||||||
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
||||||
@@ -14,13 +12,17 @@ import { EventsComponent } from "./manage/events.component";
|
|||||||
import { ManageComponent } from "./manage/manage.component";
|
import { ManageComponent } from "./manage/manage.component";
|
||||||
import { PeopleComponent } from "./manage/people.component";
|
import { PeopleComponent } from "./manage/people.component";
|
||||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||||
import { ProviderGuardService } from "./services/provider-guard.service";
|
|
||||||
import { ProviderTypeGuardService } from "./services/provider-type-guard.service";
|
|
||||||
import { AccountComponent } from "./settings/account.component";
|
|
||||||
import { SettingsComponent } from "./settings/settings.component";
|
import { SettingsComponent } from "./settings/settings.component";
|
||||||
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
||||||
import { SetupComponent } from "./setup/setup.component";
|
import { SetupComponent } from "./setup/setup.component";
|
||||||
|
|
||||||
|
import { FrontendLayoutComponent } from "src/app/layouts/frontend-layout.component";
|
||||||
|
|
||||||
|
import { ProvidersComponent } from "src/app/providers/providers.component";
|
||||||
|
import { ProviderGuardService } from "./services/provider-guard.service";
|
||||||
|
import { ProviderTypeGuardService } from "./services/provider-type-guard.service";
|
||||||
|
import { AccountComponent } from "./settings/account.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { ComponentFactoryResolver, NgModule } from "@angular/core";
|
import { ComponentFactoryResolver } from "@angular/core";
|
||||||
|
import { NgModule } from "@angular/core";
|
||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from "@angular/forms";
|
||||||
|
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
|
|
||||||
import { OssModule } from "src/app/oss.module";
|
import { ProviderGuardService } from "./services/provider-guard.service";
|
||||||
|
import { ProviderTypeGuardService } from "./services/provider-type-guard.service";
|
||||||
|
import { WebProviderService } from "./services/webProvider.service";
|
||||||
|
|
||||||
|
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||||
|
import { ProvidersRoutingModule } from "./providers-routing.module";
|
||||||
|
|
||||||
import { AddOrganizationComponent } from "./clients/add-organization.component";
|
import { AddOrganizationComponent } from "./clients/add-organization.component";
|
||||||
import { ClientsComponent } from "./clients/clients.component";
|
import { ClientsComponent } from "./clients/clients.component";
|
||||||
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
||||||
|
|
||||||
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
||||||
import { BulkConfirmComponent } from "./manage/bulk/bulk-confirm.component";
|
import { BulkConfirmComponent } from "./manage/bulk/bulk-confirm.component";
|
||||||
import { BulkRemoveComponent } from "./manage/bulk/bulk-remove.component";
|
import { BulkRemoveComponent } from "./manage/bulk/bulk-remove.component";
|
||||||
@@ -16,16 +23,15 @@ import { EventsComponent } from "./manage/events.component";
|
|||||||
import { ManageComponent } from "./manage/manage.component";
|
import { ManageComponent } from "./manage/manage.component";
|
||||||
import { PeopleComponent } from "./manage/people.component";
|
import { PeopleComponent } from "./manage/people.component";
|
||||||
import { UserAddEditComponent } from "./manage/user-add-edit.component";
|
import { UserAddEditComponent } from "./manage/user-add-edit.component";
|
||||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
|
||||||
import { ProvidersRoutingModule } from "./providers-routing.module";
|
|
||||||
import { ProviderGuardService } from "./services/provider-guard.service";
|
|
||||||
import { ProviderTypeGuardService } from "./services/provider-type-guard.service";
|
|
||||||
import { WebProviderService } from "./services/webProvider.service";
|
|
||||||
import { AccountComponent } from "./settings/account.component";
|
import { AccountComponent } from "./settings/account.component";
|
||||||
import { SettingsComponent } from "./settings/settings.component";
|
import { SettingsComponent } from "./settings/settings.component";
|
||||||
|
|
||||||
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
||||||
import { SetupComponent } from "./setup/setup.component";
|
import { SetupComponent } from "./setup/setup.component";
|
||||||
|
|
||||||
|
import { OssModule } from "src/app/oss.module";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, FormsModule, OssModule, ProvidersRoutingModule],
|
imports: [CommonModule, FormsModule, OssModule, ProvidersRoutingModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Injectable } from "@angular/core";
|
|||||||
import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router";
|
import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router";
|
||||||
|
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
|
|
||||||
import { Permissions } from "jslib-common/enums/permissions";
|
import { Permissions } from "jslib-common/enums/permissions";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Injectable } from "@angular/core";
|
|||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
import { ProviderAddOrganizationRequest } from "jslib-common/models/request/provider/providerAddOrganizationRequest";
|
import { ProviderAddOrganizationRequest } from "jslib-common/models/request/provider/providerAddOrganizationRequest";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
import { ProviderUpdateRequest } from "jslib-common/models/request/provider/providerUpdateRequest";
|
import { ProviderUpdateRequest } from "jslib-common/models/request/provider/providerUpdateRequest";
|
||||||
|
|
||||||
import { ProviderResponse } from "jslib-common/models/response/provider/providerResponse";
|
import { ProviderResponse } from "jslib-common/models/response/provider/providerResponse";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -8,11 +9,15 @@ import { ProviderService } from "jslib-common/abstractions/provider.service";
|
|||||||
templateUrl: "settings.component.html",
|
templateUrl: "settings.component.html",
|
||||||
})
|
})
|
||||||
export class SettingsComponent {
|
export class SettingsComponent {
|
||||||
constructor(private route: ActivatedRoute, private providerService: ProviderService) {}
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private providerService: ProviderService,
|
||||||
|
private platformUtilsService: PlatformUtilsService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.route.parent.params.subscribe(async (params) => {
|
this.route.parent.params.subscribe(async (params) => {
|
||||||
await this.providerService.get(params.providerId);
|
const provider = await this.providerService.get(params.providerId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export class SetupProviderComponent extends BaseAcceptComponent {
|
|||||||
this.router.navigate(["/providers/setup"], { queryParams: qParams });
|
this.router.navigate(["/providers/setup"], { queryParams: qParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
async unauthedHandler(qParams: any) {
|
// tslint:disable-next-line
|
||||||
// Empty
|
async unauthedHandler(qParams: any) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
|
|
||||||
|
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="theme_light">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta
|
<meta
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<body class="layout_frontend">
|
<body class="layout_frontend">
|
||||||
<div class="row justify-content-md-center mt-5">
|
<div class="row justify-content-md-center mt-5">
|
||||||
<div>
|
<div>
|
||||||
<img src="..//images/logo-dark@2x.png" class="logo mb-2" alt="Bitwarden" />
|
<img src="../../src/images/logo-dark@2x.png" class="logo mb-2" alt="Bitwarden" />
|
||||||
<p id="captchaRequired" class="lead text-center mx-4 mb-4">Captcha Required</p>
|
<p id="captchaRequired" class="lead text-center mx-4 mb-4">Captcha Required</p>
|
||||||
<div id="captcha"></div>
|
<div id="captcha"></div>
|
||||||
</div>
|
</div>
|
||||||
46
connectors/src/captcha/captcha-mobile.scss
Normal file
46
connectors/src/captcha/captcha-mobile.scss
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
@import "../common/styles.scss";
|
||||||
|
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -10px;
|
||||||
|
margin-left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-5,
|
||||||
|
.my-5 {
|
||||||
|
margin-top: 3rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2,
|
||||||
|
.my-2 {
|
||||||
|
margin-bottom: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-4,
|
||||||
|
.mx-4 {
|
||||||
|
margin-left: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-4,
|
||||||
|
.my-4 {
|
||||||
|
margin-bottom: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-4,
|
||||||
|
.mx-4 {
|
||||||
|
margin-right: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { b64Decode, getQsParam } from "./common";
|
import { b64Decode, getQsParam } from "../common";
|
||||||
|
|
||||||
declare let hcaptcha: any;
|
declare var hcaptcha: any;
|
||||||
|
|
||||||
if (window.location.pathname.includes("mobile")) {
|
if (window.location.pathname.includes("mobile")) {
|
||||||
|
// tslint:disable-next-line
|
||||||
require("./captcha-mobile.scss");
|
require("./captcha-mobile.scss");
|
||||||
} else {
|
} else {
|
||||||
|
// tslint:disable-next-line
|
||||||
require("./captcha.scss");
|
require("./captcha.scss");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ async function start() {
|
|||||||
|
|
||||||
let decodedData: any;
|
let decodedData: any;
|
||||||
try {
|
try {
|
||||||
decodedData = JSON.parse(b64Decode(data, true));
|
decodedData = JSON.parse(b64Decode(data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error("Cannot parse data.");
|
error("Cannot parse data.");
|
||||||
return;
|
return;
|
||||||
@@ -69,7 +71,7 @@ async function start() {
|
|||||||
script.src = src;
|
script.src = src;
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.defer = true;
|
script.defer = true;
|
||||||
script.addEventListener("load", () => {
|
script.addEventListener("load", (e) => {
|
||||||
hcaptcha.render("captcha", {
|
hcaptcha.render("captcha", {
|
||||||
sitekey: encodeURIComponent(decodedData.siteKey),
|
sitekey: encodeURIComponent(decodedData.siteKey),
|
||||||
callback: "captchaSuccess",
|
callback: "captchaSuccess",
|
||||||
@@ -126,7 +128,6 @@ function info(message: string | object) {
|
|||||||
|
|
||||||
async function watchHeight() {
|
async function watchHeight() {
|
||||||
const imagesDiv = document.body.lastChild as HTMLElement;
|
const imagesDiv = document.body.lastChild as HTMLElement;
|
||||||
// eslint-disable-next-line
|
|
||||||
while (true) {
|
while (true) {
|
||||||
info({
|
info({
|
||||||
height:
|
height:
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
export function getQsParam(name: string) {
|
export function getQsParam(name: string) {
|
||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
// eslint-disable-next-line
|
|
||||||
name = name.replace(/[\[\]]/g, "\\$&");
|
name = name.replace(/[\[\]]/g, "\\$&");
|
||||||
const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
|
const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
|
||||||
const results = regex.exec(url);
|
const results = regex.exec(url);
|
||||||
@@ -15,11 +14,7 @@ export function getQsParam(name: string) {
|
|||||||
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function b64Decode(str: string, spaceAsPlus = false) {
|
export function b64Decode(str: string) {
|
||||||
if (spaceAsPlus) {
|
|
||||||
str = str.replace(/ /g, "+");
|
|
||||||
}
|
|
||||||
|
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
Array.prototype.map
|
Array.prototype.map
|
||||||
.call(atob(str), (c: string) => {
|
.call(atob(str), (c: string) => {
|
||||||
22
connectors/src/common/styles.scss
Normal file
22
connectors/src/common/styles.scss
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@import "~bootstrap/scss/_functions";
|
||||||
|
@import "~bootstrap/scss/_variables";
|
||||||
|
@import "~bootstrap/scss/_mixins";
|
||||||
|
@import "~bootstrap/scss/_root";
|
||||||
|
@import "~bootstrap/scss/_reboot";
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.theme_light body.layout_frontend {
|
||||||
|
background-color: #ecf0f5;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.logo {
|
||||||
|
display: block;
|
||||||
|
height: 43px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
width: 284px;
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: #efeff4 url("../images/loading.svg") 0 0 no-repeat;
|
background: #efeff4 url("../../../src/images/loading.svg") 0 0 no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import * as DuoWebSDK from "duo_web_sdk";
|
import * as DuoWebSDK from "duo_web_sdk";
|
||||||
|
import { getQsParam } from "../common";
|
||||||
|
|
||||||
import { getQsParam } from "./common";
|
// tslint:disable-next-line
|
||||||
|
|
||||||
require("./duo.scss");
|
require("./duo.scss");
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", (event) => {
|
||||||
const frameElement = document.createElement("iframe");
|
const frameElement = document.createElement("iframe");
|
||||||
frameElement.setAttribute("id", "duo_iframe");
|
frameElement.setAttribute("id", "duo_iframe");
|
||||||
setFrameHeight();
|
setFrameHeight();
|
||||||
@@ -41,7 +41,7 @@ function invokeCSCode(data: string) {
|
|||||||
try {
|
try {
|
||||||
(window as any).invokeCSharpAction(data);
|
(window as any).invokeCSharpAction(data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line
|
// tslint:disable-next-line
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
connectors/src/sso.html
Normal file
47
connectors/src/sso.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="theme_light">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=1010" />
|
||||||
|
<meta name="theme-color" content="#175DDC" />
|
||||||
|
|
||||||
|
<title>Bitwarden</title>
|
||||||
|
|
||||||
|
<link
|
||||||
|
rel="apple-touch-icon"
|
||||||
|
sizes="180x180"
|
||||||
|
href="../../src/images/icons/apple-touch-icon.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="32x32"
|
||||||
|
href="../../src/images/icons/favicon-32x32.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="16x16"
|
||||||
|
href="../../src/images/icons/favicon-16x16.png"
|
||||||
|
/>
|
||||||
|
<link rel="mask-icon" href="../../src/images/icons/safari-pinned-tab.svg" color="#175DDC" />
|
||||||
|
<link rel="manifest" href="../../src/manifest.json" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="layout_frontend">
|
||||||
|
<div class="mt-5 d-flex justify-content-center">
|
||||||
|
<div>
|
||||||
|
<img src="../../src/images/logo-dark@2x.png" class="mb-4 logo" alt="Bitwarden" />
|
||||||
|
<div id="content">
|
||||||
|
<p class="text-center">
|
||||||
|
<i
|
||||||
|
class="bwi bwi-spinner bwi-spin bwi-2x text-muted"
|
||||||
|
title="Loading"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
82
connectors/src/sso/sso.scss
Normal file
82
connectors/src/sso/sso.scss
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
@import "../common/styles.scss";
|
||||||
|
|
||||||
|
.mt-5,
|
||||||
|
.my-5 {
|
||||||
|
margin-top: 3rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
|
display: -ms-flexbox !important;
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-content-center {
|
||||||
|
-ms-flex-pack: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-4,
|
||||||
|
.my-4 {
|
||||||
|
margin-bottom: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
$icomoon-font-family: "bwi-font" !default;
|
||||||
|
$icomoon-font-path: "~@bitwarden/jslib-angular/src/scss/bwicons/fonts/" !default;
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "#{$icomoon-font-family}";
|
||||||
|
src: url($icomoon-font-path + "bwi-font.svg") format("svg"),
|
||||||
|
url($icomoon-font-path + "bwi-font.ttf") format("truetype"),
|
||||||
|
url($icomoon-font-path + "bwi-font.woff") format("woff"),
|
||||||
|
url($icomoon-font-path + "bwi-font.woff2") format("woff2");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base Class
|
||||||
|
.bwi {
|
||||||
|
/* use !important to prevent issues with browser extensions that change fonts */
|
||||||
|
font-family: "#{$icomoon-font-family}" !important;
|
||||||
|
speak: never;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1;
|
||||||
|
display: inline-block;
|
||||||
|
/* Better Font Rendering */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwi-2x {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spin Animations
|
||||||
|
.bwi-spin {
|
||||||
|
animation: bwi-spin 2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bwi-spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotation
|
||||||
|
.bwi-rotate-270 {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwi-spinner:before {
|
||||||
|
content: "\e937";
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { getQsParam } from "./common";
|
import { getQsParam } from "../common";
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
require("./sso.scss");
|
require("./sso.scss");
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", (event) => {
|
||||||
const code = getQsParam("code");
|
const code = getQsParam("code");
|
||||||
const state = getQsParam("state");
|
const state = getQsParam("state");
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="theme_light">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Bitwarden WebAuthn Connector</title>
|
<title>Bitwarden WebAuthn Connector</title>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center mt-5">
|
<div class="row justify-content-center mt-5">
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<img src="../images/logo-dark@2x.png" class="mb-4 logo" alt="Bitwarden" />
|
<img src="../../src/images/logo-dark@2x.png" class="mb-4 logo" alt="Bitwarden" />
|
||||||
<div id="spinner">
|
<div id="spinner">
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<i
|
<i
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html class="theme_light">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta
|
<meta
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
<body style="background: transparent">
|
<body style="background: transparent">
|
||||||
<div class="row justify-content-md-center mt-5">
|
<div class="row justify-content-md-center mt-5">
|
||||||
<div>
|
<div>
|
||||||
<img src="../images/logo-dark@2x.png" class="logo mb-2" alt="Bitwarden" />
|
<img src="../../src/images/logo-dark@2x.png" class="logo mb-2" alt="Bitwarden" />
|
||||||
<p id="webauthn-header" class="lead text-center mx-4 mb-4"></p>
|
<p id="webauthn-header" class="lead text-center mx-4 mb-4"></p>
|
||||||
<picture>
|
<picture>
|
||||||
<source srcset="../images/u2fkey-mobile.avif" type="image/avif" />
|
<source srcset="../../src/images/u2fkey-mobile.avif" type="image/avif" />
|
||||||
<source srcset="../images/u2fkey-mobile.webp" type="image/webp" />
|
<source srcset="../../src/images/u2fkey-mobile.webp" type="image/webp" />
|
||||||
<img src="../images/u2fkey-mobile.jpg" class="rounded img-fluid" />
|
<img src="../../src/images/u2fkey-mobile.jpg" class="rounded img-fluid" />
|
||||||
</picture>
|
</picture>
|
||||||
<div class="text-center mt-4">
|
<div class="text-center mt-4">
|
||||||
<button id="webauthn-button" class="btn btn-primary btn-lg"></button>
|
<button id="webauthn-button" class="btn btn-primary btn-lg"></button>
|
||||||
@@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
<body style="background: transparent">
|
<body style="background: transparent">
|
||||||
<picture>
|
<picture>
|
||||||
<source srcset="../images/u2fkey.avif" type="image/avif" />
|
<source srcset="../../src/images/u2fkey.avif" type="image/avif" />
|
||||||
<source srcset="../images/u2fkey.webp" type="image/webp" />
|
<source srcset="../../src/images/u2fkey.webp" type="image/webp" />
|
||||||
<img src="../images/u2fkey.jpg" class="rounded img-fluid mb-3" />
|
<img src="../../src/images/u2fkey.jpg" class="rounded img-fluid mb-3" />
|
||||||
</picture>
|
</picture>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button id="webauthn-button" class="btn btn-primary"></button>
|
<button id="webauthn-button" class="btn btn-primary"></button>
|
||||||
@@ -28,7 +28,6 @@ export function parseWebauthnJson(jsonString: string) {
|
|||||||
json.challenge = Uint8Array.from(atob(challenge), (c) => c.charCodeAt(0));
|
json.challenge = Uint8Array.from(atob(challenge), (c) => c.charCodeAt(0));
|
||||||
|
|
||||||
json.allowCredentials.forEach((listItem: any) => {
|
json.allowCredentials.forEach((listItem: any) => {
|
||||||
// eslint-disable-next-line
|
|
||||||
const fixedId = listItem.id.replace(/\_/g, "/").replace(/\-/g, "+");
|
const fixedId = listItem.id.replace(/\_/g, "/").replace(/\-/g, "+");
|
||||||
listItem.id = Uint8Array.from(atob(fixedId), (c) => c.charCodeAt(0));
|
listItem.id = Uint8Array.from(atob(fixedId), (c) => c.charCodeAt(0));
|
||||||
});
|
});
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import { b64Decode, getQsParam } from "./common";
|
import { b64Decode, getQsParam } from "../common";
|
||||||
import { buildDataString, parseWebauthnJson } from "./common-webauthn";
|
import { buildDataString, parseWebauthnJson } from "./common-webauthn";
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
require("./webauthn.scss");
|
require("./webauthn.scss");
|
||||||
|
|
||||||
let parsed = false;
|
let parsed = false;
|
||||||
let webauthnJson: any;
|
let webauthnJson: any;
|
||||||
let parentUrl: string = null;
|
let parentUrl: string = null;
|
||||||
|
let parentOrigin: string = null;
|
||||||
let sentSuccess = false;
|
let sentSuccess = false;
|
||||||
let locale = "en";
|
let locale: string = "en";
|
||||||
|
|
||||||
let locales: any = {};
|
let locales: any = {};
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@ function parseParameters() {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
parentUrl = decodeURIComponent(parentUrl);
|
parentUrl = decodeURIComponent(parentUrl);
|
||||||
|
parentOrigin = new URL(parentUrl).origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
locale = getQsParam("locale").replace("-", "_");
|
locale = getQsParam("locale").replace("-", "_");
|
||||||
@@ -63,7 +66,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
try {
|
try {
|
||||||
locales = await loadLocales(locale);
|
locales = await loadLocales(locale);
|
||||||
} catch {
|
} catch {
|
||||||
// eslint-disable-next-line
|
// tslint:disable-next-line:no-console
|
||||||
console.error("Failed to load the locale", locale);
|
console.error("Failed to load the locale", locale);
|
||||||
locales = await loadLocales("en");
|
locales = await loadLocales("en");
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function loadLocales(newLocale: string) {
|
async function loadLocales(newLocale: string) {
|
||||||
const filePath = `locales/${newLocale}/messages.json?cache=${process.env.CACHE_TAG}`;
|
const filePath = `/locales/${newLocale}/messages.json?cache=${process.env.CACHE_TAG}`;
|
||||||
const localesResult = await fetch(filePath);
|
const localesResult = await fetch(filePath);
|
||||||
return await localesResult.json();
|
return await localesResult.json();
|
||||||
}
|
}
|
||||||
197
connectors/src/webauthn/webauthn.scss
Normal file
197
connectors/src/webauthn/webauthn.scss
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
@import "../common/styles.scss";
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-width: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-3,
|
||||||
|
.my-3 {
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded {
|
||||||
|
border-radius: 0.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-fluid {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
user-select: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-left-color: transparent;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
|
||||||
|
border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #175ddc;
|
||||||
|
border-color: #175ddc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:not(:disabled):not(.disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover,
|
||||||
|
.swal2-popup .swal2-actions button:hover {
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #134eb9;
|
||||||
|
border-color: #1249ae;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mobile **/
|
||||||
|
|
||||||
|
.mt-5,
|
||||||
|
.my-5 {
|
||||||
|
margin-top: 3rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-content-center,
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -10px;
|
||||||
|
margin-left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2,
|
||||||
|
.my-2 {
|
||||||
|
margin-bottom: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-4,
|
||||||
|
.mx-4 {
|
||||||
|
margin-left: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-4,
|
||||||
|
.my-4 {
|
||||||
|
margin-bottom: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-4,
|
||||||
|
.mx-4 {
|
||||||
|
margin-right: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fallback **/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 980px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-5 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
flex: 0 0 41.6666666667%;
|
||||||
|
max-width: 41.6666666667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background-color: #fff;
|
||||||
|
background-clip: border-box;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-block {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 1px;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
position: relative;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-left-color: transparent;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-danger {
|
||||||
|
color: #73271e;
|
||||||
|
background-color: #f8dbd7;
|
||||||
|
border-color: #f5cdc8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
margin-left: -1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border: 0;
|
||||||
|
border-top-color: currentcolor;
|
||||||
|
border-top-style: none;
|
||||||
|
border-top-width: 0px;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { b64Decode, getQsParam } from "./common";
|
import { b64Decode, getQsParam } from "../common";
|
||||||
import { buildDataString, parseWebauthnJson } from "./common-webauthn";
|
import { buildDataString, parseWebauthnJson } from "./common-webauthn";
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
require("./webauthn.scss");
|
require("./webauthn.scss");
|
||||||
|
|
||||||
const mobileCallbackUri = "bitwarden://webauthn-callback";
|
const mobileCallbackUri = "bitwarden://webauthn-callback";
|
||||||
150
connectors/webpack.config.js
Normal file
150
connectors/webpack.config.js
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const HtmlWebpackInjector = require("html-webpack-injector");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV == null ? "development" : process.env.NODE_ENV;
|
||||||
|
|
||||||
|
const moduleRules = [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
enforce: "pre",
|
||||||
|
loader: "tslint-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
transpileOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(html)$/,
|
||||||
|
loader: "html-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
||||||
|
exclude: /loading(|-white).svg/,
|
||||||
|
generator: {
|
||||||
|
filename: "fonts/[name].[contenthash][ext]",
|
||||||
|
},
|
||||||
|
type: "asset/resource",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(jpe?g|png|gif|svg|webp|avif)$/i,
|
||||||
|
exclude: /.*(fontawesome-webfont)\.svg/,
|
||||||
|
generator: {
|
||||||
|
filename: "images/[name].[contenthash][ext]",
|
||||||
|
},
|
||||||
|
type: "asset/resource",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: MiniCssExtractPlugin.loader,
|
||||||
|
},
|
||||||
|
"css-loader",
|
||||||
|
"sass-loader",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
new HtmlWebpackInjector(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/duo.html",
|
||||||
|
filename: "duo.html",
|
||||||
|
chunks: ["duo"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/webauthn.html",
|
||||||
|
filename: "webauthn.html",
|
||||||
|
chunks: ["webauthn"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/webauthn-mobile.html",
|
||||||
|
filename: "webauthn-mobile.html",
|
||||||
|
chunks: ["webauthn"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/webauthn-fallback.html",
|
||||||
|
filename: "webauthn-fallback.html",
|
||||||
|
chunks: ["webauthn-fallback"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/sso.html",
|
||||||
|
filename: "sso.html",
|
||||||
|
chunks: ["sso"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/captcha.html",
|
||||||
|
filename: "captcha.html",
|
||||||
|
chunks: ["captcha"],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/captcha-mobile.html",
|
||||||
|
filename: "captcha-mobile.html",
|
||||||
|
chunks: ["captcha"],
|
||||||
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: "assets/[name].[contenthash].css",
|
||||||
|
chunkFilename: "assets/[id].[contenthash].css",
|
||||||
|
}),
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
CACHE_TAG: Math.random().toString(36).substring(7),
|
||||||
|
}),
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
process: "process/browser",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const webpackConfig = {
|
||||||
|
mode: NODE_ENV,
|
||||||
|
devtool: "source-map",
|
||||||
|
entry: {
|
||||||
|
webauthn: "./src/webauthn/webauthn.ts",
|
||||||
|
"webauthn-fallback": "./src/webauthn/webauthn-fallback.ts",
|
||||||
|
duo: "./src/duo/duo.ts",
|
||||||
|
sso: "./src/sso/sso.ts",
|
||||||
|
captcha: "./src/captcha/captcha.ts",
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
commons: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: "app/vendor",
|
||||||
|
chunks: (chunk) => {
|
||||||
|
return chunk.name === "app/main";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".js"],
|
||||||
|
symlinks: false,
|
||||||
|
modules: [path.resolve("../", "node_modules")],
|
||||||
|
fallback: {
|
||||||
|
buffer: false,
|
||||||
|
util: require.resolve("util/"),
|
||||||
|
assert: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "assets/[name].[contenthash].js",
|
||||||
|
path: path.resolve(__dirname, "build"),
|
||||||
|
publicPath: "/connectors/",
|
||||||
|
clean: true,
|
||||||
|
},
|
||||||
|
module: { rules: moduleRules },
|
||||||
|
plugins: plugins,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = webpackConfig;
|
||||||
2
jslib
2
jslib
Submodule jslib updated: 212bd70986...92a65b7b36
6817
package-lock.json
generated
6817
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/web-vault",
|
"name": "@bitwarden/web-vault",
|
||||||
"version": "2.27.0",
|
"version": "2.25.1",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"repository": "https://github.com/bitwarden/web",
|
"repository": "https://github.com/bitwarden/web",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
"dist:bit:selfhost": "npm run build:bit:selfhost:prod",
|
"dist:bit:selfhost": "npm run build:bit:selfhost:prod",
|
||||||
"deploy": "npm run dist:bit && gh-pages -d build",
|
"deploy": "npm run dist:bit && gh-pages -d build",
|
||||||
"deploy:dev": "npm run dist:bit && gh-pages -d build -r git@github.com:kspearrin/bitwarden-web-dev.git",
|
"deploy:dev": "npm run dist:bit && gh-pages -d build -r git@github.com:kspearrin/bitwarden-web-dev.git",
|
||||||
"lint": "eslint . && prettier --check .",
|
"lint": "tslint 'src/**/*.ts' 'bitwarden_license/src/**/*.ts' && prettier --check .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "tslint 'src/**/*.ts' 'bitwarden_license/src/**/*.ts' --fix",
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
@@ -41,17 +41,11 @@
|
|||||||
"@types/node": "^16.11.12",
|
"@types/node": "^16.11.12",
|
||||||
"@types/webcrypto": "^0.0.28",
|
"@types/webcrypto": "^0.0.28",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^5.28.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
|
||||||
"@typescript-eslint/parser": "^5.10.1",
|
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"clean-webpack-plugin": "^4.0.0",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"copy-webpack-plugin": "^10.0.0",
|
"copy-webpack-plugin": "^10.0.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^6.5.1",
|
"css-loader": "^6.5.1",
|
||||||
"eslint": "^8.7.0",
|
|
||||||
"eslint-config-prettier": "^8.3.0",
|
|
||||||
"eslint-import-resolver-typescript": "^2.5.0",
|
|
||||||
"eslint-plugin-import": "^2.25.4",
|
|
||||||
"gh-pages": "^3.1.0",
|
"gh-pages": "^3.1.0",
|
||||||
"html-loader": "^3.0.1",
|
"html-loader": "^3.0.1",
|
||||||
"html-webpack-injector": "1.1.4",
|
"html-webpack-injector": "1.1.4",
|
||||||
@@ -61,12 +55,13 @@
|
|||||||
"mini-css-extract-plugin": "^2.4.5",
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.5.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"sass": "^1.32.10",
|
"sass": "^1.32.10",
|
||||||
"sass-loader": "^12.4.0",
|
"sass-loader": "^12.4.0",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"terser-webpack-plugin": "^5.2.5",
|
"terser-webpack-plugin": "^5.2.5",
|
||||||
"ts-loader": "^9.2.5",
|
"ts-loader": "^9.2.5",
|
||||||
|
"tslint": "^6.1.3",
|
||||||
|
"tslint-loader": "^3.5.4",
|
||||||
"typescript": "4.3.5",
|
"typescript": "4.3.5",
|
||||||
"util": "^0.12.4",
|
"util": "^0.12.4",
|
||||||
"webpack": "^5.64.4",
|
"webpack": "^5.64.4",
|
||||||
@@ -90,11 +85,10 @@
|
|||||||
"browser-hrtime": "^1.1.8",
|
"browser-hrtime": "^1.1.8",
|
||||||
"core-js": "^3.11.0",
|
"core-js": "^3.11.0",
|
||||||
"date-input-polyfill": "^2.14.0",
|
"date-input-polyfill": "^2.14.0",
|
||||||
|
"font-awesome": "4.7.0",
|
||||||
"jquery": "3.6.0",
|
"jquery": "3.6.0",
|
||||||
"jszip": "^3.7.1",
|
|
||||||
"ngx-infinite-scroll": "^10.0.1",
|
"ngx-infinite-scroll": "^10.0.1",
|
||||||
"ngx-toastr": "14.1.4",
|
"ngx-toastr": "14.1.4",
|
||||||
"node-forge": "^0.10.0",
|
|
||||||
"popper.js": "1.16.1",
|
"popper.js": "1.16.1",
|
||||||
"qrious": "4.0.2",
|
"qrious": "4.0.2",
|
||||||
"rxjs": "^7.4.0",
|
"rxjs": "^7.4.0",
|
||||||
@@ -107,8 +101,7 @@
|
|||||||
"npm": "~8"
|
"npm": "~8"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"./!(jslib)**": "prettier --ignore-unknown --write",
|
"*": "prettier --ignore-unknown --write",
|
||||||
"*.ts": "eslint --fix",
|
|
||||||
"*.png": "node scripts/optimize.js"
|
"*.png": "node scripts/optimize.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import { StateService as BaseStateService } from "jslib-common/abstractions/state.service";
|
|
||||||
import { StorageOptions } from "jslib-common/models/domain/storageOptions";
|
|
||||||
|
|
||||||
import { Account } from "src/models/account";
|
|
||||||
|
|
||||||
export abstract class StateService extends BaseStateService<Account> {
|
|
||||||
getRememberEmail: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setRememberEmail: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { EmergencyAccessAcceptRequest } from "jslib-common/models/request/emergencyAccessAcceptRequest";
|
import { EmergencyAccessAcceptRequest } from "jslib-common/models/request/emergencyAccessAcceptRequest";
|
||||||
|
|
||||||
import { BaseAcceptComponent } from "../common/base.accept.component";
|
import { BaseAcceptComponent } from "../common/base.accept.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import { LogService } from "jslib-common/abstractions/log.service";
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
|
||||||
import { Policy } from "jslib-common/models/domain/policy";
|
|
||||||
import { OrganizationUserAcceptRequest } from "jslib-common/models/request/organizationUserAcceptRequest";
|
import { OrganizationUserAcceptRequest } from "jslib-common/models/request/organizationUserAcceptRequest";
|
||||||
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
|
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
|
||||||
|
|
||||||
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
import { Policy } from "jslib-common/models/domain/policy";
|
||||||
import { BaseAcceptComponent } from "../common/base.accept.component";
|
import { BaseAcceptComponent } from "../common/base.accept.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { HintComponent as BaseHintComponent } from "jslib-angular/components/hint.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
|
import { HintComponent as BaseHintComponent } from "jslib-angular/components/hint.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-hint",
|
selector: "app-hint",
|
||||||
templateUrl: "hint.component.html",
|
templateUrl: "hint.component.html",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Component, NgZone } from "@angular/core";
|
import { Component, NgZone } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
@@ -15,6 +14,8 @@ import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.serv
|
|||||||
|
|
||||||
import { RouterService } from "../services/router.service";
|
import { RouterService } from "../services/router.service";
|
||||||
|
|
||||||
|
import { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-lock",
|
selector: "app-lock",
|
||||||
templateUrl: "lock.component.html",
|
templateUrl: "lock.component.html",
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
[queryParams]="{ email: email }"
|
[queryParams]="{ email: email }"
|
||||||
class="btn btn-outline-secondary btn-block ml-2 mt-0"
|
class="btn btn-outline-secondary btn-block ml-2 mt-0"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-pencil-square" aria-hidden="true"></i>
|
<i class="bwi bwi-pencil-square-o" aria-hidden="true"></i>
|
||||||
{{ "createAccount" | i18n }}
|
{{ "createAccount" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
import { Component, NgZone } from "@angular/core";
|
import { Component, NgZone } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { LoginComponent as BaseLoginComponent } from "jslib-angular/components/login.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
|
||||||
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { PolicyData } from "jslib-common/models/data/policyData";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
|
|
||||||
import { Policy } from "jslib-common/models/domain/policy";
|
|
||||||
import { ListResponse } from "jslib-common/models/response/listResponse";
|
|
||||||
import { PolicyResponse } from "jslib-common/models/response/policyResponse";
|
|
||||||
|
|
||||||
import { StateService } from "../../abstractions/state.service";
|
import { LoginComponent as BaseLoginComponent } from "jslib-angular/components/login.component";
|
||||||
|
|
||||||
|
import { Policy } from "jslib-common/models/domain/policy";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-login",
|
selector: "app-login",
|
||||||
@@ -27,14 +24,13 @@ import { StateService } from "../../abstractions/state.service";
|
|||||||
})
|
})
|
||||||
export class LoginComponent extends BaseLoginComponent {
|
export class LoginComponent extends BaseLoginComponent {
|
||||||
showResetPasswordAutoEnrollWarning = false;
|
showResetPasswordAutoEnrollWarning = false;
|
||||||
enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions;
|
|
||||||
policies: ListResponse<PolicyResponse>;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
authService: AuthService,
|
authService: AuthService,
|
||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
passwordGenerationService: PasswordGenerationService,
|
passwordGenerationService: PasswordGenerationService,
|
||||||
@@ -42,9 +38,7 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
ngZone: NgZone,
|
ngZone: NgZone
|
||||||
protected stateService: StateService,
|
|
||||||
private messagingService: MessagingService
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
authService,
|
authService,
|
||||||
@@ -58,9 +52,6 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
logService,
|
logService,
|
||||||
ngZone
|
ngZone
|
||||||
);
|
);
|
||||||
this.onSuccessfulLogin = async () => {
|
|
||||||
this.messagingService.send("setFullWidth");
|
|
||||||
};
|
|
||||||
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,64 +78,35 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
await super.ngOnInit();
|
await super.ngOnInit();
|
||||||
this.rememberEmail = await this.stateService.getRememberEmail();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const invite = await this.stateService.getOrganizationInvitation();
|
const invite = await this.stateService.getOrganizationInvitation();
|
||||||
if (invite != null) {
|
if (invite != null) {
|
||||||
let policyList: Policy[] = null;
|
let policyList: Policy[] = null;
|
||||||
try {
|
try {
|
||||||
this.policies = await this.apiService.getPoliciesByToken(
|
const policies = await this.apiService.getPoliciesByToken(
|
||||||
invite.organizationId,
|
invite.organizationId,
|
||||||
invite.token,
|
invite.token,
|
||||||
invite.email,
|
invite.email,
|
||||||
invite.organizationUserId
|
invite.organizationUserId
|
||||||
);
|
);
|
||||||
policyList = this.policyService.mapPoliciesFromToken(this.policies);
|
policyList = this.policyService.mapPoliciesFromToken(policies);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (policyList != null) {
|
if (policyList != null) {
|
||||||
const resetPasswordPolicy = this.policyService.getResetPasswordPolicyOptions(
|
const result = this.policyService.getResetPasswordPolicyOptions(
|
||||||
policyList,
|
policyList,
|
||||||
invite.organizationId
|
invite.organizationId
|
||||||
);
|
);
|
||||||
// Set to true if policy enabled and auto-enroll enabled
|
// Set to true if policy enabled and auto-enroll enabled
|
||||||
this.showResetPasswordAutoEnrollWarning =
|
this.showResetPasswordAutoEnrollWarning = result[1] && result[0].autoEnrollEnabled;
|
||||||
resetPasswordPolicy[1] && resetPasswordPolicy[0].autoEnrollEnabled;
|
|
||||||
|
|
||||||
this.enforcedPasswordPolicyOptions =
|
|
||||||
await this.policyService.getMasterPasswordPolicyOptions(policyList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async goAfterLogIn() {
|
async goAfterLogIn() {
|
||||||
// Check master password against policy
|
|
||||||
if (this.enforcedPasswordPolicyOptions != null) {
|
|
||||||
const strengthResult = this.passwordGenerationService.passwordStrength(
|
|
||||||
this.masterPassword,
|
|
||||||
this.getPasswordStrengthUserInput()
|
|
||||||
);
|
|
||||||
const masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
|
||||||
|
|
||||||
// If invalid, save policies and require update
|
|
||||||
if (
|
|
||||||
!this.policyService.evaluateMasterPassword(
|
|
||||||
masterPasswordScore,
|
|
||||||
this.masterPassword,
|
|
||||||
this.enforcedPasswordPolicyOptions
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const policiesData: { [id: string]: PolicyData } = {};
|
|
||||||
this.policies.data.map((p) => (policiesData[p.id] = new PolicyData(p)));
|
|
||||||
await this.policyService.replace(policiesData);
|
|
||||||
this.router.navigate(["update-password"]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loginRedirect = await this.stateService.getLoginRedirect();
|
const loginRedirect = await this.stateService.getLoginRedirect();
|
||||||
if (loginRedirect != null) {
|
if (loginRedirect != null) {
|
||||||
this.router.navigate([loginRedirect.route], { queryParams: loginRedirect.qParams });
|
this.router.navigate([loginRedirect.route], { queryParams: loginRedirect.qParams });
|
||||||
@@ -153,27 +115,4 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
this.router.navigate([this.successRoute]);
|
this.router.navigate([this.successRoute]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
|
||||||
await this.stateService.setRememberEmail(this.rememberEmail);
|
|
||||||
if (!this.rememberEmail) {
|
|
||||||
await this.stateService.setRememberedEmail(null);
|
|
||||||
}
|
|
||||||
await super.submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
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]/)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return userInput;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ApiService } from "jslib-common/abstractions/api.service";
|
|||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { DeleteRecoverRequest } from "jslib-common/models/request/deleteRecoverRequest";
|
import { DeleteRecoverRequest } from "jslib-common/models/request/deleteRecoverRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
|||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { TwoFactorRecoveryRequest } from "jslib-common/models/request/twoFactorRecoveryRequest";
|
import { TwoFactorRecoveryRequest } from "jslib-common/models/request/twoFactorRecoveryRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { RegisterComponent as BaseRegisterComponent } from "jslib-angular/components/register.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
@@ -13,9 +13,13 @@ import { PasswordGenerationService } from "jslib-common/abstractions/passwordGen
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { PolicyData } from "jslib-common/models/data/policyData";
|
|
||||||
|
import { RegisterComponent as BaseRegisterComponent } from "jslib-angular/components/register.component";
|
||||||
|
|
||||||
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
|
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
|
||||||
import { Policy } from "jslib-common/models/domain/policy";
|
import { Policy } from "jslib-common/models/domain/policy";
|
||||||
|
|
||||||
|
import { PolicyData } from "jslib-common/models/data/policyData";
|
||||||
import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest";
|
import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "jslib-angular/components/set-password.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
@@ -12,6 +11,8 @@ import { PolicyService } from "jslib-common/abstractions/policy.service";
|
|||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
|
import { SetPasswordComponent as BaseSetPasswordComponent } from "jslib-angular/components/set-password.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-set-password",
|
selector: "app-set-password",
|
||||||
templateUrl: "set-password.component.html",
|
templateUrl: "set-password.component.html",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { SsoComponent as BaseSsoComponent } from "jslib-angular/components/sso.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
@@ -13,6 +13,8 @@ import { PasswordGenerationService } from "jslib-common/abstractions/passwordGen
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
|
import { SsoComponent as BaseSsoComponent } from "jslib-angular/components/sso.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-sso",
|
selector: "app-sso",
|
||||||
templateUrl: "sso.component.html",
|
templateUrl: "sso.component.html",
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "jslib-angular/components/two-factor-options.component";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
|
||||||
|
import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "jslib-angular/components/two-factor-options.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-two-factor-options",
|
selector: "app-two-factor-options",
|
||||||
@@ -12,11 +13,11 @@ import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
|||||||
})
|
})
|
||||||
export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent {
|
export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent {
|
||||||
constructor(
|
constructor(
|
||||||
twoFactorService: TwoFactorService,
|
authService: AuthService,
|
||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService
|
platformUtilsService: PlatformUtilsService
|
||||||
) {
|
) {
|
||||||
super(twoFactorService, router, i18nService, platformUtilsService, window);
|
super(authService, router, i18nService, platformUtilsService, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,9 +114,6 @@
|
|||||||
<p>{{ "noTwoStepProviders2" | i18n }}</p>
|
<p>{{ "noTwoStepProviders2" | i18n }}</p>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<hr />
|
<hr />
|
||||||
<div [hidden]="!showCaptcha()">
|
|
||||||
<iframe id="hcaptcha_iframe" height="80"></iframe>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex mb-3">
|
<div class="d-flex mb-3">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Component, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Component, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
|
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component";
|
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
@@ -10,9 +9,13 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
|
||||||
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
|
|
||||||
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
|
||||||
|
|
||||||
|
import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component";
|
||||||
|
|
||||||
import { TwoFactorOptionsComponent } from "./two-factor-options.component";
|
import { TwoFactorOptionsComponent } from "./two-factor-options.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -33,8 +36,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
private modalService: ModalService,
|
private modalService: ModalService,
|
||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
logService: LogService,
|
logService: LogService
|
||||||
twoFactorService: TwoFactorService
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
authService,
|
authService,
|
||||||
@@ -46,8 +48,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
environmentService,
|
environmentService,
|
||||||
stateService,
|
stateService,
|
||||||
route,
|
route,
|
||||||
logService,
|
logService
|
||||||
twoFactorService
|
|
||||||
);
|
);
|
||||||
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate autocomplete="off">
|
|
||||||
<div class="row justify-content-md-center mt-5">
|
|
||||||
<div class="col-4">
|
|
||||||
<p class="lead text-center mb-4">{{ "updateMasterPassword" | i18n }}</p>
|
|
||||||
<div class="card d-block">
|
|
||||||
<div class="card-body">
|
|
||||||
<app-callout type="warning">{{ "masterPasswordInvalidWarning" | i18n }} </app-callout>
|
|
||||||
<app-callout
|
|
||||||
type="info"
|
|
||||||
[enforcedPolicyOptions]="enforcedPolicyOptions"
|
|
||||||
*ngIf="enforcedPolicyOptions"
|
|
||||||
></app-callout>
|
|
||||||
|
|
||||||
<form
|
|
||||||
#form
|
|
||||||
(ngSubmit)="submit()"
|
|
||||||
[appApiAction]="formPromise"
|
|
||||||
ngNativeValidate
|
|
||||||
autocomplete="off"
|
|
||||||
>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="currentMasterPassword">{{ "currentMasterPass" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="currentMasterPassword"
|
|
||||||
type="password"
|
|
||||||
name="MasterPasswordHash"
|
|
||||||
class="form-control"
|
|
||||||
[(ngModel)]="currentMasterPassword"
|
|
||||||
required
|
|
||||||
appInputVerbatim
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="newMasterPassword">{{ "newMasterPass" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="newMasterPassword"
|
|
||||||
type="password"
|
|
||||||
name="NewMasterPasswordHash"
|
|
||||||
class="form-control mb-1"
|
|
||||||
[(ngModel)]="masterPassword"
|
|
||||||
(input)="updatePasswordStrength()"
|
|
||||||
required
|
|
||||||
appInputVerbatim
|
|
||||||
autocomplete="new-password"
|
|
||||||
/>
|
|
||||||
<app-password-strength
|
|
||||||
[score]="masterPasswordScore"
|
|
||||||
[showText]="true"
|
|
||||||
></app-password-strength>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="masterPasswordRetype">{{ "confirmNewMasterPass" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="masterPasswordRetype"
|
|
||||||
type="password"
|
|
||||||
name="MasterPasswordRetype"
|
|
||||||
class="form-control"
|
|
||||||
[(ngModel)]="masterPasswordRetype"
|
|
||||||
required
|
|
||||||
appInputVerbatim
|
|
||||||
autocomplete="new-password"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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>{{ "changeMasterPassword" | i18n }}</span>
|
|
||||||
</button>
|
|
||||||
<button (click)="cancel()" type="button" class="btn btn-outline-secondary">
|
|
||||||
<span>{{ "cancel" | i18n }}</span>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { Component } from "@angular/core";
|
|
||||||
import { Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "jslib-angular/components/update-password.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
|
||||||
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
|
||||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
|
||||||
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-update-password",
|
|
||||||
templateUrl: "update-password.component.html",
|
|
||||||
})
|
|
||||||
export class UpdatePasswordComponent extends BaseUpdatePasswordComponent {
|
|
||||||
constructor(
|
|
||||||
router: Router,
|
|
||||||
i18nService: I18nService,
|
|
||||||
platformUtilsService: PlatformUtilsService,
|
|
||||||
passwordGenerationService: PasswordGenerationService,
|
|
||||||
policyService: PolicyService,
|
|
||||||
cryptoService: CryptoService,
|
|
||||||
messagingService: MessagingService,
|
|
||||||
apiService: ApiService,
|
|
||||||
logService: LogService,
|
|
||||||
stateService: StateService,
|
|
||||||
userVerificationService: UserVerificationService
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
router,
|
|
||||||
i18nService,
|
|
||||||
platformUtilsService,
|
|
||||||
passwordGenerationService,
|
|
||||||
policyService,
|
|
||||||
cryptoService,
|
|
||||||
messagingService,
|
|
||||||
apiService,
|
|
||||||
stateService,
|
|
||||||
userVerificationService,
|
|
||||||
logService
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from "jslib-angular/components/update-temp-password.component";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
@@ -9,9 +8,11 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
|||||||
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
|
import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from "jslib-angular/components/update-temp-password.component";
|
||||||
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-update-temp-password",
|
selector: "app-update-temp-password",
|
||||||
templateUrl: "update-temp-password.component.html",
|
templateUrl: "update-temp-password.component.html",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
@@ -7,6 +8,7 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
import { VerifyEmailRequest } from "jslib-common/models/request/verifyEmailRequest";
|
import { VerifyEmailRequest } from "jslib-common/models/request/verifyEmailRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { VerifyDeleteRecoverRequest } from "jslib-common/models/request/verifyDeleteRecoverRequest";
|
import { VerifyDeleteRecoverRequest } from "jslib-common/models/request/verifyDeleteRecoverRequest";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -21,10 +21,14 @@ import { PolicyService } from "jslib-common/abstractions/policy.service";
|
|||||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
import { SettingsService } from "jslib-common/abstractions/settings.service";
|
import { SettingsService } from "jslib-common/abstractions/settings.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
import { StorageService } from "jslib-common/abstractions/storage.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
|
import { PolicyListService } from "./services/policy-list.service";
|
||||||
|
import { RouterService } from "./services/router.service";
|
||||||
|
|
||||||
import { DisableSendPolicy } from "./organizations/policies/disable-send.component";
|
import { DisableSendPolicy } from "./organizations/policies/disable-send.component";
|
||||||
import { MasterPasswordPolicy } from "./organizations/policies/master-password.component";
|
import { MasterPasswordPolicy } from "./organizations/policies/master-password.component";
|
||||||
import { PasswordGeneratorPolicy } from "./organizations/policies/password-generator.component";
|
import { PasswordGeneratorPolicy } from "./organizations/policies/password-generator.component";
|
||||||
@@ -34,8 +38,6 @@ import { ResetPasswordPolicy } from "./organizations/policies/reset-password.com
|
|||||||
import { SendOptionsPolicy } from "./organizations/policies/send-options.component";
|
import { SendOptionsPolicy } from "./organizations/policies/send-options.component";
|
||||||
import { SingleOrgPolicy } from "./organizations/policies/single-org.component";
|
import { SingleOrgPolicy } from "./organizations/policies/single-org.component";
|
||||||
import { TwoFactorAuthenticationPolicy } from "./organizations/policies/two-factor-authentication.component";
|
import { TwoFactorAuthenticationPolicy } from "./organizations/policies/two-factor-authentication.component";
|
||||||
import { PolicyListService } from "./services/policy-list.service";
|
|
||||||
import { RouterService } from "./services/router.service";
|
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = "AppComponent";
|
const BroadcasterSubscriptionId = "AppComponent";
|
||||||
const IdleTimeout = 60000 * 10; // 10 minutes
|
const IdleTimeout = 60000 * 10; // 10 minutes
|
||||||
@@ -115,7 +117,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
break;
|
break;
|
||||||
case "syncCompleted":
|
case "syncCompleted":
|
||||||
break;
|
break;
|
||||||
case "upgradeOrganization": {
|
case "upgradeOrganization":
|
||||||
const upgradeConfirmed = await this.platformUtilsService.showDialog(
|
const upgradeConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("upgradeOrganizationDesc"),
|
this.i18nService.t("upgradeOrganizationDesc"),
|
||||||
this.i18nService.t("upgradeOrganization"),
|
this.i18nService.t("upgradeOrganization"),
|
||||||
@@ -131,8 +133,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case "premiumRequired":
|
||||||
case "premiumRequired": {
|
|
||||||
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("premiumRequiredDesc"),
|
this.i18nService.t("premiumRequiredDesc"),
|
||||||
this.i18nService.t("premiumRequired"),
|
this.i18nService.t("premiumRequired"),
|
||||||
@@ -143,8 +144,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
this.router.navigate(["settings/premium"]);
|
this.router.navigate(["settings/premium"]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case "emailVerificationRequired":
|
||||||
case "emailVerificationRequired": {
|
|
||||||
const emailVerificationConfirmed = await this.platformUtilsService.showDialog(
|
const emailVerificationConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("emailVerificationRequiredDesc"),
|
this.i18nService.t("emailVerificationRequiredDesc"),
|
||||||
this.i18nService.t("emailVerificationRequired"),
|
this.i18nService.t("emailVerificationRequired"),
|
||||||
@@ -157,7 +157,6 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case "showToast":
|
case "showToast":
|
||||||
this.showToast(message);
|
this.showToast(message);
|
||||||
break;
|
break;
|
||||||
@@ -211,6 +210,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.eventService.clearEvents(),
|
this.eventService.clearEvents(),
|
||||||
this.syncService.setLastSync(new Date(0)),
|
this.syncService.setLastSync(new Date(0)),
|
||||||
|
this.tokenService.clearToken(),
|
||||||
this.cryptoService.clearKeys(),
|
this.cryptoService.clearKeys(),
|
||||||
this.settingsService.clear(userId),
|
this.settingsService.clear(userId),
|
||||||
this.cipherService.clear(userId),
|
this.cipherService.clear(userId),
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
||||||
|
|
||||||
import { DragDropModule } from "@angular/cdk/drag-drop";
|
import { DragDropModule } from "@angular/cdk/drag-drop";
|
||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from "@angular/forms";
|
||||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||||
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
|
||||||
|
|
||||||
import { BitwardenToastModule } from "jslib-angular/components/toastr.component";
|
import { BitwardenToastModule } from "jslib-angular/components/toastr.component";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Directive, OnInit } from "@angular/core";
|
import { Directive, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { ExportService } from "jslib-common/abstractions/export.service";
|
|||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
|
import { EventView } from "jslib-common/models/view/eventView";
|
||||||
|
|
||||||
import { EventResponse } from "jslib-common/models/response/eventResponse";
|
import { EventResponse } from "jslib-common/models/response/eventResponse";
|
||||||
import { ListResponse } from "jslib-common/models/response/listResponse";
|
import { ListResponse } from "jslib-common/models/response/listResponse";
|
||||||
import { EventView } from "jslib-common/models/view/eventView";
|
|
||||||
|
|
||||||
import { EventService } from "src/app/services/event.service";
|
import { EventService } from "src/app/services/event.service";
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ export abstract class BaseEventsComponent {
|
|||||||
events: EventView[];
|
events: EventView[];
|
||||||
start: string;
|
start: string;
|
||||||
end: string;
|
end: string;
|
||||||
dirtyDates = true;
|
dirtyDates: boolean = true;
|
||||||
continuationToken: string;
|
continuationToken: string;
|
||||||
refreshPromise: Promise<any>;
|
refreshPromise: Promise<any>;
|
||||||
exportPromise: Promise<any>;
|
exportPromise: Promise<any>;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
|
|
||||||
import { SearchPipe } from "jslib-angular/pipes/search.pipe";
|
|
||||||
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
|
||||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
@@ -11,15 +7,24 @@ import { LogService } from "jslib-common/abstractions/log.service";
|
|||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
|
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||||
|
|
||||||
|
import { SearchPipe } from "jslib-angular/pipes/search.pipe";
|
||||||
|
import { UserNamePipe } from "jslib-angular/pipes/user-name.pipe";
|
||||||
|
|
||||||
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
|
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
|
||||||
import { OrganizationUserType } from "jslib-common/enums/organizationUserType";
|
import { OrganizationUserType } from "jslib-common/enums/organizationUserType";
|
||||||
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
import { ProviderUserStatusType } from "jslib-common/enums/providerUserStatusType";
|
||||||
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
import { ProviderUserType } from "jslib-common/enums/providerUserType";
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
|
||||||
import { ListResponse } from "jslib-common/models/response/listResponse";
|
import { ListResponse } from "jslib-common/models/response/listResponse";
|
||||||
import { OrganizationUserUserDetailsResponse } from "jslib-common/models/response/organizationUserResponse";
|
import { OrganizationUserUserDetailsResponse } from "jslib-common/models/response/organizationUserResponse";
|
||||||
import { ProviderUserUserDetailsResponse } from "jslib-common/models/response/provider/providerUserResponse";
|
import { ProviderUserUserDetailsResponse } from "jslib-common/models/response/provider/providerUserResponse";
|
||||||
|
|
||||||
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
import { UserConfirmComponent } from "../organizations/manage/user-confirm.component";
|
import { UserConfirmComponent } from "../organizations/manage/user-confirm.component";
|
||||||
|
|
||||||
type StatusType = OrganizationUserStatusType | ProviderUserStatusType;
|
type StatusType = OrganizationUserStatusType | ProviderUserStatusType;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||||
|
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
|
|||||||
})
|
})
|
||||||
export class FooterComponent implements OnInit {
|
export class FooterComponent implements OnInit {
|
||||||
version: string;
|
version: string;
|
||||||
year = "2015";
|
year: string = "2015";
|
||||||
|
|
||||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
constructor(private platformUtilsService: PlatformUtilsService) {}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
|
|||||||
})
|
})
|
||||||
export class FrontendLayoutComponent implements OnInit, OnDestroy {
|
export class FrontendLayoutComponent implements OnInit, OnDestroy {
|
||||||
version: string;
|
version: string;
|
||||||
year = "2015";
|
year: string = "2015";
|
||||||
|
|
||||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
constructor(private platformUtilsService: PlatformUtilsService) {}
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,7 @@
|
|||||||
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
|
||||||
{{ "myAccount" | i18n }}
|
{{ "myAccount" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a class="dropdown-item" href="https://help.bitwarden.com" target="_blank" rel="noopener">
|
||||||
class="dropdown-item"
|
|
||||||
href="https://bitwarden.com/help/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-question-circle" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-question-circle" aria-hidden="true"></i>
|
||||||
{{ "getHelp" | i18n }}
|
{{ "getHelp" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
|
|||||||
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
import { ProviderService } from "jslib-common/abstractions/provider.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||||
|
|
||||||
import { Provider } from "jslib-common/models/domain/provider";
|
import { Provider } from "jslib-common/models/domain/provider";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
||||||
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
||||||
|
|
||||||
import { Organization } from "jslib-common/models/domain/organization";
|
import { Organization } from "jslib-common/models/domain/organization";
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = "OrganizationLayoutComponent";
|
const BroadcasterSubscriptionId = "OrganizationLayoutComponent";
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user