Compare commits
37 Commits
Author | SHA1 | Date |
---|---|---|
Oscar Hinton | d7674f5c91 | |
Jake Fink | 9852f2ec22 | |
Micaiah Martin | fec6838f90 | |
Patrick H. Lauke | 55a9403ee3 | |
Oscar Hinton | 817856bc82 | |
Micaiah Martin | 508292ae39 | |
Micaiah Martin | 00fd2ec03f | |
Oscar Hinton | 9a954710d9 | |
Oscar Hinton | a81c3c95a4 | |
Kyle Spearrin | 75470dc169 | |
Oscar Hinton | 18b5e4adfd | |
Patrick H. Lauke | 0396d682b1 | |
Thomas Rittson | ef60112855 | |
Thomas Rittson | b467206448 | |
Nils Fahldieck | 55b301c267 | |
github-actions[bot] | a5ebb9fb52 | |
github-actions[bot] | 2764c9610b | |
Oscar Hinton | 241e08b7ff | |
Oscar Hinton | 865e92c94c | |
Patrick H. Lauke | c3d0a529fb | |
Oscar Hinton | 1315b3c6cd | |
Dave Nicolson | 9f77dd9d09 | |
Thomas Rittson | 5082c7708a | |
dwbit | 10d35d863b | |
Kyle Spearrin | caafbc2b73 | |
Thomas Rittson | a4ca9bf64c | |
Joseph Flinn | 3862a19571 | |
Oscar Hinton | 8be88a731c | |
Oscar Hinton | 2b0d7ac72c | |
Matt Gibson | e0d7d2b43a | |
Oscar Hinton | 70db11e659 | |
Oscar Hinton | 2e3c89269d | |
github-actions[bot] | 31523bdf0e | |
Oscar Hinton | 6b6666cd0d | |
Oscar Hinton | be1ab221f4 | |
Oscar Hinton | 78986023e7 | |
Addison Beck | 14b9decf21 |
|
@ -4,5 +4,6 @@ jslib
|
||||||
webpack.main.js
|
webpack.main.js
|
||||||
webpack.renderer.js
|
webpack.renderer.js
|
||||||
src/scripts/duo.js
|
src/scripts/duo.js
|
||||||
|
desktop_native
|
||||||
|
|
||||||
**/node_modules
|
**/node_modules
|
||||||
|
|
|
@ -149,6 +149,20 @@ jobs:
|
||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build application
|
- name: Build application
|
||||||
run: npm run dist:lin
|
run: npm run dist:lin
|
||||||
|
|
||||||
|
@ -228,11 +242,18 @@ jobs:
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: choco install checksum --no-progress
|
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
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
choco --version
|
choco --version
|
||||||
|
rustup show
|
||||||
|
|
||||||
- name: Login to Azure
|
- name: Login to Azure
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||||
|
@ -253,6 +274,20 @@ jobs:
|
||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build & Sign (dev)
|
- name: Build & Sign (dev)
|
||||||
env:
|
env:
|
||||||
ELECTRON_BUILDER_SIGN: 1
|
ELECTRON_BUILDER_SIGN: 1
|
||||||
|
@ -404,10 +439,15 @@ jobs:
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install $(node -v)
|
||||||
|
|
||||||
|
- name: Rust
|
||||||
|
shell: pwsh
|
||||||
|
run: rustup target install aarch64-apple-darwin
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
|
rustup show
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
|
@ -492,9 +532,23 @@ jobs:
|
||||||
env:
|
env:
|
||||||
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
||||||
run: |
|
run: |
|
||||||
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\package.json | ConvertFrom-Json;
|
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\electron-builder.json | ConvertFrom-Json;
|
||||||
$package.build | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
$package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
||||||
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\package.json;
|
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\electron-builder.json;
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
@ -510,14 +564,14 @@ jobs:
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
with:
|
with:
|
||||||
repository: 'bitwarden/browser'
|
repository: 'bitwarden/browser'
|
||||||
path: 'dist-safari/browser'
|
path: 'dist-safari/bitwarden'
|
||||||
ref: ${{ needs.setup.outputs.safari_ref }}
|
ref: ${{ needs.setup.outputs.safari_ref }}
|
||||||
|
|
||||||
- name: Build Safari extension
|
- name: Build Safari extension
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
npm run dist:safari
|
npm run dist:safari
|
||||||
working-directory: dist-safari/browser
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
|
|
||||||
|
|
||||||
macos-package-github:
|
macos-package-github:
|
||||||
|
@ -548,10 +602,15 @@ jobs:
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install $(node -v)
|
||||||
|
|
||||||
|
- name: Rust
|
||||||
|
shell: pwsh
|
||||||
|
run: rustup target install aarch64-apple-darwin
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
|
rustup show
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
|
@ -636,9 +695,23 @@ jobs:
|
||||||
env:
|
env:
|
||||||
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
||||||
run: |
|
run: |
|
||||||
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\package.json | ConvertFrom-Json;
|
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\electron-builder.json | ConvertFrom-Json;
|
||||||
$package.build | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
$package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
||||||
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\package.json;
|
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\electron-builder.json;
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: NPM install
|
- name: NPM install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
@ -656,8 +729,8 @@ jobs:
|
||||||
if: steps.safari-cache.outputs.cache-hit != 'true'
|
if: steps.safari-cache.outputs.cache-hit != 'true'
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
with:
|
with:
|
||||||
repository: 'bitwarden/browser'
|
repository: 'bitwarden/bitwarden'
|
||||||
path: 'dist-safari/browser'
|
path: 'dist-safari/bitwarden'
|
||||||
ref: ${{ needs.setup.outputs.safari_ref }}
|
ref: ${{ needs.setup.outputs.safari_ref }}
|
||||||
|
|
||||||
- name: Build Safari extension
|
- name: Build Safari extension
|
||||||
|
@ -665,12 +738,13 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
npm run dist:safari
|
npm run dist:safari
|
||||||
working-directory: dist-safari/browser
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
|
|
||||||
- name: Load Safari extension for .dmg
|
- name: Load Safari extension for .dmg
|
||||||
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
run: |
|
run: |
|
||||||
mkdir PlugIns
|
mkdir PlugIns
|
||||||
cp -r dist-safari/browser/dist/Safari/dmg/build/Release/safari.appex PlugIns/safari.appex
|
cp -r dist/Safari/dmg/build/Release/safari.appex PlugIns/safari.appex
|
||||||
|
|
||||||
- name: Build application (dist)
|
- name: Build application (dist)
|
||||||
env:
|
env:
|
||||||
|
@ -735,10 +809,15 @@ jobs:
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install $(node -v)
|
||||||
|
|
||||||
|
- name: Rust
|
||||||
|
shell: pwsh
|
||||||
|
run: rustup target install aarch64-apple-darwin
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
|
rustup show
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
|
@ -823,9 +902,23 @@ jobs:
|
||||||
env:
|
env:
|
||||||
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
||||||
run: |
|
run: |
|
||||||
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\package.json | ConvertFrom-Json;
|
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\electron-builder.json | ConvertFrom-Json;
|
||||||
$package.build | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
$package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
||||||
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\package.json;
|
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\electron-builder.json;
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: NPM install
|
- name: NPM install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
@ -844,7 +937,7 @@ jobs:
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
with:
|
with:
|
||||||
repository: 'bitwarden/browser'
|
repository: 'bitwarden/browser'
|
||||||
path: 'dist-safari/browser'
|
path: 'dist-safari/bitwarden'
|
||||||
ref: ${{ needs.setup.outputs.safari_ref }}
|
ref: ${{ needs.setup.outputs.safari_ref }}
|
||||||
|
|
||||||
- name: Build Safari extension
|
- name: Build Safari extension
|
||||||
|
@ -852,12 +945,13 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
npm run dist:safari
|
npm run dist:safari
|
||||||
working-directory: dist-safari/browser
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
|
|
||||||
- name: Load Safari extension for App Store
|
- name: Load Safari extension for App Store
|
||||||
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
run: |
|
run: |
|
||||||
mkdir PlugIns
|
mkdir PlugIns
|
||||||
cp -r dist-safari/browser/dist/Safari/mas/build/Release/safari.appex PlugIns/safari.appex
|
cp -r dist/Safari/mas/build/Release/safari.appex PlugIns/safari.appex
|
||||||
|
|
||||||
- name: Build application for App Store
|
- name: Build application for App Store
|
||||||
run: npm run pack:mac:mas
|
run: npm run pack:mac:mas
|
||||||
|
@ -1002,9 +1096,23 @@ jobs:
|
||||||
env:
|
env:
|
||||||
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
|
||||||
run: |
|
run: |
|
||||||
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\package.json | ConvertFrom-Json;
|
$package = Get-Content -Raw -Path $env:GITHUB_WORKSPACE\electron-builder.json | ConvertFrom-Json;
|
||||||
$package.build | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
$package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER";
|
||||||
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\package.json;
|
$package | ConvertTo-Json -Depth 32 | Set-Content $env:GITHUB_WORKSPACE\electron-builder.json;
|
||||||
|
|
||||||
|
- name: Cache Native Module
|
||||||
|
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09 # v3.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: desktop_native/*.node
|
||||||
|
key: rust-${{ runner.os }}-${{ hashFiles('desktop_native/**/*') }}
|
||||||
|
|
||||||
|
- name: Build Native Module
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
working-directory: './desktop_native'
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: NPM install
|
- name: NPM install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
@ -1023,7 +1131,7 @@ jobs:
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
with:
|
with:
|
||||||
repository: 'bitwarden/browser'
|
repository: 'bitwarden/browser'
|
||||||
path: 'dist-safari/browser'
|
path: 'dist-safari/bitwarden'
|
||||||
ref: ${{ needs.setup.outputs.safari_ref }}
|
ref: ${{ needs.setup.outputs.safari_ref }}
|
||||||
|
|
||||||
- name: Build Safari extension
|
- name: Build Safari extension
|
||||||
|
@ -1031,12 +1139,13 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
npm run dist:safari
|
npm run dist:safari
|
||||||
working-directory: dist-safari/browser
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
|
|
||||||
- name: Load Safari extension for App Store
|
- name: Load Safari extension for App Store
|
||||||
|
working-directory: dist-safari/bitwarden/apps/browser
|
||||||
run: |
|
run: |
|
||||||
mkdir PlugIns
|
mkdir PlugIns
|
||||||
cp -r dist-safari/browser/dist/Safari/masdev/build/Release/safari.appex PlugIns/safari.appex
|
cp -r dist/Safari/masdev/build/Release/safari.appex PlugIns/safari.appex
|
||||||
|
|
||||||
- name: Build dev application for App Store
|
- name: Build dev application for App Store
|
||||||
run: npm run pack:mac:masdev
|
run: npm run pack:mac:masdev
|
||||||
|
|
|
@ -62,48 +62,69 @@ jobs:
|
||||||
BRANCH_NAME=$(basename ${{ github.ref }})
|
BRANCH_NAME=$(basename ${{ github.ref }})
|
||||||
echo "::set-output name=branch-name::$BRANCH_NAME"
|
echo "::set-output name=branch-name::$BRANCH_NAME"
|
||||||
|
|
||||||
|
- name: Login to Azure
|
||||||
|
uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||||
|
|
||||||
|
- name: Retrieve secrets
|
||||||
|
id: retrieve-secrets
|
||||||
|
uses: Azure/get-keyvault-secrets@b5c723b9ac7870c022b8c35befe620b7009b336f
|
||||||
|
with:
|
||||||
|
keyvault: "bitwarden-prod-kv"
|
||||||
|
secrets: "aws-electron-access-id, aws-electron-access-key"
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
|
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
branch: ${{ steps.branch.outputs.branch-name }}
|
branch: ${{ steps.branch.outputs.branch-name }}
|
||||||
|
path: ./artifacts
|
||||||
|
|
||||||
- name: Rename .pkg to .pkg.archive
|
- name: Rename .pkg to .pkg.archive
|
||||||
env:
|
env:
|
||||||
PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
|
PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
|
||||||
|
working-directory: ./artifacts
|
||||||
run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive
|
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'
|
||||||
|
run: |
|
||||||
|
aws s3 cp ./artifacts s3://public-s3-electron-artifacts/desktop/ \
|
||||||
|
--acl "public-read" \
|
||||||
|
--recursive \
|
||||||
|
--quiet
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
|
||||||
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5
|
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5
|
||||||
env:
|
env:
|
||||||
PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
|
PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
|
||||||
with:
|
with:
|
||||||
artifacts: "Bitwarden-${{ env.PKG_VERSION }}-amd64.deb,
|
artifacts: "artifacts/Bitwarden-${{ env.PKG_VERSION }}-amd64.deb,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x86_64.rpm,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x86_64.rpm,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x64.freebsd,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x64.freebsd,
|
||||||
bitwarden_${{ env.PKG_VERSION }}_amd64.snap,
|
artifacts/bitwarden_${{ env.PKG_VERSION }}_amd64.snap,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x86_64.AppImage,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x86_64.AppImage,
|
||||||
latest-linux.yml,
|
artifacts/Bitwarden-Portable-${{ env.PKG_VERSION }}.exe,
|
||||||
Bitwarden-Portable-${{ env.PKG_VERSION }}.exe,
|
artifacts/Bitwarden-Installer-${{ env.PKG_VERSION }}.exe,
|
||||||
Bitwarden-Installer-${{ env.PKG_VERSION }}.exe,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-ia32-store.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-ia32-store.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-ia32.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-ia32.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-ia32.nsis.7z,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-ia32.nsis.7z,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x64-store.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x64-store.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x64.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x64.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-x64.nsis.7z,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-x64.nsis.7z,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-arm64-store.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-arm64-store.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-arm64.appx,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-arm64.appx,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-arm64.nsis.7z,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-arm64.nsis.7z,
|
artifacts/bitwarden.${{ env.PKG_VERSION }}.nupkg,
|
||||||
bitwarden.${{ env.PKG_VERSION }}.nupkg,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-universal-mac.zip,
|
||||||
latest.yml,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-universal.dmg,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-universal-mac.zip,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-universal.dmg.blockmap,
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-universal.dmg,
|
artifacts/Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive"
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-universal.dmg.blockmap,
|
|
||||||
latest-mac.yml,
|
|
||||||
Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive"
|
|
||||||
commit: ${{ github.sha }}
|
commit: ${{ github.sha }}
|
||||||
tag: v${{ env.PKG_VERSION }}
|
tag: v${{ env.PKG_VERSION }}
|
||||||
name: Version ${{ env.PKG_VERSION }}
|
name: Version ${{ env.PKG_VERSION }}
|
||||||
|
@ -142,7 +163,7 @@ jobs:
|
||||||
run: mkdir dist
|
run: mkdir dist
|
||||||
|
|
||||||
- name: Download Snap artifact
|
- name: Download Snap artifact
|
||||||
uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
|
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
@ -150,9 +171,6 @@ jobs:
|
||||||
artifacts: bitwarden_${{ env._PKG_VERSION }}_amd64.snap
|
artifacts: bitwarden_${{ env._PKG_VERSION }}_amd64.snap
|
||||||
path: ./dist
|
path: ./dist
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ls -alht dist
|
|
||||||
|
|
||||||
- name: Deploy to Snap Store
|
- name: Deploy to Snap Store
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
run: |
|
run: |
|
||||||
|
@ -179,7 +197,7 @@ jobs:
|
||||||
run: New-Item -ItemType directory -Path ./dist
|
run: New-Item -ItemType directory -Path ./dist
|
||||||
|
|
||||||
- name: Download choco artifact
|
- name: Download choco artifact
|
||||||
uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
|
uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
build
|
build
|
||||||
dist
|
dist
|
||||||
dist-safari
|
dist-safari
|
||||||
|
desktop_native
|
||||||
|
|
||||||
jslib
|
jslib
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ Here is how you can get involved:
|
||||||
- **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code
|
- **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code
|
||||||
- **Report a bug or submit a bugfix:** Use Github issues and pull requests
|
- **Report a bug or submit a bugfix:** Use Github issues and pull requests
|
||||||
- **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help)
|
- **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help)
|
||||||
- **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums
|
- **Help other users:** Go to the [Ask the Bitwarden Community category](https://community.bitwarden.com/c/support/) on the Community Forums
|
||||||
- **Translate:** See the localization (l10n) section below
|
- **Translate:** See the localization (l10n) section below
|
||||||
|
|
||||||
## Contributor Agreement
|
## Contributor Agreement
|
||||||
|
@ -31,6 +31,6 @@ We use a translation tool called [Crowdin](https://crowdin.com) to help manage o
|
||||||
|
|
||||||
If you are interested in helping translate the Bitwarden desktop app into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-desktop
|
If you are interested in helping translate the Bitwarden desktop app into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-desktop
|
||||||
|
|
||||||
If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/kspearrin).
|
If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/dwbit).
|
||||||
|
|
||||||
You can read Crowdin's getting started guide for translators here: https://support.crowdin.com/crowdin-intro/
|
You can read Crowdin's getting started guide for translators here: https://support.crowdin.com/crowdin-intro/
|
||||||
|
|
17
README.md
17
README.md
|
@ -2,6 +2,10 @@
|
||||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-desktop/localized.svg)](https://crowdin.com/project/bitwarden-desktop)
|
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-desktop/localized.svg)](https://crowdin.com/project/bitwarden-desktop)
|
||||||
[![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby)
|
[![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby)
|
||||||
|
|
||||||
|
> **Archived**
|
||||||
|
>
|
||||||
|
> This repository is archived, please go to https://github.com/bitwarden/clients for future development.
|
||||||
|
|
||||||
# Bitwarden Desktop Application
|
# Bitwarden Desktop Application
|
||||||
|
|
||||||
[![Platforms](https://imgur.com/SLv9paA.png "Windows, macOS, and Linux")](https://bitwarden.com/download/)
|
[![Platforms](https://imgur.com/SLv9paA.png "Windows, macOS, and Linux")](https://bitwarden.com/download/)
|
||||||
|
@ -12,20 +16,23 @@ The Bitwarden desktop app is written using Electron and Angular. The application
|
||||||
|
|
||||||
# Build/Run
|
# Build/Run
|
||||||
|
|
||||||
**Requirements**
|
## Requirements
|
||||||
|
|
||||||
- [Node.js](https://nodejs.org) v16.13.1 (LTS) or greater
|
- [Node.js](https://nodejs.org) v16.13.1 (LTS) or greater
|
||||||
- NPM v8
|
- NPM v8
|
||||||
- Windows users: To compile the native node modules used in the app you will need the _Visual C++ toolset_, available through the standard Visual Studio installer. You will also need to install the _Microsoft Build Tools 2015_ and _Windows 10 SDK 17134_ as additional dependencies in the Visual Studio installer.
|
- Windows:
|
||||||
|
- To compile the native node modules used in the app you will need the _Visual C++ toolset_, available through the standard Visual Studio installer. You will also need to install the _Microsoft Build Tools 2015_ and _Windows 10 SDK 17134_ as additional dependencies in the Visual Studio installer.
|
||||||
|
- Linux:
|
||||||
|
- The following packages `build-essential libsecret-1-dev libglib2.0-dev`
|
||||||
|
|
||||||
**Run the app**
|
## Run the app
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm ci
|
||||||
npm run electron
|
npm run electron
|
||||||
```
|
```
|
||||||
|
|
||||||
**Debug Native Messaging**
|
### Debug Native Messaging
|
||||||
|
|
||||||
Native Messaging (communication with the browser extension) works by having the browser start a lightweight proxy application baked into our desktop binary. To setup an environment which allows
|
Native Messaging (communication with the browser extension) works by having the browser start a lightweight proxy application baked into our desktop binary. To setup an environment which allows
|
||||||
for easy debugging you will need to build the application for distribution, i.e. `npm run dist:<platform>`, start the dist version and enable desktop integration. This will write some manifests
|
for easy debugging you will need to build the application for distribution, i.e. `npm run dist:<platform>`, start the dist version and enable desktop integration. This will write some manifests
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
target
|
||||||
|
index.node
|
||||||
|
**/node_modules
|
||||||
|
**/.DS_Store
|
||||||
|
npm-debug.log*
|
||||||
|
*.node
|
|
@ -0,0 +1,946 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.55"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-expr"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||||
|
dependencies = [
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxx"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce2295fe8865279f404147e9b2328e5af0ad11a2c016e58c13acfd48a07d8a55"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cxxbridge-flags",
|
||||||
|
"cxxbridge-macro",
|
||||||
|
"link-cplusplus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxx-build"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0aaaa055d4908326f1b4524b23ae53758019b806c0c4f382ea240982e9766b26"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"codespan-reporting",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"scratch",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxxbridge-flags"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a670224c6686471df12560a0b97a08145082e70bd38e2b0b5383b79e46c3da7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cxxbridge-macro"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b700096ca0dece28d9535fdb17ab784a8ae155d7f29d39c273643e6292c9620"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "desktop_native"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"core-foundation",
|
||||||
|
"gio",
|
||||||
|
"keytar",
|
||||||
|
"libsecret",
|
||||||
|
"napi",
|
||||||
|
"napi-build",
|
||||||
|
"napi-derive",
|
||||||
|
"scopeguard",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tokio",
|
||||||
|
"widestring",
|
||||||
|
"windows 0.32.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gio"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96efd8a1c00d890f6b45671916e165b5e43ccec61957d443aff6d7e44f62d348"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"gio-sys",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gio-sys"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d0fa5052773f5a56b8ae47dab09d040f5d9ce1311f4f99006e16e9a08269296"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa570813c504bdf7539a9400180c2dd4b789a819556fb86da7226d7d1b037b49"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-task",
|
||||||
|
"glib-macros",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib-macros"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41bfd8d227dead0829ac142454e97531b93f576d0805d779c42bfd799c65c572"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib-sys"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4366377bd56697de8aaee24e673c575d2694d72e7756324ded2b0428829a7b8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gobject-sys"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keytar"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d361c55fba09829ac620b040f5425bf239b1030c3d6820a84acac8da867dca4d"
|
||||||
|
dependencies = [
|
||||||
|
"keytar-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keytar-sys"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe908c6896705a1cb516cd6a5d956c63f08d95ace81b93253a98cd93e1e6a65a"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cxx",
|
||||||
|
"cxx-build",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.119"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecret"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4af5a2342942fa42d706a424e9f9914287fb8317132750fd73a241140ac38c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"libsecret-sys",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecret-sys"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "287d2a0fcd95e4d7b0ac6fc9f802691a790d7e522138713b0cacebc4e63cab91"
|
||||||
|
dependencies = [
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "link-cplusplus"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8cae2cd7ba2f3f63938b9c724475dfb7b9861b545a90324476324ed21dbc8c8"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"miow",
|
||||||
|
"ntapi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miow"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "napi"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17ec66e60f000c78dd7c6215b6fa260e0591e09805024332bc5b3f55acc12244"
|
||||||
|
dependencies = [
|
||||||
|
"ctor",
|
||||||
|
"lazy_static",
|
||||||
|
"napi-sys",
|
||||||
|
"tokio",
|
||||||
|
"windows 0.30.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "napi-build"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebd4419172727423cf30351406c54f6cc1b354a2cfb4f1dba3e6cd07f6d5522b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "napi-derive"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74ac5287a5e94a8728fc82d16c5127acc5eb5b8ad6404ef5f82d6a4ce8d5bdd2"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case",
|
||||||
|
"napi-derive-backend",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "napi-derive-backend"
|
||||||
|
version = "1.0.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "427f4f04525635cdf22005d1be62d6d671bcb5550d694a1efb480a315422b4af"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "napi-sys"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a385494dac3c52cbcacb393bb3b42669e7db8ab240c7ad5115f549eb061f2cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scratch"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96311ef4a16462c757bb6a39152c40f58f31cd2602a40fceb937e2bc34e6cbab"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.136"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-deps"
|
||||||
|
version = "6.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-expr",
|
||||||
|
"heck",
|
||||||
|
"pkg-config",
|
||||||
|
"toml",
|
||||||
|
"version-compare",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version-compare"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "widestring"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.30.0",
|
||||||
|
"windows_i686_gnu 0.30.0",
|
||||||
|
"windows_i686_msvc 0.30.0",
|
||||||
|
"windows_x86_64_gnu 0.30.0",
|
||||||
|
"windows_x86_64_msvc 0.30.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbedf6db9096bc2364adce0ae0aa636dcd89f3c3f2cd67947062aaf0ca2a10ec"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.32.0",
|
||||||
|
"windows_i686_gnu 0.32.0",
|
||||||
|
"windows_i686_msvc 0.32.0",
|
||||||
|
"windows_x86_64_gnu 0.32.0",
|
||||||
|
"windows_x86_64_msvc 0.32.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.32.0",
|
||||||
|
"windows_i686_gnu 0.32.0",
|
||||||
|
"windows_i686_msvc 0.32.0",
|
||||||
|
"windows_x86_64_gnu 0.32.0",
|
||||||
|
"windows_x86_64_msvc 0.32.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
|
@ -0,0 +1,43 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["index.node"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
name = "desktop_native"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
napi = {version = "2", features = ["async"]}
|
||||||
|
napi-derive = "2"
|
||||||
|
scopeguard = "1.1.0"
|
||||||
|
tokio = {version = "1.17.0", features = ["full"]}
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
napi-build = "1"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
widestring = "0.5.1"
|
||||||
|
windows = {version = "0.32.0", features = [
|
||||||
|
"alloc",
|
||||||
|
"Foundation",
|
||||||
|
"Storage_Streams",
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_Security_Credentials",
|
||||||
|
]}
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dev-dependencies]
|
||||||
|
keytar = "0.1.6"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
core-foundation = "0.9.3"
|
||||||
|
security-framework = "2.6.1"
|
||||||
|
security-framework-sys = "2.6.1"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
gio = "0.15.6"
|
||||||
|
libsecret = "0.1.4"
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const child_process = require("child_process");
|
||||||
|
const process = require("process");
|
||||||
|
|
||||||
|
let targets = [];
|
||||||
|
switch (process.platform) {
|
||||||
|
case "win32":
|
||||||
|
targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "darwin":
|
||||||
|
targets = ["x86_64-apple-darwin", "aarch64-apple-darwin"];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
targets = ['x86_64-unknown-linux-gnu'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.forEach(target => {
|
||||||
|
child_process.execSync(`npm run build -- --target ${target}`, {stdio: 'inherit'});
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
extern crate napi_build;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
napi_build::setup();
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/* auto-generated by NAPI-RS */
|
||||||
|
|
||||||
|
export namespace passwords {
|
||||||
|
/** Fetch the stored password from the keychain. */
|
||||||
|
export function getPassword(service: string, account: string): Promise<string>
|
||||||
|
/** Fetch the stored password from the keychain that was stored with Keytar. */
|
||||||
|
export function getPasswordKeytar(service: string, account: string): Promise<string>
|
||||||
|
/** Save the password to the keychain. Adds an entry if none exists otherwise updates the existing entry. */
|
||||||
|
export function setPassword(service: string, account: string, password: string): Promise<void>
|
||||||
|
/** Delete the stored password from the keychain. */
|
||||||
|
export function deletePassword(service: string, account: string): Promise<void>
|
||||||
|
}
|
|
@ -0,0 +1,241 @@
|
||||||
|
const { existsSync, readFileSync } = require('fs')
|
||||||
|
const { join } = require('path')
|
||||||
|
|
||||||
|
const { platform, arch } = process
|
||||||
|
|
||||||
|
let nativeBinding = null
|
||||||
|
let localFileExisted = false
|
||||||
|
let loadError = null
|
||||||
|
|
||||||
|
function isMusl() {
|
||||||
|
// For Node 10
|
||||||
|
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||||
|
try {
|
||||||
|
return readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
|
||||||
|
} catch (e) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const { glibcVersionRuntime } = process.report.getReport().header
|
||||||
|
return !glibcVersionRuntime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (platform) {
|
||||||
|
case 'android':
|
||||||
|
switch (arch) {
|
||||||
|
case 'arm64':
|
||||||
|
localFileExisted = existsSync(join(__dirname, 'desktop_native.android-arm64.node'))
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.android-arm64.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-android-arm64')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'arm':
|
||||||
|
localFileExisted = existsSync(join(__dirname, 'desktop_native.android-arm-eabi.node'))
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.android-arm-eabi.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-android-arm-eabi')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported architecture on Android ${arch}`)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'win32':
|
||||||
|
switch (arch) {
|
||||||
|
case 'x64':
|
||||||
|
localFileExisted = existsSync(
|
||||||
|
join(__dirname, 'desktop_native.win32-x64-msvc.node')
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.win32-x64-msvc.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-win32-x64-msvc')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'ia32':
|
||||||
|
localFileExisted = existsSync(
|
||||||
|
join(__dirname, 'desktop_native.win32-ia32-msvc.node')
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.win32-ia32-msvc.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-win32-ia32-msvc')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'arm64':
|
||||||
|
localFileExisted = existsSync(
|
||||||
|
join(__dirname, 'desktop_native.win32-arm64-msvc.node')
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.win32-arm64-msvc.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-win32-arm64-msvc')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'darwin':
|
||||||
|
switch (arch) {
|
||||||
|
case 'x64':
|
||||||
|
localFileExisted = existsSync(join(__dirname, 'desktop_native.darwin-x64.node'))
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.darwin-x64.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-darwin-x64')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'arm64':
|
||||||
|
localFileExisted = existsSync(
|
||||||
|
join(__dirname, 'desktop_native.darwin-arm64.node')
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.darwin-arm64.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-darwin-arm64')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'freebsd':
|
||||||
|
if (arch !== 'x64') {
|
||||||
|
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
||||||
|
}
|
||||||
|
localFileExisted = existsSync(join(__dirname, 'desktop_native.freebsd-x64.node'))
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.freebsd-x64.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-freebsd-x64')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'arm':
|
||||||
|
localFileExisted = existsSync(
|
||||||
|
join(__dirname, 'desktop_native.linux-arm-gnueabihf.node')
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (localFileExisted) {
|
||||||
|
nativeBinding = require('./desktop_native.linux-arm-gnueabihf.node')
|
||||||
|
} else {
|
||||||
|
nativeBinding = require('@bitwarden/desktop_native-linux-arm-gnueabihf')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loadError = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nativeBinding) {
|
||||||
|
if (loadError) {
|
||||||
|
throw loadError
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to load native binding`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { passwords } = nativeBinding
|
||||||
|
|
||||||
|
module.exports.passwords = passwords
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "@bitwarden/desktop_native",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.node",
|
||||||
|
"scripts": {
|
||||||
|
"build": "napi build --release --platform",
|
||||||
|
"build:debug": "napi build --platform",
|
||||||
|
"build:cross-platform": "node build.js",
|
||||||
|
"test": "cargo test"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^2.6.2"
|
||||||
|
},
|
||||||
|
"napi": {
|
||||||
|
"name": "desktop_native",
|
||||||
|
"triples": {
|
||||||
|
"defaults": true,
|
||||||
|
"additional": [
|
||||||
|
"x86_64-unknown-linux-musl",
|
||||||
|
"aarch64-unknown-linux-gnu",
|
||||||
|
"i686-pc-windows-msvc",
|
||||||
|
"armv7-unknown-linux-gnueabihf",
|
||||||
|
"aarch64-apple-darwin",
|
||||||
|
"aarch64-unknown-linux-musl",
|
||||||
|
"aarch64-pc-windows-msvc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate napi_derive;
|
||||||
|
|
||||||
|
mod password;
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub mod passwords {
|
||||||
|
/// Fetch the stored password from the keychain.
|
||||||
|
#[napi]
|
||||||
|
pub async fn get_password(service: String, account: String) -> napi::Result<String> {
|
||||||
|
super::password::get_password(&service, &account)
|
||||||
|
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the stored password from the keychain that was stored with Keytar.
|
||||||
|
#[napi]
|
||||||
|
pub async fn get_password_keytar(service: String, account: String) -> napi::Result<String> {
|
||||||
|
super::password::get_password_keytar(&service, &account)
|
||||||
|
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save the password to the keychain. Adds an entry if none exists otherwise updates the existing entry.
|
||||||
|
#[napi]
|
||||||
|
pub async fn set_password(
|
||||||
|
service: String,
|
||||||
|
account: String,
|
||||||
|
password: String,
|
||||||
|
) -> napi::Result<()> {
|
||||||
|
super::password::set_password(&service, &account, &password)
|
||||||
|
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete the stored password from the keychain.
|
||||||
|
#[napi]
|
||||||
|
pub async fn delete_password(service: String, account: String) -> napi::Result<()> {
|
||||||
|
super::password::delete_password(&service, &account)
|
||||||
|
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use security_framework::passwords::{
|
||||||
|
delete_generic_password, get_generic_password, set_generic_password,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn get_password(service: &str, account: &str) -> Result<String> {
|
||||||
|
let result = String::from_utf8(get_generic_password(&service, &account)?)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_password_keytar(service: &str, account: &str) -> Result<String> {
|
||||||
|
get_password(service, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_password(service: &str, account: &str, password: &str) -> Result<()> {
|
||||||
|
let result = set_generic_password(&service, &account, password.as_bytes())?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_password(service: &str, account: &str) -> Result<()> {
|
||||||
|
let result = delete_generic_password(&service, &account)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
scopeguard::defer!(delete_password("BitwardenTest", "BitwardenTest").unwrap_or({}););
|
||||||
|
set_password("BitwardenTest", "BitwardenTest", "Random").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
"Random",
|
||||||
|
get_password("BitwardenTest", "BitwardenTest").unwrap()
|
||||||
|
);
|
||||||
|
delete_password("BitwardenTest", "BitwardenTest").unwrap();
|
||||||
|
|
||||||
|
// Ensure password is deleted
|
||||||
|
match get_password("BitwardenTest", "BitwardenTest") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!(
|
||||||
|
"The specified item could not be found in the keychain.",
|
||||||
|
e.to_string()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_no_password() {
|
||||||
|
match get_password("Unknown", "Unknown") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!(
|
||||||
|
"The specified item could not be found in the keychain.",
|
||||||
|
e.to_string()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 password;
|
||||||
|
pub use password::*;
|
|
@ -0,0 +1,91 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use libsecret::{password_clear_sync, password_lookup_sync, password_store_sync, Schema};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn get_password(service: &str, account: &str) -> Result<String> {
|
||||||
|
let res = password_lookup_sync(
|
||||||
|
Some(&get_schema()),
|
||||||
|
build_attributes(service, account),
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Some(s) => Ok(String::from(s)),
|
||||||
|
None => Err(anyhow!("No password found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_password_keytar(service: &str, account: &str) -> Result<String> {
|
||||||
|
get_password(service, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_password(service: &str, account: &str, password: &str) -> Result<()> {
|
||||||
|
let result = password_store_sync(
|
||||||
|
Some(&get_schema()),
|
||||||
|
build_attributes(service, account),
|
||||||
|
Some(&libsecret::COLLECTION_DEFAULT),
|
||||||
|
&format!("{}/{}", service, account),
|
||||||
|
password,
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_password(service: &str, account: &str) -> Result<()> {
|
||||||
|
let result = password_clear_sync(
|
||||||
|
Some(&get_schema()),
|
||||||
|
build_attributes(service, account),
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_schema() -> Schema {
|
||||||
|
let mut attributes = std::collections::HashMap::new();
|
||||||
|
attributes.insert("service", libsecret::SchemaAttributeType::String);
|
||||||
|
attributes.insert("account", libsecret::SchemaAttributeType::String);
|
||||||
|
|
||||||
|
libsecret::Schema::new(
|
||||||
|
"org.freedesktop.Secret.Generic",
|
||||||
|
libsecret::SchemaFlags::NONE,
|
||||||
|
attributes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_attributes<'a>(service: &'a str, account: &'a str) -> HashMap<&'a str, &'a str> {
|
||||||
|
let mut attributes = HashMap::new();
|
||||||
|
attributes.insert("service", service);
|
||||||
|
attributes.insert("account", account);
|
||||||
|
|
||||||
|
attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
scopeguard::defer!(delete_password("BitwardenTest", "BitwardenTest").unwrap_or({}););
|
||||||
|
set_password("BitwardenTest", "BitwardenTest", "Random").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
"Random",
|
||||||
|
get_password("BitwardenTest", "BitwardenTest").unwrap()
|
||||||
|
);
|
||||||
|
delete_password("BitwardenTest", "BitwardenTest").unwrap();
|
||||||
|
|
||||||
|
// Ensure password is deleted
|
||||||
|
match get_password("BitwardenTest", "BitwardenTest") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!("No password found", e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_no_password() {
|
||||||
|
match get_password("BitwardenTest", "BitwardenTest") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!("No password found", e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use widestring::{U16CString, U16String};
|
||||||
|
use windows::Win32::{
|
||||||
|
Foundation::{GetLastError, ERROR_NOT_FOUND, FILETIME, PWSTR, WIN32_ERROR},
|
||||||
|
Security::Credentials::{
|
||||||
|
CredDeleteW, CredFree, CredReadW, CredWriteW, CREDENTIALW, CRED_FLAGS,
|
||||||
|
CRED_PERSIST_ENTERPRISE, CRED_TYPE_GENERIC,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const CRED_FLAGS_NONE: u32 = 0;
|
||||||
|
|
||||||
|
pub fn get_password<'a>(service: &str, account: &str) -> Result<String> {
|
||||||
|
let target_name = U16CString::from_str(target_name(service, account))?;
|
||||||
|
|
||||||
|
let mut credential: *mut CREDENTIALW = std::ptr::null_mut();
|
||||||
|
let credential_ptr = &mut credential;
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
CredReadW(
|
||||||
|
PWSTR(target_name.as_ptr()),
|
||||||
|
CRED_TYPE_GENERIC.0,
|
||||||
|
CRED_FLAGS_NONE,
|
||||||
|
credential_ptr,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
scopeguard::defer!({
|
||||||
|
unsafe { CredFree(credential as *mut _) };
|
||||||
|
});
|
||||||
|
|
||||||
|
if !result.as_bool() {
|
||||||
|
return Err(anyhow!(convert_error(unsafe { GetLastError() })));
|
||||||
|
}
|
||||||
|
|
||||||
|
let password = unsafe {
|
||||||
|
U16String::from_ptr(
|
||||||
|
(*credential).CredentialBlob as *const u16,
|
||||||
|
(*credential).CredentialBlobSize as usize / 2,
|
||||||
|
)
|
||||||
|
.to_string_lossy()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(String::from(password))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove this after sufficient releases
|
||||||
|
pub fn get_password_keytar<'a>(service: &str, account: &str) -> Result<String> {
|
||||||
|
let target_name = U16CString::from_str(target_name(service, account))?;
|
||||||
|
|
||||||
|
let mut credential: *mut CREDENTIALW = std::ptr::null_mut();
|
||||||
|
let credential_ptr = &mut credential;
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
CredReadW(
|
||||||
|
PWSTR(target_name.as_ptr()),
|
||||||
|
CRED_TYPE_GENERIC.0,
|
||||||
|
CRED_FLAGS_NONE,
|
||||||
|
credential_ptr,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
scopeguard::defer!({
|
||||||
|
unsafe { CredFree(credential as *mut _) };
|
||||||
|
});
|
||||||
|
|
||||||
|
if !result.as_bool() {
|
||||||
|
return Err(anyhow!(unsafe { GetLastError() }.0.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let password = unsafe {
|
||||||
|
std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||||
|
(*credential).CredentialBlob,
|
||||||
|
(*credential).CredentialBlobSize as usize,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(String::from(password))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_password(service: &str, account: &str, password: &str) -> Result<()> {
|
||||||
|
let target_name = U16CString::from_str(target_name(service, account))?;
|
||||||
|
let user_name = U16CString::from_str(account)?;
|
||||||
|
let last_written = FILETIME {
|
||||||
|
dwLowDateTime: 0,
|
||||||
|
dwHighDateTime: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let credential = U16CString::from_str(password)?;
|
||||||
|
let credential_len = password.len() as u32 * 2;
|
||||||
|
|
||||||
|
let credential = CREDENTIALW {
|
||||||
|
Flags: CRED_FLAGS(CRED_FLAGS_NONE),
|
||||||
|
Type: CRED_TYPE_GENERIC,
|
||||||
|
TargetName: PWSTR(target_name.as_ptr()),
|
||||||
|
Comment: PWSTR::default(),
|
||||||
|
LastWritten: last_written,
|
||||||
|
CredentialBlobSize: credential_len,
|
||||||
|
CredentialBlob: credential.as_ptr() as *mut u8,
|
||||||
|
Persist: CRED_PERSIST_ENTERPRISE,
|
||||||
|
AttributeCount: 0,
|
||||||
|
Attributes: std::ptr::null_mut(),
|
||||||
|
TargetAlias: PWSTR::default(),
|
||||||
|
UserName: PWSTR(user_name.as_ptr()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = unsafe { CredWriteW(&credential, 0) };
|
||||||
|
if !result.as_bool() {
|
||||||
|
return Err(anyhow!(unsafe { GetLastError() }.0.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_password(service: &str, account: &str) -> Result<()> {
|
||||||
|
let target_name = U16CString::from_str(target_name(service, account))?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
CredDeleteW(
|
||||||
|
PWSTR(target_name.as_ptr()),
|
||||||
|
CRED_TYPE_GENERIC.0,
|
||||||
|
CRED_FLAGS_NONE,
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_name(service: &str, account: &str) -> String {
|
||||||
|
format!("{}/{}", service, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the internal WIN32 errors to descriptive messages
|
||||||
|
fn convert_error(code: WIN32_ERROR) -> String {
|
||||||
|
match code {
|
||||||
|
ERROR_NOT_FOUND => String::from("Password not found."),
|
||||||
|
_ => code.0.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
scopeguard::defer!(delete_password("BitwardenTest", "BitwardenTest").unwrap_or({}););
|
||||||
|
set_password("BitwardenTest", "BitwardenTest", "Random").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
"Random",
|
||||||
|
get_password("BitwardenTest", "BitwardenTest").unwrap()
|
||||||
|
);
|
||||||
|
delete_password("BitwardenTest", "BitwardenTest").unwrap();
|
||||||
|
|
||||||
|
// Ensure password is deleted
|
||||||
|
match get_password("BitwardenTest", "BitwardenTest") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!("Password not found.", e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_password_keytar() {
|
||||||
|
scopeguard::defer!(delete_password("BitwardenTest", "BitwardenTest").unwrap_or({}););
|
||||||
|
keytar::set_password("BitwardenTest", "BitwardenTest", "HelloFromKeytar").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
"HelloFromKeytar",
|
||||||
|
get_password_keytar("BitwardenTest", "BitwardenTest").unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_no_password() {
|
||||||
|
match get_password("BitwardenTest", "BitwardenTest") {
|
||||||
|
Ok(_) => panic!("Got a result"),
|
||||||
|
Err(e) => assert_eq!("Password not found.", e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"extraMetadata": { "name": "bitwarden" },
|
||||||
|
"productName": "Bitwarden",
|
||||||
|
"appId": "com.bitwarden.desktop",
|
||||||
|
"buildDependenciesFromSource": true,
|
||||||
|
"copyright": "Copyright © 2015-2022 Bitwarden Inc.",
|
||||||
|
"directories": { "buildResources": "resources", "output": "dist", "app": "build" },
|
||||||
|
"afterSign": "scripts/after-sign.js",
|
||||||
|
"asarUnpack": ["**/*.node"],
|
||||||
|
"files": ["**/*", "!**/node_modules/@bitwarden/desktop-native/**/*"],
|
||||||
|
"publish": {
|
||||||
|
"provider": "generic",
|
||||||
|
"url": "https://artifacts.bitwarden.com/desktop"
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"electronUpdaterCompatibility": ">=0.0.1",
|
||||||
|
"category": "public.app-category.productivity",
|
||||||
|
"darkModeSupport": true,
|
||||||
|
"gatekeeperAssess": false,
|
||||||
|
"hardenedRuntime": true,
|
||||||
|
"entitlements": "resources/entitlements.mac.plist",
|
||||||
|
"entitlementsInherit": "resources/entitlements.mac.plist",
|
||||||
|
"extendInfo": {
|
||||||
|
"ITSAppUsesNonExemptEncryption": false,
|
||||||
|
"CFBundleLocalizations": [
|
||||||
|
"en",
|
||||||
|
"cs",
|
||||||
|
"da",
|
||||||
|
"de",
|
||||||
|
"es",
|
||||||
|
"et",
|
||||||
|
"fi",
|
||||||
|
"fr",
|
||||||
|
"hr",
|
||||||
|
"hu",
|
||||||
|
"id",
|
||||||
|
"it",
|
||||||
|
"ja",
|
||||||
|
"nb",
|
||||||
|
"nl",
|
||||||
|
"pl",
|
||||||
|
"pt-BR",
|
||||||
|
"pt-PT",
|
||||||
|
"ro",
|
||||||
|
"ru",
|
||||||
|
"sk",
|
||||||
|
"sv",
|
||||||
|
"tr",
|
||||||
|
"uk",
|
||||||
|
"vi",
|
||||||
|
"zh-Hans",
|
||||||
|
"zh-Hant"
|
||||||
|
],
|
||||||
|
"CFBundleDevelopmentRegion": "en"
|
||||||
|
},
|
||||||
|
"target": ["dmg", "zip"]
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"electronUpdaterCompatibility": ">=0.0.1",
|
||||||
|
"target": ["portable", "nsis-web", "appx"],
|
||||||
|
"sign": "./sign.js",
|
||||||
|
"extraResources": [
|
||||||
|
{ "from": "node_modules/regedit/vbs", "to": "regedit/vbs", "filter": ["**/*"] },
|
||||||
|
{ "from": "resources/native-messaging.bat", "to": "native-messaging.bat" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"category": "Utility",
|
||||||
|
"synopsis": "A secure and free password manager for all of your devices.",
|
||||||
|
"target": ["deb", "freebsd", "rpm", "AppImage", "snap"],
|
||||||
|
"desktop": { "Name": "Bitwarden", "Type": "Application", "GenericName": "Password Manager" }
|
||||||
|
},
|
||||||
|
"dmg": {
|
||||||
|
"icon": "dmg.icns",
|
||||||
|
"contents": [
|
||||||
|
{ "x": 150, "y": 185, "type": "file" },
|
||||||
|
{ "x": 390, "y": 180, "type": "link", "path": "/Applications" }
|
||||||
|
],
|
||||||
|
"window": { "width": 540, "height": 380 }
|
||||||
|
},
|
||||||
|
"mas": {
|
||||||
|
"entitlements": "resources/entitlements.mas.plist",
|
||||||
|
"entitlementsInherit": "resources/entitlements.mas.inherit.plist",
|
||||||
|
"hardenedRuntime": false,
|
||||||
|
"extendInfo": { "LSMinimumSystemVersion": "10.14.0" }
|
||||||
|
},
|
||||||
|
"nsisWeb": {
|
||||||
|
"oneClick": false,
|
||||||
|
"perMachine": false,
|
||||||
|
"allowToChangeInstallationDirectory": false,
|
||||||
|
"artifactName": "${productName}-Installer-${version}.${ext}",
|
||||||
|
"uninstallDisplayName": "${productName}",
|
||||||
|
"deleteAppDataOnUninstall": true
|
||||||
|
},
|
||||||
|
"portable": { "artifactName": "${productName}-Portable-${version}.${ext}" },
|
||||||
|
"appx": {
|
||||||
|
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
||||||
|
"backgroundColor": "#175DDC",
|
||||||
|
"applicationId": "bitwardendesktop",
|
||||||
|
"identityName": "8bitSolutionsLLC.bitwardendesktop",
|
||||||
|
"publisher": "CN=14D52771-DE3C-4886-B8BF-825BA7690418",
|
||||||
|
"publisherDisplayName": "8bit Solutions LLC",
|
||||||
|
"languages": ["en-US"]
|
||||||
|
},
|
||||||
|
"deb": {
|
||||||
|
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
||||||
|
"depends": ["libnotify4", "libxtst6", "libnss3", "libsecret-1-0", "libxss1"]
|
||||||
|
},
|
||||||
|
"appImage": {
|
||||||
|
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
||||||
|
},
|
||||||
|
"rpm": { "artifactName": "${productName}-${version}-${arch}.${ext}" },
|
||||||
|
"freebsd": { "artifactName": "${productName}-${version}-${arch}.${ext}" },
|
||||||
|
"snap": {
|
||||||
|
"autoStart": true,
|
||||||
|
"confinement": "strict",
|
||||||
|
"plugs": ["default", "password-manager-service"],
|
||||||
|
"stagePackages": ["default"]
|
||||||
|
},
|
||||||
|
"protocols": [{ "name": "Bitwarden", "schemes": ["bitwarden"] }]
|
||||||
|
}
|
2
jslib
2
jslib
|
@ -1 +1 @@
|
||||||
Subproject commit 4d58200ee90fb4fafa5d4f9f4c957654d4da306d
|
Subproject commit 80c834b52a8b00f88250a47a9bbd40c269fc2cba
|
File diff suppressed because it is too large
Load Diff
199
package.json
199
package.json
|
@ -63,199 +63,6 @@
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"build": {
|
|
||||||
"extraMetadata": {
|
|
||||||
"name": "bitwarden"
|
|
||||||
},
|
|
||||||
"productName": "Bitwarden",
|
|
||||||
"appId": "com.bitwarden.desktop",
|
|
||||||
"buildDependenciesFromSource": true,
|
|
||||||
"copyright": "Copyright © 2015-2022 Bitwarden Inc.",
|
|
||||||
"directories": {
|
|
||||||
"buildResources": "resources",
|
|
||||||
"output": "dist",
|
|
||||||
"app": "build"
|
|
||||||
},
|
|
||||||
"afterSign": "scripts/after-sign.js",
|
|
||||||
"asarUnpack": [
|
|
||||||
"**/*.node"
|
|
||||||
],
|
|
||||||
"mac": {
|
|
||||||
"electronUpdaterCompatibility": ">=0.0.1",
|
|
||||||
"category": "public.app-category.productivity",
|
|
||||||
"darkModeSupport": true,
|
|
||||||
"gatekeeperAssess": false,
|
|
||||||
"hardenedRuntime": true,
|
|
||||||
"entitlements": "resources/entitlements.mac.plist",
|
|
||||||
"entitlementsInherit": "resources/entitlements.mac.plist",
|
|
||||||
"extendInfo": {
|
|
||||||
"ITSAppUsesNonExemptEncryption": false,
|
|
||||||
"CFBundleLocalizations": [
|
|
||||||
"en",
|
|
||||||
"cs",
|
|
||||||
"da",
|
|
||||||
"de",
|
|
||||||
"es",
|
|
||||||
"et",
|
|
||||||
"fi",
|
|
||||||
"fr",
|
|
||||||
"hr",
|
|
||||||
"hu",
|
|
||||||
"id",
|
|
||||||
"it",
|
|
||||||
"ja",
|
|
||||||
"nb",
|
|
||||||
"nl",
|
|
||||||
"pl",
|
|
||||||
"pt-BR",
|
|
||||||
"pt-PT",
|
|
||||||
"ro",
|
|
||||||
"ru",
|
|
||||||
"sk",
|
|
||||||
"sv",
|
|
||||||
"tr",
|
|
||||||
"uk",
|
|
||||||
"vi",
|
|
||||||
"zh-Hans",
|
|
||||||
"zh-Hant"
|
|
||||||
],
|
|
||||||
"CFBundleDevelopmentRegion": "en"
|
|
||||||
},
|
|
||||||
"target": [
|
|
||||||
"dmg",
|
|
||||||
"zip"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"win": {
|
|
||||||
"electronUpdaterCompatibility": ">=0.0.1",
|
|
||||||
"target": [
|
|
||||||
"portable",
|
|
||||||
"nsis-web",
|
|
||||||
"appx"
|
|
||||||
],
|
|
||||||
"sign": "./sign.js",
|
|
||||||
"extraResources": [
|
|
||||||
{
|
|
||||||
"from": "node_modules/regedit/vbs",
|
|
||||||
"to": "regedit/vbs",
|
|
||||||
"filter": [
|
|
||||||
"**/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from": "resources/native-messaging.bat",
|
|
||||||
"to": "native-messaging.bat"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"linux": {
|
|
||||||
"category": "Utility",
|
|
||||||
"synopsis": "A secure and free password manager for all of your devices.",
|
|
||||||
"target": [
|
|
||||||
"deb",
|
|
||||||
"freebsd",
|
|
||||||
"rpm",
|
|
||||||
"AppImage",
|
|
||||||
"snap"
|
|
||||||
],
|
|
||||||
"desktop": {
|
|
||||||
"Name": "Bitwarden",
|
|
||||||
"Type": "Application",
|
|
||||||
"GenericName": "Password Manager"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dmg": {
|
|
||||||
"icon": "dmg.icns",
|
|
||||||
"contents": [
|
|
||||||
{
|
|
||||||
"x": 150,
|
|
||||||
"y": 185,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": 390,
|
|
||||||
"y": 180,
|
|
||||||
"type": "link",
|
|
||||||
"path": "/Applications"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"window": {
|
|
||||||
"width": 540,
|
|
||||||
"height": 380
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mas": {
|
|
||||||
"entitlements": "resources/entitlements.mas.plist",
|
|
||||||
"entitlementsInherit": "resources/entitlements.mas.inherit.plist",
|
|
||||||
"hardenedRuntime": false,
|
|
||||||
"extendInfo": {
|
|
||||||
"LSMinimumSystemVersion": "10.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nsisWeb": {
|
|
||||||
"oneClick": false,
|
|
||||||
"perMachine": false,
|
|
||||||
"allowToChangeInstallationDirectory": false,
|
|
||||||
"artifactName": "${productName}-Installer-${version}.${ext}",
|
|
||||||
"uninstallDisplayName": "${productName}",
|
|
||||||
"deleteAppDataOnUninstall": true
|
|
||||||
},
|
|
||||||
"portable": {
|
|
||||||
"artifactName": "${productName}-Portable-${version}.${ext}"
|
|
||||||
},
|
|
||||||
"appx": {
|
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
|
||||||
"backgroundColor": "#175DDC",
|
|
||||||
"applicationId": "bitwardendesktop",
|
|
||||||
"identityName": "8bitSolutionsLLC.bitwardendesktop",
|
|
||||||
"publisher": "CN=14D52771-DE3C-4886-B8BF-825BA7690418",
|
|
||||||
"publisherDisplayName": "8bit Solutions LLC",
|
|
||||||
"languages": [
|
|
||||||
"en-US"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"deb": {
|
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
|
||||||
"depends": [
|
|
||||||
"libnotify4",
|
|
||||||
"libxtst6",
|
|
||||||
"libnss3",
|
|
||||||
"libsecret-1-0",
|
|
||||||
"libxss1"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"appImage": {
|
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
|
||||||
},
|
|
||||||
"rpm": {
|
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
|
||||||
},
|
|
||||||
"freebsd": {
|
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
|
||||||
},
|
|
||||||
"snap": {
|
|
||||||
"autoStart": true,
|
|
||||||
"confinement": "strict",
|
|
||||||
"plugs": [
|
|
||||||
"default",
|
|
||||||
"password-manager-service"
|
|
||||||
],
|
|
||||||
"stagePackages": [
|
|
||||||
"default"
|
|
||||||
],
|
|
||||||
"publish": [
|
|
||||||
"github"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"protocols": [
|
|
||||||
{
|
|
||||||
"name": "Bitwarden",
|
|
||||||
"schemes": [
|
|
||||||
"bitwarden"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/compiler-cli": "^12.2.13",
|
"@angular/compiler-cli": "^12.2.13",
|
||||||
"@ngtools/webpack": "^12.2.13",
|
"@ngtools/webpack": "^12.2.13",
|
||||||
|
@ -307,12 +114,16 @@
|
||||||
"@bitwarden/jslib-angular": "file:jslib/angular",
|
"@bitwarden/jslib-angular": "file:jslib/angular",
|
||||||
"@bitwarden/jslib-common": "file:jslib/common",
|
"@bitwarden/jslib-common": "file:jslib/common",
|
||||||
"@bitwarden/jslib-electron": "file:jslib/electron",
|
"@bitwarden/jslib-electron": "file:jslib/electron",
|
||||||
|
"@nodert-win10-rs4/windows.security.credentials.ui": "^0.4.4",
|
||||||
|
"forcefocus": "^1.1.0",
|
||||||
|
"keytar": "^7.9.0",
|
||||||
"ngx-toastr": "14.1.4",
|
"ngx-toastr": "14.1.4",
|
||||||
"node-ipc": "^9.1.4",
|
"node-ipc": "^9.1.4",
|
||||||
"nord": "^0.2.1",
|
"nord": "^0.2.1",
|
||||||
"regedit": "^3.0.3",
|
"regedit": "^3.0.3",
|
||||||
"rxjs": "^7.4.0",
|
"rxjs": "^7.4.0",
|
||||||
"sweetalert2": "^10.16.6"
|
"sweetalert2": "^10.16.6",
|
||||||
|
"zone.js": "0.11.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "~16",
|
"node": "~16",
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button appBlurClick type="submit" class="primary" appA11yTitle="{{ 'save' | i18n }}">
|
<button type="submit" class="primary" appA11yTitle="{{ 'save' | i18n }}">
|
||||||
<i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i>
|
<i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
|
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="submit" class="btn primary block" [disabled]="form.loading" appBlurClick>
|
<button type="submit" class="btn primary block" [disabled]="form.loading">
|
||||||
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
|
<button type="button" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -30,12 +30,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
|
@ -45,7 +43,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,17 +57,16 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn block"
|
class="btn block"
|
||||||
[ngClass]="{ 'primary font-weight-bold': hideInput }"
|
[ngClass]="{ 'primary font-weight-bold': hideInput }"
|
||||||
appBlurClick
|
|
||||||
(click)="unlockBiometric()"
|
(click)="unlockBiometric()"
|
||||||
>
|
>
|
||||||
{{ biometricText | i18n }}
|
{{ biometricText | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons-row">
|
<div class="buttons-row">
|
||||||
<button type="submit" class="btn primary block" appBlurClick *ngIf="!hideInput">
|
<button type="submit" class="btn primary block" *ngIf="!hideInput">
|
||||||
<i class="bwi bwi-unlock" aria-hidden="true"></i> <b>{{ "unlock" | i18n }}</b>
|
<i class="bwi bwi-unlock" aria-hidden="true"></i> <b>{{ "unlock" | i18n }}</b>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn block" appBlurClick (click)="logOut()">
|
<button type="button" class="btn block" (click)="logOut()">
|
||||||
{{ "logOut" | i18n }}
|
{{ "logOut" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div id="login-page">
|
<div id="login-page">
|
||||||
<div class="login-header">
|
<div class="login-header">
|
||||||
<a
|
<button
|
||||||
href="#"
|
type="button"
|
||||||
appStopClick
|
appStopClick
|
||||||
(click)="settings()"
|
(click)="settings()"
|
||||||
class="environment-urls-settings-icon"
|
class="environment-urls-settings-icon"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
|
||||||
{{ "settings" | i18n }}
|
{{ "settings" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<form
|
<form
|
||||||
id="login-page"
|
id="login-page"
|
||||||
|
@ -48,12 +48,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
|
@ -63,7 +61,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,24 +75,28 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons with-rows">
|
<div class="buttons with-rows">
|
||||||
<div class="buttons-row">
|
<div class="buttons-row">
|
||||||
<button type="submit" class="btn primary block" [disabled]="form.loading" appBlurClick>
|
<button type="submit" class="btn primary block" [disabled]="form.loading">
|
||||||
<b [hidden]="form.loading"
|
<b [hidden]="form.loading"
|
||||||
><i class="bwi bwi-sign-in" aria-hidden="true"></i> {{ "logIn" | i18n }}</b
|
><i class="bwi bwi-sign-in" aria-hidden="true"></i> {{ "logIn" | i18n }}</b
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<a routerLink="/register" class="btn block">
|
<button type="button" routerLink="/register" class="btn block">
|
||||||
<i class="bwi bwi-pencil-square" aria-hidden="true"></i> {{ "createAccount" | i18n }}
|
<i class="bwi bwi-pencil-square" aria-hidden="true"></i> {{ "createAccount" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons-row">
|
<div class="buttons-row">
|
||||||
<a (click)="launchSsoBrowser('desktop', 'bitwarden://sso-callback')" class="btn block">
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="launchSsoBrowser('desktop', 'bitwarden://sso-callback')"
|
||||||
|
class="btn block"
|
||||||
|
>
|
||||||
<i class="bwi bwi-bank" aria-hidden="true"></i> {{ "enterpriseSingleSignOn" | i18n }}
|
<i class="bwi bwi-bank" aria-hidden="true"></i> {{ "enterpriseSingleSignOn" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sub-options">
|
<div class="sub-options">
|
||||||
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
|
<button type="button" routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -48,14 +48,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="primary" appBlurClick (click)="manage()" *ngIf="isPremium">
|
<button type="button" class="primary" (click)="manage()" *ngIf="isPremium">
|
||||||
<b>{{ "premiumManage" | i18n }}</b>
|
<b>{{ "premiumManage" | i18n }}</b>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
#purchaseBtn
|
#purchaseBtn
|
||||||
type="button"
|
type="button"
|
||||||
class="primary"
|
class="primary"
|
||||||
appBlurClick
|
|
||||||
(click)="purchase()"
|
(click)="purchase()"
|
||||||
*ngIf="!isPremium"
|
*ngIf="!isPremium"
|
||||||
[disabled]="purchaseBtn.loading"
|
[disabled]="purchaseBtn.loading"
|
||||||
|
@ -67,7 +66,6 @@
|
||||||
<button
|
<button
|
||||||
#refreshBtn
|
#refreshBtn
|
||||||
type="button"
|
type="button"
|
||||||
appBlurClick
|
|
||||||
(click)="refresh()"
|
(click)="refresh()"
|
||||||
[disabled]="refreshBtn.loading"
|
[disabled]="refreshBtn.loading"
|
||||||
appA11yTitle="{{ 'premiumRefresh' | i18n }}"
|
appA11yTitle="{{ 'premiumRefresh' | i18n }}"
|
||||||
|
|
|
@ -40,12 +40,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(false)"
|
(click)="togglePassword(false)"
|
||||||
|
@ -55,7 +53,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
@ -91,12 +89,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(true)"
|
(click)="togglePassword(true)"
|
||||||
|
@ -106,7 +102,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
|
@ -142,11 +138,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="submit" class="btn primary block" [disabled]="form.loading" appBlurClick>
|
<button type="submit" class="btn primary block" [disabled]="form.loading">
|
||||||
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
|
<button type="button" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn primary block"
|
class="btn primary block"
|
||||||
[disabled]="actionPromise"
|
[disabled]="actionPromise"
|
||||||
appBlurClick
|
|
||||||
(click)="convert()"
|
(click)="convert()"
|
||||||
>
|
>
|
||||||
<b [hidden]="continuing">{{ "removeMasterPassword" | i18n }}</b>
|
<b [hidden]="continuing">{{ "removeMasterPassword" | i18n }}</b>
|
||||||
|
@ -17,7 +16,6 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn secondary block"
|
class="btn secondary block"
|
||||||
[disabled]="actionPromise"
|
[disabled]="actionPromise"
|
||||||
appBlurClick
|
|
||||||
(click)="leave()"
|
(click)="leave()"
|
||||||
>
|
>
|
||||||
<b [hidden]="leaving">{{ "leaveOrganization" | i18n }}</b>
|
<b [hidden]="leaving">{{ "leaveOrganization" | i18n }}</b>
|
||||||
|
|
|
@ -56,12 +56,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(false)"
|
(click)="togglePassword(false)"
|
||||||
|
@ -71,7 +69,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
@ -109,12 +107,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(true)"
|
(click)="togglePassword(true)"
|
||||||
|
@ -124,7 +120,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
{{ "twoStepOptions" | i18n }}
|
{{ "twoStepOptions" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<a
|
<button
|
||||||
href="#"
|
type="button"
|
||||||
appStopClick
|
appStopClick
|
||||||
*ngFor="let p of providers"
|
*ngFor="let p of providers"
|
||||||
class="box-content-row"
|
class="box-content-row"
|
||||||
|
@ -17,11 +17,11 @@
|
||||||
<img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="img-right" />
|
<img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="img-right" />
|
||||||
<span class="text">{{ p.name }}</span>
|
<span class="text">{{ p.name }}</span>
|
||||||
<span class="detail">{{ p.description }}</span>
|
<span class="detail">{{ p.description }}</span>
|
||||||
</a>
|
</button>
|
||||||
<a href="#" appStopClick class="box-content-row" (click)="recover()">
|
<button type="button" appStopClick class="box-content-row" (click)="recover()">
|
||||||
<span class="text">{{ "recoveryCodeTitle" | i18n }}</span>
|
<span class="text">{{ "recoveryCodeTitle" | i18n }}</span>
|
||||||
<span class="detail">{{ "recoveryCodeDesc" | i18n }}</span>
|
<span class="detail">{{ "recoveryCodeDesc" | i18n }}</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -112,7 +112,6 @@
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn primary block"
|
class="btn primary block"
|
||||||
[disabled]="form.loading"
|
[disabled]="form.loading"
|
||||||
appBlurClick
|
|
||||||
*ngIf="
|
*ngIf="
|
||||||
selectedProviderType != null &&
|
selectedProviderType != null &&
|
||||||
selectedProviderType !== providerType.Duo &&
|
selectedProviderType !== providerType.Duo &&
|
||||||
|
@ -124,22 +123,21 @@
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
|
<button type="button" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="sub-options">
|
<div class="sub-options">
|
||||||
<a href="#" appStopClick (click)="anotherMethod()" role="button">{{
|
<button type="button" appStopClick (click)="anotherMethod()">
|
||||||
"useAnotherTwoStepMethod" | i18n
|
{{ "useAnotherTwoStepMethod" | i18n }}
|
||||||
}}</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
href="#"
|
type="button"
|
||||||
appStopClick
|
appStopClick
|
||||||
(click)="sendEmail(true)"
|
(click)="sendEmail(true)"
|
||||||
[appApiAction]="emailPromise"
|
[appApiAction]="emailPromise"
|
||||||
role="button"
|
|
||||||
*ngIf="selectedProviderType === providerType.Email"
|
*ngIf="selectedProviderType === providerType.Email"
|
||||||
>
|
>
|
||||||
{{ "sendVerificationCodeEmailAgain" | i18n }}
|
{{ "sendVerificationCodeEmailAgain" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component";
|
import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component";
|
||||||
import { ModalService } from "jslib-angular/services/modal.service";
|
import { ModalService } from "jslib-angular/services/modal.service";
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
|
import { AppIdService } from "jslib-common/abstractions/appId.service";
|
||||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
@ -38,7 +39,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
twoFactorService: TwoFactorService
|
twoFactorService: TwoFactorService,
|
||||||
|
appIdService: AppIdService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
authService,
|
authService,
|
||||||
|
@ -51,7 +53,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||||
stateService,
|
stateService,
|
||||||
route,
|
route,
|
||||||
logService,
|
logService,
|
||||||
twoFactorService
|
twoFactorService,
|
||||||
|
appIdService
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = () => {
|
super.onSuccessfulLogin = () => {
|
||||||
return syncService.fullSync(true);
|
return syncService.fullSync(true);
|
||||||
|
|
|
@ -36,12 +36,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(false)"
|
(click)="togglePassword(false)"
|
||||||
|
@ -51,7 +49,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
@ -84,12 +82,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword(true)"
|
(click)="togglePassword(true)"
|
||||||
|
@ -99,7 +95,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -116,11 +112,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="submit" class="btn primary block" [disabled]="form.loading" appBlurClick>
|
<button type="submit" class="btn primary block" [disabled]="form.loading">
|
||||||
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<a (click)="logOut()" class="btn block">{{ "logOut" | i18n }}</a>
|
<button type="button" (click)="logOut()" class="btn block">{{ "logOut" | i18n }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -35,9 +35,10 @@ import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
import { SystemService } from "jslib-common/abstractions/system.service";
|
import { SystemService } from "jslib-common/abstractions/system.service";
|
||||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
import { AuthenticationStatus } from "jslib-common/enums/authenticationStatus";
|
||||||
import { CipherType } from "jslib-common/enums/cipherType";
|
import { CipherType } from "jslib-common/enums/cipherType";
|
||||||
|
|
||||||
import { MenuUpdateRequest } from "src/main/menu.updater";
|
import { MenuUpdateRequest } from "../main/menu/menu.updater";
|
||||||
|
|
||||||
import { PremiumComponent } from "./accounts/premium.component";
|
import { PremiumComponent } from "./accounts/premium.component";
|
||||||
import { SettingsComponent } from "./accounts/settings.component";
|
import { SettingsComponent } from "./accounts/settings.component";
|
||||||
|
@ -330,7 +331,9 @@ export class AppComponent implements OnInit {
|
||||||
if (message.userId != null) {
|
if (message.userId != null) {
|
||||||
await this.stateService.setActiveUser(message.userId);
|
await this.stateService.setActiveUser(message.userId);
|
||||||
}
|
}
|
||||||
const locked = await this.vaultTimeoutService.isLocked(message.userId);
|
const locked =
|
||||||
|
(await this.authService.getAuthStatus(message.userId)) ===
|
||||||
|
AuthenticationStatus.Locked;
|
||||||
if (locked) {
|
if (locked) {
|
||||||
this.messagingService.send("locked", { userId: message.userId });
|
this.messagingService.send("locked", { userId: message.userId });
|
||||||
} else {
|
} else {
|
||||||
|
@ -436,7 +439,8 @@ export class AppComponent implements OnInit {
|
||||||
isAuthenticated: await this.stateService.getIsAuthenticated({
|
isAuthenticated: await this.stateService.getIsAuthenticated({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
}),
|
}),
|
||||||
isLocked: await this.vaultTimeoutService.isLocked(userId),
|
isLocked:
|
||||||
|
(await this.authService.getAuthStatus(userId)) === AuthenticationStatus.Locked,
|
||||||
email: stateAccounts[i].profile.email,
|
email: stateAccounts[i].profile.email,
|
||||||
userId: stateAccounts[i].profile.userId,
|
userId: stateAccounts[i].profile.userId,
|
||||||
};
|
};
|
||||||
|
@ -591,7 +595,7 @@ export class AppComponent implements OnInit {
|
||||||
const keys = Object.keys(accounts);
|
const keys = Object.keys(accounts);
|
||||||
if (keys.length > 0) {
|
if (keys.length > 0) {
|
||||||
for (const userId of keys) {
|
for (const userId of keys) {
|
||||||
if (!(await this.vaultTimeoutService.isLocked(userId))) {
|
if ((await this.authService.getAuthStatus(userId)) === AuthenticationStatus.Unlocked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ import { AppRoutingModule } from "./app-routing.module";
|
||||||
import { AppComponent } from "./app.component";
|
import { AppComponent } from "./app.component";
|
||||||
import { PasswordRepromptComponent } from "./components/password-reprompt.component";
|
import { PasswordRepromptComponent } from "./components/password-reprompt.component";
|
||||||
import { SetPinComponent } from "./components/set-pin.component";
|
import { SetPinComponent } from "./components/set-pin.component";
|
||||||
import { VerifyMasterPasswordComponent } from "./components/verify-master-password.component";
|
import { UserVerificationComponent } from "./components/user-verification.component";
|
||||||
import { AccountSwitcherComponent } from "./layout/account-switcher.component";
|
import { AccountSwitcherComponent } from "./layout/account-switcher.component";
|
||||||
import { HeaderComponent } from "./layout/header.component";
|
import { HeaderComponent } from "./layout/header.component";
|
||||||
import { NavComponent } from "./layout/nav.component";
|
import { NavComponent } from "./layout/nav.component";
|
||||||
|
@ -91,7 +91,7 @@ import { SearchComponent } from "./layout/search/search.component";
|
||||||
import { AddEditComponent as SendAddEditComponent } from "./send/add-edit.component";
|
import { AddEditComponent as SendAddEditComponent } from "./send/add-edit.component";
|
||||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component";
|
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component";
|
||||||
import { SendComponent } from "./send/send.component";
|
import { SendComponent } from "./send/send.component";
|
||||||
import { ServicesModule } from "./services.module";
|
import { ServicesModule } from "./services/services.module";
|
||||||
import { AddEditCustomFieldsComponent } from "./vault/add-edit-custom-fields.component";
|
import { AddEditCustomFieldsComponent } from "./vault/add-edit-custom-fields.component";
|
||||||
import { AddEditComponent } from "./vault/add-edit.component";
|
import { AddEditComponent } from "./vault/add-edit.component";
|
||||||
import { AttachmentsComponent } from "./vault/attachments.component";
|
import { AttachmentsComponent } from "./vault/attachments.component";
|
||||||
|
@ -212,9 +212,9 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||||
TwoFactorComponent,
|
TwoFactorComponent,
|
||||||
TwoFactorOptionsComponent,
|
TwoFactorOptionsComponent,
|
||||||
UpdateTempPasswordComponent,
|
UpdateTempPasswordComponent,
|
||||||
|
UserVerificationComponent,
|
||||||
VaultComponent,
|
VaultComponent,
|
||||||
VaultTimeoutInputComponent,
|
VaultTimeoutInputComponent,
|
||||||
VerifyMasterPasswordComponent,
|
|
||||||
ViewComponent,
|
ViewComponent,
|
||||||
ViewCustomFieldsComponent,
|
ViewCustomFieldsComponent,
|
||||||
],
|
],
|
||||||
|
|
|
@ -19,12 +19,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
|
@ -34,7 +32,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<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>
|
<span>{{ "ok" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
||||||
|
|
|
@ -22,11 +22,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPin"
|
[attr.aria-pressed]="showPin"
|
||||||
(click)="toggleVisibility()"
|
(click)="toggleVisibility()"
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPin, 'bwi-eye-slash': showPin }"
|
[ngClass]="{ 'bwi-eye': !showPin, 'bwi-eye-slash': showPin }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { animate, style, transition, trigger } from "@angular/animations";
|
||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { NG_VALUE_ACCESSOR } from "@angular/forms";
|
import { NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||||
|
|
||||||
import { VerifyMasterPasswordComponent as BaseComponent } from "jslib-angular/components/verify-master-password.component";
|
import { UserVerificationComponent as BaseComponent } from "jslib-angular/components/user-verification.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-verify-master-password",
|
selector: "app-user-verification",
|
||||||
templateUrl: "verify-master-password.component.html",
|
templateUrl: "user-verification.component.html",
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
multi: true,
|
multi: true,
|
||||||
useExisting: VerifyMasterPasswordComponent,
|
useExisting: UserVerificationComponent,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
animations: [
|
animations: [
|
||||||
|
@ -20,4 +20,4 @@ import { VerifyMasterPasswordComponent as BaseComponent } from "jslib-angular/co
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class VerifyMasterPasswordComponent extends BaseComponent {}
|
export class UserVerificationComponent extends BaseComponent {}
|
|
@ -53,7 +53,6 @@
|
||||||
<button
|
<button
|
||||||
*ngFor="let a of accounts | keyvalue"
|
*ngFor="let a of accounts | keyvalue"
|
||||||
class="account"
|
class="account"
|
||||||
[ngClass]="{ active: a.value.profile.authenticationStatus == 'active' }"
|
|
||||||
(click)="switch(a.key)"
|
(click)="switch(a.key)"
|
||||||
appA11yTitle="{{ 'loggedInAsOn' | i18n: a.value.profile.email:a.value.serverUrl }}"
|
appA11yTitle="{{ 'loggedInAsOn' | i18n: a.value.profile.email:a.value.serverUrl }}"
|
||||||
attr.aria-label="{{ 'switchAccount' | i18n }}"
|
attr.aria-label="{{ 'switchAccount' | i18n }}"
|
||||||
|
@ -72,17 +71,17 @@
|
||||||
<span class="server" aria-hidden="true" *ngIf="a.value.serverUrl != 'bitwarden.com'">{{
|
<span class="server" aria-hidden="true" *ngIf="a.value.serverUrl != 'bitwarden.com'">{{
|
||||||
a.value.serverUrl
|
a.value.serverUrl
|
||||||
}}</span>
|
}}</span>
|
||||||
<span class="status" aria-hidden="true">{{ a.value.profile.authenticationStatus }}</span>
|
<span class="status" aria-hidden="true">{{
|
||||||
|
(a.value.profile.authenticationStatus === authStatus.Unlocked ? "unlocked" : "locked")
|
||||||
|
| i18n
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-unlock bwi-2x text-muted"
|
class="bwi bwi-2x text-muted"
|
||||||
|
[ngClass]="
|
||||||
|
a.value.profile.authenticationStatus == authStatus.Unlocked ? 'bwi-unlock' : 'bwi-lock'
|
||||||
|
"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
*ngIf="a.value.profile.authenticationStatus == 'unlocked'"
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lock bwi-2x text-muted"
|
|
||||||
aria-hidden="true"
|
|
||||||
*ngIf="a.value.profile.authenticationStatus == 'locked'"
|
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { animate, state, style, transition, trigger } from "@angular/animations"
|
||||||
import { ConnectedPosition } from "@angular/cdk/overlay";
|
import { ConnectedPosition } from "@angular/cdk/overlay";
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
|
||||||
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
|
||||||
import { AuthenticationStatus } from "jslib-common/enums/authenticationStatus";
|
import { AuthenticationStatus } from "jslib-common/enums/authenticationStatus";
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
import { Account } from "jslib-common/models/domain/account";
|
import { Account } from "jslib-common/models/domain/account";
|
||||||
|
@ -53,6 +53,7 @@ export class AccountSwitcherComponent implements OnInit {
|
||||||
accounts: { [userId: string]: SwitcherAccount } = {};
|
accounts: { [userId: string]: SwitcherAccount } = {};
|
||||||
activeAccountEmail: string;
|
activeAccountEmail: string;
|
||||||
serverUrl: string;
|
serverUrl: string;
|
||||||
|
authStatus = AuthenticationStatus;
|
||||||
overlayPostition: ConnectedPosition[] = [
|
overlayPostition: ConnectedPosition[] = [
|
||||||
{
|
{
|
||||||
originX: "end",
|
originX: "end",
|
||||||
|
@ -78,22 +79,16 @@ export class AccountSwitcherComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
private authService: AuthService,
|
||||||
private messagingService: MessagingService
|
private messagingService: MessagingService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
this.stateService.accounts.subscribe(async (accounts) => {
|
this.stateService.accounts.subscribe(async (accounts: { [userId: string]: Account }) => {
|
||||||
for (const userId in accounts) {
|
for (const userId in accounts) {
|
||||||
if (userId === (await this.stateService.getUserId())) {
|
accounts[userId].profile.authenticationStatus = await this.authService.getAuthStatus(
|
||||||
accounts[userId].profile.authenticationStatus = AuthenticationStatus.Active;
|
userId
|
||||||
} else {
|
);
|
||||||
accounts[userId].profile.authenticationStatus = (await this.vaultTimeoutService.isLocked(
|
|
||||||
userId
|
|
||||||
))
|
|
||||||
? AuthenticationStatus.Locked
|
|
||||||
: AuthenticationStatus.Unlocked;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.accounts = await this.createSwitcherAccounts(accounts);
|
this.accounts = await this.createSwitcherAccounts(accounts);
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
<ng-container *ngFor="let item of items">
|
<ng-container *ngFor="let item of items">
|
||||||
<a [routerLink]="item.link" class="btn primary" routerLinkActive="active" [title]="item.label">
|
<button
|
||||||
|
type="button"
|
||||||
|
[routerLink]="item.link"
|
||||||
|
class="btn primary"
|
||||||
|
routerLinkActive="active"
|
||||||
|
[title]="item.label"
|
||||||
|
#rla="routerLinkActive"
|
||||||
|
[attr.aria-pressed]="rla.isActive"
|
||||||
|
>
|
||||||
<i class="bwi" [ngClass]="item.icon"></i>{{ item.label }}
|
<i class="bwi" [ngClass]="item.icon"></i>{{ item.label }}
|
||||||
</a>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
|
@ -93,21 +93,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
{{ "options" | i18n }}
|
<button
|
||||||
<a
|
type="button"
|
||||||
class="toggle"
|
class="toggle"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
(click)="toggleOptions()"
|
(click)="toggleOptions()"
|
||||||
|
[attr.aria-expanded]="showOptions"
|
||||||
>
|
>
|
||||||
|
{{ "options" | i18n }}
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }"
|
[ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div [hidden]="!showOptions">
|
<div [hidden]="!showOptions">
|
||||||
|
@ -157,12 +156,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePasswordVisible()"
|
(click)="togglePasswordVisible()"
|
||||||
|
@ -173,7 +170,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -254,7 +251,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary btn-submit"
|
class="primary btn-submit"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
@ -264,12 +260,11 @@
|
||||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||||
<span><i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i></span>
|
<span><i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button appBlurClick type="button" (click)="cancel()" [disabled]="form.loading">
|
<button type="button" (click)="cancel()" [disabled]="form.loading">
|
||||||
{{ "cancel" | i18n }}
|
{{ "cancel" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="copyLinkToClipboard(link)"
|
(click)="copyLinkToClipboard(link)"
|
||||||
appA11yTitle="{{ 'copySendLinkToClipboard' | i18n }}"
|
appA11yTitle="{{ 'copySendLinkToClipboard' | i18n }}"
|
||||||
|
@ -279,7 +274,6 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
#deleteBtn
|
#deleteBtn
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="delete()"
|
(click)="delete()"
|
||||||
class="danger"
|
class="danger"
|
||||||
|
|
|
@ -5,26 +5,41 @@
|
||||||
<h2 class="sr-only">{{ "filters" | i18n }}</h2>
|
<h2 class="sr-only">{{ "filters" | i18n }}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li [ngClass]="{ active: selectedAll }">
|
<li [ngClass]="{ active: selectedAll }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectAll()">
|
<button
|
||||||
|
type="button"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectAll()"
|
||||||
|
[attr.aria-pressed]="selectedAll"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i> {{ "allSends" | i18n }}
|
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i> {{ "allSends" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>{{ "types" | i18n }}</h2>
|
<h2>{{ "types" | i18n }}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li [ngClass]="{ active: selectedType === sendType.Text }">
|
<li [ngClass]="{ active: selectedType === sendType.Text }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.Text)">
|
<button
|
||||||
|
type="button"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(sendType.Text)"
|
||||||
|
[attr.aria-pressed]="selectedType === sendType.Text"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i> {{
|
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i> {{
|
||||||
"sendTypeText" | i18n
|
"sendTypeText" | i18n
|
||||||
}}
|
}}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedType === sendType.File }">
|
<li [ngClass]="{ active: selectedType === sendType.File }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.File)">
|
<button
|
||||||
|
type="button"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(sendType.File)"
|
||||||
|
[attr.aria-pressed]="selectedType === sendType.File"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-file" aria-hidden="true"></i> {{
|
<i class="bwi bwi-fw bwi-file" aria-hidden="true"></i> {{
|
||||||
"sendTypeFile" | i18n
|
"sendTypeFile" | i18n
|
||||||
}}
|
}}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,20 +51,21 @@
|
||||||
<div id="items" class="items">
|
<div id="items" class="items">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="list" *ngIf="filteredSends.length">
|
<div class="list" *ngIf="filteredSends.length">
|
||||||
<a
|
<button
|
||||||
*ngFor="let s of filteredSends"
|
*ngFor="let s of filteredSends"
|
||||||
appStopClick
|
appStopClick
|
||||||
(click)="selectSend(s.id)"
|
(click)="selectSend(s.id)"
|
||||||
title="{{ 'viewItem' | i18n }}"
|
title="{{ 'viewItem' | i18n }}"
|
||||||
(contextmenu)="viewSendMenu(s)"
|
(contextmenu)="viewSendMenu(s)"
|
||||||
[ngClass]="{ active: s.id === sendId }"
|
[ngClass]="{ active: s.id === sendId }"
|
||||||
|
[attr.aria-pressed]="s.id === sendId"
|
||||||
class="flex-list-item"
|
class="flex-list-item"
|
||||||
>
|
>
|
||||||
<div class="item-icon" aria-hidden="true">
|
<span class="item-icon" aria-hidden="true">
|
||||||
<i class="bwi bwi-fw bwi-lg" [ngClass]="s.type == 0 ? 'bwi-file-text' : 'bwi-file'"></i>
|
<i class="bwi bwi-fw bwi-lg" [ngClass]="s.type == 0 ? 'bwi-file-text' : 'bwi-file'"></i>
|
||||||
</div>
|
</span>
|
||||||
<div class="item-content">
|
<span class="item-content">
|
||||||
<div class="item-title">
|
<span class="item-title">
|
||||||
{{ s.name }}
|
{{ s.name }}
|
||||||
<span class="title-badges">
|
<span class="title-badges">
|
||||||
<ng-container *ngIf="s.disabled">
|
<ng-container *ngIf="s.disabled">
|
||||||
|
@ -98,10 +114,10 @@
|
||||||
<span class="sr-only">{{ "pendingDeletion" | i18n }}</span>
|
<span class="sr-only">{{ "pendingDeletion" | i18n }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</span>
|
||||||
<span class="item-details">{{ s.deletionDate | date }}</span>
|
<span class="item-details">{{ s.deletionDate | date }}</span>
|
||||||
</div>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="no-items" *ngIf="!filteredSends.length">
|
<div class="no-items" *ngIf="!filteredSends.length">
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
||||||
|
@ -112,12 +128,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button
|
<button (click)="addSend()" class="block primary" appA11yTitle="{{ 'addItem' | i18n }}">
|
||||||
appBlurClick
|
|
||||||
(click)="addSend()"
|
|
||||||
class="block primary"
|
|
||||||
appA11yTitle="{{ 'addItem' | i18n }}"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-plus bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-plus bwi-lg" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,211 +0,0 @@
|
||||||
import { APP_INITIALIZER, NgModule } from "@angular/core";
|
|
||||||
|
|
||||||
import { JslibServicesModule } from "jslib-angular/services/jslib-services.module";
|
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "jslib-common/abstractions/broadcaster.service";
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service";
|
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service";
|
|
||||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service";
|
|
||||||
import { EventService as EventServiceAbstraction } from "jslib-common/abstractions/event.service";
|
|
||||||
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
|
|
||||||
import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service";
|
|
||||||
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
|
|
||||||
import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service";
|
|
||||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
|
|
||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
|
|
||||||
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
|
||||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
|
|
||||||
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
|
||||||
import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
|
|
||||||
import { SystemService as SystemServiceAbstraction } from "jslib-common/abstractions/system.service";
|
|
||||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
|
|
||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
|
|
||||||
import { ThemeType } from "jslib-common/enums/themeType";
|
|
||||||
import { StateFactory } from "jslib-common/factories/stateFactory";
|
|
||||||
import { GlobalState } from "jslib-common/models/domain/globalState";
|
|
||||||
import { ContainerService } from "jslib-common/services/container.service";
|
|
||||||
import { EventService } from "jslib-common/services/event.service";
|
|
||||||
import { StateMigrationService } from "jslib-common/services/stateMigration.service";
|
|
||||||
import { SystemService } from "jslib-common/services/system.service";
|
|
||||||
import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service";
|
|
||||||
import { ElectronCryptoService } from "jslib-electron/services/electronCrypto.service";
|
|
||||||
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
|
|
||||||
import { ElectronPlatformUtilsService } from "jslib-electron/services/electronPlatformUtils.service";
|
|
||||||
import { ElectronRendererMessagingService } from "jslib-electron/services/electronRendererMessaging.service";
|
|
||||||
import { ElectronRendererSecureStorageService } from "jslib-electron/services/electronRendererSecureStorage.service";
|
|
||||||
import { ElectronRendererStorageService } from "jslib-electron/services/electronRendererStorage.service";
|
|
||||||
|
|
||||||
import { Account } from "../models/account";
|
|
||||||
import { I18nService } from "../services/i18n.service";
|
|
||||||
import { LoginGuardService } from "../services/loginGuard.service";
|
|
||||||
import { NativeMessagingService } from "../services/nativeMessaging.service";
|
|
||||||
import { PasswordRepromptService } from "../services/passwordReprompt.service";
|
|
||||||
import { StateService } from "../services/state.service";
|
|
||||||
|
|
||||||
import { SearchBarService } from "./layout/search/search-bar.service";
|
|
||||||
|
|
||||||
export function initFactory(
|
|
||||||
window: Window,
|
|
||||||
environmentService: EnvironmentServiceAbstraction,
|
|
||||||
syncService: SyncServiceAbstraction,
|
|
||||||
vaultTimeoutService: VaultTimeoutService,
|
|
||||||
i18nService: I18nService,
|
|
||||||
eventService: EventService,
|
|
||||||
twoFactorService: TwoFactorServiceAbstraction,
|
|
||||||
notificationsService: NotificationsServiceAbstraction,
|
|
||||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
|
||||||
stateService: StateServiceAbstraction,
|
|
||||||
cryptoService: CryptoServiceAbstraction,
|
|
||||||
nativeMessagingService: NativeMessagingService
|
|
||||||
): () => Promise<void> {
|
|
||||||
return async () => {
|
|
||||||
nativeMessagingService.init();
|
|
||||||
await stateService.init();
|
|
||||||
await environmentService.setUrlsFromStorage();
|
|
||||||
syncService.fullSync(true);
|
|
||||||
await vaultTimeoutService.init(true);
|
|
||||||
const locale = await stateService.getLocale();
|
|
||||||
await i18nService.init(locale);
|
|
||||||
eventService.init(true);
|
|
||||||
twoFactorService.init();
|
|
||||||
setTimeout(() => notificationsService.init(), 3000);
|
|
||||||
const htmlEl = window.document.documentElement;
|
|
||||||
htmlEl.classList.add("os_" + platformUtilsService.getDeviceString());
|
|
||||||
htmlEl.classList.add("locale_" + i18nService.translationLocale);
|
|
||||||
const theme = await platformUtilsService.getEffectiveTheme();
|
|
||||||
htmlEl.classList.add("theme_" + theme);
|
|
||||||
platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
|
|
||||||
const bwTheme = await stateService.getTheme();
|
|
||||||
if (bwTheme == null || bwTheme === ThemeType.System) {
|
|
||||||
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
|
|
||||||
htmlEl.classList.add("theme_" + sysTheme);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let installAction = null;
|
|
||||||
const installedVersion = await stateService.getInstalledVersion();
|
|
||||||
const currentVersion = await platformUtilsService.getApplicationVersion();
|
|
||||||
if (installedVersion == null) {
|
|
||||||
installAction = "install";
|
|
||||||
} else if (installedVersion !== currentVersion) {
|
|
||||||
installAction = "update";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installAction != null) {
|
|
||||||
await stateService.setInstalledVersion(currentVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
const containerService = new ContainerService(cryptoService);
|
|
||||||
containerService.attachToGlobal(window);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [JslibServicesModule],
|
|
||||||
declarations: [],
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: APP_INITIALIZER,
|
|
||||||
useFactory: initFactory,
|
|
||||||
deps: [
|
|
||||||
"WINDOW",
|
|
||||||
EnvironmentServiceAbstraction,
|
|
||||||
SyncServiceAbstraction,
|
|
||||||
VaultTimeoutServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
EventServiceAbstraction,
|
|
||||||
TwoFactorServiceAbstraction,
|
|
||||||
NotificationsServiceAbstraction,
|
|
||||||
PlatformUtilsServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
NativeMessagingService,
|
|
||||||
],
|
|
||||||
multi: true,
|
|
||||||
},
|
|
||||||
{ provide: LogServiceAbstraction, useClass: ElectronLogService, deps: [] },
|
|
||||||
{
|
|
||||||
provide: PlatformUtilsServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
i18nService: I18nServiceAbstraction,
|
|
||||||
messagingService: MessagingServiceAbstraction,
|
|
||||||
stateService: StateServiceAbstraction
|
|
||||||
) => new ElectronPlatformUtilsService(i18nService, messagingService, true, stateService),
|
|
||||||
deps: [I18nServiceAbstraction, MessagingServiceAbstraction, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: I18nServiceAbstraction,
|
|
||||||
useFactory: (window: Window) => new I18nService(window.navigator.language, "./locales"),
|
|
||||||
deps: ["WINDOW"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: MessagingServiceAbstraction,
|
|
||||||
useClass: ElectronRendererMessagingService,
|
|
||||||
deps: [BroadcasterServiceAbstraction],
|
|
||||||
},
|
|
||||||
{ provide: StorageServiceAbstraction, useClass: ElectronRendererStorageService },
|
|
||||||
{ provide: "SECURE_STORAGE", useClass: ElectronRendererSecureStorageService },
|
|
||||||
{
|
|
||||||
provide: CryptoServiceAbstraction,
|
|
||||||
useClass: ElectronCryptoService,
|
|
||||||
deps: [
|
|
||||||
CryptoFunctionServiceAbstraction,
|
|
||||||
PlatformUtilsServiceAbstraction,
|
|
||||||
LogServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: SystemServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
messagingService: MessagingServiceAbstraction,
|
|
||||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
|
||||||
stateService: StateServiceAbstraction
|
|
||||||
) => new SystemService(messagingService, platformUtilsService, null, stateService),
|
|
||||||
deps: [MessagingServiceAbstraction, PlatformUtilsServiceAbstraction, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
|
||||||
NativeMessagingService,
|
|
||||||
SearchBarService,
|
|
||||||
{
|
|
||||||
provide: LoginGuardService,
|
|
||||||
useClass: LoginGuardService,
|
|
||||||
deps: [StateServiceAbstraction, PlatformUtilsServiceAbstraction, I18nServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: StateServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
storageService: StorageServiceAbstraction,
|
|
||||||
secureStorageService: StorageServiceAbstraction,
|
|
||||||
logService: LogServiceAbstraction,
|
|
||||||
stateMigrationService: StateMigrationServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new StateService(
|
|
||||||
storageService,
|
|
||||||
secureStorageService,
|
|
||||||
logService,
|
|
||||||
stateMigrationService,
|
|
||||||
new StateFactory(GlobalState, Account)
|
|
||||||
),
|
|
||||||
deps: [
|
|
||||||
StorageServiceAbstraction,
|
|
||||||
"SECURE_STORAGE",
|
|
||||||
LogServiceAbstraction,
|
|
||||||
StateMigrationServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: StateMigrationServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
storageService: StorageServiceAbstraction,
|
|
||||||
secureStorageService: StorageServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new StateMigrationService(
|
|
||||||
storageService,
|
|
||||||
secureStorageService,
|
|
||||||
new StateFactory(GlobalState, Account)
|
|
||||||
),
|
|
||||||
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class ServicesModule {}
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { Inject, Injectable } from "@angular/core";
|
||||||
|
|
||||||
|
import { WINDOW } from "jslib-angular/services/jslib-services.module";
|
||||||
|
import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service";
|
||||||
|
import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service";
|
||||||
|
import { EventService as EventServiceAbstraction } from "jslib-common/abstractions/event.service";
|
||||||
|
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
|
||||||
|
import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service";
|
||||||
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
||||||
|
import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
|
||||||
|
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
|
||||||
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
import { ThemeType } from "jslib-common/enums/themeType";
|
||||||
|
import { ContainerService } from "jslib-common/services/container.service";
|
||||||
|
import { EventService } from "jslib-common/services/event.service";
|
||||||
|
import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service";
|
||||||
|
|
||||||
|
import { I18nService } from "../../services/i18n.service";
|
||||||
|
import { NativeMessagingService } from "../../services/nativeMessaging.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class InitService {
|
||||||
|
constructor(
|
||||||
|
@Inject(WINDOW) private win: Window,
|
||||||
|
private environmentService: EnvironmentServiceAbstraction,
|
||||||
|
private syncService: SyncServiceAbstraction,
|
||||||
|
private vaultTimeoutService: VaultTimeoutServiceAbstraction,
|
||||||
|
private i18nService: I18nServiceAbstraction,
|
||||||
|
private eventService: EventServiceAbstraction,
|
||||||
|
private twoFactorService: TwoFactorServiceAbstraction,
|
||||||
|
private notificationsService: NotificationsServiceAbstraction,
|
||||||
|
private platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||||
|
private stateService: StateServiceAbstraction,
|
||||||
|
private cryptoService: CryptoServiceAbstraction,
|
||||||
|
private nativeMessagingService: NativeMessagingService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
return async () => {
|
||||||
|
this.nativeMessagingService.init();
|
||||||
|
await this.stateService.init();
|
||||||
|
await this.environmentService.setUrlsFromStorage();
|
||||||
|
this.syncService.fullSync(true);
|
||||||
|
(this.vaultTimeoutService as VaultTimeoutService).init(true);
|
||||||
|
const locale = await this.stateService.getLocale();
|
||||||
|
await (this.i18nService as I18nService).init(locale);
|
||||||
|
(this.eventService as EventService).init(true);
|
||||||
|
this.twoFactorService.init();
|
||||||
|
setTimeout(() => this.notificationsService.init(), 3000);
|
||||||
|
const htmlEl = this.win.document.documentElement;
|
||||||
|
htmlEl.classList.add("os_" + this.platformUtilsService.getDeviceString());
|
||||||
|
|
||||||
|
const theme = await this.platformUtilsService.getEffectiveTheme();
|
||||||
|
htmlEl.classList.add("theme_" + theme);
|
||||||
|
this.platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
|
||||||
|
const bwTheme = await this.stateService.getTheme();
|
||||||
|
if (bwTheme == null || bwTheme === ThemeType.System) {
|
||||||
|
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
|
||||||
|
htmlEl.classList.add("theme_" + sysTheme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let installAction = null;
|
||||||
|
const installedVersion = await this.stateService.getInstalledVersion();
|
||||||
|
const currentVersion = await this.platformUtilsService.getApplicationVersion();
|
||||||
|
if (installedVersion == null) {
|
||||||
|
installAction = "install";
|
||||||
|
} else if (installedVersion !== currentVersion) {
|
||||||
|
installAction = "update";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (installAction != null) {
|
||||||
|
await this.stateService.setInstalledVersion(currentVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerService = new ContainerService(this.cryptoService);
|
||||||
|
containerService.attachToGlobal(this.win);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import {
|
||||||
|
JslibServicesModule,
|
||||||
|
SECURE_STORAGE,
|
||||||
|
STATE_FACTORY,
|
||||||
|
STATE_SERVICE_USE_CACHE,
|
||||||
|
WINDOW,
|
||||||
|
CLIENT_TYPE,
|
||||||
|
LOCALES_DIRECTORY,
|
||||||
|
SYSTEM_LANGUAGE,
|
||||||
|
} from "jslib-angular/services/jslib-services.module";
|
||||||
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "jslib-common/abstractions/broadcaster.service";
|
||||||
|
import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service";
|
||||||
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
|
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
|
||||||
|
import {
|
||||||
|
LogService,
|
||||||
|
LogService as LogServiceAbstraction,
|
||||||
|
} from "jslib-common/abstractions/log.service";
|
||||||
|
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
|
||||||
|
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
|
||||||
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
||||||
|
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
|
||||||
|
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||||
|
import { SystemService as SystemServiceAbstraction } from "jslib-common/abstractions/system.service";
|
||||||
|
import { ClientType } from "jslib-common/enums/clientType";
|
||||||
|
import { StateFactory } from "jslib-common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "jslib-common/models/domain/globalState";
|
||||||
|
import { SystemService } from "jslib-common/services/system.service";
|
||||||
|
import { ElectronCryptoService } from "jslib-electron/services/electronCrypto.service";
|
||||||
|
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
|
||||||
|
import { ElectronPlatformUtilsService } from "jslib-electron/services/electronPlatformUtils.service";
|
||||||
|
import { ElectronRendererMessagingService } from "jslib-electron/services/electronRendererMessaging.service";
|
||||||
|
import { ElectronRendererSecureStorageService } from "jslib-electron/services/electronRendererSecureStorage.service";
|
||||||
|
import { ElectronRendererStorageService } from "jslib-electron/services/electronRendererStorage.service";
|
||||||
|
|
||||||
|
import { Account } from "../../models/account";
|
||||||
|
import { I18nService } from "../../services/i18n.service";
|
||||||
|
import { LoginGuardService } from "../../services/loginGuard.service";
|
||||||
|
import { NativeMessagingService } from "../../services/nativeMessaging.service";
|
||||||
|
import { PasswordRepromptService } from "../../services/passwordReprompt.service";
|
||||||
|
import { StateService } from "../../services/state.service";
|
||||||
|
import { SearchBarService } from "../layout/search/search-bar.service";
|
||||||
|
|
||||||
|
import { InitService } from "./init.service";
|
||||||
|
|
||||||
|
const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [JslibServicesModule],
|
||||||
|
declarations: [],
|
||||||
|
providers: [
|
||||||
|
InitService,
|
||||||
|
NativeMessagingService,
|
||||||
|
SearchBarService,
|
||||||
|
LoginGuardService,
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: (initService: InitService) => initService.init(),
|
||||||
|
deps: [InitService],
|
||||||
|
multi: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: STATE_FACTORY,
|
||||||
|
useValue: new StateFactory(GlobalState, Account),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: CLIENT_TYPE,
|
||||||
|
useValue: ClientType.Desktop,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: RELOAD_CALLBACK,
|
||||||
|
useValue: null,
|
||||||
|
},
|
||||||
|
{ provide: LogServiceAbstraction, useClass: ElectronLogService, deps: [] },
|
||||||
|
{
|
||||||
|
provide: PlatformUtilsServiceAbstraction,
|
||||||
|
useClass: ElectronPlatformUtilsService,
|
||||||
|
deps: [
|
||||||
|
I18nServiceAbstraction,
|
||||||
|
MessagingServiceAbstraction,
|
||||||
|
CLIENT_TYPE,
|
||||||
|
StateServiceAbstraction,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: I18nServiceAbstraction,
|
||||||
|
useClass: I18nService,
|
||||||
|
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: MessagingServiceAbstraction,
|
||||||
|
useClass: ElectronRendererMessagingService,
|
||||||
|
deps: [BroadcasterServiceAbstraction],
|
||||||
|
},
|
||||||
|
{ provide: StorageServiceAbstraction, useClass: ElectronRendererStorageService },
|
||||||
|
{ provide: SECURE_STORAGE, useClass: ElectronRendererSecureStorageService },
|
||||||
|
{
|
||||||
|
provide: CryptoServiceAbstraction,
|
||||||
|
useClass: ElectronCryptoService,
|
||||||
|
deps: [
|
||||||
|
CryptoFunctionServiceAbstraction,
|
||||||
|
PlatformUtilsServiceAbstraction,
|
||||||
|
LogServiceAbstraction,
|
||||||
|
StateServiceAbstraction,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: SystemServiceAbstraction,
|
||||||
|
useClass: SystemService,
|
||||||
|
deps: [
|
||||||
|
MessagingServiceAbstraction,
|
||||||
|
PlatformUtilsServiceAbstraction,
|
||||||
|
RELOAD_CALLBACK,
|
||||||
|
StateServiceAbstraction,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
||||||
|
{
|
||||||
|
provide: StateServiceAbstraction,
|
||||||
|
useClass: StateService,
|
||||||
|
deps: [
|
||||||
|
StorageServiceAbstraction,
|
||||||
|
SECURE_STORAGE,
|
||||||
|
LogService,
|
||||||
|
StateMigrationServiceAbstraction,
|
||||||
|
STATE_FACTORY,
|
||||||
|
STATE_SERVICE_USE_CACHE,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ServicesModule {}
|
|
@ -10,15 +10,14 @@
|
||||||
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
|
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
|
||||||
[ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }"
|
[ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
href="#"
|
type="button"
|
||||||
appStopClick
|
appStopClick
|
||||||
(click)="removeField(f)"
|
(click)="removeField(f)"
|
||||||
appA11yTitle="{{ 'remove' | i18n }}"
|
appA11yTitle="{{ 'remove' | i18n }}"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
<label for="fieldName{{ i }}" class="sr-only">{{ "name" | i18n }}</label>
|
<label for="fieldName{{ i }}" class="sr-only">{{ "name" | i18n }}</label>
|
||||||
<label for="fieldValue{{ i }}" class="sr-only">{{ "value" | i18n }}</label>
|
<label for="fieldValue{{ i }}" class="sr-only">{{ "value" | i18n }}</label>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
@ -78,12 +77,10 @@
|
||||||
class="action-buttons"
|
class="action-buttons"
|
||||||
*ngIf="f.type === fieldType.Hidden && (cipher.viewPassword || f.newField)"
|
*ngIf="f.type === fieldType.Hidden && (cipher.viewPassword || f.newField)"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="f.showValue"
|
[attr.aria-pressed]="f.showValue"
|
||||||
(click)="toggleFieldValue(f)"
|
(click)="toggleFieldValue(f)"
|
||||||
|
@ -93,7 +90,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !f.showValue, 'bwi-eye-slash': f.showValue }"
|
[ngClass]="{ 'bwi-eye': !f.showValue, 'bwi-eye-slash': f.showValue }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="drag-handle" appA11yTitle="{{ 'dragToSort' | i18n }}" cdkDragHandle>
|
<div class="drag-handle" appA11yTitle="{{ 'dragToSort' | i18n }}" cdkDragHandle>
|
||||||
<i class="bwi bwi-hamburger" aria-hidden="true"></i>
|
<i class="bwi bwi-hamburger" aria-hidden="true"></i>
|
||||||
|
@ -102,10 +99,10 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- Add new custom field -->
|
<!-- Add new custom field -->
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<a href="#" appStopClick (click)="addField()" role="button">
|
<button type="button" appStopClick (click)="addField()">
|
||||||
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
|
||||||
{{ "newCustomField" | i18n }}
|
{{ "newCustomField" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
<label for="addFieldType" class="sr-only">{{ "type" | i18n }}</label>
|
<label for="addFieldType" class="sr-only">{{ "type" | i18n }}</label>
|
||||||
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
|
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
|
||||||
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{ o.name }}</option>
|
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{ o.name }}</option>
|
||||||
|
|
|
@ -39,17 +39,15 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'generateUsername' | i18n }}"
|
appA11yTitle="{{ 'generateUsername' | i18n }}"
|
||||||
(click)="generateUsername()"
|
(click)="generateUsername()"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||||
|
@ -70,7 +68,6 @@
|
||||||
type="button"
|
type="button"
|
||||||
#checkPasswordBtn
|
#checkPasswordBtn
|
||||||
class="row-btn btn"
|
class="row-btn btn"
|
||||||
appBlurClick
|
|
||||||
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
||||||
(click)="checkPassword()"
|
(click)="checkPassword()"
|
||||||
[appApiAction]="checkPasswordPromise"
|
[appApiAction]="checkPasswordPromise"
|
||||||
|
@ -87,12 +84,10 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
|
@ -102,18 +97,16 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'generatePassword' | i18n }}"
|
appA11yTitle="{{ 'generatePassword' | i18n }}"
|
||||||
(click)="generatePassword()"
|
(click)="generatePassword()"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
|
@ -153,12 +146,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showCardNumber"
|
[attr.aria-pressed]="showCardNumber"
|
||||||
(click)="toggleCardNumber()"
|
(click)="toggleCardNumber()"
|
||||||
|
@ -168,7 +159,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
|
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
|
@ -208,12 +199,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showCardCode"
|
[attr.aria-pressed]="showCardCode"
|
||||||
(click)="toggleCardCode()"
|
(click)="toggleCardCode()"
|
||||||
|
@ -223,7 +212,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
|
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -406,9 +395,14 @@
|
||||||
appBoxRow
|
appBoxRow
|
||||||
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
|
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
|
||||||
>
|
>
|
||||||
<a href="#" appStopClick (click)="removeUri(u)" appA11yTitle="{{ 'remove' | i18n }}">
|
<button
|
||||||
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true" role="button"></i>
|
type="button"
|
||||||
</a>
|
appStopClick
|
||||||
|
(click)="removeUri(u)"
|
||||||
|
appA11yTitle="{{ 'remove' | i18n }}"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label>
|
<label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label>
|
||||||
<input
|
<input
|
||||||
|
@ -435,31 +429,25 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'toggleOptions' | i18n }}"
|
appA11yTitle="{{ 'toggleOptions' | i18n }}"
|
||||||
(click)="toggleUriOptions(u)"
|
(click)="toggleUriOptions(u)"
|
||||||
|
[attr.aria-expanded]="
|
||||||
|
!(u.showOptions === false || (u.showOptions == null && u.match == null))
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<a
|
<button type="button" appStopClick (click)="addUri()" class="box-content-row">
|
||||||
href="#"
|
|
||||||
appStopClick
|
|
||||||
appBlurClick
|
|
||||||
(click)="addUri()"
|
|
||||||
class="box-content-row"
|
|
||||||
role="button"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
|
||||||
{{ "newUri" | i18n }}
|
{{ "newUri" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
@ -477,9 +465,13 @@
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="canUseReprompt">
|
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="canUseReprompt">
|
||||||
<label for="passwordPrompt"
|
<label for="passwordPrompt"
|
||||||
>{{ "passwordPrompt" | i18n }}
|
>{{ "passwordPrompt" | i18n }}
|
||||||
<a href="#" appA11yTitle="{{ 'learnMore' | i18n }}" (click)="openHelpReprompt()">
|
<button
|
||||||
|
type="button"
|
||||||
|
appA11yTitle="{{ 'learnMore' | i18n }}"
|
||||||
|
(click)="openHelpReprompt()"
|
||||||
|
>
|
||||||
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
|
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="passwordPrompt"
|
id="passwordPrompt"
|
||||||
|
@ -489,30 +481,26 @@
|
||||||
(change)="repromptChanged()"
|
(change)="repromptChanged()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="box-content-row box-content-row-flex text-default"
|
class="box-content-row box-content-row-flex text-default"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
(click)="attachments()"
|
(click)="attachments()"
|
||||||
*ngIf="editMode && !cloneMode"
|
*ngIf="editMode && !cloneMode"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<div class="row-main">{{ "attachments" | i18n }}</div>
|
<div class="row-main">{{ "attachments" | i18n }}</div>
|
||||||
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
|
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="box-content-row box-content-row-flex text-default"
|
class="box-content-row box-content-row-flex text-default"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
(click)="editCollections()"
|
(click)="editCollections()"
|
||||||
*ngIf="editMode && !cloneMode && cipher.organizationId"
|
*ngIf="editMode && !cloneMode && cipher.organizationId"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<div class="row-main">{{ "collections" | i18n }}</div>
|
<div class="row-main">{{ "collections" | i18n }}</div>
|
||||||
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
|
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
@ -577,7 +565,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
@ -590,12 +577,11 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
<button appBlurClick type="button" (click)="cancel()">
|
<button type="button" (click)="cancel()">
|
||||||
{{ "cancel" | i18n }}
|
{{ "cancel" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="share()"
|
(click)="share()"
|
||||||
appA11yTitle="{{ 'moveToOrganization' | i18n }}"
|
appA11yTitle="{{ 'moveToOrganization' | i18n }}"
|
||||||
|
@ -605,7 +591,6 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
#deleteBtn
|
#deleteBtn
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="delete()"
|
(click)="delete()"
|
||||||
class="danger"
|
class="danger"
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
class="row-btn btn"
|
class="row-btn btn"
|
||||||
type="button"
|
type="button"
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
appA11yTitle="{{ 'delete' | i18n }}"
|
appA11yTitle="{{ 'delete' | i18n }}"
|
||||||
(click)="delete(a)"
|
(click)="delete(a)"
|
||||||
#deleteBtn
|
#deleteBtn
|
||||||
|
@ -56,7 +55,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
*ngIf="ciphers.length"
|
*ngIf="ciphers.length"
|
||||||
>
|
>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
*cdkVirtualFor="let c of ciphers; trackBy: trackByFn"
|
*cdkVirtualFor="let c of ciphers; trackBy: trackByFn"
|
||||||
appStopClick
|
appStopClick
|
||||||
(click)="selectCipher(c)"
|
(click)="selectCipher(c)"
|
||||||
(contextmenu)="rightClickCipher(c)"
|
(contextmenu)="rightClickCipher(c)"
|
||||||
href="#"
|
|
||||||
title="{{ 'viewItem' | i18n }}"
|
title="{{ 'viewItem' | i18n }}"
|
||||||
[ngClass]="{ active: c.id === activeCipherId }"
|
[ngClass]="{ active: c.id === activeCipherId }"
|
||||||
|
[attr.aria-pressed]="c.id === activeCipherId"
|
||||||
class="flex-list-item virtual-scroll-item"
|
class="flex-list-item virtual-scroll-item"
|
||||||
>
|
>
|
||||||
<app-vault-icon [cipher]="c"></app-vault-icon>
|
<app-vault-icon [cipher]="c"></app-vault-icon>
|
||||||
|
@ -39,7 +40,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="c.subTitle" class="detail">{{ c.subTitle }}</span>
|
<span *ngIf="c.subTitle" class="detail">{{ c.subTitle }}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</cdk-virtual-scroll-viewport>
|
</cdk-virtual-scroll-viewport>
|
||||||
<div class="no-items" *ngIf="!ciphers.length">
|
<div class="no-items" *ngIf="!ciphers.length">
|
||||||
|
@ -53,7 +54,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
(click)="addCipher()"
|
(click)="addCipher()"
|
||||||
(contextmenu)="addCipherOptions()"
|
(contextmenu)="addCipherOptions()"
|
||||||
class="block primary"
|
class="block primary"
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
<option *ngFor="let f of formatOptions" [value]="f.value">{{ f.name }}</option>
|
<option *ngFor="let f of formatOptions" [value]="f.value">{{ f.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<app-verify-master-password ngDefaultControl formControlName="secret" name="secret">
|
<app-user-verification ngDefaultControl formControlName="secret" name="secret">
|
||||||
</app-verify-master-password>
|
</app-user-verification>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
<p>{{ "confirmIdentity" | i18n }}</p>
|
<p>{{ "confirmIdentity" | i18n }}</p>
|
||||||
|
@ -31,7 +31,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'submit' | i18n }}"
|
appA11yTitle="{{ 'submit' | i18n }}"
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
@ -43,7 +42,6 @@
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button
|
<button
|
||||||
#deleteBtn
|
#deleteBtn
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="delete()"
|
(click)="delete()"
|
||||||
class="danger"
|
class="danger"
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="generated-block" *ngIf="type === 'username'">
|
<div class="generated-block" *ngIf="type === 'username'">
|
||||||
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
|
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons" #form [appApiAction]="usernameGeneratingPromise">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="icon-btn primary"
|
class="icon-btn primary"
|
||||||
|
@ -57,15 +57,26 @@
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
|
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
|
||||||
(click)="regenerate()"
|
(click)="regenerate()"
|
||||||
|
[disabled]="form.loading"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
<i
|
||||||
|
class="bwi bwi-lg bwi-generate"
|
||||||
|
[ngClass]="form.loading ? 'bwi-spin' : ''"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-content condensed">
|
<div class="box-content condensed">
|
||||||
<div class="box-content-row box-content-row-radio">
|
<div
|
||||||
<label class="radio-header">{{ "whatWouldYouLikeToGenerate" | i18n }}</label>
|
class="box-content-row box-content-row-radio"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-labelledby="typeHeading"
|
||||||
|
>
|
||||||
|
<label id="typeHeading" class="radio-header">{{
|
||||||
|
"whatWouldYouLikeToGenerate" | i18n
|
||||||
|
}}</label>
|
||||||
<div
|
<div
|
||||||
class="radio-group text-default"
|
class="radio-group text-default"
|
||||||
appBoxRow
|
appBoxRow
|
||||||
|
@ -76,12 +87,12 @@
|
||||||
type="radio"
|
type="radio"
|
||||||
class="radio"
|
class="radio"
|
||||||
[(ngModel)]="type"
|
[(ngModel)]="type"
|
||||||
name="Type_{{ o.value }}"
|
name="Type"
|
||||||
id="type_{{ o.value }}"
|
id="type_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="typeChanged()"
|
(change)="typeChanged()"
|
||||||
[checked]="type === o.value"
|
[checked]="type === o.value"
|
||||||
[disabled]="comingFromAddEdit"
|
[disabled]="comingFromAddEdit && type !== o.value"
|
||||||
/>
|
/>
|
||||||
<label class="unstyled" for="type_{{ o.value }}">
|
<label class="unstyled" for="type_{{ o.value }}">
|
||||||
{{ o.name }}
|
{{ o.name }}
|
||||||
|
@ -105,8 +116,14 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content condensed" [hidden]="!showOptions">
|
<div class="box-content condensed" [hidden]="!showOptions">
|
||||||
<div class="box-content-row box-content-row-radio">
|
<div
|
||||||
<label class="radio-header">{{ "passwordType" | i18n }}</label>
|
class="box-content-row box-content-row-radio"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-labelledby="passwordTypeHeading"
|
||||||
|
>
|
||||||
|
<label id="passwordTypeHeading" class="radio-header">{{
|
||||||
|
"passwordType" | i18n
|
||||||
|
}}</label>
|
||||||
<div
|
<div
|
||||||
class="radio-group text-default"
|
class="radio-group text-default"
|
||||||
appBoxRow
|
appBoxRow
|
||||||
|
@ -117,7 +134,7 @@
|
||||||
type="radio"
|
type="radio"
|
||||||
class="radio"
|
class="radio"
|
||||||
[(ngModel)]="passwordOptions.type"
|
[(ngModel)]="passwordOptions.type"
|
||||||
name="PasswordType_{{ o.value }}"
|
name="PasswordType"
|
||||||
id="passwordType_{{ o.value }}"
|
id="passwordType_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="savePasswordOptions()"
|
(change)="savePasswordOptions()"
|
||||||
|
@ -209,6 +226,7 @@
|
||||||
(change)="savePasswordOptions()"
|
(change)="savePasswordOptions()"
|
||||||
[disabled]="enforcedPasswordPolicyOptions?.useUppercase"
|
[disabled]="enforcedPasswordPolicyOptions?.useUppercase"
|
||||||
[(ngModel)]="passwordOptions.uppercase"
|
[(ngModel)]="passwordOptions.uppercase"
|
||||||
|
attr.aria-label="{{ 'uppercase' | i18n }}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
@ -219,6 +237,7 @@
|
||||||
(change)="savePasswordOptions()"
|
(change)="savePasswordOptions()"
|
||||||
[disabled]="enforcedPasswordPolicyOptions?.useLowercase"
|
[disabled]="enforcedPasswordPolicyOptions?.useLowercase"
|
||||||
[(ngModel)]="passwordOptions.lowercase"
|
[(ngModel)]="passwordOptions.lowercase"
|
||||||
|
attr.aria-label="{{ 'lowercase' | i18n }}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
@ -229,6 +248,7 @@
|
||||||
(change)="savePasswordOptions()"
|
(change)="savePasswordOptions()"
|
||||||
[disabled]="enforcedPasswordPolicyOptions?.useNumbers"
|
[disabled]="enforcedPasswordPolicyOptions?.useNumbers"
|
||||||
[(ngModel)]="passwordOptions.number"
|
[(ngModel)]="passwordOptions.number"
|
||||||
|
attr.aria-label="{{ 'numbers' | i18n }}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
@ -239,6 +259,7 @@
|
||||||
(change)="savePasswordOptions()"
|
(change)="savePasswordOptions()"
|
||||||
[disabled]="enforcedPasswordPolicyOptions?.useSpecial"
|
[disabled]="enforcedPasswordPolicyOptions?.useSpecial"
|
||||||
[(ngModel)]="passwordOptions.special"
|
[(ngModel)]="passwordOptions.special"
|
||||||
|
attr.aria-label="{{ 'specialCharacters' | i18n }}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -295,13 +316,16 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content condensed" [hidden]="!showOptions">
|
<div class="box-content condensed" [hidden]="!showOptions">
|
||||||
<div class="box-content-row box-content-row-radio">
|
<div
|
||||||
<label class="radio-header">
|
class="box-content-row box-content-row-radio"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-labelledby="usernameTypeHeading"
|
||||||
|
>
|
||||||
|
<label id="usernameTypeHeading" class="radio-header">
|
||||||
{{ "usernameType" | i18n }}
|
{{ "usernameType" | i18n }}
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
(click)="usernameTypesLearnMore()"
|
(click)="usernameTypesLearnMore()"
|
||||||
appA11yTitle="{{ 'learnMore' | i18n }}"
|
appA11yTitle="{{ 'learnMore' | i18n }}"
|
||||||
>
|
>
|
||||||
|
@ -318,7 +342,7 @@
|
||||||
type="radio"
|
type="radio"
|
||||||
class="radio"
|
class="radio"
|
||||||
[(ngModel)]="usernameOptions.type"
|
[(ngModel)]="usernameOptions.type"
|
||||||
name="UsernameType_{{ o.value }}"
|
name="UsernameType"
|
||||||
id="usernameType_{{ o.value }}"
|
id="usernameType_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="saveUsernameOptions()"
|
(change)="saveUsernameOptions()"
|
||||||
|
@ -334,13 +358,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="usernameOptions.type === 'forwarded'" [hidden]="!showOptions">
|
<div class="box" *ngIf="usernameOptions.type === 'forwarded'" [hidden]="!showOptions">
|
||||||
<div class="box-content condensed">
|
<div class="box-content condensed">
|
||||||
<div class="box-content-row">
|
<div class="box-content-row" role="radiogroup" aria-labelledby="forwardTypeHeading">
|
||||||
<label class="radio-header">{{ "service" | i18n }}</label>
|
<label id="forwardTypeHeading" class="radio-header">{{ "service" | i18n }}</label>
|
||||||
<div class="radio-group text-default" appBoxRow *ngFor="let o of forwardOptions">
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of forwardOptions">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
[(ngModel)]="usernameOptions.forwardedService"
|
[(ngModel)]="usernameOptions.forwardedService"
|
||||||
name="ForwardType_{{ o.value }}"
|
name="ForwardType"
|
||||||
id="forwardtype_{{ o.value }}"
|
id="forwardtype_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="saveUsernameOptions()"
|
(change)="saveUsernameOptions()"
|
||||||
|
@ -351,6 +375,62 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ng-container *ngIf="usernameOptions.forwardedService === 'simplelogin'">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="simplelogin-apikey">{{ "apiKey" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="simplelogin-apikey"
|
||||||
|
type="password"
|
||||||
|
name="SimpleLoginApiKey"
|
||||||
|
[(ngModel)]="usernameOptions.forwardedSimpleLoginApiKey"
|
||||||
|
(blur)="saveUsernameOptions()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="simplelogin-hostname">{{ "hostname" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="simplelogin-hostname"
|
||||||
|
type="text"
|
||||||
|
name="SimpleLoginHostname"
|
||||||
|
[(ngModel)]="usernameOptions.forwardedSimpleLoginHostname"
|
||||||
|
(blur)="saveUsernameOptions()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="usernameOptions.forwardedService === 'anonaddy'">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="anonaddy-accessToken">{{ "apiAccessToken" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="anonaddy-accessToken"
|
||||||
|
type="password"
|
||||||
|
name="AnonAddyAccessToken"
|
||||||
|
[(ngModel)]="usernameOptions.forwardedAnonAddyApiToken"
|
||||||
|
(blur)="saveUsernameOptions()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="anonaddy-domain">{{ "domainName" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="anonaddy-domain"
|
||||||
|
type="text"
|
||||||
|
name="AnonAddyDomain"
|
||||||
|
[(ngModel)]="usernameOptions.forwardedAnonAddyDomain"
|
||||||
|
(blur)="saveUsernameOptions()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="usernameOptions.forwardedService === 'firefoxrelay'">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="firefox-apikey">{{ "apiAccessToken" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="firefox-apikey"
|
||||||
|
type="password"
|
||||||
|
name="FirefoxApiKey"
|
||||||
|
[(ngModel)]="usernameOptions.forwardedFirefoxApiToken"
|
||||||
|
(blur)="saveUsernameOptions()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="usernameOptions.type === 'subaddress'" [hidden]="!showOptions">
|
<div class="box" *ngIf="usernameOptions.type === 'subaddress'" [hidden]="!showOptions">
|
||||||
|
@ -365,13 +445,18 @@
|
||||||
(blur)="saveUsernameOptions()"
|
(blur)="saveUsernameOptions()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" *ngIf="subaddressOptions.length > 1">
|
<div
|
||||||
<label class="radio-header">{{ "type" | i18n }}</label>
|
class="box-content-row"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-labelledby="subaddressTypeHeading"
|
||||||
|
*ngIf="subaddressOptions.length > 1"
|
||||||
|
>
|
||||||
|
<label id="subaddressTypeHeading" class="radio-header">{{ "type" | i18n }}</label>
|
||||||
<div class="radio-group text-default" appBoxRow *ngFor="let o of subaddressOptions">
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of subaddressOptions">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
[(ngModel)]="usernameOptions.subaddressType"
|
[(ngModel)]="usernameOptions.subaddressType"
|
||||||
name="SubaddressType_{{ o.value }}"
|
name="SubaddressType"
|
||||||
id="subaddresstype_{{ o.value }}"
|
id="subaddresstype_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="saveUsernameOptions()"
|
(change)="saveUsernameOptions()"
|
||||||
|
@ -407,13 +492,18 @@
|
||||||
(blur)="saveUsernameOptions()"
|
(blur)="saveUsernameOptions()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" *ngIf="catchallOptions.length > 1">
|
<div
|
||||||
<label class="radio-header">{{ "type" | i18n }}</label>
|
class="box-content-row"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-labelledby="catchallTypeHeading"
|
||||||
|
*ngIf="catchallOptions.length > 1"
|
||||||
|
>
|
||||||
|
<label id="catchallTypeHeading" class="radio-header">{{ "type" | i18n }}</label>
|
||||||
<div class="radio-group text-default" appBoxRow *ngFor="let o of catchallOptions">
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of catchallOptions">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
[(ngModel)]="usernameOptions.catchallType"
|
[(ngModel)]="usernameOptions.catchallType"
|
||||||
name="CatchallType_{{ o.value }}"
|
name="CatchallType"
|
||||||
id="catchalltype_{{ o.value }}"
|
id="catchalltype_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="saveUsernameOptions()"
|
(change)="saveUsernameOptions()"
|
||||||
|
@ -465,7 +555,6 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="primary"
|
class="primary"
|
||||||
appBlurClick
|
|
||||||
*ngIf="comingFromAddEdit"
|
*ngIf="comingFromAddEdit"
|
||||||
(click)="select()"
|
(click)="select()"
|
||||||
appA11yTitle="{{ 'select' | i18n }}"
|
appA11yTitle="{{ 'select' | i18n }}"
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
import { GeneratorComponent as BaseGeneratorComponent } from "jslib-angular/components/generator.component";
|
import { GeneratorComponent as BaseGeneratorComponent } from "jslib-angular/components/generator.component";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
@ -19,7 +20,8 @@ export class GeneratorComponent extends BaseGeneratorComponent {
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
route: ActivatedRoute
|
route: ActivatedRoute,
|
||||||
|
logService: LogService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
passwordGenerationService,
|
passwordGenerationService,
|
||||||
|
@ -27,6 +29,7 @@ export class GeneratorComponent extends BaseGeneratorComponent {
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
stateService,
|
stateService,
|
||||||
i18nService,
|
i18nService,
|
||||||
|
logService,
|
||||||
route,
|
route,
|
||||||
window
|
window
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,51 +3,81 @@
|
||||||
<h2 class="sr-only">{{ "filters" | i18n }}</h2>
|
<h2 class="sr-only">{{ "filters" | i18n }}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li [ngClass]="{ active: selectedAll }">
|
<li [ngClass]="{ active: selectedAll }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectAll()">
|
<button type="button" [attr.aria-pressed]="selectedAll" appStopClick (click)="selectAll()">
|
||||||
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i> {{ "allItems" | i18n }}
|
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i> {{ "allItems" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedFavorites }">
|
<li [ngClass]="{ active: selectedFavorites }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectFavorites()">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedFavorites"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectFavorites()"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-star" aria-hidden="true"></i> {{ "favorites" | i18n }}
|
<i class="bwi bwi-fw bwi-star" aria-hidden="true"></i> {{ "favorites" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedTrash }">
|
<li [ngClass]="{ active: selectedTrash }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectTrash()">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedTrash"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectTrash()"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i> {{ "trash" | i18n }}
|
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i> {{ "trash" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>{{ "types" | i18n }}</h2>
|
<h2>{{ "types" | i18n }}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li [ngClass]="{ active: selectedType === cipherType.Login }">
|
<li [ngClass]="{ active: selectedType === cipherType.Login }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Login)">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedType === cipherType.Login"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(cipherType.Login)"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i> {{ "typeLogin" | i18n }}
|
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i> {{ "typeLogin" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedType === cipherType.Card }">
|
<li [ngClass]="{ active: selectedType === cipherType.Card }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Card)">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedType === cipherType.Card"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(cipherType.Card)"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i> {{ "typeCard" | i18n }}
|
<i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i> {{ "typeCard" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedType === cipherType.Identity }">
|
<li [ngClass]="{ active: selectedType === cipherType.Identity }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Identity)">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedType === cipherType.Identity"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(cipherType.Identity)"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i> {{ "typeIdentity" | i18n }}
|
<i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i> {{ "typeIdentity" | i18n }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li [ngClass]="{ active: selectedType === cipherType.SecureNote }">
|
<li [ngClass]="{ active: selectedType === cipherType.SecureNote }">
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.SecureNote)">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedType === cipherType.SecureNote"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectType(cipherType.SecureNote)"
|
||||||
|
>
|
||||||
<i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i> {{
|
<i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i> {{
|
||||||
"typeSecureNote" | i18n
|
"typeSecureNote" | i18n
|
||||||
}}
|
}}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p *ngIf="!loaded" class="text-muted">{{ "loading" | i18n }}</p>
|
<p *ngIf="!loaded" class="text-muted">{{ "loading" | i18n }}</p>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<h2>{{ "folders" | i18n }}</h2>
|
<h2>{{ "folders" | i18n }}</h2>
|
||||||
<button appBlurClick (click)="addFolder()" appA11yTitle="{{ 'addFolder' | i18n }}">
|
<button (click)="addFolder()" appA11yTitle="{{ 'addFolder' | i18n }}">
|
||||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,7 +87,12 @@
|
||||||
*ngFor="let f of folders"
|
*ngFor="let f of folders"
|
||||||
[ngClass]="{ active: selectedFolder && f.node.id === selectedFolderId }"
|
[ngClass]="{ active: selectedFolder && f.node.id === selectedFolderId }"
|
||||||
>
|
>
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectFolder(f.node)">
|
<button
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="selectedFolder && f.node.id === selectedFolderId"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectFolder(f.node)"
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
*ngIf="f.children.length"
|
*ngIf="f.children.length"
|
||||||
class="bwi bwi-fw"
|
class="bwi bwi-fw"
|
||||||
|
@ -86,7 +121,7 @@
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-pencil bwi-fw" aria-hidden="true"></i>
|
<i class="bwi bwi-pencil bwi-fw" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
<ul class="bwi-ul" *ngIf="f.children.length && !isCollapsed(f.node)">
|
<ul class="bwi-ul" *ngIf="f.children.length && !isCollapsed(f.node)">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="recursiveFolders; context: { $implicit: f.children }"
|
*ngTemplateOutlet="recursiveFolders; context: { $implicit: f.children }"
|
||||||
|
@ -107,7 +142,13 @@
|
||||||
*ngFor="let c of collections"
|
*ngFor="let c of collections"
|
||||||
[ngClass]="{ active: c.node.id === selectedCollectionId }"
|
[ngClass]="{ active: c.node.id === selectedCollectionId }"
|
||||||
>
|
>
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectCollection(c.node)">
|
<button
|
||||||
|
*ngIf="c.children.length == 0"
|
||||||
|
type="button"
|
||||||
|
[attr.aria-pressed]="c.node.id === selectedCollectionId"
|
||||||
|
appStopClick
|
||||||
|
(click)="selectCollection(c.node)"
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
*ngIf="c.children.length"
|
*ngIf="c.children.length"
|
||||||
class="bwi bwi-fw"
|
class="bwi bwi-fw"
|
||||||
|
@ -126,7 +167,7 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
{{ c.node.name }}
|
{{ c.node.name }}
|
||||||
</a>
|
</button>
|
||||||
<ul class="bwi-ul" *ngIf="c.children.length && !isCollapsed(c.node)">
|
<ul class="bwi-ul" *ngIf="c.children.length && !isCollapsed(c.node)">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="recursiveCollections; context: { $implicit: c.children }"
|
*ngTemplateOutlet="recursiveCollections; context: { $implicit: c.children }"
|
||||||
|
|
|
@ -17,16 +17,15 @@
|
||||||
<span class="detail">{{ h.date | date: "medium" }}</span>
|
<span class="detail">{{ h.date | date: "medium" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
||||||
(click)="copy(h.password)"
|
(click)="copy(h.password)"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" *ngIf="!history.length">
|
<div class="box-content-row" *ngIf="!history.length">
|
||||||
|
@ -39,7 +38,6 @@
|
||||||
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
|
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="clear()"
|
(click)="clear()"
|
||||||
class="danger"
|
class="danger"
|
||||||
|
|
|
@ -15,16 +15,15 @@
|
||||||
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
||||||
(click)="copy(h.password)"
|
(click)="copy(h.password)"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" *ngIf="!history.length">
|
<div class="box-content-row" *ngIf="!history.length">
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="submit"
|
type="submit"
|
||||||
class="primary"
|
class="primary"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
|
|
|
@ -35,24 +35,23 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
*ngIf="field.type === fieldType.Hidden && cipher.viewPassword"
|
*ngIf="field.type === fieldType.Hidden && cipher.viewPassword"
|
||||||
(click)="toggleFieldValue(field)"
|
(click)="toggleFieldValue(field)"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !field.showValue, 'bwi-eye-slash': field.showValue }"
|
[ngClass]="{ 'bwi-eye': !field.showValue, 'bwi-eye-slash': field.showValue }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyValue' | i18n }}"
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
*ngIf="
|
*ngIf="
|
||||||
|
@ -64,10 +63,9 @@
|
||||||
(click)="
|
(click)="
|
||||||
copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')
|
copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')
|
||||||
"
|
"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,16 +22,15 @@
|
||||||
{{ cipher.login.username }}
|
{{ cipher.login.username }}
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyUsername' | i18n }}"
|
appA11yTitle="{{ 'copyUsername' | i18n }}"
|
||||||
(click)="copy(cipher.login.username, 'username', 'Username')"
|
(click)="copy(cipher.login.username, 'username', 'Username')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-flex" *ngIf="cipher.login.password">
|
<div class="box-content-row box-content-row-flex" *ngIf="cipher.login.password">
|
||||||
|
@ -57,7 +56,6 @@
|
||||||
type="button"
|
type="button"
|
||||||
#checkPasswordBtn
|
#checkPasswordBtn
|
||||||
class="row-btn btn"
|
class="row-btn btn"
|
||||||
appBlurClick
|
|
||||||
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
||||||
(click)="checkPassword()"
|
(click)="checkPassword()"
|
||||||
[appApiAction]="checkPasswordPromise"
|
[appApiAction]="checkPasswordPromise"
|
||||||
|
@ -74,31 +72,29 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
||||||
(click)="copy(cipher.login.password, 'password', 'Password')"
|
(click)="copy(cipher.login.password, 'password', 'Password')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -131,16 +127,15 @@
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyValue' | i18n }}"
|
appA11yTitle="{{ 'copyValue' | i18n }}"
|
||||||
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,35 +148,37 @@
|
||||||
<div class="box-content-row box-content-row-flex" *ngIf="cipher.card.number">
|
<div class="box-content-row box-content-row-flex" *ngIf="cipher.card.number">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span class="row-label">{{ "number" | i18n }}</span>
|
<span class="row-label">{{ "number" | i18n }}</span>
|
||||||
<span *ngIf="!showCardNumber" class="monospaced">{{ cipher.card.maskedNumber }}</span>
|
<span *ngIf="!showCardNumber" class="monospaced">{{
|
||||||
<span *ngIf="showCardNumber" class="monospaced">{{ cipher.card.number }}</span>
|
cipher.card.maskedNumber | creditCardNumber: cipher.card.brand
|
||||||
|
}}</span>
|
||||||
|
<span *ngIf="showCardNumber" class="monospaced">{{
|
||||||
|
cipher.card.number | creditCardNumber: cipher.card.brand
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showCardNumber"
|
[attr.aria-pressed]="showCardNumber"
|
||||||
(click)="toggleCardNumber()"
|
(click)="toggleCardNumber()"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
|
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyNumber' | i18n }}"
|
appA11yTitle="{{ 'copyNumber' | i18n }}"
|
||||||
(click)="copy(cipher.card.number, 'number', 'Card Number')"
|
(click)="copy(cipher.card.number, 'number', 'Card Number')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" *ngIf="cipher.card.brand">
|
<div class="box-content-row" *ngIf="cipher.card.brand">
|
||||||
|
@ -199,31 +196,29 @@
|
||||||
<span *ngIf="showCardCode" class="monospaced">{{ cipher.card.code }}</span>
|
<span *ngIf="showCardCode" class="monospaced">{{ cipher.card.code }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showCardCode"
|
[attr.aria-pressed]="showCardCode"
|
||||||
(click)="toggleCardCode()"
|
(click)="toggleCardCode()"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
|
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copySecurityCode' | i18n }}"
|
appA11yTitle="{{ 'copySecurityCode' | i18n }}"
|
||||||
(click)="copy(cipher.card.code, 'securityCode', 'Security Code')"
|
(click)="copy(cipher.card.code, 'securityCode', 'Security Code')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -289,27 +284,25 @@
|
||||||
<span title="{{ u.uri }}">{{ u.hostOrUri }}</span>
|
<span title="{{ u.uri }}">{{ u.hostOrUri }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'launch' | i18n }}"
|
appA11yTitle="{{ 'launch' | i18n }}"
|
||||||
*ngIf="u.canLaunch"
|
*ngIf="u.canLaunch"
|
||||||
(click)="launch(u)"
|
(click)="launch(u)"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'copyUri' | i18n }}"
|
appA11yTitle="{{ 'copyUri' | i18n }}"
|
||||||
(click)="copy(u.uri, u.isWebsite ? 'website' : 'uri', 'URI')"
|
(click)="copy(u.uri, u.isWebsite ? 'website' : 'uri', 'URI')"
|
||||||
role="button"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -334,12 +327,11 @@
|
||||||
{{ "attachments" | i18n }}
|
{{ "attachments" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<a
|
<button
|
||||||
|
type="button"
|
||||||
class="box-content-row box-content-row-flex text-default"
|
class="box-content-row box-content-row-flex text-default"
|
||||||
*ngFor="let attachment of cipher.attachments"
|
*ngFor="let attachment of cipher.attachments"
|
||||||
href="#"
|
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurCLick
|
|
||||||
(click)="downloadAttachment(attachment)"
|
(click)="downloadAttachment(attachment)"
|
||||||
>
|
>
|
||||||
<span class="row-main">{{ attachment.fileName }}</span>
|
<span class="row-main">{{ attachment.fileName }}</span>
|
||||||
|
@ -354,7 +346,7 @@
|
||||||
*ngIf="attachment.downloading"
|
*ngIf="attachment.downloading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
@ -369,15 +361,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="cipher.hasPasswordHistory">
|
<div *ngIf="cipher.hasPasswordHistory">
|
||||||
<b class="font-weight-semibold">{{ "passwordHistory" | i18n }}:</b>
|
<b class="font-weight-semibold">{{ "passwordHistory" | i18n }}:</b>
|
||||||
<a
|
<button
|
||||||
href="#"
|
type="button"
|
||||||
(click)="viewHistory()"
|
(click)="viewHistory()"
|
||||||
appStopClick
|
appStopClick
|
||||||
role="button"
|
|
||||||
appA11yTitle="{{ 'passwordHistory' | i18n }}, {{ cipher.passwordHistory.length }}"
|
appA11yTitle="{{ 'passwordHistory' | i18n }}, {{ cipher.passwordHistory.length }}"
|
||||||
>
|
>
|
||||||
<span aria-hidden="true">{{ cipher.passwordHistory.length }}</span>
|
<span aria-hidden="true">{{ cipher.passwordHistory.length }}</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -385,7 +376,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer" *ngIf="cipher">
|
<div class="footer" *ngIf="cipher">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
class="primary"
|
class="primary"
|
||||||
(click)="edit()"
|
(click)="edit()"
|
||||||
appA11yTitle="{{ 'edit' | i18n }}"
|
appA11yTitle="{{ 'edit' | i18n }}"
|
||||||
|
@ -394,7 +384,6 @@
|
||||||
<i class="bwi bwi-pencil bwi-fw bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-pencil bwi-fw bwi-lg" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
class="primary"
|
class="primary"
|
||||||
(click)="restore()"
|
(click)="restore()"
|
||||||
appA11yTitle="{{ 'restore' | i18n }}"
|
appA11yTitle="{{ 'restore' | i18n }}"
|
||||||
|
@ -403,7 +392,6 @@
|
||||||
<i class="bwi bwi-undo bwi-fw bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-undo bwi-fw bwi-lg" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
class="primary"
|
class="primary"
|
||||||
*ngIf="!cipher?.organizationId && !cipher.isDeleted"
|
*ngIf="!cipher?.organizationId && !cipher.isDeleted"
|
||||||
(click)="clone()"
|
(click)="clone()"
|
||||||
|
@ -413,7 +401,6 @@
|
||||||
</button>
|
</button>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button
|
<button
|
||||||
appBlurClick
|
|
||||||
type="button"
|
type="button"
|
||||||
(click)="delete()"
|
(click)="delete()"
|
||||||
class="danger"
|
class="danger"
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Hazırkı parolun üzərinə yazmaq istədiyinizə əminsiniz?"
|
"message": "Hazırkı parolun üzərinə yazmaq istədiyinizə əminsiniz?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "İstifadəçi adının üzərinə yaz"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Hazırkı istifadəçi adının üzərinə yazmaq istədiyinizə əminsiniz?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Qovluq yoxdur",
|
"message": "Qovluq yoxdur",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Domen adı",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Yaradıcı"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Nə yaratmaq istəyirsiniz?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Parol növü"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "İstifadəçi adını yenidən yarat"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "İstifadəçi adı yarat"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "İstifadəçi adı növü"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Plyus ünvanlı e-poçt"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "E-poçt təchizatçınızın alt ünvan özəlliklərini istifadə et."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Catch-all E-poçt"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Domeninizin konfiqurasiya edilmiş hamısını yaxalama gələn qutusunu istifadə edin."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Təsadüfi"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Təsadüfi söz"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Veb sayt adı"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Xidmət"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε τον τρέχον κωδικό πρόσβασης;"
|
"message": "Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε τον τρέχον κωδικό πρόσβασης;"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Αντικατάσταση Username"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε το τρέχον username;"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Χωρίς Φάκελο",
|
"message": "Χωρίς Φάκελο",
|
||||||
|
@ -743,10 +743,10 @@
|
||||||
"message": "Γεννήτρια Κωδικού"
|
"message": "Γεννήτρια Κωδικού"
|
||||||
},
|
},
|
||||||
"contactUs": {
|
"contactUs": {
|
||||||
"message": "Contact Us"
|
"message": "Επικοινωνία"
|
||||||
},
|
},
|
||||||
"getHelp": {
|
"getHelp": {
|
||||||
"message": "Get Help"
|
"message": "Ζητήστε Βοήθεια"
|
||||||
},
|
},
|
||||||
"fileBugReport": {
|
"fileBugReport": {
|
||||||
"message": "Υποβολή Αναφοράς Σφάλματος"
|
"message": "Υποβολή Αναφοράς Σφάλματος"
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Όνομα τομέα",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1829,10 +1829,10 @@
|
||||||
"message": "Έχει λήξει το χρονικό όριο. Παρακαλώ επιστρέψτε και προσπαθήστε να συνδεθείτε ξανά."
|
"message": "Έχει λήξει το χρονικό όριο. Παρακαλώ επιστρέψτε και προσπαθήστε να συνδεθείτε ξανά."
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultTitle": {
|
"exportingPersonalVaultTitle": {
|
||||||
"message": "Exporting Personal Vault"
|
"message": "Εξαγωγή Προσωπικού Vault"
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultDescription": {
|
"exportingPersonalVaultDescription": {
|
||||||
"message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.",
|
"message": "Θα εξαχθούν μόνο τα προσωπικά αντικείμενα Vault που σχετίζονται με το $EMAIL$. Τα αντικείμενα Vault οργανισμού δεν θα συμπεριληφθούν.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"email": {
|
"email": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Γεννήτρια"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Τι θα θέλατε να δημιουργήσετε;"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Τύπος Κωδικού"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Επαναδημιουργία Ονόματος Χρήστη"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Δημιουργία Ονόματος Χρήστη"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Τύπος Ονόματος Χρήστη"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Συν Διεύθυνση Email"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Χρησιμοποιήστε τις δυνατότητες δευτερεύουσας διεύθυνσης του παρόχου email σας."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Catch-all Email"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Χρησιμοποιήστε τα διαμορφωμένα εισερχόμενα catch-all του domain σας."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Τυχαίο"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Τυχαία Λέξη"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Όνομα Ιστοσελίδας"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Υπηρεσία"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,6 +400,18 @@
|
||||||
"length": {
|
"length": {
|
||||||
"message": "Length"
|
"message": "Length"
|
||||||
},
|
},
|
||||||
|
"uppercase": {
|
||||||
|
"message": "Uppercase (A-Z)"
|
||||||
|
},
|
||||||
|
"lowercase": {
|
||||||
|
"message": "Lowercase (a-z)"
|
||||||
|
},
|
||||||
|
"numbers": {
|
||||||
|
"message": "Numbers (0-9)"
|
||||||
|
},
|
||||||
|
"specialCharacters": {
|
||||||
|
"message": "Special Characters (!@#$%^&*)"
|
||||||
|
},
|
||||||
"numWords": {
|
"numWords": {
|
||||||
"message": "Number of Words"
|
"message": "Number of Words"
|
||||||
},
|
},
|
||||||
|
@ -775,7 +787,7 @@
|
||||||
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
||||||
},
|
},
|
||||||
"goToWebVault": {
|
"goToWebVault": {
|
||||||
"message": "Go To Web Vault"
|
"message": "Go to Web Vault"
|
||||||
},
|
},
|
||||||
"getMobileApp": {
|
"getMobileApp": {
|
||||||
"message": "Get Mobile App"
|
"message": "Get Mobile App"
|
||||||
|
@ -973,7 +985,7 @@
|
||||||
"description": "Copy to clipboard"
|
"description": "Copy to clipboard"
|
||||||
},
|
},
|
||||||
"checkForUpdates": {
|
"checkForUpdates": {
|
||||||
"message": "Check For Updates"
|
"message": "Check for Updates…"
|
||||||
},
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"message": "Version $VERSION_NUM$",
|
"message": "Version $VERSION_NUM$",
|
||||||
|
@ -985,7 +997,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"restartToUpdate": {
|
"restartToUpdate": {
|
||||||
"message": "Restart To Update"
|
"message": "Restart to Update"
|
||||||
},
|
},
|
||||||
"restartToUpdateDesc": {
|
"restartToUpdateDesc": {
|
||||||
"message": "Version $VERSION_NUM$ is ready to install. You must restart the application to complete the installation. Do you want to restart and update now?",
|
"message": "Version $VERSION_NUM$ is ready to install. You must restart the application to complete the installation. Do you want to restart and update now?",
|
||||||
|
@ -1587,7 +1599,8 @@
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
"maxAccessCount": {
|
"maxAccessCount": {
|
||||||
"message": "Maximum Access Count"
|
"message": "Maximum Access Count",
|
||||||
|
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
||||||
},
|
},
|
||||||
"maxAccessCountDesc": {
|
"maxAccessCountDesc": {
|
||||||
"message": "If set, users will no longer be able to access this Send once the maximum access count is reached.",
|
"message": "If set, users will no longer be able to access this Send once the maximum access count is reached.",
|
||||||
|
@ -1840,6 +1853,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"locked": {
|
||||||
|
"message": "Locked"
|
||||||
|
},
|
||||||
|
"unlocked": {
|
||||||
|
"message": "Unlocked"
|
||||||
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Generator"
|
||||||
},
|
},
|
||||||
|
@ -1859,7 +1878,8 @@
|
||||||
"message": "Username Type"
|
"message": "Username Type"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Plus Addressed Email",
|
||||||
|
"description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Use your email provider's sub-addressing capabilities."
|
||||||
|
@ -1881,5 +1901,21 @@
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Service"
|
||||||
|
},
|
||||||
|
"forwardedEmail": {
|
||||||
|
"message": "Forwarded Email Alias"
|
||||||
|
},
|
||||||
|
"forwardedEmailDesc": {
|
||||||
|
"message": "Generate an email alias with an external forwarding service."
|
||||||
|
},
|
||||||
|
"hostname": {
|
||||||
|
"message": "Hostname",
|
||||||
|
"description": "Part of a URL."
|
||||||
|
},
|
||||||
|
"apiAccessToken": {
|
||||||
|
"message": "API Access Token"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"message": "API Key"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
"description": "Toggling an expand/collapse state."
|
"description": "Toggling an expand/collapse state."
|
||||||
},
|
},
|
||||||
"cardholderName": {
|
"cardholderName": {
|
||||||
"message": "Nombre en la tarjeta"
|
"message": "Nombre del propietario de la tarjeta"
|
||||||
},
|
},
|
||||||
"number": {
|
"number": {
|
||||||
"message": "Número"
|
"message": "Número"
|
||||||
|
@ -370,10 +370,10 @@
|
||||||
"message": "¿Estás seguro de que quieres sobreescribir la contraseña actual?"
|
"message": "¿Estás seguro de que quieres sobreescribir la contraseña actual?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Reemplazar nombre de usuario"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "¿Esta seguro que desea reemplazar el nombre de usuario?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Sin carpeta",
|
"message": "Sin carpeta",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Nombre de dominio",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,25 +1841,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Generador"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "¿Qué deseas generar?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Tipo de contraseña"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Regenerar nombre de usuario"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Generar nombre de usuario"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Tipo de nombre de usuario"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Dirección adicional de correo electrónico"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Use your email provider's sub-addressing capabilities."
|
||||||
|
@ -1871,15 +1871,15 @@
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Use your domain's configured catch-all inbox."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Aleatorio"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Palabra aleatoria"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Nombre del sitio web"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Servicio"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Oled kindel, et soovid olemasolevat parooli üle kirjutada?"
|
"message": "Oled kindel, et soovid olemasolevat parooli üle kirjutada?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Kasutajanime ülekirjutamine"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Oled kindel, et soovid praegust kasutajanime üle kirjutada?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Kaust puudub",
|
"message": "Kaust puudub",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Domeeni nimi",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Genereerija"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Mida sa soovid genereerida?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Parooli tüüp"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Genereeri kasutajanimi uuesti"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Genereeri kasutajanimi"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Kasutajanime tüüp"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Lisaks e-post"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Kasuta e-posti teenuspakkuja alamadressimise võimalusi."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Kogumisaadress"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Kasuta domeenipõhist kogumisaadressi."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Juhuslik"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Juhuslik sõna"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Veebilehe nimi"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Teenus"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "آیا از بازنویسی بر روی پسورد فعلی مطمئن هستید؟"
|
"message": "آیا از بازنویسی بر روی پسورد فعلی مطمئن هستید؟"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "بازنویسی نام کاربری"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "آیا از بازنویسی نام کاربری فعلی مطمئن هستید؟"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "بدون پوشه",
|
"message": "بدون پوشه",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "نام دامنه",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "تولید کننده"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "چه چیزی دوست دارید تولید کنید؟"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "نوع گذرواژه"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "ایجاد مجدد نام کاربری"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "ایجاد نام کاربری"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "نوع نام کاربری"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "به علاوه ایمیل آدرس داده شده"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "از قابلیت های آدرس دهی فرعی ارائه دهنده ایمیل خود استفاده کنید."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "رایانامه همهگیر"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "از صندوق ورودی پیکربندی شده دامنه خود استفاده کنید."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "تصادفی"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "کلمه تصادفی"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "نام وب سایت"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "خدمت"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "האם אתה בטוח שברצונך לדרוס את הסיסמה הנוכחית?"
|
"message": "האם אתה בטוח שברצונך לדרוס את הסיסמה הנוכחית?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "כתוב מחדש את שם המשתמש"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "האם אתה בטוח שברצונך לדרוס את שם המשתמש הנוכחי?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "ללא תיקיה",
|
"message": "ללא תיקיה",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "שם דומיין",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1829,10 +1829,10 @@
|
||||||
"message": "זמן ההפעלה שלך תם. נא לחזור ולנסות להיכנס שוב."
|
"message": "זמן ההפעלה שלך תם. נא לחזור ולנסות להיכנס שוב."
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultTitle": {
|
"exportingPersonalVaultTitle": {
|
||||||
"message": "Exporting Personal Vault"
|
"message": "הכספת האישית מיוצאת"
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultDescription": {
|
"exportingPersonalVaultDescription": {
|
||||||
"message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.",
|
"message": "רק פריטי הכספת האישית שמשויכת עם $EMAIL$ ייוצאו. פריטי הכספת הארגוניים לא יהיו חלק מהייצוא.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"email": {
|
"email": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
|
@ -1841,22 +1841,22 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "מחולל"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "מה ברצונך לחולל?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "סוג סיסמה"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "חולל מחדש שם משתמש"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "חולל שם משתמש"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "סוג שם משתמש"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Plus Addressed Email"
|
||||||
|
@ -1871,15 +1871,15 @@
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Use your domain's configured catch-all inbox."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "אקראי"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "מילה אקראית"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "שם אתר"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "שירות"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "정말 현재 비밀번호를 덮어쓰시겠습니까?"
|
"message": "정말 현재 비밀번호를 덮어쓰시겠습니까?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "아이디 덮어쓰기"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "정말 현재 아이디를 덮어쓰시겠습니까?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "폴더 없음",
|
"message": "폴더 없음",
|
||||||
|
@ -743,10 +743,10 @@
|
||||||
"message": "비밀번호 생성기"
|
"message": "비밀번호 생성기"
|
||||||
},
|
},
|
||||||
"contactUs": {
|
"contactUs": {
|
||||||
"message": "Contact Us"
|
"message": "문의하기"
|
||||||
},
|
},
|
||||||
"getHelp": {
|
"getHelp": {
|
||||||
"message": "Get Help"
|
"message": "도움말"
|
||||||
},
|
},
|
||||||
"fileBugReport": {
|
"fileBugReport": {
|
||||||
"message": "버그 보고서 첨부"
|
"message": "버그 보고서 첨부"
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "도메인 이름",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1829,7 +1829,7 @@
|
||||||
"message": "세션 시간이 초과되었습니다. 다시 로그인해주세요."
|
"message": "세션 시간이 초과되었습니다. 다시 로그인해주세요."
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultTitle": {
|
"exportingPersonalVaultTitle": {
|
||||||
"message": "Exporting Personal Vault"
|
"message": "개인 보관함을 내보내는 중"
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultDescription": {
|
"exportingPersonalVaultDescription": {
|
||||||
"message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.",
|
"message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.",
|
||||||
|
@ -1841,22 +1841,22 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "생성기"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "무엇을 생성하실건가요?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "비밀번호 유형"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "아이디 재생성"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "아이디 생성"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "아이디 유형"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Plus Addressed Email"
|
||||||
|
@ -1871,15 +1871,15 @@
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Use your domain's configured catch-all inbox."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "무작위"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "무작위 단어"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "웹사이트 이름"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "서비스"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Vai tiešām pārrakstīt esošo paroli?"
|
"message": "Vai tiešām pārrakstīt esošo paroli?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Pārrakstīt lietotājvārdu"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Vai tiešām pārrakstīt pašreizējo lietotājvārdu?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Nav mapes",
|
"message": "Nav mapes",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Domēna vārds",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Veidotājs"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Ko ir nepieciešams izveidot?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Paroles veids"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Pārizveidot lietotājvārdu"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Izveidot lietotājvārdu"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Lietotājvārda veids"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "E-pasta adrese ar plusu"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Izmantot e-pasta pakalpojuma nodrošinātāja apakšadresēšanas spējas."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Visu tverošā e-pasta adrese"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Izmantot uzstādīto domēna visu tverošo iesūtni."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Nejauši"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Nejaušs vārds"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Tīmekļa vietnes nosaukums"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Pakalpojums"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@
|
||||||
"message": "Czy na pewno chcesz zastąpić obecne hasło?"
|
"message": "Czy na pewno chcesz zastąpić obecne hasło?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Nadpisz nazwę użytkownika"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Are you sure you want to overwrite the current username?"
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Nazwa domeny",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1844,42 +1844,42 @@
|
||||||
"message": "Generator"
|
"message": "Generator"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Co chcesz wygenerować?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Rodzaj hasła"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Wygeneruj ponownie nazwę użytkownika"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Wygeneruj nazwę użytkownika"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Rodzaj nazwy użytkownika"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Adres e-mail z plusem"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Użyj możliwości dodawania aliasów u swojego dostawcy poczty e-mail."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Adres catch-all"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Użyj skonfigurowanej skrzynki catch-all w swojej domenie."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Random"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Losowe słowo"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Nazwa witryny"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Usługa"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,7 +373,7 @@
|
||||||
"message": "Overwrite Username"
|
"message": "Overwrite Username"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Tem certeza que deseja substituir o usuário atual?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Nenhuma Pasta",
|
"message": "Nenhuma Pasta",
|
||||||
|
|
|
@ -373,7 +373,7 @@
|
||||||
"message": "Перезаписать имя пользователя"
|
"message": "Перезаписать имя пользователя"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Вы уверены, что хотите перезаписать текущее имя пользователя?"
|
"message": "Вы хотите перезаписать текущее имя пользователя?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Без папки",
|
"message": "Без папки",
|
||||||
|
@ -1850,7 +1850,7 @@
|
||||||
"message": "Тип пароля"
|
"message": "Тип пароля"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Восстановить имя пользователя"
|
"message": "Пересоздать имя пользователя"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Создать имя пользователя"
|
"message": "Создать имя пользователя"
|
||||||
|
@ -1859,16 +1859,16 @@
|
||||||
"message": "Тип имени пользователя"
|
"message": "Тип имени пользователя"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Плюс-адресованные email"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Использовать возможности суб-адресации вашего провайдера электронной почты."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Универсальная электронная почта"
|
"message": "Catch-all-адрес электронной почты"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Использовать настроенную в вашем домене почту catch-all."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Случайно"
|
"message": "Случайно"
|
||||||
|
@ -1880,6 +1880,6 @@
|
||||||
"message": "Название сайта"
|
"message": "Название сайта"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Служба"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Сигурно променити тренутну лозинку?"
|
"message": "Сигурно променити тренутну лозинку?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Препиши име"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Сигурно преписати тренутно име?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Без фасцикле",
|
"message": "Без фасцикле",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Име домена",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Генератор"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Шта желите да генеришете?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Тип лозинке"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Поново генериши име"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Генериши име"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Тип имена"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Плус имејл адресе"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Користите могућности подадресирања вашег добављача е-поште."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "„Ухвати све“ е-порука"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Use your domain's configured catch-all inbox."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Случајно"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Случајна реч"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Име Вашег веб-сајта"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Сервис"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Domännamn",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
|
|
@ -370,10 +370,10 @@
|
||||||
"message": "Ви дійсно хочете перезаписати поточний пароль?"
|
"message": "Ви дійсно хочете перезаписати поточний пароль?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite Username"
|
"message": "Перезаписати ім'я користувача"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "Ви дійсно бажаєте перезаписати поточне ім'я користувача?"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "Без теки",
|
"message": "Без теки",
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain Name",
|
"message": "Ім'я домену",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
|
@ -1841,45 +1841,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generator": {
|
"generator": {
|
||||||
"message": "Generator"
|
"message": "Генератор"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "Що ви бажаєте згенерувати?"
|
||||||
},
|
},
|
||||||
"passwordType": {
|
"passwordType": {
|
||||||
"message": "Password Type"
|
"message": "Тип пароля"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate Username"
|
"message": "Повторно генерувати ім'я користувача"
|
||||||
},
|
},
|
||||||
"generateUsername": {
|
"generateUsername": {
|
||||||
"message": "Generate Username"
|
"message": "Генерувати ім'я користувача"
|
||||||
},
|
},
|
||||||
"usernameType": {
|
"usernameType": {
|
||||||
"message": "Username Type"
|
"message": "Тип імені користувача"
|
||||||
},
|
},
|
||||||
"plusAddressedEmail": {
|
"plusAddressedEmail": {
|
||||||
"message": "Plus Addressed Email"
|
"message": "Плюс адреса електронної пошти"
|
||||||
},
|
},
|
||||||
"plusAddressedEmailDesc": {
|
"plusAddressedEmailDesc": {
|
||||||
"message": "Use your email provider's sub-addressing capabilities."
|
"message": "Використовуйте розширені можливості адрес вашого постачальника електронної пошти."
|
||||||
},
|
},
|
||||||
"catchallEmail": {
|
"catchallEmail": {
|
||||||
"message": "Catch-all Email"
|
"message": "Адреса е-пошти Catch-all"
|
||||||
},
|
},
|
||||||
"catchallEmailDesc": {
|
"catchallEmailDesc": {
|
||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Використовуйте свою скриньку вхідних Catch-All власного домену."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Випадково"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random Word"
|
"message": "Випадкове слово"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website Name"
|
"message": "Назва вебсайту"
|
||||||
},
|
},
|
||||||
"service": {
|
"service": {
|
||||||
"message": "Service"
|
"message": "Послуга"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/main.ts
19
src/main.ts
|
@ -2,11 +2,9 @@ import * as path from "path";
|
||||||
|
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
|
|
||||||
import { BiometricMain } from "jslib-common/abstractions/biometric.main";
|
|
||||||
import { StateFactory } from "jslib-common/factories/stateFactory";
|
import { StateFactory } from "jslib-common/factories/stateFactory";
|
||||||
import { GlobalState } from "jslib-common/models/domain/globalState";
|
import { GlobalState } from "jslib-common/models/domain/globalState";
|
||||||
import { StateService } from "jslib-common/services/state.service";
|
import { StateService } from "jslib-common/services/state.service";
|
||||||
import { KeytarStorageListener } from "jslib-electron/keytarStorageListener";
|
|
||||||
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
|
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
|
||||||
import { ElectronMainMessagingService } from "jslib-electron/services/electronMainMessaging.service";
|
import { ElectronMainMessagingService } from "jslib-electron/services/electronMainMessaging.service";
|
||||||
import { ElectronStorageService } from "jslib-electron/services/electronStorage.service";
|
import { ElectronStorageService } from "jslib-electron/services/electronStorage.service";
|
||||||
|
@ -14,7 +12,9 @@ import { TrayMain } from "jslib-electron/tray.main";
|
||||||
import { UpdaterMain } from "jslib-electron/updater.main";
|
import { UpdaterMain } from "jslib-electron/updater.main";
|
||||||
import { WindowMain } from "jslib-electron/window.main";
|
import { WindowMain } from "jslib-electron/window.main";
|
||||||
|
|
||||||
import { MenuMain } from "./main/menu.main";
|
import { BiometricMain } from "./main/biometric/biometric.main";
|
||||||
|
import { DesktopCredentialStorageListener } from "./main/desktopCredentialStorageListener";
|
||||||
|
import { MenuMain } from "./main/menu/menu.main";
|
||||||
import { MessagingMain } from "./main/messaging.main";
|
import { MessagingMain } from "./main/messaging.main";
|
||||||
import { NativeMessagingMain } from "./main/nativeMessaging.main";
|
import { NativeMessagingMain } from "./main/nativeMessaging.main";
|
||||||
import { PowerMonitorMain } from "./main/powerMonitor.main";
|
import { PowerMonitorMain } from "./main/powerMonitor.main";
|
||||||
|
@ -27,7 +27,7 @@ export class Main {
|
||||||
storageService: ElectronStorageService;
|
storageService: ElectronStorageService;
|
||||||
messagingService: ElectronMainMessagingService;
|
messagingService: ElectronMainMessagingService;
|
||||||
stateService: StateService;
|
stateService: StateService;
|
||||||
keytarStorageListener: KeytarStorageListener;
|
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
||||||
|
|
||||||
windowMain: WindowMain;
|
windowMain: WindowMain;
|
||||||
messagingMain: MessagingMain;
|
messagingMain: MessagingMain;
|
||||||
|
@ -116,7 +116,7 @@ export class Main {
|
||||||
|
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const BiometricWindowsMain = require("jslib-electron/biometric.windows.main").default;
|
const BiometricWindowsMain = require("./main/biometric/biometric.windows.main").default;
|
||||||
this.biometricMain = new BiometricWindowsMain(
|
this.biometricMain = new BiometricWindowsMain(
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.windowMain,
|
this.windowMain,
|
||||||
|
@ -125,11 +125,14 @@ export class Main {
|
||||||
);
|
);
|
||||||
} else if (process.platform === "darwin") {
|
} else if (process.platform === "darwin") {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const BiometricDarwinMain = require("jslib-electron/biometric.darwin.main").default;
|
const BiometricDarwinMain = require("./main/biometric/biometric.darwin.main").default;
|
||||||
this.biometricMain = new BiometricDarwinMain(this.i18nService, this.stateService);
|
this.biometricMain = new BiometricDarwinMain(this.i18nService, this.stateService);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.keytarStorageListener = new KeytarStorageListener("Bitwarden", this.biometricMain);
|
this.desktopCredentialStorageListener = new DesktopCredentialStorageListener(
|
||||||
|
"Bitwarden",
|
||||||
|
this.biometricMain
|
||||||
|
);
|
||||||
|
|
||||||
this.nativeMessagingMain = new NativeMessagingMain(
|
this.nativeMessagingMain = new NativeMessagingMain(
|
||||||
this.logService,
|
this.logService,
|
||||||
|
@ -140,7 +143,7 @@ export class Main {
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap() {
|
bootstrap() {
|
||||||
this.keytarStorageListener.init();
|
this.desktopCredentialStorageListener.init();
|
||||||
this.windowMain.init().then(
|
this.windowMain.init().then(
|
||||||
async () => {
|
async () => {
|
||||||
const locale = await this.stateService.getLocale();
|
const locale = await this.stateService.getLocale();
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { ipcMain, systemPreferences } from "electron";
|
||||||
|
|
||||||
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
|
import { BiometricMain } from "../biometric/biometric.main";
|
||||||
|
|
||||||
|
export default class BiometricDarwinMain implements BiometricMain {
|
||||||
|
isError = false;
|
||||||
|
|
||||||
|
constructor(private i18nservice: I18nService, private stateService: StateService) {}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.stateService.setEnableBiometric(await this.supportsBiometric());
|
||||||
|
await this.stateService.setBiometricText("unlockWithTouchId");
|
||||||
|
await this.stateService.setNoAutoPromptBiometricsText("noAutoPromptTouchId");
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
ipcMain.on("biometric", async (event: any, message: any) => {
|
||||||
|
event.returnValue = await this.authenticateBiometric();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
supportsBiometric(): Promise<boolean> {
|
||||||
|
return Promise.resolve(systemPreferences.canPromptTouchID());
|
||||||
|
}
|
||||||
|
|
||||||
|
async authenticateBiometric(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await systemPreferences.promptTouchID(this.i18nservice.t("touchIdConsentMessage"));
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export abstract class BiometricMain {
|
||||||
|
isError: boolean;
|
||||||
|
init: () => Promise<void>;
|
||||||
|
supportsBiometric: () => Promise<boolean>;
|
||||||
|
authenticateBiometric: () => Promise<boolean>;
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
import { ipcMain } from "electron";
|
||||||
|
import forceFocus from "forcefocus";
|
||||||
|
|
||||||
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
import { WindowMain } from "jslib-electron/window.main";
|
||||||
|
|
||||||
|
import { BiometricMain } from "src/main/biometric/biometric.main";
|
||||||
|
|
||||||
|
export default class BiometricWindowsMain implements BiometricMain {
|
||||||
|
isError = false;
|
||||||
|
|
||||||
|
private windowsSecurityCredentialsUiModule: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private i18nservice: I18nService,
|
||||||
|
private windowMain: WindowMain,
|
||||||
|
private stateService: StateService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.windowsSecurityCredentialsUiModule = this.getWindowsSecurityCredentialsUiModule();
|
||||||
|
let supportsBiometric = false;
|
||||||
|
try {
|
||||||
|
supportsBiometric = await this.supportsBiometric();
|
||||||
|
} catch {
|
||||||
|
// store error state so we can let the user know on the settings page
|
||||||
|
this.isError = true;
|
||||||
|
}
|
||||||
|
await this.stateService.setEnableBiometric(supportsBiometric);
|
||||||
|
await this.stateService.setBiometricText("unlockWithWindowsHello");
|
||||||
|
await this.stateService.setNoAutoPromptBiometricsText("noAutoPromptWindowsHello");
|
||||||
|
|
||||||
|
ipcMain.on("biometric", async (event: any, message: any) => {
|
||||||
|
event.returnValue = await this.authenticateBiometric();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async supportsBiometric(): Promise<boolean> {
|
||||||
|
const availability = await this.checkAvailabilityAsync();
|
||||||
|
|
||||||
|
return this.getAllowedAvailabilities().includes(availability);
|
||||||
|
}
|
||||||
|
|
||||||
|
async authenticateBiometric(): Promise<boolean> {
|
||||||
|
const module = this.getWindowsSecurityCredentialsUiModule();
|
||||||
|
if (module == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const verification = await this.requestVerificationAsync(
|
||||||
|
this.i18nservice.t("windowsHelloConsentMessage")
|
||||||
|
);
|
||||||
|
|
||||||
|
return verification === module.UserConsentVerificationResult.verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
getWindowsSecurityCredentialsUiModule(): any {
|
||||||
|
try {
|
||||||
|
if (this.windowsSecurityCredentialsUiModule == null && this.getWindowsMajorVersion() >= 10) {
|
||||||
|
this.windowsSecurityCredentialsUiModule = require("@nodert-win10-rs4/windows.security.credentials.ui");
|
||||||
|
}
|
||||||
|
return this.windowsSecurityCredentialsUiModule;
|
||||||
|
} catch {
|
||||||
|
this.isError = true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkAvailabilityAsync(): Promise<any> {
|
||||||
|
const module = this.getWindowsSecurityCredentialsUiModule();
|
||||||
|
if (module != null) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
module.UserConsentVerifier.checkAvailabilityAsync((error: Error, result: any) => {
|
||||||
|
if (error) {
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
return resolve(result);
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
this.isError = true;
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestVerificationAsync(message: string): Promise<any> {
|
||||||
|
const module = this.getWindowsSecurityCredentialsUiModule();
|
||||||
|
if (module != null) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
module.UserConsentVerifier.requestVerificationAsync(
|
||||||
|
message,
|
||||||
|
(error: Error, result: any) => {
|
||||||
|
if (error) {
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
return resolve(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
forceFocus.focusWindow(this.windowMain.win);
|
||||||
|
} catch (error) {
|
||||||
|
this.isError = true;
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllowedAvailabilities(): any[] {
|
||||||
|
try {
|
||||||
|
const module = this.getWindowsSecurityCredentialsUiModule();
|
||||||
|
if (module != null) {
|
||||||
|
return [
|
||||||
|
module.UserConsentVerifierAvailability.available,
|
||||||
|
module.UserConsentVerifierAvailability.deviceBusy,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/*Ignore error*/
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getWindowsMajorVersion(): number {
|
||||||
|
if (process.platform !== "win32") {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const version = require("os").release();
|
||||||
|
return Number.parseInt(version.split(".")[0], 10);
|
||||||
|
} catch {
|
||||||
|
this.logService.error("Unable to resolve windows major version number");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { ipcMain } from "electron";
|
||||||
|
import { deletePassword, getPassword, setPassword } from "keytar";
|
||||||
|
|
||||||
|
import { BiometricMain } from "./biometric/biometric.main";
|
||||||
|
|
||||||
|
const AuthRequiredSuffix = "_biometric";
|
||||||
|
const AuthenticatedActions = ["getPassword"];
|
||||||
|
|
||||||
|
export class DesktopCredentialStorageListener {
|
||||||
|
constructor(private serviceName: string, private biometricService: BiometricMain) {}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
ipcMain.on("keytar", async (event: any, message: any) => {
|
||||||
|
try {
|
||||||
|
let serviceName = this.serviceName;
|
||||||
|
message.keySuffix = "_" + (message.keySuffix ?? "");
|
||||||
|
if (message.keySuffix !== "_") {
|
||||||
|
serviceName += message.keySuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authenticationRequired =
|
||||||
|
AuthenticatedActions.includes(message.action) && AuthRequiredSuffix === message.keySuffix;
|
||||||
|
const authenticated = !authenticationRequired || (await this.authenticateBiometric());
|
||||||
|
|
||||||
|
let val: string | boolean = null;
|
||||||
|
if (authenticated && message.action && message.key) {
|
||||||
|
if (message.action === "getPassword") {
|
||||||
|
val = await getPassword(serviceName, message.key);
|
||||||
|
} else if (message.action === "hasPassword") {
|
||||||
|
const result = await getPassword(serviceName, message.key);
|
||||||
|
val = result != null;
|
||||||
|
} else if (message.action === "setPassword" && message.value) {
|
||||||
|
await setPassword(serviceName, message.key, message.value);
|
||||||
|
} else if (message.action === "deletePassword") {
|
||||||
|
await deletePassword(serviceName, message.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.returnValue = val;
|
||||||
|
} catch {
|
||||||
|
event.returnValue = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async authenticateBiometric(): Promise<boolean> {
|
||||||
|
if (this.biometricService) {
|
||||||
|
return await this.biometricService.authenticateBiometric();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import { app, Menu } from "electron";
|
||||||
|
|
||||||
import { BaseMenu } from "jslib-electron/baseMenu";
|
import { BaseMenu } from "jslib-electron/baseMenu";
|
||||||
|
|
||||||
import { Main } from "../main";
|
import { Main } from "../../main";
|
||||||
|
|
||||||
import { MenuUpdateRequest } from "./menu.updater";
|
import { MenuUpdateRequest } from "./menu.updater";
|
||||||
import { Menubar } from "./menubar";
|
import { Menubar } from "./menubar";
|
|
@ -7,7 +7,7 @@ import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
import { Main } from "../main";
|
import { Main } from "../main";
|
||||||
|
|
||||||
import { MenuUpdateRequest } from "./menu.updater";
|
import { MenuUpdateRequest } from "./menu/menu.updater";
|
||||||
|
|
||||||
const SyncInterval = 5 * 60 * 1000; // 5 minutes
|
const SyncInterval = 5 * 60 * 1000; // 5 minutes
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "1.30.1",
|
"version": "1.33.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "1.30.1",
|
"version": "1.33.1",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodert-win10-rs4/windows.security.credentials.ui": "^0.4.4",
|
"@nodert-win10-rs4/windows.security.credentials.ui": "^0.4.4",
|
||||||
"forcefocus": "^1.1.0",
|
"forcefocus": "^1.1.0",
|
||||||
"keytar": "7.7.0"
|
"keytar": "^7.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nodert-win10-rs4/windows.security.credentials.ui": {
|
"node_modules/@nodert-win10-rs4/windows.security.credentials.ui": {
|
||||||
|
@ -286,31 +286,75 @@
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
"node_modules/keytar": {
|
"node_modules/keytar": {
|
||||||
"version": "7.7.0",
|
"version": "7.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
|
||||||
"integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==",
|
"integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-addon-api": "^3.0.0",
|
"node-addon-api": "^4.3.0",
|
||||||
"prebuild-install": "^6.0.0"
|
"prebuild-install": "^7.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/decompress-response": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/detect-libc": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/node-abi": {
|
||||||
|
"version": "3.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz",
|
||||||
|
"integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/keytar/node_modules/prebuild-install": {
|
"node_modules/keytar/node_modules/prebuild-install": {
|
||||||
"version": "6.1.4",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.0.tgz",
|
||||||
"integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
|
"integrity": "sha512-CNcMgI1xBypOyGqjp3wOc8AAo1nMhZS3Cwd3iHIxOdAUbb+YxdNuM4Z5iIrZ8RLvOsf3F3bl7b7xGq6DjQoNYA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"detect-libc": "^1.0.3",
|
"detect-libc": "^2.0.0",
|
||||||
"expand-template": "^2.0.3",
|
"expand-template": "^2.0.3",
|
||||||
"github-from-package": "0.0.0",
|
"github-from-package": "0.0.0",
|
||||||
"minimist": "^1.2.3",
|
"minimist": "^1.2.3",
|
||||||
"mkdirp-classic": "^0.5.3",
|
"mkdirp-classic": "^0.5.3",
|
||||||
"napi-build-utils": "^1.0.1",
|
"napi-build-utils": "^1.0.1",
|
||||||
"node-abi": "^2.21.0",
|
"node-abi": "^3.3.0",
|
||||||
"npmlog": "^4.0.1",
|
"npmlog": "^4.0.1",
|
||||||
"pump": "^3.0.0",
|
"pump": "^3.0.0",
|
||||||
"rc": "^1.2.7",
|
"rc": "^1.2.7",
|
||||||
"simple-get": "^3.0.3",
|
"simple-get": "^4.0.0",
|
||||||
"tar-fs": "^2.0.0",
|
"tar-fs": "^2.0.0",
|
||||||
"tunnel-agent": "^0.6.0"
|
"tunnel-agent": "^0.6.0"
|
||||||
},
|
},
|
||||||
|
@ -318,7 +362,56 @@
|
||||||
"prebuild-install": "bin.js"
|
"prebuild-install": "bin.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/semver": {
|
||||||
|
"version": "7.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keytar/node_modules/simple-get": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mimic-response": {
|
"node_modules/mimic-response": {
|
||||||
|
@ -333,9 +426,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp-classic": {
|
"node_modules/mkdirp-classic": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
|
@ -361,9 +454,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-addon-api": {
|
"node_modules/node-addon-api": {
|
||||||
"version": "3.2.1",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
|
||||||
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
|
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
|
||||||
},
|
},
|
||||||
"node_modules/noop-logger": {
|
"node_modules/noop-logger": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
@ -494,9 +587,9 @@
|
||||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
},
|
},
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||||
},
|
},
|
||||||
"node_modules/simple-concat": {
|
"node_modules/simple-concat": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -518,9 +611,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/simple-get": {
|
"node_modules/simple-get": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decompress-response": "^4.2.0",
|
"decompress-response": "^4.2.0",
|
||||||
"once": "^1.3.1",
|
"once": "^1.3.1",
|
||||||
|
@ -623,9 +716,12 @@
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"node_modules/which-pm-runs": {
|
"node_modules/which-pm-runs": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz",
|
||||||
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
|
"integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wide-align": {
|
"node_modules/wide-align": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
|
@ -639,6 +735,11 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
},
|
||||||
|
"node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -842,45 +943,97 @@
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
"keytar": {
|
"keytar": {
|
||||||
"version": "7.7.0",
|
"version": "7.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
|
||||||
"integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==",
|
"integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-addon-api": "^3.0.0",
|
"node-addon-api": "^4.3.0",
|
||||||
"prebuild-install": "^6.0.0"
|
"prebuild-install": "^7.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prebuild-install": {
|
"decompress-response": {
|
||||||
"version": "6.1.4",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
"integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"detect-libc": "^1.0.3",
|
"mimic-response": "^3.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detect-libc": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w=="
|
||||||
|
},
|
||||||
|
"mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
|
||||||
|
},
|
||||||
|
"node-abi": {
|
||||||
|
"version": "3.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz",
|
||||||
|
"integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==",
|
||||||
|
"requires": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prebuild-install": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-CNcMgI1xBypOyGqjp3wOc8AAo1nMhZS3Cwd3iHIxOdAUbb+YxdNuM4Z5iIrZ8RLvOsf3F3bl7b7xGq6DjQoNYA==",
|
||||||
|
"requires": {
|
||||||
|
"detect-libc": "^2.0.0",
|
||||||
"expand-template": "^2.0.3",
|
"expand-template": "^2.0.3",
|
||||||
"github-from-package": "0.0.0",
|
"github-from-package": "0.0.0",
|
||||||
"minimist": "^1.2.3",
|
"minimist": "^1.2.3",
|
||||||
"mkdirp-classic": "^0.5.3",
|
"mkdirp-classic": "^0.5.3",
|
||||||
"napi-build-utils": "^1.0.1",
|
"napi-build-utils": "^1.0.1",
|
||||||
"node-abi": "^2.21.0",
|
"node-abi": "^3.3.0",
|
||||||
"npmlog": "^4.0.1",
|
"npmlog": "^4.0.1",
|
||||||
"pump": "^3.0.0",
|
"pump": "^3.0.0",
|
||||||
"rc": "^1.2.7",
|
"rc": "^1.2.7",
|
||||||
"simple-get": "^3.0.3",
|
"simple-get": "^4.0.0",
|
||||||
"tar-fs": "^2.0.0",
|
"tar-fs": "^2.0.0",
|
||||||
"tunnel-agent": "^0.6.0"
|
"tunnel-agent": "^0.6.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "7.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"simple-get": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||||
|
"requires": {
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mimic-response": {
|
"mimic-response": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
|
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
},
|
},
|
||||||
"mkdirp-classic": {
|
"mkdirp-classic": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
|
@ -906,9 +1059,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-addon-api": {
|
"node-addon-api": {
|
||||||
"version": "3.2.1",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
|
||||||
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
|
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
|
||||||
},
|
},
|
||||||
"noop-logger": {
|
"noop-logger": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
@ -1021,9 +1174,9 @@
|
||||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
},
|
},
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||||
},
|
},
|
||||||
"simple-concat": {
|
"simple-concat": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -1031,9 +1184,9 @@
|
||||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||||
},
|
},
|
||||||
"simple-get": {
|
"simple-get": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"decompress-response": "^4.2.0",
|
"decompress-response": "^4.2.0",
|
||||||
"once": "^1.3.1",
|
"once": "^1.3.1",
|
||||||
|
@ -1120,9 +1273,9 @@
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"which-pm-runs": {
|
"which-pm-runs": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz",
|
||||||
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
|
"integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="
|
||||||
},
|
},
|
||||||
"wide-align": {
|
"wide-align": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
|
@ -1136,6 +1289,11 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"productName": "Bitwarden",
|
"productName": "Bitwarden",
|
||||||
"description": "A secure and free password manager for all of your devices.",
|
"description": "A secure and free password manager for all of your devices.",
|
||||||
"version": "1.32.2",
|
"version": "1.33.1",
|
||||||
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||||
"homepage": "https://bitwarden.com",
|
"homepage": "https://bitwarden.com",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
@ -14,6 +14,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodert-win10-rs4/windows.security.credentials.ui": "^0.4.4",
|
"@nodert-win10-rs4/windows.security.credentials.ui": "^0.4.4",
|
||||||
"forcefocus": "^1.1.0",
|
"forcefocus": "^1.1.0",
|
||||||
"keytar": "7.7.0"
|
"keytar": "^7.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue