merging master into feature branch

This commit is contained in:
CarleyDiaz-Bitwarden 2022-08-03 14:20:15 -04:00
parent a7eaa26c74
commit e287715251
371 changed files with 16725 additions and 22348 deletions

View File

@ -1,5 +1,6 @@
**/build
**/dist
.angular
**/node_modules

View File

@ -16,7 +16,7 @@ on:
branches:
- 'master'
- 'rc'
- 'hotfix-rc/**'
- 'hotfix-rc'
paths:
- 'apps/browser/**'
- 'libs/**'
@ -347,7 +347,7 @@ jobs:
trigger-desktop-build:
name: Trigger desktop build
if: ${{ (github.ref == 'refs/heads/master') || (github.ref == 'refs/heads/rc') || contains(github.ref, 'hotfix-rc') }}
if: ${{ (github.ref == 'refs/heads/master') || (github.ref == 'refs/heads/rc') || github.ref != 'refs/heads/hotfix-rc' }}
runs-on: ubuntu-20.04
needs:
- build

View File

@ -17,7 +17,7 @@ on:
branches:
- 'master'
- 'rc'
- 'hotfix-rc/**'
- 'hotfix-rc'
paths:
- 'apps/cli/**'
- 'libs/**'

View File

@ -159,7 +159,7 @@ jobs:
- name: Set up environment
run: |
sudo apt-get update
sudo apt-get -y install pkg-config libxss-dev libsecret-1-dev rpm
sudo apt-get -y install pkg-config libxss-dev libsecret-1-dev rpm musl-dev musl-tools
- name: Set up Snap
run: sudo snap install snapcraft --classic
@ -175,6 +175,27 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: |
apps/desktop/desktop_native/*.node
${{ env.RUNNER_TEMP }}/.cargo/registry
${{ env.RUNNER_TEMP }}/.cargo/git
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
env:
PKG_CONFIG_ALLOW_CROSS: true
PKG_CONFIG_ALL_STATIC: true
TARGET: musl
run: |
rustup target add x86_64-unknown-linux-musl
npm run build:cross-platform
- name: Build application
run: npm run dist:lin
@ -256,11 +277,18 @@ jobs:
- name: Set up environment
run: choco install checksum --no-progress
- name: Rust
shell: pwsh
run: |
rustup target install i686-pc-windows-msvc
rustup target install aarch64-pc-windows-msvc
- name: Print environment
run: |
node --version
npm --version
choco --version
rustup show
- name: Login to Azure
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
@ -282,6 +310,19 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: apps/desktop/desktop_native/*.node
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
run: |
npm run build:cross-platform
- name: Build & Sign (dev)
env:
ELECTRON_BUILDER_SIGN: 1
@ -443,10 +484,15 @@ jobs:
npm install -g node-gyp
node-gyp install $(node -v)
- name: Rust
shell: pwsh
run: rustup target install aarch64-apple-darwin
- name: Print environment
run: |
node --version
npm --version
rustup show
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
@ -536,6 +582,19 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: apps/desktop/desktop_native/*.node
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
run: |
npm run build:cross-platform
- name: Build application (dev)
run: npm run build
@ -570,10 +629,15 @@ jobs:
npm install -g node-gyp
node-gyp install $(node -v)
- name: Rust
shell: pwsh
run: rustup target install aarch64-apple-darwin
- name: Print environment
run: |
node --version
npm --version
rustup show
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
@ -663,23 +727,30 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: apps/desktop/desktop_native/*.node
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
run: |
npm run build:cross-platform
- name: Build
if: steps.build-cache.outputs.cache-hit != 'true'
run: npm run build
- name: Extract branch name
if: contains(github.ref, 'hotfix-rc')
id: extract_branch
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
- name: Download artifact from hotfix-rc
if: contains(github.ref, 'hotfix-rc')
if: github.ref == 'refs/heads/hotfix-rc'
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
workflow_conclusion: success
branch: ${{ steps.extract_branch.outputs.branch }}
branch: hotfix-rc
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from rc
@ -692,7 +763,7 @@ jobs:
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from master
if: ${{ github.ref != 'refs/heads/rc' && !contains(github.ref, 'hotfix-rc') }}
if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }}
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
@ -776,10 +847,15 @@ jobs:
npm install -g node-gyp
node-gyp install $(node -v)
- name: Rust
shell: pwsh
run: rustup target install aarch64-apple-darwin
- name: Print environment
run: |
node --version
npm --version
rustup show
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
@ -869,23 +945,30 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: apps/desktop/desktop_native/*.node
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
run: |
npm run build:cross-platform
- name: Build
if: steps.build-cache.outputs.cache-hit != 'true'
run: npm run build
- name: Extract branch name
if: contains(github.ref, 'hotfix-rc')
id: extract_branch
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
- name: Download artifact from hotfix-rc
if: contains(github.ref, 'hotfix-rc')
if: github.ref == 'refs/heads/hotfix-rc'
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
workflow_conclusion: success
branch: ${{ steps.extract_branch.outputs.branch }}
branch: hotfix-rc
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from rc
@ -898,7 +981,7 @@ jobs:
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from master
if: ${{ github.ref != 'refs/heads/rc' && !contains(github.ref, 'hotfix-rc') }}
if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }}
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
@ -1067,6 +1150,19 @@ jobs:
run: npm ci
working-directory: ./
- name: Cache Native Module
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
id: cache
with:
path: apps/desktop/desktop_native/*.node
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
- name: Build Native Module
if: steps.cache.outputs.cache-hit != 'true'
working-directory: apps/desktop/desktop_native
run: |
npm run build:cross-platform
- name: Build
if: steps.build-cache.outputs.cache-hit != 'true'
run: npm run build

View File

@ -17,7 +17,7 @@ on:
branches:
- 'master'
- 'rc'
- 'hotfix-rc/**'
- 'hotfix-rc'
paths:
- 'apps/web/**'
- 'libs/**'

View File

@ -31,9 +31,9 @@ jobs:
- name: Branch check
if: ${{ github.event.inputs.release_type != 'Dry 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-rc ]]; then
echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix-rc/*' branches"
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
@ -90,6 +90,22 @@ jobs:
- setup
- locales-test
steps:
- name: Create GitHub deployment
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment: 'Browser - Production'
description: 'Deployment ${{ needs.setup.outputs.release-version }} from branch ${{ github.ref_name }}'
task: release
- name: Update deployment status to In Progress
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'in_progress'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Download latest Release build artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
@ -141,3 +157,19 @@ jobs:
body: "<insert release notes here>"
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
- name: Update deployment status to Success
if: success()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure
if: failure()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}

View File

@ -47,9 +47,9 @@ jobs:
- name: Branch check
if: ${{ github.event.inputs.release_type != 'Dry 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-rc ]]; then
echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix-rc/*' branches"
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
@ -64,6 +64,22 @@ jobs:
monorepo: true
monorepo-project: cli
- name: Create GitHub deployment for Snap
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment: 'CLI - Production'
description: 'Deployment ${{ steps.version.outputs.version }} from branch ${{ github.ref_name }}'
task: release
- name: Update deployment status to In Progress
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'in_progress'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Download all Release artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
@ -104,6 +120,21 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
- name: Update deployment status to Success
if: success()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure
if: failure()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
snap:
name: Deploy Snap
@ -159,7 +190,6 @@ jobs:
snapcraft push bw_${{ env._PKG_VERSION }}_amd64.snap --release stable
snapcraft logout
choco:
name: Deploy Choco
runs-on: windows-2019
@ -219,7 +249,6 @@ jobs:
cd dist
choco push
npm:
name: Publish NPM
runs-on: ubuntu-20.04
@ -274,3 +303,4 @@ jobs:
- name: Publish NPM
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
run: npm publish --access public

View File

@ -19,18 +19,19 @@ jobs:
outputs:
release-version: ${{ steps.version.outputs.version }}
release-channel: ${{ steps.release-channel.outputs.channel }}
branch-name: ${{ steps.branch.outputs.branch-name }}
steps:
- name: Checkout repo
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
# - name: Branch check
# run: |
# if [[ "$GITHUB_REF" != "refs/heads/master" ]] && [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ $GITHUB_REF != refs/heads/hotfix-rc/* ]]; then
# echo "==================================="
# echo "[!] Can only release from the 'master', 'rc' or 'hotfix-rc/*' branches"
# echo "==================================="
# exit 1
# fi
- name: Branch check
run: |
if [[ "$GITHUB_REF" != "refs/heads/master" ]] && [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ $GITHUB_REF != "refs/heads/hotfix-rc" ]]; then
echo "==================================="
echo "[!] Can only release from the 'master', 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
- name: Bump Desktop Version - Root
env:
@ -70,18 +71,45 @@ jobs:
;;
esac
- name: Setup git config
run: |
git config --global user.name "GitHub Action Bot"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
git config --global url."https://".insteadOf ssh://
- name: Create desktop-beta-release branch
id: branch
env:
VERSION: ${{ github.event.inputs.version_number }}
run: |
find="."
replace="_"
ver=${VERSION//$find/$replace}
branch_name=desktop-beta-release-$ver-beta
git switch -c $branch_name
git add .
git commit -m "Bump desktop version to $VERSION-beta"
git push -u origin $branch_name
echo "::set-output name=branch-name::$branch_name"
linux:
name: Linux Build
runs-on: ubuntu-20.04
needs: setup
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
defaults:
run:
working-directory: apps/desktop
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
with:
ref: ${{ needs.setup.outputs.branch-name }}
- name: Set up Node
uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
@ -158,8 +186,8 @@ jobs:
- name: Upload auto-update artifact
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with:
name: ${{ needs.setup.outputs.release_channel }}-linux.yml
path: apps/desktop/dist/${{ needs.setup.outputs.release_channel }}-linux.yml
name: ${{ needs.setup.outputs.release-channel }}-linux.yml
path: apps/desktop/dist/${{ needs.setup.outputs.release-channel }}-linux.yml
if-no-files-found: error
@ -172,10 +200,12 @@ jobs:
shell: pwsh
working-directory: apps/desktop
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
with:
ref: ${{ needs.setup.outputs.branch-name }}
- name: Set up Node
uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
@ -352,8 +382,8 @@ jobs:
- name: Upload auto-update artifact
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with:
name: ${{ needs.setup.outputs.release_channel }}.yml
path: apps/desktop/dist/nsis-web/${{ needs.setup.outputs.release_channel }}.yml
name: ${{ needs.setup.outputs.release-channel }}.yml
path: apps/desktop/dist/nsis-web/${{ needs.setup.outputs.release-channel }}.yml
if-no-files-found: error
@ -362,13 +392,15 @@ jobs:
runs-on: macos-11
needs: setup
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
defaults:
run:
working-directory: apps/desktop
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
with:
ref: ${{ needs.setup.outputs.branch-name }}
- name: Set up Node
uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
@ -489,13 +521,15 @@ jobs:
- setup
- macos-build
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
defaults:
run:
working-directory: apps/desktop
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
with:
ref: ${{ needs.setup.outputs.branch-name }}
- name: Set up Node
uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
@ -609,19 +643,13 @@ jobs:
if: steps.build-cache.outputs.cache-hit != 'true'
run: npm run build
- name: Extract branch name
if: contains(github.ref, 'hotfix-rc')
id: extract_branch
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
- name: Download artifact from hotfix-rc
if: contains(github.ref, 'hotfix-rc')
if: github.ref == 'refs/heads/hotfix-rc')
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
workflow_conclusion: success
branch: ${{ steps.extract_branch.outputs.branch }}
branch: hotfix-rc
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from rc
@ -634,7 +662,7 @@ jobs:
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from master
if: ${{ github.ref != 'refs/heads/rc' && !contains(github.ref, 'hotfix-rc') }}
if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }}
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
@ -683,8 +711,8 @@ jobs:
- name: Upload auto-update artifact
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with:
name: ${{ needs.setup.outputs.release_channel }}-mac.yml
path: apps/desktop/dist/${{ needs.setup.outputs.release_channel }}-mac.yml
name: ${{ needs.setup.outputs.release-channel }}-mac.yml
path: apps/desktop/dist/${{ needs.setup.outputs.release-channel }}-mac.yml
if-no-files-found: error
@ -695,13 +723,15 @@ jobs:
- setup
- macos-build
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
defaults:
run:
working-directory: apps/desktop
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
with:
ref: ${{ needs.setup.outputs.branch-name }}
- name: Set up Node
uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
@ -815,19 +845,13 @@ jobs:
if: steps.build-cache.outputs.cache-hit != 'true'
run: npm run build
- name: Extract branch name
if: contains(github.ref, 'hotfix-rc')
id: extract_branch
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
- name: Download artifact from hotfix-rc
if: contains(github.ref, 'hotfix-rc')
if: github.ref == 'refs/heads/hotfix-rc')
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
workflow_conclusion: success
branch: ${{ steps.extract_branch.outputs.branch }}
branch: hotfix-rc
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from rc
@ -840,7 +864,7 @@ jobs:
path: ${{ github.workspace }}/browser-build-artifacts
- name: Download artifact from master
if: ${{ github.ref != 'refs/heads/rc' && !contains(github.ref, 'hotfix-rc') }}
if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }}
uses: dawidd6/action-download-artifact@b2abf1705491048a2d7074f7d90513044fd25d39 # v2.19.0
with:
workflow: build-browser.yml
@ -873,7 +897,7 @@ jobs:
if-no-files-found: error
release:
name: MacOS Package Prod Release Asset
name: Release beta channel to S3
runs-on: ubuntu-20.04
needs:
- setup
@ -896,7 +920,7 @@ jobs:
secrets: "aws-electron-access-id, aws-electron-access-key, aws-electron-bucket-name"
- name: Download all artifacts
uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 # v3.0.0
with:
path: apps/desktop/artifacts
@ -906,15 +930,44 @@ jobs:
working-directory: apps/desktop/artifacts
run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive
# - name: Publish artifacts to S3
# env:
# AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }}
# AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
# AWS_DEFAULT_REGION: 'us-west-2'
# AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
# working-directory: apps/desktop/artifacts
# run: |
# aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \
# --acl "public-read" \
# --recursive \
# --quiet
- name: Publish artifacts to S3
env:
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }}
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
AWS_DEFAULT_REGION: 'us-west-2'
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
working-directory: apps/desktop/artifacts
run: |
aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \
--acl "public-read" \
--recursive \
--quiet
remove-branch:
name: Remove branch
runs-on: ubuntu-20.04
if: always()
needs:
- setup
- linux
- windows
- macos-build
- macos-package-github
- macos-package-mas
- release
steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Setup git config
run: |
git config --global user.name "GitHub Action Bot"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
git config --global url."https://".insteadOf ssh://
- name: Remove branch
env:
BRANCH: ${{ needs.setup.outputs.branch-name }}
run: git push origin --delete $BRANCH

View File

@ -42,9 +42,9 @@ jobs:
- name: Branch check
if: ${{ github.event.inputs.release_type != 'Dry 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-rc ]]; then
echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix-rc/*' branches"
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
@ -76,6 +76,22 @@ jobs:
;;
esac
- name: Create GitHub deployment
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment: 'Desktop - Production'
description: 'Deployment ${{ steps.version.outputs.version }} to channel ${{ steps.release-channel.outputs.channel }} from branch ${{ github.ref_name }}'
task: release
- name: Update deployment status to In Progress
uses: chrnorm/deployment-status@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Login to Azure
uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010
with:
@ -164,6 +180,21 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
- name: Update deployment status to Success
if: success()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure
if: failure()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
snap:
name: Deploy Snap

View File

@ -72,6 +72,23 @@ jobs:
name: Deploy Web Vault to QA CloudFlare Pages branch
runs-on: ubuntu-20.04
steps:
- name: Create GitHub deployment
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.qa.bitwarden.pw
environment: 'Web Vault - QA'
description: 'Deployment from branch ${{ github.ref_name }}'
- name: Update deployment status to In Progress
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.qa.bitwarden.pw
state: 'in_progress'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Checkout Repo
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
@ -118,3 +135,21 @@ jobs:
echo "No changes to commit!";
fi
working-directory: deployment
- name: Update deployment status to Success
if: success()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.qa.bitwarden.pw
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure
if: failure()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.qa.bitwarden.pw
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}

View File

@ -28,9 +28,9 @@ jobs:
- name: Branch check
if: ${{ github.event.inputs.release_type != 'Dry 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-rc" ]]; then
echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix-rc/*' branches"
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
@ -147,7 +147,7 @@ jobs:
- self-host
env:
_RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
_TAG_VERSION: ${{ needs.setup.outputs.tag_version }}
_TAG_VERSION: ${{ needs.setup.outputs.release_version }}
steps:
- name: Checkout Repo
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
@ -227,6 +227,24 @@ jobs:
- self-host
- cfpages-deploy
steps:
- name: Create GitHub deployment
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.bitwarden.com
environment: 'Web Vault - Production'
description: 'Deployment ${{ needs.setup.outputs.release_version }} from branch ${{ github.ref_name }}'
task: release
- name: Update deployment status to In Progress
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.bitwarden.com
state: 'in_progress'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Download latest build artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
@ -259,11 +277,29 @@ jobs:
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 # v1.10.0
with:
name: "Version v${{ needs.setup.outputs.release_version }}"
name: "Web v${{ needs.setup.outputs.release_version }}"
commit: ${{ github.sha }}
tag: web-v${{ needs.setup.outputs.tag_version }}
tag: web-v${{ needs.setup.outputs.release_version }}
body: "<insert release notes here>"
artifacts: "apps/web/artifacts/web-${{ needs.setup.outputs.release_version }}-selfhosted-COMMERCIAL.zip,
apps/web/artifacts/web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip"
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
- name: Update deployment status to Success
if: success()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.bitwarden.com
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure
if: failure()
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
with:
token: '${{ secrets.GITHUB_TOKEN }}'
environment-url: http://vault.bitwarden.com
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}

68
.github/workflows/version-auto-bump.yml vendored Normal file
View File

@ -0,0 +1,68 @@
---
name: Version Auto Bump
on:
release:
types: [published]
defaults:
run:
shell: bash
jobs:
setup:
name: "Setup"
runs-on: ubuntu-20.04
outputs:
version_number: ${{ steps.version.outputs.new-version }}
if: contains(github.event.release.tag, 'desktop')
steps:
- name: Checkout Branch
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
- name: Get version to bump
id: version
env:
RELEASE_TAG: ${{ github.event.release.tag }}
run: |
CURR_MAJOR=$(echo $RELEASE_TAG | sed -r 's/desktop-v([0-9]{4}\.[0-9]\.)([0-9])/\1/')
CURR_VER=$(echo $RELEASE_TAG | sed -r 's/desktop-v([0-9]{4}\.[0-9]\.)([0-9])/\2/')
echo $CURR_VER
((CURR_VER++))
NEW_VER=$CURR_MAJOR$CURR_VER
echo "::set-output name=new-version::$NEW_VER"
trigger_version_bump:
name: "Trigger desktop version bump workflow"
runs-on: ubuntu-20.04
needs:
- setup
steps:
- name: Login to Azure
uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010
with:
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
- name: Retrieve secrets
id: retrieve-secrets
env:
KEYVAULT: bitwarden-prod-kv
SECRET: "github-pat-bitwarden-devops-bot-repo-scope"
run: |
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRET --query value --output tsv)
echo "::add-mask::$VALUE"
echo "::set-output name=$SECRET::$VALUE"
- name: Call GitHub API to trigger workflow bump
env:
TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
VERSION: ${{ needs.setup.outputs.version_number}}
run: |
JSON_STRING=$(printf '{"ref":"master", "inputs": { "client":"Desktop", "version_number":"%s"}}' "$VERSION")
curl \
-X POST \
-i -u bitwarden-devops-bot:$TOKEN \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/bitwarden/clients/actions/workflows/version-bump.yml/dispatches \
-d $JSON_STRING

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ npm-debug.log
# Build directories
dist
build
.angular/cache
# Testing
coverage

View File

@ -2,6 +2,7 @@
**/build
**/dist
**/coverage
.angular
# External libraries / auto synced locales
apps/browser/src/_locales

View File

@ -4,7 +4,10 @@
"types": ["node"],
"allowSyntheticDefaultImports": true
},
"exclude": ["../src/test.setup.ts", "../src/**/*.spec.ts", "../projects/**/*.spec.ts"],
"include": ["../src/**/*", "../projects/**/*"],
"files": ["./typings.d.ts"]
"exclude": ["../src/test.setup.ts", "../apps/src/**/*.spec.ts", "../libs/**/*.spec.ts"],
"files": [
"./typings.d.ts",
"../libs/components/src/main.ts",
"../libs/components/src/polyfills.ts"
]
}

View File

@ -3,6 +3,83 @@
"version": 1,
"newProjectRoot": "apps",
"projects": {
"web": {
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"root": "apps/web",
"sourceRoot": "apps/web/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/web",
"index": "apps/web/src/index.html",
"main": "apps/web/src/app/main.ts",
"polyfills": "apps/web/src/app/polyfills.ts",
"tsConfig": "apps/web/tsconfig.json",
"assets": ["apps/web/src/favicon.ico"],
"styles": [],
"scripts": []
}
}
}
},
"browser": {
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"root": "apps/browser",
"sourceRoot": "apps/browser/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/browser",
"index": "apps/browser/src/popup/index.html",
"main": "apps/browser/src/popup/main.ts",
"polyfills": "apps/browser/src/popup/polyfills.ts",
"tsConfig": "apps/browser/tsconfig.json",
"assets": [],
"styles": [],
"scripts": []
}
}
}
},
"desktop": {
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"root": "apps/desktop",
"sourceRoot": "apps/desktop/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/desktop",
"index": "apps/desktop/src/index.html",
"main": "apps/desktop/src/app/main.ts",
"tsConfig": "apps/desktop/tsconfig.json",
"assets": [],
"styles": [],
"scripts": []
}
}
}
},
"components": {
"projectType": "application",
"schematics": {
@ -10,9 +87,9 @@
"strict": true
}
},
"root": "./libs/components",
"root": "libs/components",
"sourceRoot": "libs/components/src",
"prefix": "components",
"prefix": "bit",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
@ -31,18 +108,6 @@
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
@ -60,22 +125,42 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "components:build:production"
"browserTarget": "test-storybook:build:production"
},
"development": {
"browserTarget": "components:build:development"
"browserTarget": "test-storybook:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
}
}
},
"storybook": {
"projectType": "application",
"root": "libs/components",
"sourceRoot": "libs/components/src",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"browserTarget": "components:build"
"tsConfig": ".storybook/tsconfig.json",
"styles": ["libs/components/src/styles.scss", "libs/components/src/styles.css"],
"scripts": []
}
}
}
},
"angular": {
"projectType": "library",
"root": "libs/angular",
"sourceRoot": "libs/angular/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"defaultConfiguration": "production"
}
}
}
},
"defaultProject": "components"
}
}

View File

@ -1339,7 +1339,7 @@
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Biguna",
"message": "Ahula",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
@ -1415,7 +1415,7 @@
"message": "Berreskuratu elementua"
},
"restoreItemConfirmation": {
"message": "Ziur zaude elementu hau ezabatu nahi duzula?"
"message": "Ziur zaude elementu hau berreskuratu nahi duzula?"
},
"restoredItem": {
"message": "Elementua berreskuratua"
@ -1580,15 +1580,15 @@
}
},
"send": {
"message": "Bidalketa",
"message": "Send",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"searchSends": {
"message": "Bildalketak bilatu",
"message": "Send-ak bilatu",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"addSend": {
"message": "Gehitu Bidalketa",
"message": "Gehitu Send-a",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTypeText": {
@ -1598,7 +1598,7 @@
"message": "Fitxategia"
},
"allSends": {
"message": "Bidalketa guztiak",
"message": "Send guztiak",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"maxAccessCountReached": {
@ -1615,7 +1615,7 @@
"message": "Pasahitz babestua"
},
"copySendLink": {
"message": "Bidalketa esteka kopiatu",
"message": "Send esteka kopiatu",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"removePassword": {
@ -1628,11 +1628,11 @@
"message": "Pasahitza kendua"
},
"deletedSend": {
"message": "Bidalketa ezabatua",
"message": "Send-a ezabatua",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLink": {
"message": "Bidalketa esteka",
"message": "Send esteka",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"disabled": {
@ -1642,23 +1642,23 @@
"message": "Ziur zaude pasahitz hau ezabatu nahi duzula?"
},
"deleteSend": {
"message": "Ezabatu Bidalketa",
"message": "Ezabatu Send-a",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"deleteSendConfirmation": {
"message": "Ziur al zaude Bidalketa hau ezabatu nahi duzula?",
"message": "Ziur al zaude Send hau ezabatu nahi duzula?",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"editSend": {
"message": "Bidalketa editatu",
"message": "Editatu Send-a",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTypeHeader": {
"message": "Zein Bidalketa mota da hau?",
"message": "Zein Send mota da hau?",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendNameDesc": {
"message": "Bidalketa hau deskribatzeko izena.",
"message": "Send hau deskribatzeko izena.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendFileDesc": {
@ -1668,14 +1668,14 @@
"message": "Ezabatze data"
},
"deletionDateDesc": {
"message": "Bidalketa betiko ezabatuko da zehaztutako datan eta orduan.",
"message": "Send-a betiko ezabatuko da zehaztutako datan eta orduan.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"expirationDate": {
"message": "Iraungitze data"
},
"expirationDateDesc": {
"message": "Hala ezartzen bada, Bidalketa honetarako sarbidea zehaztutako egunean eta orduan amaituko da.",
"message": "Hala ezartzen bada, Send honetarako sarbidea zehaztutako egunean eta orduan amaituko da.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"oneDay": {
@ -1697,56 +1697,56 @@
"message": "Sarbide kopuru maximoa"
},
"maximumAccessCountDesc": {
"message": "Hala ezartzen bada, erabiltzaileak ezin izango dira Bidalketa honetara sartu gehienezko sarbide kopurura iritsi ondoren.",
"message": "Hala ezartzen bada, erabiltzaileak ezin izango dira Send honetara sartu gehienezko sarbide kopurura iritsi ondoren.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendPasswordDesc": {
"message": "Nahi izanez gero, pasahitza eskatu erabiltzaileak bidalketa honetara sar daitezen.",
"message": "Nahi izanez gero, pasahitza eskatu erabiltzaileak Send honetara sar daitezen.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendNotesDesc": {
"message": "Bidalketa honi buruzko ohar pribatuak.",
"message": "Send honi buruzko ohar pribatuak.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendDisableDesc": {
"message": "Desgaitu Bidalketa hau inor sar ez dadin.",
"message": "Desgaitu Send hau inor sar ez dadin.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendShareDesc": {
"message": "Gordetzean, kopiatu Bidalketa honen esteka arbelean.",
"message": "Gordetzean, kopiatu Send honen esteka arbelean.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTextDesc": {
"message": "Bidali nahi duzun testua."
},
"sendHideText": {
"message": "Ezkutatu Bidalketako testu hau, modu lehenetsian.",
"message": "Ezkutatu Send-eko testu hau, modu lehenetsian.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"currentAccessCount": {
"message": "Uneko sarbide kopurua"
},
"createSend": {
"message": "Sortu Bidalketa berria",
"message": "Sortu Send berria",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"newPassword": {
"message": "Pasahitz berria"
},
"sendDisabled": {
"message": "Bidalketa desgaituta",
"message": "Send-a desgaitua",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendDisabledWarning": {
"message": "Enpresa-politika baten ondorioz, lehendik dagoen Bidalketa bakarrik ezaba dezakezu.",
"message": "Enpresa-politika baten ondorioz, lehendik dagoen Send-a bakarrik ezaba dezakezu.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"createdSend": {
"message": "Bidalketa sortua",
"message": "Send-a sortua",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"editedSend": {
"message": "Bidalketa editatua",
"message": "Send-a editatua",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendLinuxChromiumFileWarning": {
@ -1792,7 +1792,7 @@
"message": "Ezkutatu nire helbide elektronikoa hartzaileei."
},
"sendOptionsPolicyInEffect": {
"message": "Erakundeko politika batek edo gehiagok Bidalketa aukerei eragiten diote."
"message": "Erakundeko politika batek edo gehiagok Send-eko aukerei eragiten diote."
},
"passwordPrompt": {
"message": "Berriro eskatu pasahitz nagusia"

View File

@ -367,7 +367,7 @@
"message": "Blokowanie sejfu"
},
"lockNow": {
"message": "Zablokuj teraz"
"message": "Zablokuj"
},
"immediately": {
"message": "Natychmiast"

View File

@ -517,7 +517,7 @@ export default class MainBackground {
}
async bootstrap() {
this.containerService.attachToWindow(window);
this.containerService.attachToGlobal(window);
await this.stateService.init();

View File

@ -156,7 +156,7 @@ export class BrowserApi {
static reloadExtension(win: Window) {
if (win != null) {
return win.location.reload(true);
return (win.location as any).reload(true);
} else {
return chrome.runtime.reload();
}

View File

@ -87,7 +87,7 @@ button.neutral {
}
}
@media (print) {
@media print {
body {
display: none;
}

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()">
<header>
<div class="left">
<a routerLink="/home">{{ "close" | i18n }}</a>
<button type="button" routerLink="/home">{{ "close" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "appName" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a routerLink="/login">{{ "cancel" | i18n }}</a>
<button type="button" routerLink="/login">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "passwordHint" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "submit" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>

View File

@ -2,15 +2,17 @@
<div class="content">
<div class="logo-image"></div>
<p class="lead text-center">{{ "loginOrCreateNewAccount" | i18n }}</p>
<a class="btn primary block" routerLink="/login"
><b>{{ "login" | i18n }}</b></a
>
<button type="button" class="btn primary block" routerLink="/login">
<b>{{ "login" | i18n }}</b>
</button>
<button type="button" (click)="launchSsoBrowser()" class="btn block">
<i class="bwi bwi-bank" aria-hidden="true"></i> {{ "enterpriseSingleSignOn" | i18n }}
</button>
<a class="btn block" routerLink="/register">{{ "createAccount" | i18n }}</a>
<button type="button" class="btn block" routerLink="/register">
{{ "createAccount" | i18n }}
</button>
</div>
</div>
<a routerLink="/environment" class="settings-icon">
<button type="button" routerLink="/environment" class="settings-icon">
<i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span>&nbsp;{{ "settings" | i18n }}</span>
</a>
</button>

View File

@ -5,7 +5,7 @@
<span class="title">{{ "verifyIdentity" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick *ngIf="!hideInput">{{ "unlock" | i18n }}</button>
<button type="submit" *ngIf="!hideInput">{{ "unlock" | i18n }}</button>
</div>
</header>
<main tabindex="-1">
@ -41,7 +41,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a routerLink="/home">{{ "cancel" | i18n }}</a>
<button type="button" routerLink="/home">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "appName" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "login" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -46,7 +46,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"
@ -65,7 +64,7 @@
</div>
</div>
<p class="text-center">
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
<button type="button" routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</button>
</p>
<app-private-mode-warning></app-private-mode-warning>
</main>

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" [formGroup]="formGroup">
<header>
<div class="left">
<a routerLink="/home">{{ "cancel" | i18n }}</a>
<button type="button" routerLink="/home">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "createAccount" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "submit" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -25,11 +25,8 @@
<div class="row-main">
<label for="masterPassword">
{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreColor }}"
*ngIf="masterPasswordScoreText"
>
{{ masterPasswordScoreText }}
<strong class="sub-label text-{{ color }}" *ngIf="text">
{{ text }}
</strong>
</label>
<input
@ -38,7 +35,6 @@
class="monospaced"
formControlName="masterPassword"
appInputVerbatim
(input)="updatePasswordStrength()"
/>
</div>
<div class="action-buttons">
@ -46,7 +42,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"
@ -59,17 +54,14 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreColor }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreWidth + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreWidth }}"
></div>
</div>
<app-password-strength
[password]="formGroup.get('masterPassword')?.value"
[email]="formGroup.get('email')?.value"
[name]="formGroup.get('name')?.value"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
<div class="box-footer">
@ -94,7 +86,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"

View File

@ -1,5 +1,5 @@
import { Component } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { UntypedFormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
@ -19,9 +19,12 @@ import { StateService } from "@bitwarden/common/abstractions/state.service";
templateUrl: "register.component.html",
})
export class RegisterComponent extends BaseRegisterComponent {
color: string;
text: string;
constructor(
formValidationErrorService: FormValidationErrorsService,
formBuilder: FormBuilder,
formBuilder: UntypedFormBuilder,
authService: AuthService,
router: Router,
i18nService: I18nService,

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a routerLink="/home">{{ "cancel" | i18n }}</a>
<button type="button" routerLink="/home">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "setMasterPassword" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "submit" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -42,10 +42,10 @@
<label for="masterPassword"
>{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreColor }}"
*ngIf="masterPasswordScoreText"
class="sub-label text-{{ passwordStrengthComponent?.masterPasswordScoreColor }}"
*ngIf="passwordStrengthComponent?.masterPasswordScoreText"
>
{{ masterPasswordScoreText }}
{{ passwordStrengthComponent?.masterPasswordScoreText }}
</strong>
</label>
<input
@ -55,7 +55,6 @@
class="monospaced"
[(ngModel)]="masterPassword"
required
(input)="updatePasswordStrength()"
appInputVerbatim
/>
</div>
@ -64,7 +63,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword(false)"
[attr.aria-pressed]="showPassword"
@ -77,17 +75,14 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreColor }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreWidth + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreWidth }}"
></div>
</div>
<app-password-strength
[password]="masterPassword"
[email]="email"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
<div class="box-footer">
@ -116,7 +111,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword(true)"
[attr.aria-pressed]="showPassword"

View File

@ -44,34 +44,4 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
stateService
);
}
get masterPasswordScoreWidth() {
return this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
}
get masterPasswordScoreColor() {
switch (this.masterPasswordScore) {
case 4:
return "success";
case 3:
return "primary";
case 2:
return "warning";
default:
return "danger";
}
}
get masterPasswordScoreText() {
switch (this.masterPasswordScore) {
case 4:
return this.i18nService.t("strong");
case 3:
return this.i18nService.t("good");
case 2:
return this.i18nService.t("weak");
default:
return this.masterPasswordScore != null ? this.i18nService.t("weak") : null;
}
}
}

View File

@ -1,6 +1,6 @@
<header>
<div class="left">
<a routerLink="/2fa">{{ "close" | i18n }}</a>
<button type="button" routerLink="/2fa">{{ "close" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "twoStepOptions" | i18n }}</span>

View File

@ -1,7 +1,7 @@
<form id="two-factor-page" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a routerLink="/login">{{ "back" | i18n }}</a>
<button type="button" routerLink="/login">{{ "back" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ title }}</span>
@ -9,7 +9,6 @@
<div class="right">
<button
type="submit"
appBlurClick
[disabled]="form.loading"
*ngIf="
selectedProviderType != null &&

View File

@ -7,7 +7,7 @@
<span class="title">{{ "updateMasterPassword" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "submit" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -30,11 +30,8 @@
<div class="row-main">
<label for="masterPassword">
{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreStyle.Color }}"
*ngIf="masterPasswordScoreStyle.Text"
>
{{ masterPasswordScoreStyle.Text }}
<strong class="sub-label text-{{ color }}" *ngIf="text">
{{ text }}
</strong>
</label>
<input
@ -45,7 +42,6 @@
[(ngModel)]="masterPassword"
required
appInputVerbatim
(input)="updatePasswordStrength()"
/>
</div>
<div class="action-buttons">
@ -53,7 +49,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword(false)"
[attr.aria-pressed]="showPassword"
@ -66,17 +61,13 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreStyle.Color }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreStyle.Width + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreStyle.Width }}"
></div>
</div>
<app-password-strength
[password]="masterPassword"
[email]="email"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
</div>
@ -100,7 +91,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword(true)"
[attr.aria-pressed]="showPassword"

View File

@ -12,47 +12,11 @@ import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
interface MasterPasswordScore {
Color: string;
Text: string;
Width: number;
}
@Component({
selector: "app-update-temp-password",
templateUrl: "update-temp-password.component.html",
})
export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent {
get masterPasswordScoreStyle(): MasterPasswordScore {
const scoreWidth = this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
switch (this.masterPasswordScore) {
case 4:
return {
Color: "bg-success",
Text: "strong",
Width: scoreWidth,
};
case 3:
return {
Color: "bg-primary",
Text: "good",
Width: scoreWidth,
};
case 2:
return {
Color: "bg-warning",
Text: "weak",
Width: scoreWidth,
};
default:
return {
Color: "bg-danger",
Text: "weak",
Width: scoreWidth,
};
}
}
constructor(
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,

View File

@ -239,7 +239,6 @@ registerLocaleData(localeZhTw, "zh-TW");
RemovePasswordComponent,
VaultSelectComponent,
],
entryComponents: [],
providers: [CurrencyPipe, DatePipe],
bootstrap: [AppComponent],
})

View File

@ -23,7 +23,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"
@ -43,7 +42,7 @@
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
<button type="submit" class="btn btn-primary btn-submit">
<span>{{ "ok" | i18n }}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">

View File

@ -25,7 +25,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="toggleVisibility()"
[attr.aria-pressed]="showPin"
@ -53,7 +52,7 @@
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
<button type="submit" class="btn btn-primary btn-submit">
<span>{{ "ok" | i18n }}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">

View File

@ -1,7 +1,7 @@
<header>
<div class="left">
<app-pop-out [show]="!comingFromAddEdit"></app-pop-out>
<button type="button" appBlurClick (click)="close()" *ngIf="comingFromAddEdit">
<button type="button" (click)="close()" *ngIf="comingFromAddEdit">
{{ "cancel" | i18n }}
</button>
</div>
@ -9,7 +9,7 @@
<span class="title">{{ "generator" | i18n }}</span>
</h1>
<div class="right">
<button type="button" appBlurClick (click)="select()" *ngIf="comingFromAddEdit">
<button type="button" (click)="select()" *ngIf="comingFromAddEdit">
{{ "select" | i18n }}
</button>
</div>
@ -33,7 +33,6 @@
<button
type="button"
appStopClick
appBlurClick
appA11yTitle="{{ 'regeneratePassword' | i18n }}"
(click)="regenerate()"
>
@ -56,7 +55,6 @@
<button
type="button"
appStopClick
appBlurClick
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
(click)="regenerate()"
[disabled]="form.loading"

View File

@ -1,6 +1,6 @@
<header>
<div class="left">
<button type="button" appBlurClick type="button" (click)="close()">
<button type="button" type="button" (click)="close()">
<span class="header-icon" aria-hidden="true"><i class="bwi bwi-angle-left"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
@ -9,7 +9,7 @@
<span class="title">{{ "passwordHistory" | i18n }}</span>
</h1>
<div class="right">
<button type="button" appBlurClick type="button" (click)="clear()">
<button type="button" type="button" (click)="clear()">
{{ "clear" | i18n }}
</button>
</div>

View File

@ -1,4 +1,3 @@
import "core-js/stable";
import "date-input-polyfill";
import "web-animations-js";
import "zone.js/dist/zone";

View File

@ -56,7 +56,7 @@ app-home {
margin-top: 10px;
}
a.settings-icon {
button.settings-icon {
position: absolute;
top: 10px;
left: 10px;

View File

@ -11,4 +11,4 @@
@import "plugins.scss";
@import "environment.scss";
@import "pages.scss";
@import "~@angular/cdk/overlay-prebuilt.css";
@import "@angular/cdk/overlay-prebuilt.css";

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" appBlurClick (click)="cancel()">{{ "cancel" | i18n }}</button>
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ title }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading || disableSend">
<button type="submit" [disabled]="form.loading || disableSend">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -226,7 +226,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePasswordVisible()"
[attr.aria-pressed]="showPassword"
@ -300,7 +299,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="delete()"
[appApiAction]="deletePromise"
#deleteBtn

View File

@ -18,7 +18,6 @@
<div class="right">
<button
type="button"
appBlurClick
(click)="addSend()"
appA11yTitle="{{ 'addSend' | i18n }}"
[disabled]="disableSend"
@ -56,7 +55,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(sendType.Text)"
>
<div class="row-main">
@ -70,7 +68,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(sendType.File)"
>
<div class="row-main">

View File

@ -1,6 +1,6 @@
<header>
<div class="left">
<button type="button" appBlurClick (click)="back()">
<button type="button" (click)="back()">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
@ -21,7 +21,6 @@
<div class="right">
<button
type="button"
appBlurClick
(click)="addSend()"
appA11yTitle="{{ 'addSend' | i18n }}"
[disabled]="disableSend"

View File

@ -1,16 +1,16 @@
<form #form (ngSubmit)="submit()">
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "excludedDomains" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick>{{ "save" | i18n }}</button>
<button type="submit">{{ "save" | i18n }}</button>
</div>
</header>
<main tabindex="-1">
@ -73,7 +73,6 @@
<button
type="button"
appStopClick
appBlurClick
(click)="addUri()"
class="box-content-row box-content-row-newmulti"
>

View File

@ -22,6 +22,7 @@ const BroadcasterSubscriptionId = "excludedDomains";
})
export class ExcludedDomainsComponent implements OnInit, OnDestroy {
excludedDomains: ExcludedDomain[] = [];
existingExcludedDomains: ExcludedDomain[] = [];
currentUris: string[];
loadCurrentUrisTimeout: number;
@ -39,6 +40,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
if (savedDomains) {
for (const uri of Object.keys(savedDomains)) {
this.excludedDomains.push({ uri: uri, showCurrentUris: false });
this.existingExcludedDomains.push({ uri: uri, showCurrentUris: false });
}
}
@ -78,20 +80,27 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
async submit() {
const savedDomains: { [name: string]: null } = {};
const newExcludedDomains = this.getNewlyAddedDomians(this.excludedDomains);
for (const domain of this.excludedDomains) {
if (domain.uri && domain.uri !== "") {
const validDomain = Utils.getHostname(domain.uri);
if (!validDomain) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("excludedDomainsInvalidDomain", domain.uri)
);
return;
const resp = newExcludedDomains.filter((e) => e.uri === domain.uri);
if (resp.length === 0) {
savedDomains[domain.uri] = null;
} else {
if (domain.uri && domain.uri !== "") {
const validDomain = Utils.getHostname(domain.uri);
if (!validDomain) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("excludedDomainsInvalidDomain", domain.uri)
);
return;
}
savedDomains[validDomain] = null;
}
savedDomains[validDomain] = null;
}
}
await this.stateService.setNeverDomains(savedDomains);
this.router.navigate(["/tabs/settings"]);
}
@ -100,6 +109,14 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
return index;
}
getNewlyAddedDomians(domain: ExcludedDomain[]): ExcludedDomain[] {
const result = this.excludedDomains.filter(
(newDomain) =>
!this.existingExcludedDomains.some((oldDomain) => newDomain.uri === oldDomain.uri)
);
return result;
}
toggleUriInput(domain: ExcludedDomain) {
domain.showCurrentUris = !domain.showCurrentUris;
}

View File

@ -1,16 +1,16 @@
<form (ngSubmit)="submit()" [formGroup]="exportForm">
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon" aria-hidden="true"><i class="bwi bwi-angle-left"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "exportVault" | i18n }}</span>
</h1>
<div class="right">
<button appBlurClick type="submit" [disabled]="!exportForm.enabled">
<button type="submit" [disabled]="!exportForm.enabled">
{{ "submit" | i18n }}
</button>
</div>

View File

@ -1,5 +1,5 @@
import { Component } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { UntypedFormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component";
@ -28,7 +28,7 @@ export class ExportComponent extends BaseExportComponent {
private router: Router,
logService: LogService,
userVerificationService: UserVerificationService,
formBuilder: FormBuilder,
formBuilder: UntypedFormBuilder,
fileDownloadService: FileDownloadService
) {
super(

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a routerLink="/folders">{{ "cancel" | i18n }}</a>
<button type="button" routerLink="/folders">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ title }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -34,7 +34,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="delete()"
[appApiAction]="deletePromise"
#deleteBtn

View File

@ -1,20 +1,15 @@
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "folders" | i18n }}</span>
</h1>
<div class="right">
<button
type="button"
appBlurClick
(click)="addFolder()"
appA11yTitle="{{ 'addFolder' | i18n }}"
>
<button type="button" (click)="addFolder()" appA11yTitle="{{ 'addFolder' | i18n }}">
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
</div>

View File

@ -1,9 +1,9 @@
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "options" | i18n }}</span>

View File

@ -1,9 +1,9 @@
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "premiumMembership" | i18n }}</span>
@ -42,13 +42,12 @@
</li>
</ul>
<p class="text-center lead">{{ priceString }}</p>
<button type="button" class="btn primary block" appBlurClick (click)="purchase()">
<button type="button" class="btn primary block" (click)="purchase()">
<b>{{ "premiumPurchase" | i18n }}</b>
</button>
<button
#refreshBtn
type="button"
appBlurClick
(click)="refresh()"
[disabled]="refreshBtn.loading"
[appApiAction]="refreshPromise"
@ -65,7 +64,7 @@
<ng-container *ngIf="isPremium">
<p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p>
<p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p>
<button type="button" class="btn block primary" appBlurClick (click)="manage()">
<button type="button" class="btn block primary" (click)="manage()">
<b>{{ "premiumManage" | i18n }}</b>
</button>
</ng-container>

View File

@ -11,18 +11,30 @@
<div class="box list">
<h2 class="box-header">{{ "manage" | i18n }}</h2>
<div class="box-content single-line">
<a class="box-content-row box-content-row-flex text-default" routerLink="/folders">
<button
type="button"
class="box-content-row box-content-row-flex text-default"
routerLink="/folders"
>
<div class="row-main">{{ "folders" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</a>
<a class="box-content-row box-content-row-flex text-default" routerLink="/sync">
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
routerLink="/sync"
>
<div class="row-main">{{ "sync" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</a>
<a class="box-content-row box-content-row-flex text-default" routerLink="/excluded-domains">
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
routerLink="/excluded-domains"
>
<div class="row-main">{{ "excludedDomains" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</a>
</button>
</div>
</div>
<div class="box list">
@ -77,7 +89,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="lock()"
>
<div class="row-main">{{ "lockNow" | i18n }}</div>
@ -87,7 +98,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="twoStep()"
>
<div class="row-main">{{ "twoStepLogin" | i18n }}</div>
@ -98,7 +108,7 @@
<div class="box list">
<h2 class="box-header">{{ "account" | i18n }}</h2>
<div class="box-content single-line">
<a class="box-content-row" routerLink="/premium">
<button type="button" class="box-content-row" routerLink="/premium">
<div class="row-main">
<div class="icon text-primary">
<i class="bwi bwi-fw bwi-lg bwi-star-f" aria-hidden="true"></i>
@ -108,12 +118,11 @@
>
</div>
<span><i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i></span>
</a>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="changePassword()"
*ngIf="showChangeMasterPass"
>
@ -124,7 +133,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="fingerprint()"
>
<div class="row-main">{{ "fingerprintPhrase" | i18n }}</div>
@ -134,7 +142,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="logOut()"
>
<div class="row-main">{{ "logOut" | i18n }}</div>
@ -149,7 +156,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="import()"
>
<div class="row-main">{{ "importItems" | i18n }}</div>
@ -159,7 +165,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="export()"
>
<div class="row-main">{{ "exportVault" | i18n }}</div>
@ -169,7 +174,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="webVault()"
>
<div class="row-main">{{ "bitWebVault" | i18n }}</div>
@ -180,15 +184,18 @@
<div class="box list">
<h2 class="box-header">{{ "other" | i18n }}</h2>
<div class="box-content single-line">
<a class="box-content-row box-content-row-flex text-default" routerLink="/options">
<button
type="button"
class="box-content-row box-content-row-flex text-default"
routerLink="/options"
>
<div class="row-main">{{ "options" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</a>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="about()"
>
<div class="row-main">{{ "about" | i18n }}</div>
@ -198,7 +205,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="share()"
>
<div class="row-main">{{ "learnOrg" | i18n }}</div>
@ -208,7 +214,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="help()"
>
<div class="row-main">{{ "helpFeedback" | i18n }}</div>
@ -218,7 +223,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="rate()"
>
<div class="row-main">{{ "rateExtension" | i18n }}</div>

View File

@ -1,5 +1,5 @@
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { FormControl } from "@angular/forms";
import { UntypedFormControl } from "@angular/forms";
import { Router } from "@angular/router";
import Swal from "sweetalert2";
@ -50,7 +50,7 @@ export class SettingsComponent implements OnInit {
previousVaultTimeout: number = null;
showChangeMasterPass = true;
vaultTimeout: FormControl = new FormControl(null);
vaultTimeout: UntypedFormControl = new UntypedFormControl(null);
constructor(
private platformUtilsService: PlatformUtilsService,

View File

@ -1,9 +1,9 @@
<header>
<div class="left">
<a routerLink="/tabs/settings">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</a>
</button>
</div>
<h1 class="center">
<span class="title">{{ "sync" | i18n }}</span>

View File

@ -4,6 +4,7 @@
<ul>
<li routerLinkActive="active" #rlaCurrentTab="routerLinkActive" *ngIf="showCurrentTab">
<button
type="button"
routerLink="current"
appA11yTitle="{{ 'currentTab' | i18n }}"
[attr.aria-pressed]="rlaCurrentTab.isActive"
@ -13,6 +14,7 @@
</li>
<li routerLinkActive="active" #rlaMyVault="routerLinkActive">
<button
type="button"
routerLink="vault"
appA11yTitle="{{ 'myVault' | i18n }}"
[attr.aria-pressed]="rlaMyVault.isActive"
@ -22,6 +24,7 @@
</li>
<li routerLinkActive="active" #rlaSend="routerLinkActive">
<button
type="button"
routerLink="send"
appA11yTitle="{{ 'send' | i18n }}"
[attr.aria-pressed]="rlaSend.isActive"
@ -31,6 +34,7 @@
</li>
<li routerLinkActive="active" #rlaGenerator="routerLinkActive">
<button
type="button"
routerLink="generator"
appA11yTitle="{{ 'passGen' | i18n }}"
[attr.aria-pressed]="rlaGenerator.isActive"
@ -40,6 +44,7 @@
</li>
<li routerLinkActive="active" #rlaSettings="routerLinkActive">
<button
type="button"
routerLink="settings"
appA11yTitle="{{ 'settings' | i18n }}"
[attr.aria-pressed]="rlaSettings.isActive"

View File

@ -83,7 +83,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="toggleFieldValue(f)"
[attr.aria-pressed]="f.showValue"

View File

@ -1,13 +1,13 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" appBlurClick (click)="cancel()">{{ "cancel" | i18n }}</button>
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ title }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -51,7 +51,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'generateUsername' | i18n }}"
(click)="generateUsername()"
>
@ -77,7 +76,6 @@
type="button"
#checkPasswordBtn
class="row-btn btn"
appBlurClick
appA11yTitle="{{ 'checkPassword' | i18n }}"
(click)="checkPassword()"
[appApiAction]="checkPasswordPromise"
@ -99,7 +97,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
*ngIf="cipher.viewPassword"
@ -115,7 +112,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'generatePassword' | i18n }}"
(click)="generatePassword()"
*ngIf="cipher.viewPassword"
@ -165,7 +161,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="toggleCardNumber()"
[attr.aria-pressed]="showCardNumber"
@ -219,7 +214,6 @@
type="button"
class="row-btn"
appStopClick
appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="toggleCardCode()"
[attr.aria-pressed]="showCardCode"
@ -486,7 +480,6 @@
<button
type="button"
appStopClick
appBlurClick
(click)="addUri()"
class="box-content-row box-content-row-newmulti"
>
@ -546,7 +539,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="attachments()"
*ngIf="editMode && showAttachments && !cloneMode"
>
@ -566,7 +558,6 @@
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
appBlurClick
(click)="editCollections()"
*ngIf="editMode && cipher.organizationId && !cloneMode"
>
@ -641,7 +632,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="delete()"
[appApiAction]="deletePromise"
#deleteBtn

View File

@ -1,10 +1,10 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" appBlurClick (click)="close()" *ngIf="openedAttachmentsInPopup">
<button type="button" (click)="close()" *ngIf="openedAttachmentsInPopup">
{{ "close" | i18n }}
</button>
<button type="button" appBlurClick (click)="back()" *ngIf="!openedAttachmentsInPopup">
<button type="button" (click)="back()" *ngIf="!openedAttachmentsInPopup">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
@ -13,7 +13,7 @@
<span class="title">{{ "attachments" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
@ -33,7 +33,6 @@
class="row-btn btn"
type="button"
appStopClick
appBlurClick
appA11yTitle="{{ 'deleteAttachment' | i18n }}"
(click)="delete(a)"
#deleteBtn

View File

@ -1,6 +1,6 @@
<header>
<div class="left">
<button type="button" appBlurClick (click)="back()">
<button type="button" (click)="back()">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
@ -19,7 +19,7 @@
<i class="bwi bwi-search" aria-hidden="true"></i>
</div>
<div class="right">
<button type="button" appBlurClick (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<button type="button" (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
</div>
@ -40,7 +40,6 @@
*ngFor="let f of nestedFolders"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectFolder(f.node)"
>
<div class="row-main">
@ -63,7 +62,6 @@
*ngFor="let c of nestedCollections"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectCollection(c.node)"
>
<div class="row-main">

View File

@ -1,7 +1,7 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" appBlurClick (click)="back()">
<button type="button" (click)="back()">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
@ -10,7 +10,7 @@
<span class="title">{{ "collections" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<button type="submit" [disabled]="form.loading">
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>

View File

@ -4,7 +4,6 @@
<app-pop-out *ngIf="!inSidebar"></app-pop-out>
<button
type="button"
appBlurClick
(click)="refresh()"
appA11yTitle="{{ 'refresh' | i18n }}"
*ngIf="inSidebar"
@ -25,7 +24,7 @@
<i class="bwi bwi-search" aria-hidden="true"></i>
</div>
<div class="right">
<button type="button" appBlurClick (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<button type="button" (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
</div>

View File

@ -1,6 +1,6 @@
<header>
<div class="left">
<button type="button" appBlurClick (click)="close()">{{ "close" | i18n }}</button>
<button type="button" (click)="close()">{{ "close" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "passwordHistory" | i18n }}</span>

View File

@ -1,7 +1,7 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" appBlurClick (click)="cancel()">{{ "cancel" | i18n }}</button>
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "moveToOrganization" | i18n }}</span>
@ -9,7 +9,6 @@
<div class="right">
<button
type="submit"
appBlurClick
[disabled]="form.loading || !canSave"
*ngIf="organizations && organizations.length"
>

View File

@ -17,7 +17,7 @@
<i class="bwi bwi-search"></i>
</div>
<div class="right">
<button type="button" appBlurClick (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<button type="button" (click)="addCipher()" appA11yTitle="{{ 'addItem' | i18n }}">
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
</div>
@ -61,7 +61,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(cipherType.Login)"
>
<div class="row-main">
@ -75,7 +74,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(cipherType.Card)"
>
<div class="row-main">
@ -89,7 +87,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(cipherType.Identity)"
>
<div class="row-main">
@ -103,7 +100,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectType(cipherType.SecureNote)"
>
<div class="row-main">
@ -126,7 +122,6 @@
*ngFor="let f of nestedFolders"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectFolder(f.node)"
>
<div class="row-main">
@ -151,7 +146,6 @@
*ngFor="let nestedCollection of nestedCollections"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectCollection(nestedCollection.node)"
>
<div class="row-main">
@ -187,13 +181,7 @@
<span class="flex-right">{{ deletedCount }}</span>
</h2>
<div class="box-content single-line">
<button
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="selectTrash()"
>
<button type="button" class="box-content-row" appStopClick (click)="selectTrash()">
<div class="row-main">
<div class="icon"><i class="bwi bwi-fw bwi-lg bwi-trash"></i></div>
<span class="text">{{ "trash" | i18n }}</span>

View File

@ -58,7 +58,7 @@
class="bwi bwi-fw bwi-family"
aria-hidden="true"
></i>
<span>&nbsp;{{ organization.name | ellipsis: 21:true }}</span>
<span>&nbsp;{{ organization.name | ellipsis: (organization.enabled ? 21 : 18):true }}</span>
<i
*ngIf="!organization.enabled"
class="bwi bwi-fw bwi-exclamation-triangle text-danger"

View File

@ -1,12 +1,12 @@
<header>
<div class="left">
<button type="button" appBlurClick (click)="close()">{{ "close" | i18n }}</button>
<button type="button" (click)="close()">{{ "close" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "viewItem" | i18n }}</span>
</h1>
<div class="right" *ngIf="cipher">
<button type="button" appBlurClick (click)="edit()" *ngIf="!cipher.isDeleted">
<button type="button" (click)="edit()" *ngIf="!cipher.isDeleted">
{{ "edit" | i18n }}
</button>
</div>
@ -79,7 +79,6 @@
type="button"
#checkPasswordBtn
class="row-btn btn"
appBlurClick
appA11yTitle="{{ 'checkPassword' | i18n }}"
(click)="checkPassword()"
[appApiAction]="checkPasswordPromise"
@ -397,7 +396,6 @@
class="box-content-row box-content-row-flex text-default"
*ngFor="let attachment of cipher.attachments"
appStopClick
appBlurCLick
(click)="downloadAttachment(attachment)"
>
<span class="row-main">{{ attachment.fileName }}</span>
@ -421,7 +419,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="fillCipher()"
*ngIf="cipher.type !== cipherType.SecureNote && !cipher.isDeleted && !inPopout"
>
@ -436,7 +433,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="fillCipherAndSave()"
*ngIf="cipher.type === cipherType.Login && !cipher.isDeleted && !inPopout"
>
@ -451,7 +447,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="clone()"
*ngIf="!cipher.organizationId && !cipher.isDeleted"
>
@ -466,7 +461,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="share()"
*ngIf="!cipher.organizationId"
>
@ -481,7 +475,6 @@
type="button"
class="box-content-row"
appStopClick
appBlurClick
(click)="restore()"
*ngIf="cipher.isDeleted"
>
@ -492,7 +485,7 @@
<span>{{ "restoreItem" | i18n }}</span>
</div>
</button>
<button type="button" class="box-content-row" appStopClick appBlurClick (click)="delete()">
<button type="button" class="box-content-row" appStopClick (click)="delete()">
<div class="row-main text-danger">
<div class="icon text-danger" aria-hidden="true">
<i class="bwi bwi-trash bwi-lg bwi-fw"></i>
@ -514,14 +507,14 @@
</div>
<div *ngIf="cipher.hasPasswordHistory">
<b class="font-weight-semibold">{{ "passwordHistory" | i18n }}:</b>
<a
<button
routerLink="/cipher-password-history"
[queryParams]="{ cipherId: cipher.id }"
appStopClick
title="{{ 'passwordHistory' | i18n }}"
>
{{ cipher.passwordHistory.length }}
</a>
</button>
</div>
</div>
</div>

View File

@ -29,8 +29,8 @@ export class BrowserFileDownloadService implements FileDownloadService {
true
);
} else {
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(builder.blob, request.fileName);
if ((navigator as any).msSaveOrOpenBlob) {
(navigator as any).msSaveBlob(builder.blob, request.fileName);
} else {
const a = window.document.createElement("a");
a.href = URL.createObjectURL(builder.blob);

View File

@ -132,7 +132,7 @@ Gailu guztien artean pasahitz mugagabeak kudeatu, biltegiratu, babestu eta parte
Pasahitz sendoak, bakarrak eta ausazkoak sortzen ditu, webgune bakoitzaren segurtasun-baldintzetan oinarrituta.
Bitwarden Bidalketak-ek azkar transmititzen dio zifratutako informazioa --- artxiboak eta testu sinplea -- edozein pertsonari zuzenean.
Bitwarden Send-ek azkar transmititzen du zifratutako informazioa --- artxiboak eta testu sinplea -- edozein pertsonari zuzenean.
Bitwarden-ek Taldeak eta Enpresak planak eskaintzen ditu, enpresa bereko lankideek pasahitzak modu seguruan parteka ditzaten.

View File

@ -46,13 +46,20 @@ const moduleRules = [
"sass-loader",
],
},
// Hide System.import warnings. ref: https://github.com/angular/angular/issues/21560
{
test: /[\/\\]@angular[\/\\].+\.js$/,
parser: { system: true },
test: /\.[cm]?js$/,
use: [
{
loader: "babel-loader",
options: {
configFile: false,
plugins: ["@angular/compiler-cli/linker/babel"],
},
},
],
},
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
test: /\.[jt]sx?$/,
loader: "@ngtools/webpack",
},
];
@ -102,7 +109,7 @@ const plugins = [
cleanAfterEveryBuildPatterns: ["!popup/fonts/**/*"],
}),
new webpack.ProvidePlugin({
process: "process/browser",
process: "process/browser.js",
}),
new webpack.SourceMapDevToolPlugin({
exclude: [/content\/.*/, /notification\/.*/],

View File

@ -11,27 +11,27 @@
"dependencies": {
"@koa/multer": "^3.0.0",
"@koa/router": "^10.1.1",
"big-integer": "1.6.48",
"big-integer": "^1.6.51",
"browser-hrtime": "^1.1.8",
"chalk": "^4.1.1",
"commander": "7.2.0",
"form-data": "4.0.0",
"https-proxy-agent": "5.0.0",
"inquirer": "8.0.0",
"jsdom": "^16.5.3",
"jszip": "^3.7.1",
"jsdom": "^16.7.0",
"jszip": "^3.10.0",
"koa": "^2.13.4",
"koa-bodyparser": "^4.3.0",
"koa-json": "^2.0.2",
"lowdb": "1.0.0",
"lunr": "^2.3.9",
"multer": "^1.4.4",
"node-fetch": "^2.6.1",
"multer": "^1.4.5-lts.1",
"node-fetch": "^2.6.7",
"node-forge": "1.3.1",
"open": "^8.0.8",
"papaparse": "^5.3.0",
"open": "^8.4.0",
"papaparse": "^5.3.2",
"proper-lockfile": "^4.1.2",
"rxjs": "6.6.7",
"rxjs": "^7.5.5",
"tldjs": "^2.3.1",
"zxcvbn": "^4.4.2"
},
@ -187,9 +187,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/big-integer": {
"version": "1.6.48",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==",
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
"engines": {
"node": ">=0.6"
}
@ -210,38 +210,16 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/busboy": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
"integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"dicer": "0.2.5",
"readable-stream": "1.1.x"
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=0.8.0"
"node": ">=10.16.0"
}
},
"node_modules/busboy/node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"node_modules/busboy/node_modules/readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/busboy/node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -534,39 +512,6 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dicer": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
"integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==",
"dependencies": {
"readable-stream": "1.1.x",
"streamsearch": "0.1.2"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/dicer/node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"node_modules/dicer/node_modules/readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/dicer/node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/domexception": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@ -901,6 +846,22 @@
"node": ">=8.0.0"
}
},
"node_modules/inquirer/node_modules/rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dependencies": {
"tslib": "^1.9.0"
},
"engines": {
"npm": ">=2.0.0"
}
},
"node_modules/inquirer/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/is-docker": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
@ -1242,22 +1203,20 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/multer": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
"integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
"deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.",
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^0.2.11",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"on-finished": "^2.3.0",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
},
"engines": {
"node": ">= 0.10.0"
"node": ">= 6.0.0"
}
},
"node_modules/mute-stream": {
@ -1586,14 +1545,11 @@
}
},
"node_modules/rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz",
"integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==",
"dependencies": {
"tslib": "^1.9.0"
},
"engines": {
"npm": ">=2.0.0"
"tslib": "^2.1.0"
}
},
"node_modules/safe-buffer": {
@ -1694,11 +1650,11 @@
}
},
"node_modules/streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=0.8.0"
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
@ -1831,9 +1787,9 @@
}
},
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/tsscmp": {
"version": "1.0.6",
@ -2128,9 +2084,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"big-integer": {
"version": "1.6.48",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w=="
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
},
"browser-hrtime": {
"version": "1.1.8",
@ -2148,35 +2104,11 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"busboy": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
"integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"dicer": "0.2.5",
"readable-stream": "1.1.x"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
}
"streamsearch": "^1.1.0"
}
},
"bytes": {
@ -2399,38 +2331,6 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"dicer": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
"integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==",
"requires": {
"readable-stream": "1.1.x",
"streamsearch": "0.1.2"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
}
}
},
"domexception": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@ -2671,6 +2571,21 @@
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6"
},
"dependencies": {
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"requires": {
"tslib": "^1.9.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"is-docker": {
@ -2944,16 +2859,15 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"multer": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
"integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^0.2.11",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"on-finished": "^2.3.0",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
}
@ -3210,11 +3124,11 @@
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="
},
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz",
"integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==",
"requires": {
"tslib": "^1.9.0"
"tslib": "^2.1.0"
}
},
"safe-buffer": {
@ -3289,9 +3203,9 @@
}
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA=="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": {
"version": "1.1.1",
@ -3398,9 +3312,9 @@
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"tsscmp": {
"version": "1.0.6",

View File

@ -377,7 +377,7 @@ export class Main {
private async init() {
await this.storageService.init();
await this.stateService.init();
this.containerService.attachToWindow(global);
this.containerService.attachToGlobal(global);
await this.environmentService.setUrlsFromStorage();
const locale = await this.stateService.getLocale();
await this.i18nService.init(locale);

View File

@ -1,6 +1,7 @@
import * as fet from "node-fetch";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EncArrayBuffer } from "@bitwarden/common/models/domain/encArrayBuffer";
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey";
import { Response } from "@bitwarden/node/cli/models/response";
import { FileResponse } from "@bitwarden/node/cli/models/response/fileResponse";
@ -24,8 +25,8 @@ export abstract class DownloadCommand {
}
try {
const buf = await response.arrayBuffer();
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
const encBuf = await EncArrayBuffer.fromResponse(response);
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
if (process.env.BW_SERVE === "true") {
const res = new FileResponse(Buffer.from(decBuf), fileName);
return Response.success(res);

View File

@ -2,6 +2,7 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
import { Utils } from "@bitwarden/common/misc/utils";
import { EncArrayBuffer } from "@bitwarden/common/models/domain/encArrayBuffer";
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey";
export class NodeEnvSecureStorageService implements AbstractStorageService {
@ -63,10 +64,8 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
return null;
}
const decValue = await this.cryptoService().decryptFromBytes(
Utils.fromB64ToArray(encValue).buffer,
sessionKey
);
const encBuf = EncArrayBuffer.fromB64(encValue);
const decValue = await this.cryptoService().decryptFromBytes(encBuf, sessionKey);
if (decValue == null) {
this.logService.info("Failed to decrypt.");
return null;

View File

@ -0,0 +1,8 @@
[target.x86_64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]
[target.i686-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]
[target.aarch64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]

View File

@ -25,9 +25,11 @@ widestring = "0.5.1"
windows = {version = "0.32.0", features = [
"alloc",
"Foundation",
"Security_Credentials_UI",
"Storage_Streams",
"Win32_Foundation",
"Win32_Security_Credentials",
"Win32_System_WinRT",
]}
[target.'cfg(windows)'.dev-dependencies]

View File

@ -13,7 +13,7 @@ switch (process.platform) {
break;
default:
targets = ['x86_64-unknown-linux-gnu'];
targets = ['x86_64-unknown-linux-musl'];
break;
}

View File

@ -13,3 +13,7 @@ export namespace passwords {
/** Delete the stored password from the keychain. */
export function deletePassword(service: string, account: string): Promise<void>
}
export namespace biometrics {
export function prompt(hwnd: Buffer, message: string): Promise<boolean>
export function available(): Promise<boolean>
}

View File

@ -30,7 +30,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.android-arm64.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-android-arm64')
nativeBinding = require('@bitwarden/desktop-native-android-arm64')
}
} catch (e) {
loadError = e
@ -42,7 +42,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.android-arm-eabi.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-android-arm-eabi')
nativeBinding = require('@bitwarden/desktop-native-android-arm-eabi')
}
} catch (e) {
loadError = e
@ -62,7 +62,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.win32-x64-msvc.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-win32-x64-msvc')
nativeBinding = require('@bitwarden/desktop-native-win32-x64-msvc')
}
} catch (e) {
loadError = e
@ -76,7 +76,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.win32-ia32-msvc.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-win32-ia32-msvc')
nativeBinding = require('@bitwarden/desktop-native-win32-ia32-msvc')
}
} catch (e) {
loadError = e
@ -90,7 +90,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.win32-arm64-msvc.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-win32-arm64-msvc')
nativeBinding = require('@bitwarden/desktop-native-win32-arm64-msvc')
}
} catch (e) {
loadError = e
@ -108,7 +108,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.darwin-x64.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-darwin-x64')
nativeBinding = require('@bitwarden/desktop-native-darwin-x64')
}
} catch (e) {
loadError = e
@ -122,7 +122,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.darwin-arm64.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-darwin-arm64')
nativeBinding = require('@bitwarden/desktop-native-darwin-arm64')
}
} catch (e) {
loadError = e
@ -141,7 +141,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.freebsd-x64.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-freebsd-x64')
nativeBinding = require('@bitwarden/desktop-native-freebsd-x64')
}
} catch (e) {
loadError = e
@ -150,61 +150,31 @@ switch (platform) {
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-x64-musl.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-x64-gnu.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-linux-x64-gnu')
}
} catch (e) {
loadError = e
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-x64-musl.node')
} else {
nativeBinding = require('@bitwarden/desktop-native-linux-x64-musl')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-arm64-musl.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-arm64-gnu.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-linux-arm64-gnu')
}
} catch (e) {
loadError = e
localFileExisted = existsSync(
join(__dirname, 'desktop_native.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-arm64-musl.node')
} else {
nativeBinding = require('@bitwarden/desktop-native-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
break
case 'arm':
@ -215,7 +185,7 @@ switch (platform) {
if (localFileExisted) {
nativeBinding = require('./desktop_native.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@bitwarden/desktop_native-linux-arm-gnueabihf')
nativeBinding = require('@bitwarden/desktop-native-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
@ -236,6 +206,7 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { passwords } = nativeBinding
const { passwords, biometrics } = nativeBinding
module.exports.passwords = passwords
module.exports.biometrics = biometrics

View File

@ -1,41 +0,0 @@
{
"name": "@bitwarden/desktop_native",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/desktop_native",
"version": "0.1.0",
"hasInstallScript": true,
"license": "GPL-3.0",
"devDependencies": {
"@napi-rs/cli": "^2.6.2"
}
},
"node_modules/@napi-rs/cli": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.6.2.tgz",
"integrity": "sha512-EmH+DQDEBUIoqMim0cc+X96ImtcIZLFjgW5WWORpzYnA9Ug7zNPO7jCLMhIQRd/p5AdWaXrT4SVXc/aip09rKQ==",
"dev": true,
"bin": {
"napi": "scripts/index.js"
},
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
}
},
"dependencies": {
"@napi-rs/cli": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.6.2.tgz",
"integrity": "sha512-EmH+DQDEBUIoqMim0cc+X96ImtcIZLFjgW5WWORpzYnA9Ug7zNPO7jCLMhIQRd/p5AdWaXrT4SVXc/aip09rKQ==",
"dev": true
}
}
}

View File

@ -1,11 +1,10 @@
{
"name": "@bitwarden/desktop_native",
"name": "@bitwarden/desktop-native",
"version": "0.1.0",
"description": "",
"main": "index.node",
"scripts": {
"build": "napi build --release --platform",
"build:debug": "napi build --platform",
"build": "napi build --release --platform --js false",
"build:debug": "napi build --platform --js false",
"build:cross-platform": "node build.js",
"test": "cargo test"
},

View File

@ -0,0 +1,9 @@
use anyhow::{Result, bail};
pub fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
bail!("platform not supported");
}
pub fn available() -> Result<bool> {
bail!("platform not supported");
}

View File

@ -0,0 +1,5 @@
#[cfg_attr(target_os = "linux", path = "unix.rs")]
#[cfg_attr(target_os = "windows", path = "windows.rs")]
#[cfg_attr(target_os = "macos", path = "macos.rs")]
mod biometric;
pub use biometric::*;

View File

@ -0,0 +1,9 @@
use anyhow::{Result, bail};
pub fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
bail!("platform not supported");
}
pub fn available() -> Result<bool> {
bail!("platform not supported");
}

View File

@ -0,0 +1,51 @@
use anyhow::Result;
use windows::{
core::factory, Foundation::IAsyncOperation, Security::Credentials::UI::*,
Win32::Foundation::HWND, Win32::System::WinRT::IUserConsentVerifierInterop,
};
pub fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
let interop = factory::<UserConsentVerifier, IUserConsentVerifierInterop>()?;
let h = isize::from_le_bytes(hwnd.try_into().unwrap());
let window = HWND(h);
let operation: IAsyncOperation<UserConsentVerificationResult> =
unsafe { interop.RequestVerificationForWindowAsync(window, message)? };
let result: UserConsentVerificationResult = operation.get()?;
match result {
UserConsentVerificationResult::Verified => Ok(true),
_ => Ok(false),
}
}
pub fn available() -> Result<bool> {
let ucv_available = UserConsentVerifier::CheckAvailabilityAsync()?.get()?;
match ucv_available {
UserConsentVerifierAvailability::Available => Ok(true),
UserConsentVerifierAvailability::DeviceBusy => Ok(true), // TODO: Look into removing this and making the check more ad-hoc
_ => Ok(false),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_prompt() {
prompt(
vec![0, 0, 0, 0, 0, 0, 0, 0],
String::from("Hello from Rust"),
)
.unwrap();
}
#[test]
fn test_available() {
assert!(available().unwrap())
}
}

View File

@ -1,6 +1,7 @@
#[macro_use]
extern crate napi_derive;
mod biometric;
mod password;
#[napi]
@ -37,3 +38,21 @@ pub mod passwords {
.map_err(|e| napi::Error::from_reason(e.to_string()))
}
}
#[napi]
pub mod biometrics {
// Prompt for biometric confirmation
#[napi]
pub async fn prompt(
hwnd: napi::bindgen_prelude::Buffer,
message: String,
) -> napi::Result<bool> {
super::biometric::prompt(hwnd.into(), message)
.map_err(|e| napi::Error::from_reason(e.to_string()))
}
#[napi]
pub async fn available() -> napi::Result<bool> {
super::biometric::available().map_err(|e| napi::Error::from_reason(e.to_string()))
}
}

View File

@ -13,7 +13,12 @@
},
"afterSign": "scripts/after-sign.js",
"asarUnpack": ["**/*.node"],
"files": ["**/*", "!**/node_modules/@bitwarden/desktop-native/**/*"],
"files": [
"**/*",
"!**/node_modules/@bitwarden/desktop-native/**/*",
"**/node_modules/@bitwarden/desktop-native/index.js",
"**/node_modules/@bitwarden/desktop-native/desktop_native.${platform}-${arch}*.node"
],
"electronVersion": "19.0.8",
"generateUpdatesFilesForAllChannels": true,
"publish": {

View File

@ -1,5 +1,5 @@
import { Component, NgZone } from "@angular/core";
import { FormControl, FormGroup, Validators } from "@angular/forms";
import { UntypedFormControl, UntypedFormGroup, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
@ -19,8 +19,8 @@ export class AccessibilityCookieComponent {
listenForCookie = false;
hCaptchaWindow: Window;
accessibilityForm = new FormGroup({
link: new FormControl("", Validators.required),
accessibilityForm = new UntypedFormGroup({
link: new UntypedFormControl("", Validators.required),
});
constructor(

View File

@ -0,0 +1,38 @@
<div class="modal fade" role="dialog" aria-modal="true" attr.aria-label="{{ 'settings' | i18n }}">
<div class="modal-dialog" role="document">
<form
class="modal-content"
#form
[appApiAction]="formPromise"
(ngSubmit)="submit()"
[formGroup]="deleteForm"
>
<div class="modal-body">
<p class="modal-text">{{ "deleteAccountDesc" | i18n }}</p>
<app-callout type="warning" title="{{ 'warning' | i18n }}">
{{ "deleteAccountWarning" | i18n }}
</app-callout>
<div class="box last">
<div class="box-header">{{ "deleteAccount" | i18n }}</div>
<div class="box-content">
<app-user-verification
ngDefaultControl
formControlName="verification"
name="verification"
>
</app-user-verification>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="danger" [disabled]="form.loading || !secret">
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
<span [hidden]="form.loading">{{ "deleteAccount" | i18n }}</span>
</button>
<button type="button" data-dismiss="modal" [disabled]="form.loading">
{{ "cancel" | i18n }}
</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,48 @@
import { Component } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { AccountService } from "@bitwarden/common/abstractions/account/account.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { Verification } from "../../../../../libs/common/src/types/verification";
@Component({
selector: "app-delete-account",
templateUrl: "delete-account.component.html",
})
export class DeleteAccountComponent {
formPromise: Promise<void>;
deleteForm = this.formBuilder.group({
verification: undefined as Verification | undefined,
});
constructor(
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private formBuilder: FormBuilder,
private accountService: AccountService,
private logService: LogService
) {}
get secret() {
return this.deleteForm.get("verification")?.value?.secret;
}
async submit() {
try {
const verification = this.deleteForm.get("verification").value;
this.formPromise = this.accountService.delete(verification);
await this.formPromise;
this.platformUtilsService.showToast(
"success",
this.i18nService.t("accountDeleted"),
this.i18nService.t("accountDeletedDesc")
);
} catch (e) {
this.logService.error(e);
}
}
}

View File

@ -18,11 +18,8 @@
<div class="row-main">
<label for="masterPassword">
{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreColor }}"
*ngIf="masterPasswordScoreText"
>
{{ masterPasswordScoreText }}
<strong class="sub-label text-{{ color }}" *ngIf="text">
{{ text }}
</strong>
</label>
<input
@ -30,7 +27,6 @@
type="{{ showPassword ? 'text' : 'password' }}"
class="monospaced"
formControlName="masterPassword"
(input)="updatePasswordStrength()"
appInputVerbatim
/>
</div>
@ -51,17 +47,14 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreColor }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreWidth + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreWidth }}"
></div>
</div>
<app-password-strength
[password]="formGroup.get('masterPassword')?.value"
[email]="formGroup.get('email')?.value"
[name]="formGroup.get('name')?.value"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
<div class="box-footer">

View File

@ -1,5 +1,5 @@
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { UntypedFormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
@ -24,7 +24,7 @@ const BroadcasterSubscriptionId = "RegisterComponent";
export class RegisterComponent extends BaseRegisterComponent implements OnInit, OnDestroy {
constructor(
formValidationErrorService: FormValidationErrorsService,
formBuilder: FormBuilder,
formBuilder: UntypedFormBuilder,
authService: AuthService,
router: Router,
i18nService: I18nService,

View File

@ -37,11 +37,8 @@
<div class="row-main">
<label for="masterPassword"
>{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreColor }}"
*ngIf="masterPasswordScoreText"
>
{{ masterPasswordScoreText }}
<strong class="sub-label text-{{ color }}" *ngIf="text">
{{ text }}
</strong>
</label>
<input
@ -51,7 +48,6 @@
class="monospaced"
[(ngModel)]="masterPassword"
required
(input)="updatePasswordStrength()"
appInputVerbatim
/>
</div>
@ -72,17 +68,13 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreColor }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreWidth + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreWidth }}"
></div>
</div>
<app-password-strength
[password]="masterPassword"
[email]="email"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
<div class="box-footer">
@ -147,7 +139,7 @@
></i>
<span>{{ "submit" | i18n }}</span>
</button>
<button class="btn block" (click)="logOut()">
<button type="button" class="btn block" (click)="logOut()">
<span>{{ "logOut" | i18n }}</span>
</button>
</div>

View File

@ -50,36 +50,6 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
);
}
get masterPasswordScoreWidth() {
return this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
}
get masterPasswordScoreColor() {
switch (this.masterPasswordScore) {
case 4:
return "success";
case 3:
return "primary";
case 2:
return "warning";
default:
return "danger";
}
}
get masterPasswordScoreText() {
switch (this.masterPasswordScore) {
case 4:
return this.i18nService.t("strong");
case 3:
return this.i18nService.t("good");
case 2:
return this.i18nService.t("weak");
default:
return this.masterPasswordScore != null ? this.i18nService.t("weak") : null;
}
}
async ngOnInit() {
await super.ngOnInit();
this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => {

View File

@ -108,6 +108,14 @@
</label>
</div>
</div>
<div class="form-group">
<label>{{ "deleteAccount" | i18n }}</label>
<small class="help-block">
{{ "deleteAccountDesc" | i18n }}
<a (click)="openDeleteAccount()">{{ "deleteAccount" | i18n }}</a>
</small>
</div>
</ng-container>
</div>
</div>

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { FormControl } from "@angular/forms";
import { UntypedFormControl } from "@angular/forms";
import { debounceTime } from "rxjs/operators";
import { ModalService } from "@bitwarden/angular/services/modal.service";
@ -18,6 +18,8 @@ import { isWindowsStore } from "@bitwarden/electron/utils";
import { SetPinComponent } from "../components/set-pin.component";
import { DeleteAccountComponent } from "./delete-account.component";
@Component({
selector: "app-settings",
templateUrl: "settings.component.html",
@ -60,7 +62,7 @@ export class SettingsComponent implements OnInit {
startToTrayText: string;
startToTrayDescText: string;
vaultTimeout: FormControl = new FormControl(null);
vaultTimeout: UntypedFormControl = new UntypedFormControl(null);
showSecurity = true;
showAccountPreferences = true;
@ -437,4 +439,8 @@ export class SettingsComponent implements OnInit {
this.enableBrowserIntegrationFingerprint
);
}
async openDeleteAccount() {
this.modalService.open(DeleteAccountComponent, { replaceTopModal: true });
}
}

View File

@ -16,11 +16,8 @@
<div class="row-main">
<label for="masterPassword">
{{ "masterPass" | i18n }}
<strong
class="sub-label text-{{ masterPasswordScoreStyle.Color }}"
*ngIf="masterPasswordScoreStyle.Text"
>
{{ masterPasswordScoreStyle.Text }}
<strong class="sub-label text-{{ color }}" *ngIf="text">
{{ text }}
</strong>
</label>
<input
@ -31,7 +28,6 @@
[(ngModel)]="masterPassword"
required
[appAutofocus]="masterPassword === ''"
(input)="updatePasswordStrength()"
appInputVerbatim
/>
</div>
@ -52,17 +48,13 @@
</button>
</div>
</div>
<div class="progress">
<div
class="progress-bar bg-{{ masterPasswordScoreStyle.Color }}"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: masterPasswordScoreStyle.Width + '%' }"
attr.aria-valuenow="{{ masterPasswordScoreStyle.Width }}"
></div>
</div>
<app-password-strength
[password]="masterPassword"
[email]="email"
(passwordStrengthResult)="getStrengthResult($event)"
(passwordScoreColor)="getPasswordScoreText($event)"
>
</app-password-strength>
</div>
</div>
</div>

View File

@ -12,46 +12,11 @@ import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
interface MasterPasswordScore {
Color: string;
Text: string;
Width: number;
}
@Component({
selector: "app-update-temp-password",
templateUrl: "update-temp-password.component.html",
})
export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent {
get masterPasswordScoreStyle(): MasterPasswordScore {
const scoreWidth = this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
switch (this.masterPasswordScore) {
case 4:
return {
Color: "bg-success",
Text: "strong",
Width: scoreWidth,
};
case 3:
return {
Color: "bg-primary",
Text: "good",
Width: scoreWidth,
};
case 2:
return {
Color: "bg-warning",
Text: "weak",
Width: scoreWidth,
};
default:
return {
Color: "bg-danger",
Text: "weak",
Width: scoreWidth,
};
}
}
constructor(
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,

View File

@ -40,6 +40,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType";
import { MenuUpdateRequest } from "../main/menu/menu.updater";
import { DeleteAccountComponent } from "./accounts/delete-account.component";
import { PremiumComponent } from "./accounts/premium.component";
import { SettingsComponent } from "./accounts/settings.component";
import { ExportComponent } from "./vault/export.component";
@ -153,9 +154,7 @@ export class AppComponent implements OnInit {
this.systemService.cancelProcessReload();
break;
case "loggedOut":
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
this.notificationsService.updateConnection();
this.updateAppMenu();
await this.systemService.clearPendingClipboard();
@ -180,9 +179,7 @@ export class AppComponent implements OnInit {
}
break;
case "locked":
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
if (
message.userId == null ||
message.userId === (await this.stateService.getUserId())
@ -195,7 +192,7 @@ export class AppComponent implements OnInit {
await this.reloadProcess();
break;
case "reloadProcess":
window.location.reload();
(window.location as any).reload(true);
break;
case "syncStarted":
break;
@ -223,6 +220,9 @@ export class AppComponent implements OnInit {
}
break;
}
case "deleteAccount":
this.modalService.open(DeleteAccountComponent, { replaceTopModal: true });
break;
case "openPasswordHistory":
await this.openModal<PasswordGeneratorHistoryComponent>(
PasswordGeneratorHistoryComponent,
@ -368,9 +368,7 @@ export class AppComponent implements OnInit {
}
async openExportVault() {
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
const [modal, childComponent] = await this.modalService.openViewRef(
ExportComponent,
@ -388,9 +386,7 @@ export class AppComponent implements OnInit {
}
async addFolder() {
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
const [modal, childComponent] = await this.modalService.openViewRef(
FolderAddEditComponent,
@ -410,9 +406,7 @@ export class AppComponent implements OnInit {
}
async openGenerator() {
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
[this.modal] = await this.modalService.openViewRef(
GeneratorComponent,
@ -542,9 +536,7 @@ export class AppComponent implements OnInit {
}
private async openModal<T>(type: Type<T>, ref: ViewContainerRef) {
if (this.modal != null) {
this.modal.close();
}
this.modalService.closeAll();
[this.modal] = await this.modalService.openViewRef(type, ref);

Some files were not shown because too many files have changed in this diff Show More