mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 18:23:31 +00:00
[PM-5189] Merging main into current branch
This commit is contained in:
@@ -7,5 +7,6 @@ checkmarx:
|
|||||||
scan:
|
scan:
|
||||||
configs:
|
configs:
|
||||||
sast:
|
sast:
|
||||||
|
presetName: "BW ASA Premium"
|
||||||
# Exclude spec files, and test specific files
|
# Exclude spec files, and test specific files
|
||||||
filter: "!*.spec.ts,!**/spec/**,!apps/desktop/native-messaging-test-runner/**"
|
filter: "!*.spec.ts,!**/spec/**,!apps/desktop/native-messaging-test-runner/**"
|
||||||
|
|||||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -61,6 +61,7 @@ apps/web/src/app/billing @bitwarden/team-billing-dev
|
|||||||
libs/angular/src/billing @bitwarden/team-billing-dev
|
libs/angular/src/billing @bitwarden/team-billing-dev
|
||||||
libs/common/src/billing @bitwarden/team-billing-dev
|
libs/common/src/billing @bitwarden/team-billing-dev
|
||||||
libs/billing @bitwarden/team-billing-dev
|
libs/billing @bitwarden/team-billing-dev
|
||||||
|
bitwarden_license/bit-web/src/app/billing @bitwarden/team-billing-dev
|
||||||
|
|
||||||
## Platform team files ##
|
## Platform team files ##
|
||||||
apps/browser/src/platform @bitwarden/team-platform-dev
|
apps/browser/src/platform @bitwarden/team-platform-dev
|
||||||
|
|||||||
4
.github/renovate.json
vendored
4
.github/renovate.json
vendored
@@ -16,6 +16,10 @@
|
|||||||
"matchManagers": ["cargo"],
|
"matchManagers": ["cargo"],
|
||||||
"commitMessagePrefix": "[deps] Platform:"
|
"commitMessagePrefix": "[deps] Platform:"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"groupName": "napi",
|
||||||
|
"matchPackageNames": ["napi", "napi-build", "napi-derive"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"matchPackageNames": ["typescript", "zone.js"],
|
"matchPackageNames": ["typescript", "zone.js"],
|
||||||
"matchUpdateTypes": ["major", "minor"],
|
"matchUpdateTypes": ["major", "minor"],
|
||||||
|
|||||||
20
.github/workflows/build-desktop.yml
vendored
20
.github/workflows/build-desktop.yml
vendored
@@ -444,7 +444,10 @@ jobs:
|
|||||||
|
|
||||||
macos-build:
|
macos-build:
|
||||||
name: MacOS Build
|
name: MacOS Build
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs: setup
|
needs: setup
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
@@ -602,7 +605,10 @@ jobs:
|
|||||||
|
|
||||||
macos-package-github:
|
macos-package-github:
|
||||||
name: MacOS Package GitHub Release Assets
|
name: MacOS Package GitHub Release Assets
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs:
|
needs:
|
||||||
- browser-build
|
- browser-build
|
||||||
- macos-build
|
- macos-build
|
||||||
@@ -808,7 +814,10 @@ jobs:
|
|||||||
|
|
||||||
macos-package-mas:
|
macos-package-mas:
|
||||||
name: MacOS Package Prod Release Asset
|
name: MacOS Package Prod Release Asset
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs:
|
needs:
|
||||||
- browser-build
|
- browser-build
|
||||||
- macos-build
|
- macos-build
|
||||||
@@ -1006,7 +1015,10 @@ jobs:
|
|||||||
macos-package-dev:
|
macos-package-dev:
|
||||||
name: MacOS Package Dev Release Asset
|
name: MacOS Package Dev Release Asset
|
||||||
if: false # We need to look into how code signing works for dev
|
if: false # We need to look into how code signing works for dev
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs:
|
needs:
|
||||||
- browser-build
|
- browser-build
|
||||||
- macos-build
|
- macos-build
|
||||||
|
|||||||
4
.github/workflows/build-web.yml
vendored
4
.github/workflows/build-web.yml
vendored
@@ -299,7 +299,7 @@ jobs:
|
|||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
|
|
||||||
- name: Trigger web vault deploy
|
- name: Trigger web vault deploy using GitHub Run ID
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||||
with:
|
with:
|
||||||
github-token: ${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
github-token: ${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||||
@@ -311,7 +311,7 @@ jobs:
|
|||||||
ref: 'main',
|
ref: 'main',
|
||||||
inputs: {
|
inputs: {
|
||||||
'environment': 'USDEV',
|
'environment': 'USDEV',
|
||||||
'branch-or-tag': 'main'
|
'build-web-run-id': '${{ github.run_id }}'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
34
.github/workflows/deploy-web.yml
vendored
34
.github/workflows/deploy-web.yml
vendored
@@ -27,6 +27,10 @@ on:
|
|||||||
description: "Debug mode"
|
description: "Debug mode"
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
|
build-web-run-id:
|
||||||
|
description: "Build-web workflow Run ID to use for artifact download"
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -46,6 +50,10 @@ on:
|
|||||||
description: "Debug mode"
|
description: "Debug mode"
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
|
build-web-run-id:
|
||||||
|
description: "Build-web workflow Run ID to use for artifact download"
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
deployments: write
|
deployments: write
|
||||||
@@ -168,7 +176,20 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
_ENVIRONMENT_ARTIFACT: ${{ needs.setup.outputs.environment-artifact }}
|
_ENVIRONMENT_ARTIFACT: ${{ needs.setup.outputs.environment-artifact }}
|
||||||
steps:
|
steps:
|
||||||
|
- name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}'
|
||||||
|
if: ${{ inputs.build-web-run-id }}
|
||||||
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
|
id: download-latest-artifacts
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
workflow: build-web.yml
|
||||||
|
path: apps/web
|
||||||
|
workflow_conclusion: success
|
||||||
|
run_id: ${{ inputs.build-web-run-id }}
|
||||||
|
artifacts: ${{ env._ENVIRONMENT_ARTIFACT }}
|
||||||
|
|
||||||
- name: 'Download latest cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
|
- name: 'Download latest cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
|
||||||
|
if: ${{ !inputs.build-web-run-id }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@main
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
id: download-artifacts
|
id: download-artifacts
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -249,7 +270,20 @@ jobs:
|
|||||||
keyvault: ${{ needs.setup.outputs.retrieve-secrets-keyvault }}
|
keyvault: ${{ needs.setup.outputs.retrieve-secrets-keyvault }}
|
||||||
secrets: "sa-bitwarden-web-vault-name,sp-bitwarden-web-vault-password,sp-bitwarden-web-vault-appid,sp-bitwarden-web-vault-tenant"
|
secrets: "sa-bitwarden-web-vault-name,sp-bitwarden-web-vault-password,sp-bitwarden-web-vault-appid,sp-bitwarden-web-vault-tenant"
|
||||||
|
|
||||||
|
- name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}'
|
||||||
|
if: ${{ inputs.build-web-run-id }}
|
||||||
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
|
id: download-latest-artifacts
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
workflow: build-web.yml
|
||||||
|
path: apps/web
|
||||||
|
workflow_conclusion: success
|
||||||
|
run_id: ${{ inputs.build-web-run-id }}
|
||||||
|
artifacts: ${{ env._ENVIRONMENT_ARTIFACT }}
|
||||||
|
|
||||||
- name: 'Download cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
|
- name: 'Download cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
|
||||||
|
if: ${{ !inputs.build-web-run-id }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@main
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
with:
|
with:
|
||||||
workflow: build-web.yml
|
workflow: build-web.yml
|
||||||
|
|||||||
15
.github/workflows/release-desktop-beta.yml
vendored
15
.github/workflows/release-desktop-beta.yml
vendored
@@ -393,7 +393,10 @@ jobs:
|
|||||||
|
|
||||||
macos-build:
|
macos-build:
|
||||||
name: MacOS Build
|
name: MacOS Build
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs: setup
|
needs: setup
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
|
||||||
@@ -522,7 +525,10 @@ jobs:
|
|||||||
|
|
||||||
macos-package-github:
|
macos-package-github:
|
||||||
name: MacOS Package GitHub Release Assets
|
name: MacOS Package GitHub Release Assets
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs:
|
needs:
|
||||||
- setup
|
- setup
|
||||||
- macos-build
|
- macos-build
|
||||||
@@ -732,7 +738,10 @@ jobs:
|
|||||||
|
|
||||||
macos-package-mas:
|
macos-package-mas:
|
||||||
name: MacOS Package Prod Release Asset
|
name: MacOS Package Prod Release Asset
|
||||||
runs-on: macos-13
|
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
|
||||||
|
# as the newer versions will case the native modules to be incompatible with older macOS systems
|
||||||
|
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
|
||||||
|
runs-on: macos-11
|
||||||
needs:
|
needs:
|
||||||
- setup
|
- setup
|
||||||
- macos-build
|
- macos-build
|
||||||
|
|||||||
9
.github/workflows/scan.yml
vendored
9
.github/workflows/scan.yml
vendored
@@ -10,8 +10,6 @@ on:
|
|||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize]
|
||||||
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-run:
|
check-run:
|
||||||
name: Check PR run
|
name: Check PR run
|
||||||
@@ -22,6 +20,8 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: check-run
|
needs: check-run
|
||||||
permissions:
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
security-events: write
|
security-events: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
additional_params: --report-format sarif --output-path . ${{ env.INCREMENTAL }}
|
additional_params: --report-format sarif --output-path . ${{ env.INCREMENTAL }}
|
||||||
|
|
||||||
- name: Upload Checkmarx results to GitHub
|
- name: Upload Checkmarx results to GitHub
|
||||||
uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
|
uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
|
||||||
with:
|
with:
|
||||||
sarif_file: cx_result.sarif
|
sarif_file: cx_result.sarif
|
||||||
|
|
||||||
@@ -51,6 +51,9 @@ jobs:
|
|||||||
name: Quality scan
|
name: Quality scan
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: check-run
|
needs: check-run
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repo
|
- name: Check out repo
|
||||||
|
|||||||
28
.github/workflows/version-bump.yml
vendored
28
.github/workflows/version-bump.yml
vendored
@@ -367,21 +367,27 @@ jobs:
|
|||||||
id: set-final-version-output
|
id: set-final-version-output
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ steps.bump-browser-version-override.outcome }}" = "success" ]]; then
|
if [[ "${{ steps.bump-browser-version-override.outcome }}" = "success" ]]; then
|
||||||
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
echo "version_browser=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-browser-version-automatic.outcome }}" = "success" ]]; then
|
elif [[ "${{ steps.bump-browser-version-automatic.outcome }}" = "success" ]]; then
|
||||||
echo "version=${{ steps.calculate-next-browser-version.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "version_browser=${{ steps.calculate-next-browser-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-cli-version-override.outcome }}" = "success" ]]; then
|
fi
|
||||||
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
|
||||||
|
if [[ "${{ steps.bump-cli-version-override.outcome }}" = "success" ]]; then
|
||||||
|
echo "version_cli=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-cli-version-automatic.outcome }}" = "success" ]]; then
|
elif [[ "${{ steps.bump-cli-version-automatic.outcome }}" = "success" ]]; then
|
||||||
echo "version=${{ steps.calculate-next-cli-version.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "version_cli=${{ steps.calculate-next-cli-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-desktop-version-override.outcome }}" = "success" ]]; then
|
fi
|
||||||
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
|
||||||
|
if [[ "${{ steps.bump-desktop-version-override.outcome }}" = "success" ]]; then
|
||||||
|
echo "version_desktop=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-desktop-version-automatic.outcome }}" = "success" ]]; then
|
elif [[ "${{ steps.bump-desktop-version-automatic.outcome }}" = "success" ]]; then
|
||||||
echo "version=${{ steps.calculate-next-desktop-version.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "version_desktop=${{ steps.calculate-next-desktop-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-web-version-override.outcome }}" = "success" ]]; then
|
fi
|
||||||
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
|
||||||
|
if [[ "${{ steps.bump-web-version-override.outcome }}" = "success" ]]; then
|
||||||
|
echo "version_web=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ steps.bump-web-version-automatic.outcome }}" = "success" ]]; then
|
elif [[ "${{ steps.bump-web-version-automatic.outcome }}" = "success" ]]; then
|
||||||
echo "version=${{ steps.calculate-next-web-version.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "version_web=${{ steps.calculate-next-web-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check if version changed
|
- name: Check if version changed
|
||||||
|
|||||||
26
apps/browser/.eslintrc.json
Normal file
26
apps/browser/.eslintrc.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"webextensions": true
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["src/**/*.ts"],
|
||||||
|
"excludedFiles": [
|
||||||
|
"src/**/{content,popup,spec}/**/*.ts",
|
||||||
|
"src/**/autofill/{notification,overlay}/**/*.ts",
|
||||||
|
"src/**/autofill/**/{autofill-overlay-content,collect-autofill-content,dom-element-visibility,insert-autofill-content}.service.ts",
|
||||||
|
"src/**/*.spec.ts"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-globals": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"name": "window",
|
||||||
|
"message": "The `window` object is not available in service workers and may not be available within the background script. Consider using `self`, `globalThis`, or another global property instead."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/browser",
|
"name": "@bitwarden/browser",
|
||||||
"version": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",
|
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",
|
||||||
|
|||||||
@@ -709,7 +709,7 @@
|
|||||||
"message": "Vis indstillinger i kontekstmenuen"
|
"message": "Vis indstillinger i kontekstmenuen"
|
||||||
},
|
},
|
||||||
"contextMenuItemDesc": {
|
"contextMenuItemDesc": {
|
||||||
"message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til hjemmesiden."
|
"message": "Brug et sekundært klik for at tilgå adgangskodegenerering og matchende logins til webstedet."
|
||||||
},
|
},
|
||||||
"contextMenuItemDescAlt": {
|
"contextMenuItemDescAlt": {
|
||||||
"message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til webstedet. Gælder alle indloggede konti."
|
"message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til webstedet. Gælder alle indloggede konti."
|
||||||
@@ -1033,7 +1033,7 @@
|
|||||||
"message": "Server URL"
|
"message": "Server URL"
|
||||||
},
|
},
|
||||||
"apiUrl": {
|
"apiUrl": {
|
||||||
"message": "API server URL"
|
"message": "API-server URL"
|
||||||
},
|
},
|
||||||
"webVaultUrl": {
|
"webVaultUrl": {
|
||||||
"message": "Web-boks server URL"
|
"message": "Web-boks server URL"
|
||||||
@@ -1574,7 +1574,7 @@
|
|||||||
"message": "Advarsel: Dette er en ikke-sikret HTTP side, og alle indsendte oplysninger kan potentielt ses og ændres af andre. Dette login blev oprindeligt gemt på en sikker (HTTPS) side."
|
"message": "Advarsel: Dette er en ikke-sikret HTTP side, og alle indsendte oplysninger kan potentielt ses og ændres af andre. Dette login blev oprindeligt gemt på en sikker (HTTPS) side."
|
||||||
},
|
},
|
||||||
"insecurePageWarningFillPrompt": {
|
"insecurePageWarningFillPrompt": {
|
||||||
"message": "Do you still wish to fill this login?"
|
"message": "Ønsker dette login stadig udfyldt?"
|
||||||
},
|
},
|
||||||
"autofillIframeWarning": {
|
"autofillIframeWarning": {
|
||||||
"message": "Formularen hostes af et andet domæne end URI'en for det gemte login. Vælg OK for at autoudfylde alligevel, eller Afbryd for at stoppe."
|
"message": "Formularen hostes af et andet domæne end URI'en for det gemte login. Vælg OK for at autoudfylde alligevel, eller Afbryd for at stoppe."
|
||||||
@@ -1712,7 +1712,7 @@
|
|||||||
"message": "Biometri mislykkedes"
|
"message": "Biometri mislykkedes"
|
||||||
},
|
},
|
||||||
"biometricsFailedDesc": {
|
"biometricsFailedDesc": {
|
||||||
"message": "Biometri kan ikke fuldføres, overvej at bruge en hovedadgangskode eller logge ud og ind igen. Fortsætter problemet, kontakt Bitwarden-supporten."
|
"message": "Biometri kan ikke gennemføres. Overvej at bruge en hovedadgangskode eller at logge ud. Fortsætter problemet, kontakt Bitwarden-supporten."
|
||||||
},
|
},
|
||||||
"nativeMessaginPermissionErrorTitle": {
|
"nativeMessaginPermissionErrorTitle": {
|
||||||
"message": "Tilladelse ikke givet"
|
"message": "Tilladelse ikke givet"
|
||||||
@@ -2027,7 +2027,7 @@
|
|||||||
"message": "Minutter"
|
"message": "Minutter"
|
||||||
},
|
},
|
||||||
"vaultTimeoutPolicyInEffect": {
|
"vaultTimeoutPolicyInEffect": {
|
||||||
"message": "Organisationspolitikker har sat maks. tilladt boks-timeout. til $HOURS$ time(r) og $MINUTES$ minut(ter).",
|
"message": "Organisationspolitikkerne har fastsat den maksimalt tilladte boks-timeout til $HOURS$ time(r) og $MINUTES$ minut(ter).",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"hours": {
|
"hours": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2314,7 +2314,7 @@
|
|||||||
"message": "Sådan autoudfyldes"
|
"message": "Sådan autoudfyldes"
|
||||||
},
|
},
|
||||||
"autofillSelectInfoWithCommand": {
|
"autofillSelectInfoWithCommand": {
|
||||||
"message": "Select an item from this screen, use the shortcut $COMMAND$, or explore other options in settings.",
|
"message": "Vælg et emne fra denne skærm, brug genvejen $COMMAND$ eller udforsk andre valgmuligheder i Indstillinger.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"command": {
|
"command": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2323,7 +2323,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autofillSelectInfoWithoutCommand": {
|
"autofillSelectInfoWithoutCommand": {
|
||||||
"message": "Select an item from this screen, or explore other options in settings."
|
"message": "Vælg et emne fra denne skærm eller udforsk andre valgmuligheder i Indstillinger."
|
||||||
},
|
},
|
||||||
"gotIt": {
|
"gotIt": {
|
||||||
"message": "Forstået"
|
"message": "Forstået"
|
||||||
@@ -2700,7 +2700,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"launchDuoAndFollowStepsToFinishLoggingIn": {
|
"launchDuoAndFollowStepsToFinishLoggingIn": {
|
||||||
"message": "Start DUO og følg trinene for at fuldføre indlogningen."
|
"message": "Start Duo og følg trinnene for at fuldføre indlogningen."
|
||||||
},
|
},
|
||||||
"duoRequiredForAccount": {
|
"duoRequiredForAccount": {
|
||||||
"message": "Duo-totrinsindlogning kræves for kontoen."
|
"message": "Duo-totrinsindlogning kræves for kontoen."
|
||||||
@@ -2712,7 +2712,7 @@
|
|||||||
"message": "Pop ud-udvidelse"
|
"message": "Pop ud-udvidelse"
|
||||||
},
|
},
|
||||||
"launchDuo": {
|
"launchDuo": {
|
||||||
"message": "Start DUO"
|
"message": "Start Duo"
|
||||||
},
|
},
|
||||||
"importFormatError": {
|
"importFormatError": {
|
||||||
"message": "Data er ikke korrekt formateret. Tjek importfilen og forsøg igen."
|
"message": "Data er ikke korrekt formateret. Tjek importfilen og forsøg igen."
|
||||||
|
|||||||
@@ -2999,5 +2999,11 @@
|
|||||||
"saveCipherAttemptFailed": {
|
"saveCipherAttemptFailed": {
|
||||||
"message": "Error saving credentials. Check console for details.",
|
"message": "Error saving credentials. Check console for details.",
|
||||||
"description": "Notification message for when saving credentials has failed."
|
"description": "Notification message for when saving credentials has failed."
|
||||||
|
},
|
||||||
|
"removePasskey": {
|
||||||
|
"message": "Remove passkey"
|
||||||
|
},
|
||||||
|
"passkeyRemoved": {
|
||||||
|
"message": "Passkey removed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"message": "Masuk"
|
"message": "Masuk"
|
||||||
},
|
},
|
||||||
"enterpriseSingleSignOn": {
|
"enterpriseSingleSignOn": {
|
||||||
"message": "Sistem Masuk Tunggal Perusahaan"
|
"message": "SSO Perusahaan"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"message": "Batal"
|
"message": "Batal"
|
||||||
|
|||||||
@@ -2913,7 +2913,7 @@
|
|||||||
"message": "Mudar de conta"
|
"message": "Mudar de conta"
|
||||||
},
|
},
|
||||||
"switchAccounts": {
|
"switchAccounts": {
|
||||||
"message": "Mudar de contas"
|
"message": "Mudar de conta"
|
||||||
},
|
},
|
||||||
"switchToAccount": {
|
"switchToAccount": {
|
||||||
"message": "Mudar para conta"
|
"message": "Mudar para conta"
|
||||||
|
|||||||
@@ -1500,7 +1500,7 @@
|
|||||||
"message": "无效 PIN 码。"
|
"message": "无效 PIN 码。"
|
||||||
},
|
},
|
||||||
"tooManyInvalidPinEntryAttemptsLoggingOut": {
|
"tooManyInvalidPinEntryAttemptsLoggingOut": {
|
||||||
"message": "无效的 PIN 输入尝试次数过多,正在退出登录。"
|
"message": "无效的 PIN 输入尝试次数过多,正在注销。"
|
||||||
},
|
},
|
||||||
"unlockWithBiometrics": {
|
"unlockWithBiometrics": {
|
||||||
"message": "使用生物识别解锁"
|
"message": "使用生物识别解锁"
|
||||||
@@ -1742,7 +1742,7 @@
|
|||||||
"message": "Bitwarden 将不会询问是否为这些域名保存登录信息。您必须刷新页面才能使更改生效。"
|
"message": "Bitwarden 将不会询问是否为这些域名保存登录信息。您必须刷新页面才能使更改生效。"
|
||||||
},
|
},
|
||||||
"excludedDomainsDescAlt": {
|
"excludedDomainsDescAlt": {
|
||||||
"message": "Bitwarden 不会询问保存所有已登录的账户的这些域名的登录信息。您必须刷新页面才能使更改生效。"
|
"message": "Bitwarden 不会询问保存所有已登录的账户的这些域名的登录信息。必须刷新页面才能使更改生效。"
|
||||||
},
|
},
|
||||||
"excludedDomainsInvalidDomain": {
|
"excludedDomainsInvalidDomain": {
|
||||||
"message": "$DOMAIN$ 不是一个有效的域名",
|
"message": "$DOMAIN$ 不是一个有效的域名",
|
||||||
@@ -2314,7 +2314,7 @@
|
|||||||
"message": "如何自动填充"
|
"message": "如何自动填充"
|
||||||
},
|
},
|
||||||
"autofillSelectInfoWithCommand": {
|
"autofillSelectInfoWithCommand": {
|
||||||
"message": "从此界面选择一个项目,使用快捷方式 $COMMAND$,或探索设置中的其他选项。",
|
"message": "从此界面选择一个项目,使用快捷键 $COMMAND$,或探索设置中的其他选项。",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"command": {
|
"command": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2335,10 +2335,10 @@
|
|||||||
"message": "自动填充键盘快捷键"
|
"message": "自动填充键盘快捷键"
|
||||||
},
|
},
|
||||||
"autofillShortcutNotSet": {
|
"autofillShortcutNotSet": {
|
||||||
"message": "未设置自动填充快捷方式。请在浏览器设置中更改此设置。"
|
"message": "未设置自动填充快捷键。可在浏览器的设置中更改它。"
|
||||||
},
|
},
|
||||||
"autofillShortcutText": {
|
"autofillShortcutText": {
|
||||||
"message": "自动填充快捷方式为: $COMMAND$。在浏览器设置中更改此项。",
|
"message": "自动填充快捷键为:$COMMAND$。可在浏览器的设置中更改它。",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"command": {
|
"command": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2928,7 +2928,7 @@
|
|||||||
"message": "已达到账户上限。请注销一个账户后再添加其他账户。"
|
"message": "已达到账户上限。请注销一个账户后再添加其他账户。"
|
||||||
},
|
},
|
||||||
"active": {
|
"active": {
|
||||||
"message": "已生效"
|
"message": "活动的"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"message": "已锁定"
|
"message": "已锁定"
|
||||||
@@ -2961,7 +2961,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commonImportFormats": {
|
"commonImportFormats": {
|
||||||
"message": "通用格式",
|
"message": "常规格式",
|
||||||
"description": "Label indicating the most common import formats"
|
"description": "Label indicating the most common import formats"
|
||||||
},
|
},
|
||||||
"overrideDefaultBrowserAutofillTitle": {
|
"overrideDefaultBrowserAutofillTitle": {
|
||||||
@@ -2969,7 +2969,7 @@
|
|||||||
"description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior"
|
"description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior"
|
||||||
},
|
},
|
||||||
"overrideDefaultBrowserAutofillDescription": {
|
"overrideDefaultBrowserAutofillDescription": {
|
||||||
"message": "忽略此设置可能会导致 Bitwarden 自动填充菜单与浏览器自带功能产生冲突。",
|
"message": "忽略此选项可能会导致 Bitwarden 自动填充菜单与浏览器自带功能产生冲突。",
|
||||||
"description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior"
|
"description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior"
|
||||||
},
|
},
|
||||||
"overrideDefaultBrowserAutoFillSettings": {
|
"overrideDefaultBrowserAutoFillSettings": {
|
||||||
|
|||||||
@@ -23,13 +23,18 @@ import {
|
|||||||
stateServiceFactory,
|
stateServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-service.factory";
|
||||||
|
|
||||||
|
import { AccountServiceInitOptions, accountServiceFactory } from "./account-service.factory";
|
||||||
|
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
|
||||||
|
|
||||||
type AuthServiceFactoryOptions = FactoryOptions;
|
type AuthServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type AuthServiceInitOptions = AuthServiceFactoryOptions &
|
export type AuthServiceInitOptions = AuthServiceFactoryOptions &
|
||||||
|
AccountServiceInitOptions &
|
||||||
MessagingServiceInitOptions &
|
MessagingServiceInitOptions &
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
ApiServiceInitOptions &
|
ApiServiceInitOptions &
|
||||||
StateServiceInitOptions;
|
StateServiceInitOptions &
|
||||||
|
TokenServiceInitOptions;
|
||||||
|
|
||||||
export function authServiceFactory(
|
export function authServiceFactory(
|
||||||
cache: { authService?: AbstractAuthService } & CachedServices,
|
cache: { authService?: AbstractAuthService } & CachedServices,
|
||||||
@@ -41,10 +46,12 @@ export function authServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new AuthService(
|
new AuthService(
|
||||||
|
await accountServiceFactory(cache, opts),
|
||||||
await messagingServiceFactory(cache, opts),
|
await messagingServiceFactory(cache, opts),
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
await stateServiceFactory(cache, opts),
|
await stateServiceFactory(cache, opts),
|
||||||
|
await tokenServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,13 @@ import {
|
|||||||
platformUtilsServiceFactory,
|
platformUtilsServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/platform-utils-service.factory";
|
} from "../../../platform/background/service-factories/platform-utils-service.factory";
|
||||||
import {
|
import {
|
||||||
StateServiceInitOptions,
|
StateProviderInitOptions,
|
||||||
stateServiceFactory,
|
stateProviderFactory,
|
||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
import {
|
||||||
|
SecureStorageServiceInitOptions,
|
||||||
|
secureStorageServiceFactory,
|
||||||
|
} from "../../../platform/background/service-factories/storage-service.factory";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
UserDecryptionOptionsServiceInitOptions,
|
UserDecryptionOptionsServiceInitOptions,
|
||||||
@@ -55,11 +59,12 @@ export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactor
|
|||||||
CryptoFunctionServiceInitOptions &
|
CryptoFunctionServiceInitOptions &
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
EncryptServiceInitOptions &
|
EncryptServiceInitOptions &
|
||||||
StateServiceInitOptions &
|
|
||||||
AppIdServiceInitOptions &
|
AppIdServiceInitOptions &
|
||||||
DevicesApiServiceInitOptions &
|
DevicesApiServiceInitOptions &
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
PlatformUtilsServiceInitOptions &
|
PlatformUtilsServiceInitOptions &
|
||||||
|
StateProviderInitOptions &
|
||||||
|
SecureStorageServiceInitOptions &
|
||||||
UserDecryptionOptionsServiceInitOptions;
|
UserDecryptionOptionsServiceInitOptions;
|
||||||
|
|
||||||
export function deviceTrustCryptoServiceFactory(
|
export function deviceTrustCryptoServiceFactory(
|
||||||
@@ -76,11 +81,12 @@ export function deviceTrustCryptoServiceFactory(
|
|||||||
await cryptoFunctionServiceFactory(cache, opts),
|
await cryptoFunctionServiceFactory(cache, opts),
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await encryptServiceFactory(cache, opts),
|
await encryptServiceFactory(cache, opts),
|
||||||
await stateServiceFactory(cache, opts),
|
|
||||||
await appIdServiceFactory(cache, opts),
|
await appIdServiceFactory(cache, opts),
|
||||||
await devicesApiServiceFactory(cache, opts),
|
await devicesApiServiceFactory(cache, opts),
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await platformUtilsServiceFactory(cache, opts),
|
await platformUtilsServiceFactory(cache, opts),
|
||||||
|
await stateProviderFactory(cache, opts),
|
||||||
|
await secureStorageServiceFactory(cache, opts),
|
||||||
await userDecryptionOptionsServiceFactory(cache, opts),
|
await userDecryptionOptionsServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import {
|
|||||||
LogServiceInitOptions,
|
LogServiceInitOptions,
|
||||||
} from "../../../platform/background/service-factories/log-service.factory";
|
} from "../../../platform/background/service-factories/log-service.factory";
|
||||||
import {
|
import {
|
||||||
stateServiceFactory,
|
stateProviderFactory,
|
||||||
StateServiceInitOptions,
|
StateProviderInitOptions,
|
||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
|
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
|
||||||
|
|
||||||
@@ -40,13 +40,13 @@ type KeyConnectorServiceFactoryOptions = FactoryOptions & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions &
|
export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions &
|
||||||
StateServiceInitOptions &
|
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
ApiServiceInitOptions &
|
ApiServiceInitOptions &
|
||||||
TokenServiceInitOptions &
|
TokenServiceInitOptions &
|
||||||
LogServiceInitOptions &
|
LogServiceInitOptions &
|
||||||
OrganizationServiceInitOptions &
|
OrganizationServiceInitOptions &
|
||||||
KeyGenerationServiceInitOptions;
|
KeyGenerationServiceInitOptions &
|
||||||
|
StateProviderInitOptions;
|
||||||
|
|
||||||
export function keyConnectorServiceFactory(
|
export function keyConnectorServiceFactory(
|
||||||
cache: { keyConnectorService?: AbstractKeyConnectorService } & CachedServices,
|
cache: { keyConnectorService?: AbstractKeyConnectorService } & CachedServices,
|
||||||
@@ -58,7 +58,6 @@ export function keyConnectorServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new KeyConnectorService(
|
new KeyConnectorService(
|
||||||
await stateServiceFactory(cache, opts),
|
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
await tokenServiceFactory(cache, opts),
|
await tokenServiceFactory(cache, opts),
|
||||||
@@ -66,6 +65,7 @@ export function keyConnectorServiceFactory(
|
|||||||
await organizationServiceFactory(cache, opts),
|
await organizationServiceFactory(cache, opts),
|
||||||
await keyGenerationServiceFactory(cache, opts),
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
opts.keyConnectorServiceOptions.logoutCallback,
|
opts.keyConnectorServiceOptions.logoutCallback,
|
||||||
|
await stateProviderFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { LoginEmailServiceAbstraction, LoginEmailService } from "@bitwarden/auth/common";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CachedServices,
|
||||||
|
factory,
|
||||||
|
FactoryOptions,
|
||||||
|
} from "../../../platform/background/service-factories/factory-options";
|
||||||
|
import {
|
||||||
|
stateProviderFactory,
|
||||||
|
StateProviderInitOptions,
|
||||||
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
|
type LoginEmailServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type LoginEmailServiceInitOptions = LoginEmailServiceFactoryOptions &
|
||||||
|
StateProviderInitOptions;
|
||||||
|
|
||||||
|
export function loginEmailServiceFactory(
|
||||||
|
cache: { loginEmailService?: LoginEmailServiceAbstraction } & CachedServices,
|
||||||
|
opts: LoginEmailServiceInitOptions,
|
||||||
|
): Promise<LoginEmailServiceAbstraction> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"loginEmailService",
|
||||||
|
opts,
|
||||||
|
async () => new LoginEmailService(await stateProviderFactory(cache, opts)),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||||
|
|
||||||
|
import {
|
||||||
|
EncryptServiceInitOptions,
|
||||||
|
encryptServiceFactory,
|
||||||
|
} from "../../../platform/background/service-factories/encrypt-service.factory";
|
||||||
import {
|
import {
|
||||||
FactoryOptions,
|
FactoryOptions,
|
||||||
CachedServices,
|
CachedServices,
|
||||||
@@ -10,6 +14,14 @@ import {
|
|||||||
GlobalStateProviderInitOptions,
|
GlobalStateProviderInitOptions,
|
||||||
globalStateProviderFactory,
|
globalStateProviderFactory,
|
||||||
} from "../../../platform/background/service-factories/global-state-provider.factory";
|
} from "../../../platform/background/service-factories/global-state-provider.factory";
|
||||||
|
import {
|
||||||
|
KeyGenerationServiceInitOptions,
|
||||||
|
keyGenerationServiceFactory,
|
||||||
|
} from "../../../platform/background/service-factories/key-generation-service.factory";
|
||||||
|
import {
|
||||||
|
LogServiceInitOptions,
|
||||||
|
logServiceFactory,
|
||||||
|
} from "../../../platform/background/service-factories/log-service.factory";
|
||||||
import {
|
import {
|
||||||
PlatformUtilsServiceInitOptions,
|
PlatformUtilsServiceInitOptions,
|
||||||
platformUtilsServiceFactory,
|
platformUtilsServiceFactory,
|
||||||
@@ -29,7 +41,10 @@ export type TokenServiceInitOptions = TokenServiceFactoryOptions &
|
|||||||
SingleUserStateProviderInitOptions &
|
SingleUserStateProviderInitOptions &
|
||||||
GlobalStateProviderInitOptions &
|
GlobalStateProviderInitOptions &
|
||||||
PlatformUtilsServiceInitOptions &
|
PlatformUtilsServiceInitOptions &
|
||||||
SecureStorageServiceInitOptions;
|
SecureStorageServiceInitOptions &
|
||||||
|
KeyGenerationServiceInitOptions &
|
||||||
|
EncryptServiceInitOptions &
|
||||||
|
LogServiceInitOptions;
|
||||||
|
|
||||||
export function tokenServiceFactory(
|
export function tokenServiceFactory(
|
||||||
cache: { tokenService?: AbstractTokenService } & CachedServices,
|
cache: { tokenService?: AbstractTokenService } & CachedServices,
|
||||||
@@ -45,6 +60,9 @@ export function tokenServiceFactory(
|
|||||||
await globalStateProviderFactory(cache, opts),
|
await globalStateProviderFactory(cache, opts),
|
||||||
(await platformUtilsServiceFactory(cache, opts)).supportsSecureStorage(),
|
(await platformUtilsServiceFactory(cache, opts)).supportsSecureStorage(),
|
||||||
await secureStorageServiceFactory(cache, opts),
|
await secureStorageServiceFactory(cache, opts),
|
||||||
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
|
await encryptServiceFactory(cache, opts),
|
||||||
|
await logServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { Component } from "@angular/core";
|
|||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { HintComponent as BaseHintComponent } from "@bitwarden/angular/auth/components/hint.component";
|
import { HintComponent as BaseHintComponent } from "@bitwarden/angular/auth/components/hint.component";
|
||||||
|
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -20,9 +20,9 @@ export class HintComponent extends BaseHintComponent {
|
|||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
loginService: LoginService,
|
loginEmailService: LoginEmailServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
super(router, i18nService, apiService, platformUtilsService, logService, loginService);
|
super(router, i18nService, apiService, platformUtilsService, logService, loginEmailService);
|
||||||
|
|
||||||
super.onSuccessfulSubmit = async () => {
|
super.onSuccessfulSubmit = async () => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<p class="createAccountLink">
|
<p class="createAccountLink">
|
||||||
{{ "newAroundHere" | i18n }}
|
{{ "newAroundHere" | i18n }}
|
||||||
<a routerLink="/register" (click)="setFormValues()">{{ "createAccount" | i18n }}</a>
|
<a routerLink="/register" (click)="setLoginEmailValues()">{{ "createAccount" | i18n }}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||||
import { FormBuilder, Validators } from "@angular/forms";
|
import { FormBuilder, Validators } from "@angular/forms";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
import { Subject, firstValueFrom, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
|
|
||||||
import { AccountSwitcherService } from "./account-switching/services/account-switcher.service";
|
import { AccountSwitcherService } from "./account-switching/services/account-switcher.service";
|
||||||
|
|
||||||
@@ -29,38 +28,32 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
private stateService: StateService,
|
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
private loginService: LoginService,
|
private loginEmailService: LoginEmailServiceAbstraction,
|
||||||
private accountSwitcherService: AccountSwitcherService,
|
private accountSwitcherService: AccountSwitcherService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
let savedEmail = this.loginService.getEmail();
|
const email = this.loginEmailService.getEmail();
|
||||||
const rememberEmail = this.loginService.getRememberEmail();
|
const rememberEmail = this.loginEmailService.getRememberEmail();
|
||||||
|
|
||||||
if (savedEmail != null) {
|
if (email != null) {
|
||||||
this.formGroup.patchValue({
|
this.formGroup.patchValue({ email, rememberEmail });
|
||||||
email: savedEmail,
|
|
||||||
rememberEmail: rememberEmail,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
savedEmail = await this.stateService.getRememberedEmail();
|
const storedEmail = await firstValueFrom(this.loginEmailService.storedEmail$);
|
||||||
if (savedEmail != null) {
|
|
||||||
this.formGroup.patchValue({
|
if (storedEmail != null) {
|
||||||
email: savedEmail,
|
this.formGroup.patchValue({ email: storedEmail, rememberEmail: true });
|
||||||
rememberEmail: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.environmentSelector.onOpenSelfHostedSettings
|
this.environmentSelector.onOpenSelfHostedSettings
|
||||||
.pipe(takeUntil(this.destroyed$))
|
.pipe(takeUntil(this.destroyed$))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.setFormValues();
|
this.setLoginEmailValues();
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.router.navigate(["environment"]);
|
this.router.navigate(["environment"]);
|
||||||
@@ -76,8 +69,9 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
return this.accountSwitcherService.availableAccounts$;
|
return this.accountSwitcherService.availableAccounts$;
|
||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
async submit() {
|
||||||
this.formGroup.markAllAsTouched();
|
this.formGroup.markAllAsTouched();
|
||||||
|
|
||||||
if (this.formGroup.invalid) {
|
if (this.formGroup.invalid) {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
@@ -87,15 +81,12 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loginService.setEmail(this.formGroup.value.email);
|
this.setLoginEmailValues();
|
||||||
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
|
await this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFormValues() {
|
setLoginEmailValues() {
|
||||||
this.loginService.setEmail(this.formGroup.value.email);
|
this.loginEmailService.setEmail(this.formGroup.value.email);
|
||||||
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
|
this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaul
|
|||||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
@@ -62,6 +63,7 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
pinCryptoService: PinCryptoServiceAbstraction,
|
pinCryptoService: PinCryptoServiceAbstraction,
|
||||||
private routerService: BrowserRouterService,
|
private routerService: BrowserRouterService,
|
||||||
biometricStateService: BiometricStateService,
|
biometricStateService: BiometricStateService,
|
||||||
|
accountService: AccountService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
router,
|
router,
|
||||||
@@ -84,6 +86,7 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
userVerificationService,
|
userVerificationService,
|
||||||
pinCryptoService,
|
pinCryptoService,
|
||||||
biometricStateService,
|
biometricStateService,
|
||||||
|
accountService,
|
||||||
);
|
);
|
||||||
this.successRoute = "/tabs/current";
|
this.successRoute = "/tabs/current";
|
||||||
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
|
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Location } from "@angular/common";
|
import { Location } from "@angular/common";
|
||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component";
|
import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component";
|
||||||
import {
|
import {
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
|
LoginEmailServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service";
|
import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -28,10 +29,7 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv
|
|||||||
selector: "app-login-via-auth-request",
|
selector: "app-login-via-auth-request",
|
||||||
templateUrl: "login-via-auth-request.component.html",
|
templateUrl: "login-via-auth-request.component.html",
|
||||||
})
|
})
|
||||||
export class LoginViaAuthRequestComponent
|
export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent {
|
||||||
extends BaseLoginWithDeviceComponent
|
|
||||||
implements OnInit, OnDestroy
|
|
||||||
{
|
|
||||||
constructor(
|
constructor(
|
||||||
router: Router,
|
router: Router,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
@@ -47,11 +45,12 @@ export class LoginViaAuthRequestComponent
|
|||||||
anonymousHubService: AnonymousHubService,
|
anonymousHubService: AnonymousHubService,
|
||||||
validationService: ValidationService,
|
validationService: ValidationService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
loginService: LoginService,
|
loginEmailService: LoginEmailServiceAbstraction,
|
||||||
syncService: SyncService,
|
syncService: SyncService,
|
||||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
authRequestService: AuthRequestServiceAbstraction,
|
authRequestService: AuthRequestServiceAbstraction,
|
||||||
loginStrategyService: LoginStrategyServiceAbstraction,
|
loginStrategyService: LoginStrategyServiceAbstraction,
|
||||||
|
accountService: AccountService,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -69,10 +68,11 @@ export class LoginViaAuthRequestComponent
|
|||||||
anonymousHubService,
|
anonymousHubService,
|
||||||
validationService,
|
validationService,
|
||||||
stateService,
|
stateService,
|
||||||
loginService,
|
loginEmailService,
|
||||||
deviceTrustCryptoService,
|
deviceTrustCryptoService,
|
||||||
authRequestService,
|
authRequestService,
|
||||||
loginStrategyService,
|
loginStrategyService,
|
||||||
|
accountService,
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = async () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
await syncService.fullSync(true);
|
await syncService.fullSync(true);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
<button type="button" class="btn link" routerLink="/hint" (click)="setFormValues()">
|
<button type="button" class="btn link" routerLink="/hint" (click)="setLoginEmailValues()">
|
||||||
<b>{{ "getMasterPasswordHint" | i18n }}</b>
|
<b>{{ "getMasterPasswordHint" | i18n }}</b>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import { firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
import {
|
||||||
|
LoginStrategyServiceAbstraction,
|
||||||
|
LoginEmailServiceAbstraction,
|
||||||
|
} from "@bitwarden/auth/common";
|
||||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction";
|
import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
@@ -46,7 +48,7 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
formBuilder: FormBuilder,
|
formBuilder: FormBuilder,
|
||||||
formValidationErrorService: FormValidationErrorsService,
|
formValidationErrorService: FormValidationErrorsService,
|
||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
loginService: LoginService,
|
loginEmailService: LoginEmailServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
webAuthnLoginService: WebAuthnLoginServiceAbstraction,
|
webAuthnLoginService: WebAuthnLoginServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
@@ -66,7 +68,7 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
formBuilder,
|
formBuilder,
|
||||||
formValidationErrorService,
|
formValidationErrorService,
|
||||||
route,
|
route,
|
||||||
loginService,
|
loginEmailService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
webAuthnLoginService,
|
webAuthnLoginService,
|
||||||
);
|
);
|
||||||
@@ -77,8 +79,8 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
this.showPasswordless = flagEnabled("showPasswordless");
|
this.showPasswordless = flagEnabled("showPasswordless");
|
||||||
|
|
||||||
if (this.showPasswordless) {
|
if (this.showPasswordless) {
|
||||||
this.formGroup.controls.email.setValue(this.loginService.getEmail());
|
this.formGroup.controls.email.setValue(this.loginEmailService.getEmail());
|
||||||
this.formGroup.controls.rememberEmail.setValue(this.loginService.getRememberEmail());
|
this.formGroup.controls.rememberEmail.setValue(this.loginEmailService.getRememberEmail());
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.validateEmail();
|
this.validateEmail();
|
||||||
@@ -94,7 +96,7 @@ export class LoginComponent extends BaseLoginComponent {
|
|||||||
async launchSsoBrowser() {
|
async launchSsoBrowser() {
|
||||||
// Save off email for SSO
|
// Save off email for SSO
|
||||||
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
|
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
|
||||||
await this.loginService.saveEmailSettings();
|
await this.loginEmailService.saveEmailSettings();
|
||||||
// Generate necessary sso params
|
// Generate necessary sso params
|
||||||
const passwordOptions: any = {
|
const passwordOptions: any = {
|
||||||
type: "password",
|
type: "password",
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
|
|
||||||
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
|
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UnauthGuardService extends BaseUnauthGuardService {
|
export class UnauthGuardService extends BaseUnauthGuardService {
|
||||||
protected homepage = "tabs/current";
|
protected homepage = "tabs/current";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
@@ -44,7 +44,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
@Inject(WINDOW) private win: Window,
|
@Inject(WINDOW) private win: Window,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular
|
|||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import {
|
import {
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
|
LoginEmailServiceAbstraction,
|
||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@@ -57,9 +57,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
twoFactorService: TwoFactorService,
|
twoFactorService: TwoFactorService,
|
||||||
appIdService: AppIdService,
|
appIdService: AppIdService,
|
||||||
loginService: LoginService,
|
loginEmailService: LoginEmailServiceAbstraction,
|
||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigService,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
@@ -78,7 +78,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
logService,
|
logService,
|
||||||
twoFactorService,
|
twoFactorService,
|
||||||
appIdService,
|
appIdService,
|
||||||
loginService,
|
loginEmailService,
|
||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default class WebRequestBackground {
|
|||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
) {
|
) {
|
||||||
if (BrowserApi.isManifestVersion(2)) {
|
if (BrowserApi.isManifestVersion(2)) {
|
||||||
this.webRequest = (window as any).chrome.webRequest;
|
this.webRequest = chrome.webRequest;
|
||||||
}
|
}
|
||||||
this.isFirefox = platformUtilsService.isFirefox();
|
this.isFirefox = platformUtilsService.isFirefox();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
authServiceFactory,
|
authServiceFactory,
|
||||||
AuthServiceInitOptions,
|
AuthServiceInitOptions,
|
||||||
} from "../../auth/background/service-factories/auth-service.factory";
|
} from "../../auth/background/service-factories/auth-service.factory";
|
||||||
|
import { KeyConnectorServiceInitOptions } from "../../auth/background/service-factories/key-connector-service.factory";
|
||||||
import { userVerificationServiceFactory } from "../../auth/background/service-factories/user-verification-service.factory";
|
import { userVerificationServiceFactory } from "../../auth/background/service-factories/user-verification-service.factory";
|
||||||
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
||||||
import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory";
|
import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory";
|
||||||
@@ -78,7 +79,9 @@ export class ContextMenuClickedHandler {
|
|||||||
|
|
||||||
static async mv3Create(cachedServices: CachedServices) {
|
static async mv3Create(cachedServices: CachedServices) {
|
||||||
const stateFactory = new StateFactory(GlobalState, Account);
|
const stateFactory = new StateFactory(GlobalState, Account);
|
||||||
const serviceOptions: AuthServiceInitOptions & CipherServiceInitOptions = {
|
const serviceOptions: AuthServiceInitOptions &
|
||||||
|
CipherServiceInitOptions &
|
||||||
|
KeyConnectorServiceInitOptions = {
|
||||||
apiServiceOptions: {
|
apiServiceOptions: {
|
||||||
logoutCallback: NOT_IMPLEMENTED,
|
logoutCallback: NOT_IMPLEMENTED,
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ function loadAutofiller() {
|
|||||||
let pageHref: string = null;
|
let pageHref: string = null;
|
||||||
let filledThisHref = false;
|
let filledThisHref = false;
|
||||||
let delayFillTimeout: number;
|
let delayFillTimeout: number;
|
||||||
let doFillInterval: NodeJS.Timeout;
|
let doFillInterval: number | NodeJS.Timeout;
|
||||||
const handleExtensionDisconnect = () => {
|
const handleExtensionDisconnect = () => {
|
||||||
clearDoFillInterval();
|
clearDoFillInterval();
|
||||||
clearDelayFillTimeout();
|
clearDelayFillTimeout();
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("resize", adjustHeight);
|
globalThis.addEventListener("resize", adjustHeight);
|
||||||
adjustHeight();
|
adjustHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ function setupLogoLink(i18n: Record<string, string>) {
|
|||||||
function setNotificationBarTheme() {
|
function setNotificationBarTheme() {
|
||||||
let theme = notificationBarIframeInitData.theme;
|
let theme = notificationBarIframeInitData.theme;
|
||||||
if (theme === ThemeType.System) {
|
if (theme === ThemeType.System) {
|
||||||
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
theme = globalThis.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
? ThemeType.Dark
|
? ThemeType.Dark
|
||||||
: ThemeType.Light;
|
: ThemeType.Light;
|
||||||
}
|
}
|
||||||
@@ -393,5 +393,5 @@ function setNotificationBarTheme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function postMessageToParent(message: NotificationBarWindowMessage) {
|
function postMessageToParent(message: NotificationBarWindowMessage) {
|
||||||
window.parent.postMessage(message, windowMessageOrigin || "*");
|
globalThis.parent.postMessage(message, windowMessageOrigin || "*");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
let borderColor: string;
|
let borderColor: string;
|
||||||
let verifiedTheme = theme;
|
let verifiedTheme = theme;
|
||||||
if (verifiedTheme === ThemeType.System) {
|
if (verifiedTheme === ThemeType.System) {
|
||||||
verifiedTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
verifiedTheme = globalThis.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
? ThemeType.Dark
|
? ThemeType.Dark
|
||||||
: ThemeType.Light;
|
: ThemeType.Light;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
private ciphers: OverlayCipherData[] = [];
|
private ciphers: OverlayCipherData[] = [];
|
||||||
private ciphersList: HTMLUListElement;
|
private ciphersList: HTMLUListElement;
|
||||||
private cipherListScrollIsDebounced = false;
|
private cipherListScrollIsDebounced = false;
|
||||||
private cipherListScrollDebounceTimeout: NodeJS.Timeout;
|
private cipherListScrollDebounceTimeout: number | NodeJS.Timeout;
|
||||||
private currentCipherIndex = 0;
|
private currentCipherIndex = 0;
|
||||||
private readonly showCiphersPerPage = 6;
|
private readonly showCiphersPerPage = 6;
|
||||||
private readonly overlayListWindowMessageHandlers: OverlayListWindowMessageHandlers = {
|
private readonly overlayListWindowMessageHandlers: OverlayListWindowMessageHandlers = {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface PageDetail {
|
|||||||
export interface AutoFillOptions {
|
export interface AutoFillOptions {
|
||||||
cipher: CipherView;
|
cipher: CipherView;
|
||||||
pageDetails: PageDetail[];
|
pageDetails: PageDetail[];
|
||||||
doc?: typeof window.document;
|
doc?: typeof self.document;
|
||||||
tab: chrome.tabs.Tab;
|
tab: chrome.tabs.Tab;
|
||||||
skipUsernameOnlyFill?: boolean;
|
skipUsernameOnlyFill?: boolean;
|
||||||
onlyEmptyFields?: boolean;
|
onlyEmptyFields?: boolean;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe("a placeholder", () => {
|
|||||||
//
|
//
|
||||||
// const defaultWindowReadyState = document.readyState;
|
// const defaultWindowReadyState = document.readyState;
|
||||||
// const defaultDocumentVisibilityState = document.visibilityState;
|
// const defaultDocumentVisibilityState = document.visibilityState;
|
||||||
// describe("AutofillOverlayContentService", () => {
|
// describe.skip("AutofillOverlayContentService", () => {
|
||||||
// let autofillOverlayContentService: AutofillOverlayContentService;
|
// let autofillOverlayContentService: AutofillOverlayContentService;
|
||||||
// let sendExtensionMessageSpy: jest.SpyInstance;
|
// let sendExtensionMessageSpy: jest.SpyInstance;
|
||||||
//
|
//
|
||||||
@@ -177,12 +177,10 @@ describe("a placeholder", () => {
|
|||||||
// autofillFieldData = mock<AutofillField>();
|
// autofillFieldData = mock<AutofillField>();
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that are readonly", () => {
|
// it("ignores fields that are readonly", async () => {
|
||||||
// autofillFieldData.readonly = true;
|
// autofillFieldData.readonly = true;
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -190,12 +188,10 @@ describe("a placeholder", () => {
|
|||||||
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that contain a disabled attribute", () => {
|
// it("ignores fields that contain a disabled attribute", async () => {
|
||||||
// autofillFieldData.disabled = true;
|
// autofillFieldData.disabled = true;
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -203,12 +199,10 @@ describe("a placeholder", () => {
|
|||||||
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that are not viewable", () => {
|
// it("ignores fields that are not viewable", async () => {
|
||||||
// autofillFieldData.viewable = false;
|
// autofillFieldData.viewable = false;
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -217,12 +211,10 @@ describe("a placeholder", () => {
|
|||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that are part of the ExcludedOverlayTypes", () => {
|
// it("ignores fields that are part of the ExcludedOverlayTypes", () => {
|
||||||
// AutoFillConstants.ExcludedOverlayTypes.forEach((excludedType) => {
|
// AutoFillConstants.ExcludedOverlayTypes.forEach(async (excludedType) => {
|
||||||
// autofillFieldData.type = excludedType;
|
// autofillFieldData.type = excludedType;
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -231,12 +223,10 @@ describe("a placeholder", () => {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that contain the keyword `search`", () => {
|
// it("ignores fields that contain the keyword `search`", async () => {
|
||||||
// autofillFieldData.placeholder = "search";
|
// autofillFieldData.placeholder = "search";
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -244,12 +234,10 @@ describe("a placeholder", () => {
|
|||||||
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that contain the keyword `captcha` ", () => {
|
// it("ignores fields that contain the keyword `captcha` ", async () => {
|
||||||
// autofillFieldData.placeholder = "captcha";
|
// autofillFieldData.placeholder = "captcha";
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -257,12 +245,10 @@ describe("a placeholder", () => {
|
|||||||
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it("ignores fields that do not appear as a login field", () => {
|
// it("ignores fields that do not appear as a login field", async () => {
|
||||||
// autofillFieldData.placeholder = "not-a-login-field";
|
// autofillFieldData.placeholder = "not-a-login-field";
|
||||||
//
|
//
|
||||||
// // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
// autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
|
||||||
// autofillFieldElement,
|
// autofillFieldElement,
|
||||||
// autofillFieldData,
|
// autofillFieldData,
|
||||||
// );
|
// );
|
||||||
@@ -271,6 +257,17 @@ describe("a placeholder", () => {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
|
// it("skips setup on fields that have been previously set up", async () => {
|
||||||
|
// autofillOverlayContentService["formFieldElements"].add(autofillFieldElement);
|
||||||
|
//
|
||||||
|
// await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||||
|
// autofillFieldElement,
|
||||||
|
// autofillFieldData,
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||||
|
// });
|
||||||
|
//
|
||||||
// describe("identifies the overlay visibility setting", () => {
|
// describe("identifies the overlay visibility setting", () => {
|
||||||
// it("defaults the overlay visibility setting to `OnFieldFocus` if a value is not set", async () => {
|
// it("defaults the overlay visibility setting to `OnFieldFocus` if a value is not set", async () => {
|
||||||
// sendExtensionMessageSpy.mockResolvedValueOnce(undefined);
|
// sendExtensionMessageSpy.mockResolvedValueOnce(undefined);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
formFieldElement: ElementWithOpId<FormFieldElement>,
|
formFieldElement: ElementWithOpId<FormFieldElement>,
|
||||||
autofillFieldData: AutofillField,
|
autofillFieldData: AutofillField,
|
||||||
) {
|
) {
|
||||||
if (this.isIgnoredField(autofillFieldData)) {
|
if (this.isIgnoredField(autofillFieldData) || this.formFieldElements.has(formFieldElement)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,7 +620,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
private async getBoundingClientRectFromIntersectionObserver(
|
private async getBoundingClientRectFromIntersectionObserver(
|
||||||
formFieldElement: ElementWithOpId<FormFieldElement>,
|
formFieldElement: ElementWithOpId<FormFieldElement>,
|
||||||
): Promise<DOMRectReadOnly | null> {
|
): Promise<DOMRectReadOnly | null> {
|
||||||
if (!("IntersectionObserver" in window) && !("IntersectionObserverEntry" in window)) {
|
if (!("IntersectionObserver" in globalThis) && !("IntersectionObserverEntry" in globalThis)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,7 +749,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
this.focusedFieldData.focusedFieldRects?.top > 0 &&
|
this.focusedFieldData.focusedFieldRects?.top > 0 &&
|
||||||
this.focusedFieldData.focusedFieldRects?.top < window.innerHeight + window.scrollY
|
this.focusedFieldData.focusedFieldRects?.top < globalThis.innerHeight + globalThis.scrollY
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import {
|
|||||||
|
|
||||||
export default class AutofillService implements AutofillServiceInterface {
|
export default class AutofillService implements AutofillServiceInterface {
|
||||||
private openVaultItemPasswordRepromptPopout = openVaultItemPasswordRepromptPopout;
|
private openVaultItemPasswordRepromptPopout = openVaultItemPasswordRepromptPopout;
|
||||||
private openPasswordRepromptPopoutDebounce: NodeJS.Timeout;
|
private openPasswordRepromptPopoutDebounce: number | NodeJS.Timeout;
|
||||||
private currentlyOpeningPasswordRepromptPopout = false;
|
private currentlyOpeningPasswordRepromptPopout = false;
|
||||||
private autofillScriptPortsSet = new Set<chrome.runtime.Port>();
|
private autofillScriptPortsSet = new Set<chrome.runtime.Port>();
|
||||||
static searchFieldNamesSet = new Set(AutoFillConstants.SearchFieldNames);
|
static searchFieldNamesSet = new Set(AutoFillConstants.SearchFieldNames);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ describe("CollectAutofillContentService", () => {
|
|||||||
const domElementVisibilityService = new DomElementVisibilityService();
|
const domElementVisibilityService = new DomElementVisibilityService();
|
||||||
const autofillOverlayContentService = new AutofillOverlayContentService();
|
const autofillOverlayContentService = new AutofillOverlayContentService();
|
||||||
let collectAutofillContentService: CollectAutofillContentService;
|
let collectAutofillContentService: CollectAutofillContentService;
|
||||||
|
const mockIntersectionObserver = mock<IntersectionObserver>();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = mockLoginForm;
|
document.body.innerHTML = mockLoginForm;
|
||||||
@@ -34,6 +35,7 @@ describe("CollectAutofillContentService", () => {
|
|||||||
domElementVisibilityService,
|
domElementVisibilityService,
|
||||||
autofillOverlayContentService,
|
autofillOverlayContentService,
|
||||||
);
|
);
|
||||||
|
window.IntersectionObserver = jest.fn(() => mockIntersectionObserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -2527,10 +2529,10 @@ describe("CollectAutofillContentService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
updatedAttributes.forEach((attribute) => {
|
updatedAttributes.forEach((attribute) => {
|
||||||
it(`will update the ${attribute} value for the field element`, async () => {
|
it(`will update the ${attribute} value for the field element`, () => {
|
||||||
jest.spyOn(collectAutofillContentService["autofillFieldElements"], "set");
|
jest.spyOn(collectAutofillContentService["autofillFieldElements"], "set");
|
||||||
|
|
||||||
await collectAutofillContentService["updateAutofillFieldElementData"](
|
collectAutofillContentService["updateAutofillFieldElementData"](
|
||||||
attribute,
|
attribute,
|
||||||
fieldElement,
|
fieldElement,
|
||||||
autofillField,
|
autofillField,
|
||||||
@@ -2543,10 +2545,10 @@ describe("CollectAutofillContentService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("will not update an attribute value if it is not present in the updateActions object", async () => {
|
it("will not update an attribute value if it is not present in the updateActions object", () => {
|
||||||
jest.spyOn(collectAutofillContentService["autofillFieldElements"], "set");
|
jest.spyOn(collectAutofillContentService["autofillFieldElements"], "set");
|
||||||
|
|
||||||
await collectAutofillContentService["updateAutofillFieldElementData"](
|
collectAutofillContentService["updateAutofillFieldElementData"](
|
||||||
"random-attribute",
|
"random-attribute",
|
||||||
fieldElement,
|
fieldElement,
|
||||||
autofillField,
|
autofillField,
|
||||||
@@ -2555,4 +2557,67 @@ describe("CollectAutofillContentService", () => {
|
|||||||
expect(collectAutofillContentService["autofillFieldElements"].set).not.toBeCalled();
|
expect(collectAutofillContentService["autofillFieldElements"].set).not.toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("handleFormElementIntersection", () => {
|
||||||
|
let isFormFieldViewableSpy: jest.SpyInstance;
|
||||||
|
let setupAutofillOverlayListenerOnFieldSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
isFormFieldViewableSpy = jest.spyOn(
|
||||||
|
collectAutofillContentService["domElementVisibilityService"],
|
||||||
|
"isFormFieldViewable",
|
||||||
|
);
|
||||||
|
setupAutofillOverlayListenerOnFieldSpy = jest.spyOn(
|
||||||
|
collectAutofillContentService["autofillOverlayContentService"],
|
||||||
|
"setupAutofillOverlayListenerOnField",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips the initial intersection event for an observed element", async () => {
|
||||||
|
const formFieldElement = document.createElement("input") as ElementWithOpId<FormFieldElement>;
|
||||||
|
collectAutofillContentService["elementInitializingIntersectionObserver"].add(
|
||||||
|
formFieldElement,
|
||||||
|
);
|
||||||
|
const entries = [
|
||||||
|
{ target: formFieldElement, isIntersecting: true },
|
||||||
|
] as unknown as IntersectionObserverEntry[];
|
||||||
|
|
||||||
|
await collectAutofillContentService["handleFormElementIntersection"](entries);
|
||||||
|
|
||||||
|
expect(isFormFieldViewableSpy).not.toHaveBeenCalled();
|
||||||
|
expect(setupAutofillOverlayListenerOnFieldSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips setting up the overlay listeners on a field that is not viewable", async () => {
|
||||||
|
const formFieldElement = document.createElement("input") as ElementWithOpId<FormFieldElement>;
|
||||||
|
const entries = [
|
||||||
|
{ target: formFieldElement, isIntersecting: true },
|
||||||
|
] as unknown as IntersectionObserverEntry[];
|
||||||
|
isFormFieldViewableSpy.mockReturnValueOnce(false);
|
||||||
|
|
||||||
|
await collectAutofillContentService["handleFormElementIntersection"](entries);
|
||||||
|
|
||||||
|
expect(isFormFieldViewableSpy).toHaveBeenCalledWith(formFieldElement);
|
||||||
|
expect(setupAutofillOverlayListenerOnFieldSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets up the overlay listeners on a viewable field", async () => {
|
||||||
|
const formFieldElement = document.createElement("input") as ElementWithOpId<FormFieldElement>;
|
||||||
|
const autofillField = mock<AutofillField>();
|
||||||
|
const entries = [
|
||||||
|
{ target: formFieldElement, isIntersecting: true },
|
||||||
|
] as unknown as IntersectionObserverEntry[];
|
||||||
|
isFormFieldViewableSpy.mockReturnValueOnce(true);
|
||||||
|
collectAutofillContentService["autofillFieldElements"].set(formFieldElement, autofillField);
|
||||||
|
collectAutofillContentService["intersectionObserver"] = mockIntersectionObserver;
|
||||||
|
|
||||||
|
await collectAutofillContentService["handleFormElementIntersection"](entries);
|
||||||
|
|
||||||
|
expect(isFormFieldViewableSpy).toHaveBeenCalledWith(formFieldElement);
|
||||||
|
expect(setupAutofillOverlayListenerOnFieldSpy).toHaveBeenCalledWith(
|
||||||
|
formFieldElement,
|
||||||
|
autofillField,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,8 +38,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
private autofillFormElements: AutofillFormElements = new Map();
|
private autofillFormElements: AutofillFormElements = new Map();
|
||||||
private autofillFieldElements: AutofillFieldElements = new Map();
|
private autofillFieldElements: AutofillFieldElements = new Map();
|
||||||
private currentLocationHref = "";
|
private currentLocationHref = "";
|
||||||
|
private intersectionObserver: IntersectionObserver;
|
||||||
|
private elementInitializingIntersectionObserver: Set<Element> = new Set();
|
||||||
private mutationObserver: MutationObserver;
|
private mutationObserver: MutationObserver;
|
||||||
private updateAutofillElementsAfterMutationTimeout: NodeJS.Timeout;
|
private updateAutofillElementsAfterMutationTimeout: number | NodeJS.Timeout;
|
||||||
private readonly updateAfterMutationTimeoutDelay = 1000;
|
private readonly updateAfterMutationTimeoutDelay = 1000;
|
||||||
private readonly ignoredInputTypes = new Set([
|
private readonly ignoredInputTypes = new Set([
|
||||||
"hidden",
|
"hidden",
|
||||||
@@ -70,6 +72,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
this.setupMutationObserver();
|
this.setupMutationObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.intersectionObserver) {
|
||||||
|
this.setupIntersectionObserver();
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.domRecentlyMutated && this.noFieldsFound) {
|
if (!this.domRecentlyMutated && this.noFieldsFound) {
|
||||||
return this.getFormattedPageDetails({}, []);
|
return this.getFormattedPageDetails({}, []);
|
||||||
}
|
}
|
||||||
@@ -180,7 +186,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
): AutofillPageDetails {
|
): AutofillPageDetails {
|
||||||
return {
|
return {
|
||||||
title: document.title,
|
title: document.title,
|
||||||
url: (document.defaultView || window).location.href,
|
url: (document.defaultView || globalThis).location.href,
|
||||||
documentUrl: document.location.href,
|
documentUrl: document.location.href,
|
||||||
forms: autofillFormsData,
|
forms: autofillFormsData,
|
||||||
fields: autofillFieldsData,
|
fields: autofillFieldsData,
|
||||||
@@ -240,7 +246,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private getFormActionAttribute(element: ElementWithOpId<HTMLFormElement>): string {
|
private getFormActionAttribute(element: ElementWithOpId<HTMLFormElement>): string {
|
||||||
return new URL(this.getPropertyOrAttribute(element, "action"), window.location.href).href;
|
return new URL(this.getPropertyOrAttribute(element, "action"), globalThis.location.href).href;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -360,11 +366,14 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
tagName: this.getAttributeLowerCase(element, "tagName"),
|
tagName: this.getAttributeLowerCase(element, "tagName"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!autofillFieldBase.viewable) {
|
||||||
|
this.elementInitializingIntersectionObserver.add(element);
|
||||||
|
this.intersectionObserver.observe(element);
|
||||||
|
}
|
||||||
|
|
||||||
if (elementIsSpanElement(element)) {
|
if (elementIsSpanElement(element)) {
|
||||||
this.cacheAutofillFieldElement(index, element, autofillFieldBase);
|
this.cacheAutofillFieldElement(index, element, autofillFieldBase);
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
|
||||||
element,
|
element,
|
||||||
autofillFieldBase,
|
autofillFieldBase,
|
||||||
);
|
);
|
||||||
@@ -407,9 +416,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.cacheAutofillFieldElement(index, element, autofillField);
|
this.cacheAutofillFieldElement(index, element, autofillField);
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
element,
|
||||||
this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(element, autofillField);
|
autofillField,
|
||||||
|
);
|
||||||
return autofillField;
|
return autofillField;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1189,8 +1199,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.updateAutofillFieldElementData(
|
this.updateAutofillFieldElementData(
|
||||||
attributeName,
|
attributeName,
|
||||||
targetElement as ElementWithOpId<FormFieldElement>,
|
targetElement as ElementWithOpId<FormFieldElement>,
|
||||||
@@ -1232,13 +1240,12 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the autofill field element data based on the passed attribute name.
|
* Updates the autofill field element data based on the passed attribute name.
|
||||||
|
*
|
||||||
* @param {string} attributeName
|
* @param {string} attributeName
|
||||||
* @param {ElementWithOpId<FormFieldElement>} element
|
* @param {ElementWithOpId<FormFieldElement>} element
|
||||||
* @param {AutofillField} dataTarget
|
* @param {AutofillField} dataTarget
|
||||||
* @returns {Promise<void>}
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
private async updateAutofillFieldElementData(
|
private updateAutofillFieldElementData(
|
||||||
attributeName: string,
|
attributeName: string,
|
||||||
element: ElementWithOpId<FormFieldElement>,
|
element: ElementWithOpId<FormFieldElement>,
|
||||||
dataTarget: AutofillField,
|
dataTarget: AutofillField,
|
||||||
@@ -1304,6 +1311,52 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
return attributeValue;
|
return attributeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up an IntersectionObserver to observe found form
|
||||||
|
* field elements that are not viewable in the viewport.
|
||||||
|
*/
|
||||||
|
private setupIntersectionObserver() {
|
||||||
|
this.intersectionObserver = new IntersectionObserver(this.handleFormElementIntersection, {
|
||||||
|
root: null,
|
||||||
|
rootMargin: "0px",
|
||||||
|
threshold: 1.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles observed form field elements that are not viewable in the viewport.
|
||||||
|
* Will re-evaluate the visibility of the element and set up the autofill
|
||||||
|
* overlay listeners on the field if it is viewable.
|
||||||
|
*
|
||||||
|
* @param entries - The entries observed by the IntersectionObserver
|
||||||
|
*/
|
||||||
|
private handleFormElementIntersection = async (entries: IntersectionObserverEntry[]) => {
|
||||||
|
for (let entryIndex = 0; entryIndex < entries.length; entryIndex++) {
|
||||||
|
const entry = entries[entryIndex];
|
||||||
|
const formFieldElement = entry.target as ElementWithOpId<FormFieldElement>;
|
||||||
|
if (this.elementInitializingIntersectionObserver.has(formFieldElement)) {
|
||||||
|
this.elementInitializingIntersectionObserver.delete(formFieldElement);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isViewable =
|
||||||
|
await this.domElementVisibilityService.isFormFieldViewable(formFieldElement);
|
||||||
|
if (!isViewable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedAutofillFieldElement = this.autofillFieldElements.get(formFieldElement);
|
||||||
|
cachedAutofillFieldElement.viewable = true;
|
||||||
|
|
||||||
|
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||||
|
formFieldElement,
|
||||||
|
cachedAutofillFieldElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.intersectionObserver.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the CollectAutofillContentService. Clears all
|
* Destroys the CollectAutofillContentService. Clears all
|
||||||
* timeouts and disconnects the mutation observer.
|
* timeouts and disconnects the mutation observer.
|
||||||
@@ -1313,6 +1366,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
|||||||
clearTimeout(this.updateAutofillElementsAfterMutationTimeout);
|
clearTimeout(this.updateAutofillElementsAfterMutationTimeout);
|
||||||
}
|
}
|
||||||
this.mutationObserver?.disconnect();
|
this.mutationObserver?.disconnect();
|
||||||
|
this.intersectionObserver?.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class DomElementVisibilityService implements domElementVisibilityServiceInterfac
|
|||||||
*/
|
*/
|
||||||
private getElementStyle(element: HTMLElement, styleProperty: string): string {
|
private getElementStyle(element: HTMLElement, styleProperty: string): string {
|
||||||
if (!this.cachedComputedStyle) {
|
if (!this.cachedComputedStyle) {
|
||||||
this.cachedComputedStyle = (element.ownerDocument.defaultView || window).getComputedStyle(
|
this.cachedComputedStyle = (element.ownerDocument.defaultView || globalThis).getComputedStyle(
|
||||||
element,
|
element,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const initEventCount = Object.freeze(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let confirmSpy: jest.SpyInstance<boolean, [message?: string]>;
|
let confirmSpy: jest.SpyInstance<boolean, [message?: string]>;
|
||||||
let windowSpy: jest.SpyInstance<any>;
|
let windowLocationSpy: jest.SpyInstance<any>;
|
||||||
let savedURLs: string[] | null = ["https://bitwarden.com"];
|
let savedURLs: string[] | null = ["https://bitwarden.com"];
|
||||||
function setMockWindowLocation({
|
function setMockWindowLocation({
|
||||||
protocol,
|
protocol,
|
||||||
@@ -56,11 +56,9 @@ function setMockWindowLocation({
|
|||||||
protocol: "http:" | "https:";
|
protocol: "http:" | "https:";
|
||||||
hostname: string;
|
hostname: string;
|
||||||
}) {
|
}) {
|
||||||
windowSpy.mockImplementation(() => ({
|
windowLocationSpy.mockImplementation(() => ({
|
||||||
location: {
|
|
||||||
protocol,
|
protocol,
|
||||||
hostname,
|
hostname,
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +74,8 @@ describe("InsertAutofillContentService", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = mockLoginForm;
|
document.body.innerHTML = mockLoginForm;
|
||||||
confirmSpy = jest.spyOn(window, "confirm");
|
confirmSpy = jest.spyOn(globalThis, "confirm");
|
||||||
windowSpy = jest.spyOn(window, "window", "get");
|
windowLocationSpy = jest.spyOn(globalThis, "location", "get");
|
||||||
insertAutofillContentService = new InsertAutofillContentService(
|
insertAutofillContentService = new InsertAutofillContentService(
|
||||||
domElementVisibilityService,
|
domElementVisibilityService,
|
||||||
collectAutofillContentService,
|
collectAutofillContentService,
|
||||||
@@ -101,7 +99,7 @@ describe("InsertAutofillContentService", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
windowSpy.mockRestore();
|
windowLocationSpy.mockRestore();
|
||||||
confirmSpy.mockRestore();
|
confirmSpy.mockRestore();
|
||||||
document.body.innerHTML = "";
|
document.body.innerHTML = "";
|
||||||
});
|
});
|
||||||
@@ -245,8 +243,8 @@ describe("InsertAutofillContentService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns true if the frameElement has a sandbox attribute", () => {
|
it("returns true if the frameElement has a sandbox attribute", () => {
|
||||||
Object.defineProperty(globalThis, "window", {
|
Object.defineProperty(globalThis, "frameElement", {
|
||||||
value: { frameElement: { hasAttribute: jest.fn(() => true) } },
|
value: { hasAttribute: jest.fn(() => true) },
|
||||||
writable: true,
|
writable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -991,11 +989,11 @@ describe("InsertAutofillContentService", () => {
|
|||||||
const inputElement = document.querySelector('input[type="text"]') as HTMLInputElement;
|
const inputElement = document.querySelector('input[type="text"]') as HTMLInputElement;
|
||||||
inputElement.value = "test";
|
inputElement.value = "test";
|
||||||
jest.spyOn(inputElement, "focus");
|
jest.spyOn(inputElement, "focus");
|
||||||
jest.spyOn(window, "String");
|
jest.spyOn(globalThis, "String");
|
||||||
|
|
||||||
insertAutofillContentService["triggerFocusOnElement"](inputElement, true);
|
insertAutofillContentService["triggerFocusOnElement"](inputElement, true);
|
||||||
|
|
||||||
expect(window.String).toHaveBeenCalledWith(value);
|
expect(globalThis.String).toHaveBeenCalledWith(value);
|
||||||
expect(inputElement.focus).toHaveBeenCalled();
|
expect(inputElement.focus).toHaveBeenCalled();
|
||||||
expect(inputElement.value).toEqual(value);
|
expect(inputElement.value).toEqual(value);
|
||||||
});
|
});
|
||||||
@@ -1005,11 +1003,11 @@ describe("InsertAutofillContentService", () => {
|
|||||||
const inputElement = document.querySelector('input[type="text"]') as HTMLInputElement;
|
const inputElement = document.querySelector('input[type="text"]') as HTMLInputElement;
|
||||||
inputElement.value = "test";
|
inputElement.value = "test";
|
||||||
jest.spyOn(inputElement, "focus");
|
jest.spyOn(inputElement, "focus");
|
||||||
jest.spyOn(window, "String");
|
jest.spyOn(globalThis, "String");
|
||||||
|
|
||||||
insertAutofillContentService["triggerFocusOnElement"](inputElement, false);
|
insertAutofillContentService["triggerFocusOnElement"](inputElement, false);
|
||||||
|
|
||||||
expect(window.String).not.toHaveBeenCalledWith();
|
expect(globalThis.String).not.toHaveBeenCalledWith();
|
||||||
expect(inputElement.focus).toHaveBeenCalled();
|
expect(inputElement.focus).toHaveBeenCalled();
|
||||||
expect(inputElement.value).toEqual(value);
|
expect(inputElement.value).toEqual(value);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
|
|||||||
private fillingWithinSandboxedIframe() {
|
private fillingWithinSandboxedIframe() {
|
||||||
return (
|
return (
|
||||||
String(self.origin).toLowerCase() === "null" ||
|
String(self.origin).toLowerCase() === "null" ||
|
||||||
window.frameElement?.hasAttribute("sandbox") ||
|
globalThis.frameElement?.hasAttribute("sandbox") ||
|
||||||
window.location.hostname === ""
|
globalThis.location.hostname === ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
|
|||||||
*/
|
*/
|
||||||
private userCancelledInsecureUrlAutofill(savedUrls?: string[] | null): boolean {
|
private userCancelledInsecureUrlAutofill(savedUrls?: string[] | null): boolean {
|
||||||
if (
|
if (
|
||||||
!savedUrls?.some((url) => url.startsWith(`https://${window.location.hostname}`)) ||
|
!savedUrls?.some((url) => url.startsWith(`https://${globalThis.location.hostname}`)) ||
|
||||||
window.location.protocol !== "http:" ||
|
globalThis.location.protocol !== "http:" ||
|
||||||
!this.isPasswordFieldWithinDocument()
|
!this.isPasswordFieldWithinDocument()
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
@@ -88,10 +88,10 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
|
|||||||
|
|
||||||
const confirmationWarning = [
|
const confirmationWarning = [
|
||||||
chrome.i18n.getMessage("insecurePageWarning"),
|
chrome.i18n.getMessage("insecurePageWarning"),
|
||||||
chrome.i18n.getMessage("insecurePageWarningFillPrompt", [window.location.hostname]),
|
chrome.i18n.getMessage("insecurePageWarningFillPrompt", [globalThis.location.hostname]),
|
||||||
].join("\n\n");
|
].join("\n\n");
|
||||||
|
|
||||||
return !confirm(confirmationWarning);
|
return !globalThis.confirm(confirmationWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,10 +129,10 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
|
|||||||
|
|
||||||
const confirmationWarning = [
|
const confirmationWarning = [
|
||||||
chrome.i18n.getMessage("autofillIframeWarning"),
|
chrome.i18n.getMessage("autofillIframeWarning"),
|
||||||
chrome.i18n.getMessage("autofillIframeWarningTip", [window.location.hostname]),
|
chrome.i18n.getMessage("autofillIframeWarningTip", [globalThis.location.hostname]),
|
||||||
].join("\n\n");
|
].join("\n\n");
|
||||||
|
|
||||||
return !confirm(confirmationWarning);
|
return !globalThis.confirm(confirmationWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const IdleInterval = 60 * 5; // 5 minutes
|
|||||||
|
|
||||||
export default class IdleBackground {
|
export default class IdleBackground {
|
||||||
private idle: typeof chrome.idle | typeof browser.idle | null;
|
private idle: typeof chrome.idle | typeof browser.idle | null;
|
||||||
private idleTimer: number = null;
|
private idleTimer: number | NodeJS.Timeout = null;
|
||||||
private idleState = "active";
|
private idleState = "active";
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -73,7 +73,7 @@ export default class IdleBackground {
|
|||||||
|
|
||||||
private pollIdle(handler: (newState: string) => void) {
|
private pollIdle(handler: (newState: string) => void) {
|
||||||
if (this.idleTimer != null) {
|
if (this.idleTimer != null) {
|
||||||
window.clearTimeout(this.idleTimer);
|
globalThis.clearTimeout(this.idleTimer);
|
||||||
this.idleTimer = null;
|
this.idleTimer = null;
|
||||||
}
|
}
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
@@ -83,7 +83,7 @@ export default class IdleBackground {
|
|||||||
this.idleState = state;
|
this.idleState = state;
|
||||||
handler(state);
|
handler(state);
|
||||||
}
|
}
|
||||||
this.idleTimer = window.setTimeout(() => this.pollIdle(handler), 5000);
|
this.idleTimer = globalThis.setTimeout(() => this.pollIdle(handler), 5000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
UserDecryptionOptionsService,
|
UserDecryptionOptionsService,
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
AuthRequestService,
|
AuthRequestService,
|
||||||
|
LoginEmailServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
||||||
@@ -70,6 +71,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||||
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
@@ -93,6 +95,7 @@ import { StateFactory } from "@bitwarden/common/platform/factories/state-factory
|
|||||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
||||||
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
||||||
|
import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||||
@@ -143,6 +146,8 @@ import {
|
|||||||
} from "@bitwarden/common/tools/password-strength";
|
} from "@bitwarden/common/tools/password-strength";
|
||||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
||||||
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||||
|
import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider";
|
||||||
|
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
|
||||||
import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
@@ -200,10 +205,10 @@ import { BrowserApi } from "../platform/browser/browser-api";
|
|||||||
import { flagEnabled } from "../platform/flags";
|
import { flagEnabled } from "../platform/flags";
|
||||||
import { UpdateBadge } from "../platform/listeners/update-badge";
|
import { UpdateBadge } from "../platform/listeners/update-badge";
|
||||||
import { BrowserStateService as StateServiceAbstraction } from "../platform/services/abstractions/browser-state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../platform/services/abstractions/browser-state.service";
|
||||||
import { BrowserConfigService } from "../platform/services/browser-config.service";
|
|
||||||
import { BrowserCryptoService } from "../platform/services/browser-crypto.service";
|
import { BrowserCryptoService } from "../platform/services/browser-crypto.service";
|
||||||
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
||||||
import BrowserLocalStorageService from "../platform/services/browser-local-storage.service";
|
import BrowserLocalStorageService from "../platform/services/browser-local-storage.service";
|
||||||
|
import BrowserMemoryStorageService from "../platform/services/browser-memory-storage.service";
|
||||||
import BrowserMessagingPrivateModeBackgroundService from "../platform/services/browser-messaging-private-mode-background.service";
|
import BrowserMessagingPrivateModeBackgroundService from "../platform/services/browser-messaging-private-mode-background.service";
|
||||||
import BrowserMessagingService from "../platform/services/browser-messaging.service";
|
import BrowserMessagingService from "../platform/services/browser-messaging.service";
|
||||||
import { BrowserStateService } from "../platform/services/browser-state.service";
|
import { BrowserStateService } from "../platform/services/browser-state.service";
|
||||||
@@ -213,7 +218,6 @@ import { BackgroundPlatformUtilsService } from "../platform/services/platform-ut
|
|||||||
import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service";
|
import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service";
|
||||||
import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider";
|
import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider";
|
||||||
import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service";
|
import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service";
|
||||||
import { BrowserSendService } from "../services/browser-send.service";
|
|
||||||
import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service";
|
import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service";
|
||||||
import FilelessImporterBackground from "../tools/background/fileless-importer.background";
|
import FilelessImporterBackground from "../tools/background/fileless-importer.background";
|
||||||
import { BrowserFido2UserInterfaceService } from "../vault/fido2/browser-fido2-user-interface.service";
|
import { BrowserFido2UserInterfaceService } from "../vault/fido2/browser-fido2-user-interface.service";
|
||||||
@@ -228,7 +232,7 @@ import RuntimeBackground from "./runtime.background";
|
|||||||
|
|
||||||
export default class MainBackground {
|
export default class MainBackground {
|
||||||
messagingService: MessagingServiceAbstraction;
|
messagingService: MessagingServiceAbstraction;
|
||||||
storageService: AbstractStorageService;
|
storageService: AbstractStorageService & ObservableStorageService;
|
||||||
secureStorageService: AbstractStorageService;
|
secureStorageService: AbstractStorageService;
|
||||||
memoryStorageService: AbstractMemoryStorageService;
|
memoryStorageService: AbstractMemoryStorageService;
|
||||||
memoryStorageForStateProviders: AbstractMemoryStorageService & ObservableStorageService;
|
memoryStorageForStateProviders: AbstractMemoryStorageService & ObservableStorageService;
|
||||||
@@ -257,6 +261,7 @@ export default class MainBackground {
|
|||||||
auditService: AuditServiceAbstraction;
|
auditService: AuditServiceAbstraction;
|
||||||
authService: AuthServiceAbstraction;
|
authService: AuthServiceAbstraction;
|
||||||
loginStrategyService: LoginStrategyServiceAbstraction;
|
loginStrategyService: LoginStrategyServiceAbstraction;
|
||||||
|
loginEmailService: LoginEmailServiceAbstraction;
|
||||||
importApiService: ImportApiServiceAbstraction;
|
importApiService: ImportApiServiceAbstraction;
|
||||||
importService: ImportServiceAbstraction;
|
importService: ImportServiceAbstraction;
|
||||||
exportService: VaultExportServiceAbstraction;
|
exportService: VaultExportServiceAbstraction;
|
||||||
@@ -272,6 +277,7 @@ export default class MainBackground {
|
|||||||
eventUploadService: EventUploadServiceAbstraction;
|
eventUploadService: EventUploadServiceAbstraction;
|
||||||
policyService: InternalPolicyServiceAbstraction;
|
policyService: InternalPolicyServiceAbstraction;
|
||||||
sendService: InternalSendServiceAbstraction;
|
sendService: InternalSendServiceAbstraction;
|
||||||
|
sendStateProvider: SendStateProvider;
|
||||||
fileUploadService: FileUploadServiceAbstraction;
|
fileUploadService: FileUploadServiceAbstraction;
|
||||||
cipherFileUploadService: CipherFileUploadServiceAbstraction;
|
cipherFileUploadService: CipherFileUploadServiceAbstraction;
|
||||||
organizationService: InternalOrganizationServiceAbstraction;
|
organizationService: InternalOrganizationServiceAbstraction;
|
||||||
@@ -293,7 +299,7 @@ export default class MainBackground {
|
|||||||
avatarService: AvatarServiceAbstraction;
|
avatarService: AvatarServiceAbstraction;
|
||||||
mainContextMenuHandler: MainContextMenuHandler;
|
mainContextMenuHandler: MainContextMenuHandler;
|
||||||
cipherContextMenuHandler: CipherContextMenuHandler;
|
cipherContextMenuHandler: CipherContextMenuHandler;
|
||||||
configService: BrowserConfigService;
|
configService: ConfigService;
|
||||||
configApiService: ConfigApiServiceAbstraction;
|
configApiService: ConfigApiServiceAbstraction;
|
||||||
devicesApiService: DevicesApiServiceAbstraction;
|
devicesApiService: DevicesApiServiceAbstraction;
|
||||||
devicesService: DevicesServiceAbstraction;
|
devicesService: DevicesServiceAbstraction;
|
||||||
@@ -362,22 +368,28 @@ export default class MainBackground {
|
|||||||
this.cryptoFunctionService = new WebCryptoFunctionService(self);
|
this.cryptoFunctionService = new WebCryptoFunctionService(self);
|
||||||
this.keyGenerationService = new KeyGenerationService(this.cryptoFunctionService);
|
this.keyGenerationService = new KeyGenerationService(this.cryptoFunctionService);
|
||||||
this.storageService = new BrowserLocalStorageService();
|
this.storageService = new BrowserLocalStorageService();
|
||||||
|
|
||||||
|
const mv3MemoryStorageCreator = (partitionName: string) => {
|
||||||
|
// TODO: Consider using multithreaded encrypt service in popup only context
|
||||||
|
return new LocalBackedSessionStorageService(
|
||||||
|
new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false),
|
||||||
|
this.keyGenerationService,
|
||||||
|
new BrowserLocalStorageService(),
|
||||||
|
new BrowserMemoryStorageService(),
|
||||||
|
partitionName,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
this.secureStorageService = this.storageService; // secure storage is not supported in browsers, so we use local storage and warn users when it is used
|
this.secureStorageService = this.storageService; // secure storage is not supported in browsers, so we use local storage and warn users when it is used
|
||||||
this.memoryStorageService = BrowserApi.isManifestVersion(3)
|
this.memoryStorageService = BrowserApi.isManifestVersion(3)
|
||||||
? new LocalBackedSessionStorageService(
|
? mv3MemoryStorageCreator("stateService")
|
||||||
new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false),
|
|
||||||
this.keyGenerationService,
|
|
||||||
)
|
|
||||||
: new MemoryStorageService();
|
: new MemoryStorageService();
|
||||||
this.memoryStorageForStateProviders = BrowserApi.isManifestVersion(3)
|
this.memoryStorageForStateProviders = BrowserApi.isManifestVersion(3)
|
||||||
? new LocalBackedSessionStorageService(
|
? mv3MemoryStorageCreator("stateProviders")
|
||||||
new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false),
|
|
||||||
this.keyGenerationService,
|
|
||||||
)
|
|
||||||
: new BackgroundMemoryStorageService();
|
: new BackgroundMemoryStorageService();
|
||||||
|
|
||||||
const storageServiceProvider = new StorageServiceProvider(
|
const storageServiceProvider = new StorageServiceProvider(
|
||||||
this.storageService as BrowserLocalStorageService,
|
this.storageService,
|
||||||
this.memoryStorageForStateProviders,
|
this.memoryStorageForStateProviders,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -443,6 +455,9 @@ export default class MainBackground {
|
|||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
this.platformUtilsService.supportsSecureStorage(),
|
this.platformUtilsService.supportsSecureStorage(),
|
||||||
this.secureStorageService,
|
this.secureStorageService,
|
||||||
|
this.keyGenerationService,
|
||||||
|
this.encryptService,
|
||||||
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationRunner = new MigrationRunner(
|
const migrationRunner = new MigrationRunner(
|
||||||
@@ -510,7 +525,6 @@ export default class MainBackground {
|
|||||||
this.badgeSettingsService = new BadgeSettingsService(this.stateProvider);
|
this.badgeSettingsService = new BadgeSettingsService(this.stateProvider);
|
||||||
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
||||||
this.keyConnectorService = new KeyConnectorService(
|
this.keyConnectorService = new KeyConnectorService(
|
||||||
this.stateService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -518,6 +532,7 @@ export default class MainBackground {
|
|||||||
this.organizationService,
|
this.organizationService,
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
logoutCallback,
|
logoutCallback,
|
||||||
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.passwordStrengthService = new PasswordStrengthService();
|
this.passwordStrengthService = new PasswordStrengthService();
|
||||||
@@ -550,11 +565,12 @@ export default class MainBackground {
|
|||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
this.stateService,
|
|
||||||
this.appIdService,
|
this.appIdService,
|
||||||
this.devicesApiService,
|
this.devicesApiService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
|
this.stateProvider,
|
||||||
|
this.secureStorageService,
|
||||||
this.userDecryptionOptionsService,
|
this.userDecryptionOptionsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -568,14 +584,16 @@ export default class MainBackground {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.authService = new AuthService(
|
this.authService = new AuthService(
|
||||||
|
this.accountService,
|
||||||
backgroundMessagingService,
|
backgroundMessagingService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
|
this.tokenService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
||||||
this.activeUserStateProvider,
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.loginStrategyService = new LoginStrategyService(
|
this.loginStrategyService = new LoginStrategyService(
|
||||||
@@ -605,16 +623,13 @@ export default class MainBackground {
|
|||||||
|
|
||||||
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||||
|
|
||||||
this.configApiService = new ConfigApiService(this.apiService, this.authService);
|
this.configApiService = new ConfigApiService(this.apiService, this.tokenService);
|
||||||
|
|
||||||
this.configService = new BrowserConfigService(
|
this.configService = new DefaultConfigService(
|
||||||
this.stateService,
|
|
||||||
this.configApiService,
|
this.configApiService,
|
||||||
this.authService,
|
|
||||||
this.environmentService,
|
this.environmentService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.cipherService = new CipherService(
|
this.cipherService = new CipherService(
|
||||||
@@ -694,11 +709,14 @@ export default class MainBackground {
|
|||||||
logoutCallback,
|
logoutCallback,
|
||||||
);
|
);
|
||||||
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
|
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
|
||||||
this.sendService = new BrowserSendService(
|
|
||||||
|
this.sendStateProvider = new SendStateProvider(this.stateProvider);
|
||||||
|
this.sendService = new SendService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.stateService,
|
this.sendStateProvider,
|
||||||
|
this.encryptService,
|
||||||
);
|
);
|
||||||
this.sendApiService = new SendApiService(
|
this.sendApiService = new SendApiService(
|
||||||
this.apiService,
|
this.apiService,
|
||||||
@@ -989,7 +1007,7 @@ export default class MainBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async bootstrap() {
|
async bootstrap() {
|
||||||
this.containerService.attachToGlobal(window);
|
this.containerService.attachToGlobal(self);
|
||||||
|
|
||||||
await this.stateService.init();
|
await this.stateService.init();
|
||||||
|
|
||||||
@@ -1001,7 +1019,6 @@ export default class MainBackground {
|
|||||||
this.filelessImporterBackground.init();
|
this.filelessImporterBackground.init();
|
||||||
await this.commandsBackground.init();
|
await this.commandsBackground.init();
|
||||||
|
|
||||||
this.configService.init();
|
|
||||||
this.twoFactorService.init();
|
this.twoFactorService.init();
|
||||||
|
|
||||||
await this.overlayBackground.init();
|
await this.overlayBackground.init();
|
||||||
@@ -1079,7 +1096,9 @@ export default class MainBackground {
|
|||||||
await this.stateService.setActiveUser(userId);
|
await this.stateService.setActiveUser(userId);
|
||||||
|
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
await this.stateService.setRememberedEmail(null);
|
this.loginEmailService.setRememberEmail(false);
|
||||||
|
await this.loginEmailService.saveEmailSettings();
|
||||||
|
|
||||||
await this.refreshBadge();
|
await this.refreshBadge();
|
||||||
await this.refreshMenu();
|
await this.refreshMenu();
|
||||||
await this.overlayBackground.updateOverlayCiphers();
|
await this.overlayBackground.updateOverlayCiphers();
|
||||||
@@ -1124,7 +1143,6 @@ export default class MainBackground {
|
|||||||
this.policyService.clear(userId),
|
this.policyService.clear(userId),
|
||||||
this.passwordGenerationService.clear(userId),
|
this.passwordGenerationService.clear(userId),
|
||||||
this.vaultTimeoutSettingsService.clear(userId),
|
this.vaultTimeoutSettingsService.clear(userId),
|
||||||
this.keyConnectorService.clear(),
|
|
||||||
this.vaultFilterService.clear(),
|
this.vaultFilterService.clear(),
|
||||||
this.biometricStateService.logout(userId),
|
this.biometricStateService.logout(userId),
|
||||||
this.providerService.save(null, userId),
|
this.providerService.save(null, userId),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
@@ -46,7 +46,7 @@ export default class RuntimeBackground {
|
|||||||
private environmentService: BrowserEnvironmentService,
|
private environmentService: BrowserEnvironmentService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private configService: ConfigServiceAbstraction,
|
private configService: ConfigService,
|
||||||
private fido2Service: Fido2Service,
|
private fido2Service: Fido2Service,
|
||||||
) {
|
) {
|
||||||
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
||||||
@@ -89,7 +89,7 @@ export default class RuntimeBackground {
|
|||||||
|
|
||||||
BrowserApi.messageListener("runtime.background", backgroundMessageListener);
|
BrowserApi.messageListener("runtime.background", backgroundMessageListener);
|
||||||
if (this.main.popupOnlyContext) {
|
if (this.main.popupOnlyContext) {
|
||||||
(window as any).bitwardenBackgroundMessageListener = backgroundMessageListener;
|
(self as any).bitwardenBackgroundMessageListener = backgroundMessageListener;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ export default class RuntimeBackground {
|
|||||||
await this.main.refreshBadge();
|
await this.main.refreshBadge();
|
||||||
await this.main.refreshMenu();
|
await this.main.refreshMenu();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
this.configService.triggerServerConfigFetch();
|
await this.configService.ensureConfigFetched();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "openPopup":
|
case "openPopup":
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
|
||||||
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CryptoServiceInitOptions,
|
CryptoServiceInitOptions,
|
||||||
cryptoServiceFactory,
|
cryptoServiceFactory,
|
||||||
} from "../../platform/background/service-factories/crypto-service.factory";
|
} from "../../platform/background/service-factories/crypto-service.factory";
|
||||||
|
import {
|
||||||
|
EncryptServiceInitOptions,
|
||||||
|
encryptServiceFactory,
|
||||||
|
} from "../../platform/background/service-factories/encrypt-service.factory";
|
||||||
import {
|
import {
|
||||||
FactoryOptions,
|
FactoryOptions,
|
||||||
CachedServices,
|
CachedServices,
|
||||||
@@ -17,11 +22,11 @@ import {
|
|||||||
KeyGenerationServiceInitOptions,
|
KeyGenerationServiceInitOptions,
|
||||||
keyGenerationServiceFactory,
|
keyGenerationServiceFactory,
|
||||||
} from "../../platform/background/service-factories/key-generation-service.factory";
|
} from "../../platform/background/service-factories/key-generation-service.factory";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
stateServiceFactory,
|
SendStateProviderInitOptions,
|
||||||
StateServiceInitOptions,
|
sendStateProviderFactory,
|
||||||
} from "../../platform/background/service-factories/state-service.factory";
|
} from "./send-state-provider.factory";
|
||||||
import { BrowserSendService } from "../../services/browser-send.service";
|
|
||||||
|
|
||||||
type SendServiceFactoryOptions = FactoryOptions;
|
type SendServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
@@ -29,7 +34,8 @@ export type SendServiceInitOptions = SendServiceFactoryOptions &
|
|||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
KeyGenerationServiceInitOptions &
|
KeyGenerationServiceInitOptions &
|
||||||
StateServiceInitOptions;
|
SendStateProviderInitOptions &
|
||||||
|
EncryptServiceInitOptions;
|
||||||
|
|
||||||
export function sendServiceFactory(
|
export function sendServiceFactory(
|
||||||
cache: { sendService?: InternalSendService } & CachedServices,
|
cache: { sendService?: InternalSendService } & CachedServices,
|
||||||
@@ -40,11 +46,12 @@ export function sendServiceFactory(
|
|||||||
"sendService",
|
"sendService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new BrowserSendService(
|
new SendService(
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await keyGenerationServiceFactory(cache, opts),
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
await stateServiceFactory(cache, opts),
|
await sendStateProviderFactory(cache, opts),
|
||||||
|
await encryptServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CachedServices,
|
||||||
|
FactoryOptions,
|
||||||
|
factory,
|
||||||
|
} from "../../platform/background/service-factories/factory-options";
|
||||||
|
import {
|
||||||
|
StateProviderInitOptions,
|
||||||
|
stateProviderFactory,
|
||||||
|
} from "../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
|
type SendStateProviderFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type SendStateProviderInitOptions = SendStateProviderFactoryOptions &
|
||||||
|
StateProviderInitOptions;
|
||||||
|
|
||||||
|
export function sendStateProviderFactory(
|
||||||
|
cache: { sendStateProvider?: SendStateProvider } & CachedServices,
|
||||||
|
opts: SendStateProviderInitOptions,
|
||||||
|
): Promise<SendStateProvider> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"sendStateProvider",
|
||||||
|
opts,
|
||||||
|
async () => new SendStateProvider(await stateProviderFactory(cache, opts)),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "__MSG_extName__",
|
"name": "__MSG_extName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Bitwarden Inc.",
|
"author": "Bitwarden Inc.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"minimum_chrome_version": "102.0",
|
"minimum_chrome_version": "102.0",
|
||||||
"name": "__MSG_extName__",
|
"name": "__MSG_extName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Bitwarden Inc.",
|
"author": "Bitwarden Inc.",
|
||||||
|
|||||||
@@ -1,42 +1,35 @@
|
|||||||
|
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||||
|
|
||||||
import MainBackground from "../background/main.background";
|
import MainBackground from "../background/main.background";
|
||||||
|
|
||||||
import { onAlarmListener } from "./alarms/on-alarm-listener";
|
|
||||||
import { registerAlarms } from "./alarms/register-alarms";
|
|
||||||
import { BrowserApi } from "./browser/browser-api";
|
import { BrowserApi } from "./browser/browser-api";
|
||||||
import {
|
|
||||||
contextMenusClickedListener,
|
|
||||||
onCommandListener,
|
|
||||||
onInstallListener,
|
|
||||||
runtimeMessageListener,
|
|
||||||
windowsOnFocusChangedListener,
|
|
||||||
tabsOnActivatedListener,
|
|
||||||
tabsOnReplacedListener,
|
|
||||||
tabsOnUpdatedListener,
|
|
||||||
} from "./listeners";
|
|
||||||
|
|
||||||
if (BrowserApi.isManifestVersion(3)) {
|
const logService = new ConsoleLogService(false);
|
||||||
chrome.commands.onCommand.addListener(onCommandListener);
|
const bitwardenMain = ((self as any).bitwardenMain = new MainBackground());
|
||||||
chrome.runtime.onInstalled.addListener(onInstallListener);
|
bitwardenMain
|
||||||
chrome.alarms.onAlarm.addListener(onAlarmListener);
|
.bootstrap()
|
||||||
registerAlarms();
|
.then(() => {
|
||||||
chrome.windows.onFocusChanged.addListener(windowsOnFocusChangedListener);
|
|
||||||
chrome.tabs.onActivated.addListener(tabsOnActivatedListener);
|
|
||||||
chrome.tabs.onReplaced.addListener(tabsOnReplacedListener);
|
|
||||||
chrome.tabs.onUpdated.addListener(tabsOnUpdatedListener);
|
|
||||||
chrome.contextMenus.onClicked.addListener(contextMenusClickedListener);
|
|
||||||
BrowserApi.messageListener(
|
|
||||||
"runtime.background",
|
|
||||||
(message: { command: string }, sender, sendResponse) => {
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
runtimeMessageListener(message, sender);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
bitwardenMain.bootstrap().then(() => {
|
|
||||||
// Finished bootstrapping
|
// Finished bootstrapping
|
||||||
});
|
if (BrowserApi.isManifestVersion(3)) {
|
||||||
|
startHeartbeat().catch((error) => logService.error(error));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => logService.error(error));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks when a service worker was last alive and extends the service worker
|
||||||
|
* lifetime by writing the current time to extension storage every 20 seconds.
|
||||||
|
*/
|
||||||
|
async function runHeartbeat() {
|
||||||
|
await chrome.storage.local.set({ "last-heartbeat": new Date().getTime() });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the heartbeat interval which keeps the service worker alive.
|
||||||
|
*/
|
||||||
|
async function startHeartbeat() {
|
||||||
|
// Run the heartbeat once at service worker startup, then again every 20 seconds.
|
||||||
|
runHeartbeat()
|
||||||
|
.then(() => setInterval(runHeartbeat, 20 * 1000))
|
||||||
|
.catch((error) => logService.error(error));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||||
|
|
||||||
import { activeUserStateProviderFactory } from "./active-user-state-provider.factory";
|
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
import { StateProviderInitOptions } from "./state-provider.factory";
|
import { StateProviderInitOptions, stateProviderFactory } from "./state-provider.factory";
|
||||||
|
|
||||||
type BillingAccountProfileStateServiceFactoryOptions = FactoryOptions;
|
type BillingAccountProfileStateServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
@@ -21,8 +20,6 @@ export function billingAccountProfileStateServiceFactory(
|
|||||||
"billingAccountProfileStateService",
|
"billingAccountProfileStateService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new DefaultBillingAccountProfileStateService(
|
new DefaultBillingAccountProfileStateService(await stateProviderFactory(cache, opts)),
|
||||||
await activeUserStateProviderFactory(cache, opts),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstract
|
|||||||
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
authServiceFactory,
|
tokenServiceFactory,
|
||||||
AuthServiceInitOptions,
|
TokenServiceInitOptions,
|
||||||
} from "../../../auth/background/service-factories/auth-service.factory";
|
} from "../../../auth/background/service-factories/token-service.factory";
|
||||||
|
|
||||||
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
@@ -13,7 +13,7 @@ type ConfigApiServiceFactoyOptions = FactoryOptions;
|
|||||||
|
|
||||||
export type ConfigApiServiceInitOptions = ConfigApiServiceFactoyOptions &
|
export type ConfigApiServiceInitOptions = ConfigApiServiceFactoyOptions &
|
||||||
ApiServiceInitOptions &
|
ApiServiceInitOptions &
|
||||||
AuthServiceInitOptions;
|
TokenServiceInitOptions;
|
||||||
|
|
||||||
export function configApiServiceFactory(
|
export function configApiServiceFactory(
|
||||||
cache: { configApiService?: ConfigApiServiceAbstraction } & CachedServices,
|
cache: { configApiService?: ConfigApiServiceAbstraction } & CachedServices,
|
||||||
@@ -26,7 +26,7 @@ export function configApiServiceFactory(
|
|||||||
async () =>
|
async () =>
|
||||||
new ConfigApiService(
|
new ConfigApiService(
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
await authServiceFactory(cache, opts),
|
await tokenServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service";
|
||||||
|
|
||||||
import {
|
|
||||||
authServiceFactory,
|
|
||||||
AuthServiceInitOptions,
|
|
||||||
} from "../../../auth/background/service-factories/auth-service.factory";
|
|
||||||
|
|
||||||
import { configApiServiceFactory, ConfigApiServiceInitOptions } from "./config-api.service.factory";
|
import { configApiServiceFactory, ConfigApiServiceInitOptions } from "./config-api.service.factory";
|
||||||
import {
|
import {
|
||||||
@@ -13,39 +8,30 @@ import {
|
|||||||
} from "./environment-service.factory";
|
} from "./environment-service.factory";
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
import { stateProviderFactory } from "./state-provider.factory";
|
import { stateProviderFactory, StateProviderInitOptions } from "./state-provider.factory";
|
||||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
|
||||||
|
|
||||||
type ConfigServiceFactoryOptions = FactoryOptions & {
|
type ConfigServiceFactoryOptions = FactoryOptions;
|
||||||
configServiceOptions?: {
|
|
||||||
subscribe?: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ConfigServiceInitOptions = ConfigServiceFactoryOptions &
|
export type ConfigServiceInitOptions = ConfigServiceFactoryOptions &
|
||||||
StateServiceInitOptions &
|
|
||||||
ConfigApiServiceInitOptions &
|
ConfigApiServiceInitOptions &
|
||||||
AuthServiceInitOptions &
|
|
||||||
EnvironmentServiceInitOptions &
|
EnvironmentServiceInitOptions &
|
||||||
LogServiceInitOptions;
|
LogServiceInitOptions &
|
||||||
|
StateProviderInitOptions;
|
||||||
|
|
||||||
export function configServiceFactory(
|
export function configServiceFactory(
|
||||||
cache: { configService?: ConfigServiceAbstraction } & CachedServices,
|
cache: { configService?: ConfigService } & CachedServices,
|
||||||
opts: ConfigServiceInitOptions,
|
opts: ConfigServiceInitOptions,
|
||||||
): Promise<ConfigServiceAbstraction> {
|
): Promise<ConfigService> {
|
||||||
return factory(
|
return factory(
|
||||||
cache,
|
cache,
|
||||||
"configService",
|
"configService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new ConfigService(
|
new DefaultConfigService(
|
||||||
await stateServiceFactory(cache, opts),
|
|
||||||
await configApiServiceFactory(cache, opts),
|
await configApiServiceFactory(cache, opts),
|
||||||
await authServiceFactory(cache, opts),
|
|
||||||
await environmentServiceFactory(cache, opts),
|
await environmentServiceFactory(cache, opts),
|
||||||
await logServiceFactory(cache, opts),
|
await logServiceFactory(cache, opts),
|
||||||
await stateProviderFactory(cache, opts),
|
await stateProviderFactory(cache, opts),
|
||||||
opts.configServiceOptions?.subscribe ?? true,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory
|
|||||||
|
|
||||||
import { BrowserApi } from "../../browser/browser-api";
|
import { BrowserApi } from "../../browser/browser-api";
|
||||||
import BrowserLocalStorageService from "../../services/browser-local-storage.service";
|
import BrowserLocalStorageService from "../../services/browser-local-storage.service";
|
||||||
|
import BrowserMemoryStorageService from "../../services/browser-memory-storage.service";
|
||||||
import { LocalBackedSessionStorageService } from "../../services/local-backed-session-storage.service";
|
import { LocalBackedSessionStorageService } from "../../services/local-backed-session-storage.service";
|
||||||
import { BackgroundMemoryStorageService } from "../../storage/background-memory-storage.service";
|
import { BackgroundMemoryStorageService } from "../../storage/background-memory-storage.service";
|
||||||
|
|
||||||
@@ -17,13 +18,14 @@ import {
|
|||||||
keyGenerationServiceFactory,
|
keyGenerationServiceFactory,
|
||||||
} from "./key-generation-service.factory";
|
} from "./key-generation-service.factory";
|
||||||
|
|
||||||
type StorageServiceFactoryOptions = FactoryOptions;
|
export type DiskStorageServiceInitOptions = FactoryOptions;
|
||||||
|
export type SecureStorageServiceInitOptions = FactoryOptions;
|
||||||
export type DiskStorageServiceInitOptions = StorageServiceFactoryOptions;
|
export type SessionStorageServiceInitOptions = FactoryOptions;
|
||||||
export type SecureStorageServiceInitOptions = StorageServiceFactoryOptions;
|
export type MemoryStorageServiceInitOptions = FactoryOptions &
|
||||||
export type MemoryStorageServiceInitOptions = StorageServiceFactoryOptions &
|
|
||||||
EncryptServiceInitOptions &
|
EncryptServiceInitOptions &
|
||||||
KeyGenerationServiceInitOptions;
|
KeyGenerationServiceInitOptions &
|
||||||
|
DiskStorageServiceInitOptions &
|
||||||
|
SessionStorageServiceInitOptions;
|
||||||
|
|
||||||
export function diskStorageServiceFactory(
|
export function diskStorageServiceFactory(
|
||||||
cache: { diskStorageService?: AbstractStorageService } & CachedServices,
|
cache: { diskStorageService?: AbstractStorageService } & CachedServices,
|
||||||
@@ -47,6 +49,13 @@ export function secureStorageServiceFactory(
|
|||||||
return factory(cache, "secureStorageService", opts, () => new BrowserLocalStorageService());
|
return factory(cache, "secureStorageService", opts, () => new BrowserLocalStorageService());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function sessionStorageServiceFactory(
|
||||||
|
cache: { sessionStorageService?: AbstractStorageService } & CachedServices,
|
||||||
|
opts: SessionStorageServiceInitOptions,
|
||||||
|
): Promise<AbstractStorageService> {
|
||||||
|
return factory(cache, "sessionStorageService", opts, () => new BrowserMemoryStorageService());
|
||||||
|
}
|
||||||
|
|
||||||
export function memoryStorageServiceFactory(
|
export function memoryStorageServiceFactory(
|
||||||
cache: { memoryStorageService?: AbstractMemoryStorageService } & CachedServices,
|
cache: { memoryStorageService?: AbstractMemoryStorageService } & CachedServices,
|
||||||
opts: MemoryStorageServiceInitOptions,
|
opts: MemoryStorageServiceInitOptions,
|
||||||
@@ -56,6 +65,9 @@ export function memoryStorageServiceFactory(
|
|||||||
return new LocalBackedSessionStorageService(
|
return new LocalBackedSessionStorageService(
|
||||||
await encryptServiceFactory(cache, opts),
|
await encryptServiceFactory(cache, opts),
|
||||||
await keyGenerationServiceFactory(cache, opts),
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
|
await diskStorageServiceFactory(cache, opts),
|
||||||
|
await sessionStorageServiceFactory(cache, opts),
|
||||||
|
"serviceFactories",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new MemoryStorageService();
|
return new MemoryStorageService();
|
||||||
|
|||||||
@@ -357,11 +357,11 @@ export class BrowserApi {
|
|||||||
private static setupUnloadListeners() {
|
private static setupUnloadListeners() {
|
||||||
// The MDN recommend using 'visibilitychange' but that event is fired any time the popup window is obscured as well
|
// The MDN recommend using 'visibilitychange' but that event is fired any time the popup window is obscured as well
|
||||||
// 'pagehide' works just like 'unload' but is compatible with the back/forward cache, so we prefer using that one
|
// 'pagehide' works just like 'unload' but is compatible with the back/forward cache, so we prefer using that one
|
||||||
window.onpagehide = () => {
|
self.addEventListener("pagehide", () => {
|
||||||
for (const [event, callback] of BrowserApi.trackedChromeEventListeners) {
|
for (const [event, callback] of BrowserApi.trackedChromeEventListeners) {
|
||||||
event.removeListener(callback);
|
event.removeListener(callback);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static sendMessage(subscriber: string, arg: any = {}) {
|
static sendMessage(subscriber: string, arg: any = {}) {
|
||||||
@@ -429,7 +429,7 @@ export class BrowserApi {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentHref = window.location.href;
|
const currentHref = self.location.href;
|
||||||
views
|
views
|
||||||
.filter((w) => w.location.href != null && !w.location.href.includes("background.html"))
|
.filter((w) => w.location.href != null && !w.location.href.includes("background.html"))
|
||||||
.filter((w) => !exemptCurrentHref || w.location.href !== currentHref)
|
.filter((w) => !exemptCurrentHref || w.location.href !== currentHref)
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ class OffscreenDocument implements OffscreenDocumentInterface {
|
|||||||
* @param message - The extension message containing the text to copy
|
* @param message - The extension message containing the text to copy
|
||||||
*/
|
*/
|
||||||
private async handleOffscreenCopyToClipboard(message: OffscreenDocumentExtensionMessage) {
|
private async handleOffscreenCopyToClipboard(message: OffscreenDocumentExtensionMessage) {
|
||||||
await BrowserClipboardService.copy(window, message.text);
|
await BrowserClipboardService.copy(self, message.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the user's clipboard and returns the text.
|
* Reads the user's clipboard and returns the text.
|
||||||
*/
|
*/
|
||||||
private async handleOffscreenReadFromClipboard() {
|
private async handleOffscreenReadFromClipboard() {
|
||||||
return await BrowserClipboardService.read(window);
|
return await BrowserClipboardService.read(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { FileDownloadRequest } from "@bitwarden/common/platform/abstractions/fil
|
|||||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
import { SafariApp } from "../../browser/safariApp";
|
import { SafariApp } from "../../../browser/safariApp";
|
||||||
import { BrowserApi } from "../browser/browser-api";
|
import { BrowserApi } from "../../browser/browser-api";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BrowserFileDownloadService implements FileDownloadService {
|
export class BrowserFileDownloadService implements FileDownloadService {
|
||||||
@@ -3,22 +3,9 @@ import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage
|
|||||||
|
|
||||||
import { Account } from "../../../models/account";
|
import { Account } from "../../../models/account";
|
||||||
import { BrowserComponentState } from "../../../models/browserComponentState";
|
import { BrowserComponentState } from "../../../models/browserComponentState";
|
||||||
import { BrowserGroupingsComponentState } from "../../../models/browserGroupingsComponentState";
|
|
||||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||||
|
|
||||||
export abstract class BrowserStateService extends BaseStateServiceAbstraction<Account> {
|
export abstract class BrowserStateService extends BaseStateServiceAbstraction<Account> {
|
||||||
getBrowserGroupingComponentState: (
|
|
||||||
options?: StorageOptions,
|
|
||||||
) => Promise<BrowserGroupingsComponentState>;
|
|
||||||
setBrowserGroupingComponentState: (
|
|
||||||
value: BrowserGroupingsComponentState,
|
|
||||||
options?: StorageOptions,
|
|
||||||
) => Promise<void>;
|
|
||||||
getBrowserVaultItemsComponentState: (options?: StorageOptions) => Promise<BrowserComponentState>;
|
|
||||||
setBrowserVaultItemsComponentState: (
|
|
||||||
value: BrowserComponentState,
|
|
||||||
options?: StorageOptions,
|
|
||||||
) => Promise<void>;
|
|
||||||
getBrowserSendComponentState: (options?: StorageOptions) => Promise<BrowserSendComponentState>;
|
getBrowserSendComponentState: (options?: StorageOptions) => Promise<BrowserSendComponentState>;
|
||||||
setBrowserSendComponentState: (
|
setBrowserSendComponentState: (
|
||||||
value: BrowserSendComponentState,
|
value: BrowserSendComponentState,
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import { ReplaySubject } from "rxjs";
|
|
||||||
|
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
|
||||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
|
||||||
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
|
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
|
||||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
|
||||||
|
|
||||||
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
|
||||||
|
|
||||||
@browserSession
|
|
||||||
export class BrowserConfigService extends ConfigService {
|
|
||||||
@sessionSync<ServerConfig>({ initializer: ServerConfig.fromJSON })
|
|
||||||
protected _serverConfig: ReplaySubject<ServerConfig | null>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
stateService: StateService,
|
|
||||||
configApiService: ConfigApiServiceAbstraction,
|
|
||||||
authService: AuthService,
|
|
||||||
environmentService: EnvironmentService,
|
|
||||||
logService: LogService,
|
|
||||||
stateProvider: StateProvider,
|
|
||||||
subscribe = false,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
stateService,
|
|
||||||
configApiService,
|
|
||||||
authService,
|
|
||||||
environmentService,
|
|
||||||
logService,
|
|
||||||
stateProvider,
|
|
||||||
subscribe,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
export default class BrowserMessagingPrivateModeBackgroundService implements MessagingService {
|
export default class BrowserMessagingPrivateModeBackgroundService implements MessagingService {
|
||||||
send(subscriber: string, arg: any = {}) {
|
send(subscriber: string, arg: any = {}) {
|
||||||
const message = Object.assign({}, { command: subscriber }, arg);
|
const message = Object.assign({}, { command: subscriber }, arg);
|
||||||
(window as any).bitwardenPopupMainMessageListener(message);
|
(self as any).bitwardenPopupMainMessageListener(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
export default class BrowserMessagingPrivateModePopupService implements MessagingService {
|
export default class BrowserMessagingPrivateModePopupService implements MessagingService {
|
||||||
send(subscriber: string, arg: any = {}) {
|
send(subscriber: string, arg: any = {}) {
|
||||||
const message = Object.assign({}, { command: subscriber }, arg);
|
const message = Object.assign({}, { command: subscriber }, arg);
|
||||||
(window as any).bitwardenBackgroundMessageListener(message);
|
(self as any).bitwardenBackgroundMessageListener(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { UserId } from "@bitwarden/common/types/guid";
|
|||||||
|
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { BrowserComponentState } from "../../models/browserComponentState";
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
|
||||||
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
||||||
|
|
||||||
import { BrowserStateService } from "./browser-state.service";
|
import { BrowserStateService } from "./browser-state.service";
|
||||||
@@ -86,27 +85,6 @@ describe("Browser State Service", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getBrowserGroupingComponentState", () => {
|
|
||||||
it("should return a BrowserGroupingsComponentState", async () => {
|
|
||||||
state.accounts[userId].groupings = new BrowserGroupingsComponentState();
|
|
||||||
|
|
||||||
const actual = await sut.getBrowserGroupingComponentState();
|
|
||||||
expect(actual).toBeInstanceOf(BrowserGroupingsComponentState);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getBrowserVaultItemsComponentState", () => {
|
|
||||||
it("should return a BrowserComponentState", async () => {
|
|
||||||
const componentState = new BrowserComponentState();
|
|
||||||
componentState.scrollY = 0;
|
|
||||||
componentState.searchText = "test";
|
|
||||||
state.accounts[userId].ciphers = componentState;
|
|
||||||
|
|
||||||
const actual = await sut.getBrowserVaultItemsComponentState();
|
|
||||||
expect(actual).toStrictEqual(componentState);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getBrowserSendComponentState", () => {
|
describe("getBrowserSendComponentState", () => {
|
||||||
it("should return a BrowserSendComponentState", async () => {
|
it("should return a BrowserSendComponentState", async () => {
|
||||||
const sendState = new BrowserSendComponentState();
|
const sendState = new BrowserSendComponentState();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { StateService as BaseStateService } from "@bitwarden/common/platform/ser
|
|||||||
|
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { BrowserComponentState } from "../../models/browserComponentState";
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
|
||||||
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
||||||
import { BrowserApi } from "../browser/browser-api";
|
import { BrowserApi } from "../browser/browser-api";
|
||||||
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||||
@@ -116,50 +115,6 @@ export class BrowserStateService
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBrowserGroupingComponentState(
|
|
||||||
options?: StorageOptions,
|
|
||||||
): Promise<BrowserGroupingsComponentState> {
|
|
||||||
return (
|
|
||||||
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
|
||||||
)?.groupings;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setBrowserGroupingComponentState(
|
|
||||||
value: BrowserGroupingsComponentState,
|
|
||||||
options?: StorageOptions,
|
|
||||||
): Promise<void> {
|
|
||||||
const account = await this.getAccount(
|
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
|
||||||
);
|
|
||||||
account.groupings = value;
|
|
||||||
await this.saveAccount(
|
|
||||||
account,
|
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBrowserVaultItemsComponentState(
|
|
||||||
options?: StorageOptions,
|
|
||||||
): Promise<BrowserComponentState> {
|
|
||||||
return (
|
|
||||||
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
|
||||||
)?.ciphers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setBrowserVaultItemsComponentState(
|
|
||||||
value: BrowserComponentState,
|
|
||||||
options?: StorageOptions,
|
|
||||||
): Promise<void> {
|
|
||||||
const account = await this.getAccount(
|
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
|
||||||
);
|
|
||||||
account.ciphers = value;
|
|
||||||
await this.saveAccount(
|
|
||||||
account,
|
|
||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBrowserSendComponentState(options?: StorageOptions): Promise<BrowserSendComponentState> {
|
async getBrowserSendComponentState(options?: StorageOptions): Promise<BrowserSendComponentState> {
|
||||||
return (
|
return (
|
||||||
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export default class I18nService extends BaseI18nService {
|
|||||||
"bs",
|
"bs",
|
||||||
"ca",
|
"ca",
|
||||||
"cs",
|
"cs",
|
||||||
|
"cy",
|
||||||
"da",
|
"da",
|
||||||
"de",
|
"de",
|
||||||
"el",
|
"el",
|
||||||
@@ -37,6 +38,7 @@ export default class I18nService extends BaseI18nService {
|
|||||||
"fi",
|
"fi",
|
||||||
"fil",
|
"fil",
|
||||||
"fr",
|
"fr",
|
||||||
|
"gl",
|
||||||
"he",
|
"he",
|
||||||
"hi",
|
"hi",
|
||||||
"hr",
|
"hr",
|
||||||
@@ -51,9 +53,13 @@ export default class I18nService extends BaseI18nService {
|
|||||||
"lt",
|
"lt",
|
||||||
"lv",
|
"lv",
|
||||||
"ml",
|
"ml",
|
||||||
|
"mr",
|
||||||
|
"my",
|
||||||
"nb",
|
"nb",
|
||||||
|
"ne",
|
||||||
"nl",
|
"nl",
|
||||||
"nn",
|
"nn",
|
||||||
|
"or",
|
||||||
"pl",
|
"pl",
|
||||||
"pt-BR",
|
"pt-BR",
|
||||||
"pt-PT",
|
"pt-PT",
|
||||||
@@ -64,6 +70,7 @@ export default class I18nService extends BaseI18nService {
|
|||||||
"sl",
|
"sl",
|
||||||
"sr",
|
"sr",
|
||||||
"sv",
|
"sv",
|
||||||
|
"te",
|
||||||
"th",
|
"th",
|
||||||
"tr",
|
"tr",
|
||||||
"uk",
|
"uk",
|
||||||
|
|||||||
@@ -2,45 +2,70 @@ import { mock, MockProxy } from "jest-mock-extended";
|
|||||||
|
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
|
import {
|
||||||
|
AbstractMemoryStorageService,
|
||||||
|
AbstractStorageService,
|
||||||
|
StorageUpdate,
|
||||||
|
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import BrowserLocalStorageService from "./browser-local-storage.service";
|
|
||||||
import BrowserMemoryStorageService from "./browser-memory-storage.service";
|
|
||||||
import { LocalBackedSessionStorageService } from "./local-backed-session-storage.service";
|
import { LocalBackedSessionStorageService } from "./local-backed-session-storage.service";
|
||||||
|
|
||||||
describe("Browser Session Storage Service", () => {
|
describe("LocalBackedSessionStorage", () => {
|
||||||
let encryptService: MockProxy<EncryptService>;
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let keyGenerationService: MockProxy<KeyGenerationService>;
|
let keyGenerationService: MockProxy<KeyGenerationService>;
|
||||||
|
let localStorageService: MockProxy<AbstractStorageService>;
|
||||||
|
let sessionStorageService: MockProxy<AbstractMemoryStorageService>;
|
||||||
|
|
||||||
let cache: Map<string, any>;
|
let cache: Map<string, any>;
|
||||||
const testObj = { a: 1, b: 2 };
|
const testObj = { a: 1, b: 2 };
|
||||||
|
|
||||||
let localStorage: BrowserLocalStorageService;
|
|
||||||
let sessionStorage: BrowserMemoryStorageService;
|
|
||||||
|
|
||||||
const key = new SymmetricCryptoKey(Utils.fromUtf8ToArray("00000000000000000000000000000000"));
|
const key = new SymmetricCryptoKey(Utils.fromUtf8ToArray("00000000000000000000000000000000"));
|
||||||
let getSessionKeySpy: jest.SpyInstance;
|
let getSessionKeySpy: jest.SpyInstance;
|
||||||
|
let sendUpdateSpy: jest.SpyInstance<void, [storageUpdate: StorageUpdate]>;
|
||||||
const mockEnc = (input: string) => Promise.resolve(new EncString("ENCRYPTED" + input));
|
const mockEnc = (input: string) => Promise.resolve(new EncString("ENCRYPTED" + input));
|
||||||
|
|
||||||
let sut: LocalBackedSessionStorageService;
|
let sut: LocalBackedSessionStorageService;
|
||||||
|
|
||||||
|
const mockExistingSessionKey = (key: SymmetricCryptoKey) => {
|
||||||
|
sessionStorageService.get.mockImplementation((storageKey) => {
|
||||||
|
if (storageKey === "localEncryptionKey_test") {
|
||||||
|
return Promise.resolve(key?.toJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject("No implementation for " + storageKey);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
encryptService = mock<EncryptService>();
|
encryptService = mock<EncryptService>();
|
||||||
keyGenerationService = mock<KeyGenerationService>();
|
keyGenerationService = mock<KeyGenerationService>();
|
||||||
|
localStorageService = mock<AbstractStorageService>();
|
||||||
|
sessionStorageService = mock<AbstractMemoryStorageService>();
|
||||||
|
|
||||||
sut = new LocalBackedSessionStorageService(encryptService, keyGenerationService);
|
sut = new LocalBackedSessionStorageService(
|
||||||
|
encryptService,
|
||||||
|
keyGenerationService,
|
||||||
|
localStorageService,
|
||||||
|
sessionStorageService,
|
||||||
|
"test",
|
||||||
|
);
|
||||||
|
|
||||||
cache = sut["cache"];
|
cache = sut["cache"];
|
||||||
localStorage = sut["localStorage"];
|
|
||||||
sessionStorage = sut["sessionStorage"];
|
keyGenerationService.createKeyWithPurpose.mockResolvedValue({
|
||||||
getSessionKeySpy = jest.spyOn(sut, "getSessionEncKey");
|
derivedKey: key,
|
||||||
getSessionKeySpy.mockResolvedValue(key);
|
salt: "bitwarden-ephemeral",
|
||||||
|
material: null, // Not used
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should exist", () => {
|
getSessionKeySpy = jest.spyOn(sut, "getSessionEncKey");
|
||||||
expect(sut).toBeInstanceOf(LocalBackedSessionStorageService);
|
getSessionKeySpy.mockResolvedValue(key);
|
||||||
|
|
||||||
|
sendUpdateSpy = jest.spyOn(sut, "sendUpdate");
|
||||||
|
sendUpdateSpy.mockReturnValue();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("get", () => {
|
describe("get", () => {
|
||||||
@@ -54,7 +79,7 @@ describe("Browser Session Storage Service", () => {
|
|||||||
const session = { test: testObj };
|
const session = { test: testObj };
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(sut, "getSessionEncKey").mockResolvedValue(key);
|
mockExistingSessionKey(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("no session retrieved", () => {
|
describe("no session retrieved", () => {
|
||||||
@@ -62,6 +87,7 @@ describe("Browser Session Storage Service", () => {
|
|||||||
let spy: jest.SpyInstance;
|
let spy: jest.SpyInstance;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
spy = jest.spyOn(sut, "getLocalSession").mockResolvedValue(null);
|
spy = jest.spyOn(sut, "getLocalSession").mockResolvedValue(null);
|
||||||
|
localStorageService.get.mockResolvedValue(null);
|
||||||
result = await sut.get("test");
|
result = await sut.get("test");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -123,31 +149,31 @@ describe("Browser Session Storage Service", () => {
|
|||||||
|
|
||||||
describe("remove", () => {
|
describe("remove", () => {
|
||||||
it("should save null", async () => {
|
it("should save null", async () => {
|
||||||
const spy = jest.spyOn(sut, "save");
|
|
||||||
spy.mockResolvedValue(null);
|
|
||||||
await sut.remove("test");
|
await sut.remove("test");
|
||||||
expect(spy).toHaveBeenCalledWith("test", null);
|
expect(sendUpdateSpy).toHaveBeenCalledWith({ key: "test", updateType: "remove" });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("save", () => {
|
describe("save", () => {
|
||||||
describe("caching", () => {
|
describe("caching", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(localStorage, "get").mockResolvedValue(null);
|
localStorageService.get.mockResolvedValue(null);
|
||||||
jest.spyOn(sessionStorage, "get").mockResolvedValue(null);
|
sessionStorageService.get.mockResolvedValue(null);
|
||||||
jest.spyOn(localStorage, "save").mockResolvedValue();
|
|
||||||
jest.spyOn(sessionStorage, "save").mockResolvedValue();
|
localStorageService.save.mockResolvedValue();
|
||||||
|
sessionStorageService.save.mockResolvedValue();
|
||||||
|
|
||||||
encryptService.encrypt.mockResolvedValue(mockEnc("{}"));
|
encryptService.encrypt.mockResolvedValue(mockEnc("{}"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove key from cache if value is null", async () => {
|
it("should remove key from cache if value is null", async () => {
|
||||||
cache.set("test", {});
|
cache.set("test", {});
|
||||||
const deleteSpy = jest.spyOn(cache, "delete");
|
const cacheSetSpy = jest.spyOn(cache, "set");
|
||||||
expect(cache.has("test")).toBe(true);
|
expect(cache.has("test")).toBe(true);
|
||||||
await sut.save("test", null);
|
await sut.save("test", null);
|
||||||
expect(cache.has("test")).toBe(false);
|
// Don't remove from cache, just replace with null
|
||||||
expect(deleteSpy).toHaveBeenCalledWith("test");
|
expect(cache.get("test")).toBe(null);
|
||||||
|
expect(cacheSetSpy).toHaveBeenCalledWith("test", null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set cache if value is non-null", async () => {
|
it("should set cache if value is non-null", async () => {
|
||||||
@@ -197,7 +223,7 @@ describe("Browser Session Storage Service", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return the stored symmetric crypto key", async () => {
|
it("should return the stored symmetric crypto key", async () => {
|
||||||
jest.spyOn(sessionStorage, "get").mockResolvedValue({ ...key });
|
sessionStorageService.get.mockResolvedValue({ ...key });
|
||||||
const result = await sut.getSessionEncKey();
|
const result = await sut.getSessionEncKey();
|
||||||
|
|
||||||
expect(result).toStrictEqual(key);
|
expect(result).toStrictEqual(key);
|
||||||
@@ -205,7 +231,6 @@ describe("Browser Session Storage Service", () => {
|
|||||||
|
|
||||||
describe("new key creation", () => {
|
describe("new key creation", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(sessionStorage, "get").mockResolvedValue(null);
|
|
||||||
keyGenerationService.createKeyWithPurpose.mockResolvedValue({
|
keyGenerationService.createKeyWithPurpose.mockResolvedValue({
|
||||||
salt: "salt",
|
salt: "salt",
|
||||||
material: null,
|
material: null,
|
||||||
@@ -218,25 +243,24 @@ describe("Browser Session Storage Service", () => {
|
|||||||
const result = await sut.getSessionEncKey();
|
const result = await sut.getSessionEncKey();
|
||||||
|
|
||||||
expect(result).toStrictEqual(key);
|
expect(result).toStrictEqual(key);
|
||||||
expect(keyGenerationService.createKeyWithPurpose).toBeCalledTimes(1);
|
expect(keyGenerationService.createKeyWithPurpose).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should store a symmetric crypto key if it makes one", async () => {
|
it("should store a symmetric crypto key if it makes one", async () => {
|
||||||
const spy = jest.spyOn(sut, "setSessionEncKey").mockResolvedValue();
|
const spy = jest.spyOn(sut, "setSessionEncKey").mockResolvedValue();
|
||||||
await sut.getSessionEncKey();
|
await sut.getSessionEncKey();
|
||||||
|
|
||||||
expect(spy).toBeCalledWith(key);
|
expect(spy).toHaveBeenCalledWith(key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getLocalSession", () => {
|
describe("getLocalSession", () => {
|
||||||
it("should return null if session is null", async () => {
|
it("should return null if session is null", async () => {
|
||||||
const spy = jest.spyOn(localStorage, "get").mockResolvedValue(null);
|
|
||||||
const result = await sut.getLocalSession(key);
|
const result = await sut.getLocalSession(key);
|
||||||
|
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
expect(spy).toBeCalledWith("session");
|
expect(localStorageService.get).toHaveBeenCalledWith("session_test");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("non-null sessions", () => {
|
describe("non-null sessions", () => {
|
||||||
@@ -245,7 +269,7 @@ describe("Browser Session Storage Service", () => {
|
|||||||
const decryptedSession = JSON.stringify(session);
|
const decryptedSession = JSON.stringify(session);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(localStorage, "get").mockResolvedValue(encSession.encryptedString);
|
localStorageService.get.mockResolvedValue(encSession.encryptedString);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should decrypt returned sessions", async () => {
|
it("should decrypt returned sessions", async () => {
|
||||||
@@ -267,13 +291,12 @@ describe("Browser Session Storage Service", () => {
|
|||||||
it("should remove state if decryption fails", async () => {
|
it("should remove state if decryption fails", async () => {
|
||||||
encryptService.decryptToUtf8.mockResolvedValue(null);
|
encryptService.decryptToUtf8.mockResolvedValue(null);
|
||||||
const setSessionEncKeySpy = jest.spyOn(sut, "setSessionEncKey").mockResolvedValue();
|
const setSessionEncKeySpy = jest.spyOn(sut, "setSessionEncKey").mockResolvedValue();
|
||||||
const removeLocalSessionSpy = jest.spyOn(localStorage, "remove").mockResolvedValue();
|
|
||||||
|
|
||||||
const result = await sut.getLocalSession(key);
|
const result = await sut.getLocalSession(key);
|
||||||
|
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
expect(setSessionEncKeySpy).toHaveBeenCalledWith(null);
|
expect(setSessionEncKeySpy).toHaveBeenCalledWith(null);
|
||||||
expect(removeLocalSessionSpy).toHaveBeenCalledWith("session");
|
expect(localStorageService.remove).toHaveBeenCalledWith("session_test");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -284,7 +307,7 @@ describe("Browser Session Storage Service", () => {
|
|||||||
|
|
||||||
it("should encrypt a stringified session", async () => {
|
it("should encrypt a stringified session", async () => {
|
||||||
encryptService.encrypt.mockImplementation(mockEnc);
|
encryptService.encrypt.mockImplementation(mockEnc);
|
||||||
jest.spyOn(localStorage, "save").mockResolvedValue();
|
localStorageService.save.mockResolvedValue();
|
||||||
await sut.setLocalSession(testSession, key);
|
await sut.setLocalSession(testSession, key);
|
||||||
|
|
||||||
expect(encryptService.encrypt).toHaveBeenNthCalledWith(1, testJSON, key);
|
expect(encryptService.encrypt).toHaveBeenNthCalledWith(1, testJSON, key);
|
||||||
@@ -292,32 +315,31 @@ describe("Browser Session Storage Service", () => {
|
|||||||
|
|
||||||
it("should remove local session if null", async () => {
|
it("should remove local session if null", async () => {
|
||||||
encryptService.encrypt.mockResolvedValue(null);
|
encryptService.encrypt.mockResolvedValue(null);
|
||||||
const spy = jest.spyOn(localStorage, "remove").mockResolvedValue();
|
|
||||||
await sut.setLocalSession(null, key);
|
await sut.setLocalSession(null, key);
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith("session");
|
expect(localStorageService.remove).toHaveBeenCalledWith("session_test");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should save encrypted string", async () => {
|
it("should save encrypted string", async () => {
|
||||||
encryptService.encrypt.mockImplementation(mockEnc);
|
encryptService.encrypt.mockImplementation(mockEnc);
|
||||||
const spy = jest.spyOn(localStorage, "save").mockResolvedValue();
|
|
||||||
await sut.setLocalSession(testSession, key);
|
await sut.setLocalSession(testSession, key);
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith("session", (await mockEnc(testJSON)).encryptedString);
|
expect(localStorageService.save).toHaveBeenCalledWith(
|
||||||
|
"session_test",
|
||||||
|
(await mockEnc(testJSON)).encryptedString,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("setSessionKey", () => {
|
describe("setSessionKey", () => {
|
||||||
it("should remove if null", async () => {
|
it("should remove if null", async () => {
|
||||||
const spy = jest.spyOn(sessionStorage, "remove").mockResolvedValue();
|
|
||||||
await sut.setSessionEncKey(null);
|
await sut.setSessionEncKey(null);
|
||||||
expect(spy).toHaveBeenCalledWith("localEncryptionKey");
|
expect(sessionStorageService.remove).toHaveBeenCalledWith("localEncryptionKey_test");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should save key when not null", async () => {
|
it("should save key when not null", async () => {
|
||||||
const spy = jest.spyOn(sessionStorage, "save").mockResolvedValue();
|
|
||||||
await sut.setSessionEncKey(key);
|
await sut.setSessionEncKey(key);
|
||||||
expect(spy).toHaveBeenCalledWith("localEncryptionKey", key);
|
expect(sessionStorageService.save).toHaveBeenCalledWith("localEncryptionKey_test", key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,40 +1,60 @@
|
|||||||
import { Subject } from "rxjs";
|
import { Observable, Subject, filter, map, merge, share, tap } from "rxjs";
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
import {
|
import {
|
||||||
AbstractMemoryStorageService,
|
AbstractMemoryStorageService,
|
||||||
|
AbstractStorageService,
|
||||||
|
ObservableStorageService,
|
||||||
StorageUpdate,
|
StorageUpdate,
|
||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { MemoryStorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
import { MemoryStorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
|
import { fromChromeEvent } from "../browser/from-chrome-event";
|
||||||
import { devFlag } from "../decorators/dev-flag.decorator";
|
import { devFlag } from "../decorators/dev-flag.decorator";
|
||||||
import { devFlagEnabled } from "../flags";
|
import { devFlagEnabled } from "../flags";
|
||||||
|
|
||||||
import BrowserLocalStorageService from "./browser-local-storage.service";
|
export class LocalBackedSessionStorageService
|
||||||
import BrowserMemoryStorageService from "./browser-memory-storage.service";
|
extends AbstractMemoryStorageService
|
||||||
|
implements ObservableStorageService
|
||||||
const keys = {
|
{
|
||||||
encKey: "localEncryptionKey",
|
|
||||||
sessionKey: "session",
|
|
||||||
};
|
|
||||||
|
|
||||||
export class LocalBackedSessionStorageService extends AbstractMemoryStorageService {
|
|
||||||
private cache = new Map<string, unknown>();
|
private cache = new Map<string, unknown>();
|
||||||
private localStorage = new BrowserLocalStorageService();
|
|
||||||
private sessionStorage = new BrowserMemoryStorageService();
|
|
||||||
private updatesSubject = new Subject<StorageUpdate>();
|
private updatesSubject = new Subject<StorageUpdate>();
|
||||||
updates$;
|
|
||||||
|
private commandName = `localBackedSessionStorage_${this.name}`;
|
||||||
|
private encKey = `localEncryptionKey_${this.name}`;
|
||||||
|
private sessionKey = `session_${this.name}`;
|
||||||
|
|
||||||
|
updates$: Observable<StorageUpdate>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private encryptService: EncryptService,
|
private encryptService: EncryptService,
|
||||||
private keyGenerationService: KeyGenerationService,
|
private keyGenerationService: KeyGenerationService,
|
||||||
|
private localStorage: AbstractStorageService,
|
||||||
|
private sessionStorage: AbstractStorageService,
|
||||||
|
private name: string,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.updates$ = this.updatesSubject.asObservable();
|
|
||||||
|
const remoteObservable = fromChromeEvent(chrome.runtime.onMessage).pipe(
|
||||||
|
filter(([msg]) => msg.command === this.commandName),
|
||||||
|
map(([msg]) => msg.update as StorageUpdate),
|
||||||
|
tap((update) => {
|
||||||
|
if (update.updateType === "remove") {
|
||||||
|
this.cache.set(update.key, null);
|
||||||
|
} else {
|
||||||
|
this.cache.delete(update.key);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
share(),
|
||||||
|
);
|
||||||
|
|
||||||
|
remoteObservable.subscribe();
|
||||||
|
|
||||||
|
this.updates$ = merge(this.updatesSubject.asObservable(), remoteObservable);
|
||||||
}
|
}
|
||||||
|
|
||||||
get valuesRequireDeserialization(): boolean {
|
get valuesRequireDeserialization(): boolean {
|
||||||
@@ -70,23 +90,37 @@ export class LocalBackedSessionStorageService extends AbstractMemoryStorageServi
|
|||||||
|
|
||||||
async save<T>(key: string, obj: T): Promise<void> {
|
async save<T>(key: string, obj: T): Promise<void> {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
this.cache.delete(key);
|
return await this.remove(key);
|
||||||
} else {
|
|
||||||
this.cache.set(key, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cache.set(key, obj);
|
||||||
|
await this.updateLocalSessionValue(key, obj);
|
||||||
|
this.sendUpdate({ key, updateType: "save" });
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(key: string): Promise<void> {
|
||||||
|
this.cache.set(key, null);
|
||||||
|
await this.updateLocalSessionValue(key, null);
|
||||||
|
this.sendUpdate({ key, updateType: "remove" });
|
||||||
|
}
|
||||||
|
|
||||||
|
sendUpdate(storageUpdate: StorageUpdate) {
|
||||||
|
this.updatesSubject.next(storageUpdate);
|
||||||
|
void chrome.runtime.sendMessage({
|
||||||
|
command: this.commandName,
|
||||||
|
update: storageUpdate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateLocalSessionValue<T>(key: string, obj: T) {
|
||||||
const sessionEncKey = await this.getSessionEncKey();
|
const sessionEncKey = await this.getSessionEncKey();
|
||||||
const localSession = (await this.getLocalSession(sessionEncKey)) ?? {};
|
const localSession = (await this.getLocalSession(sessionEncKey)) ?? {};
|
||||||
localSession[key] = obj;
|
localSession[key] = obj;
|
||||||
await this.setLocalSession(localSession, sessionEncKey);
|
await this.setLocalSession(localSession, sessionEncKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(key: string): Promise<void> {
|
|
||||||
await this.save(key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getLocalSession(encKey: SymmetricCryptoKey): Promise<Record<string, unknown>> {
|
async getLocalSession(encKey: SymmetricCryptoKey): Promise<Record<string, unknown>> {
|
||||||
const local = await this.localStorage.get<string>(keys.sessionKey);
|
const local = await this.localStorage.get<string>(this.sessionKey);
|
||||||
|
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -100,7 +134,7 @@ export class LocalBackedSessionStorageService extends AbstractMemoryStorageServi
|
|||||||
if (sessionJson == null) {
|
if (sessionJson == null) {
|
||||||
// Error with decryption -- session is lost, delete state and key and start over
|
// Error with decryption -- session is lost, delete state and key and start over
|
||||||
await this.setSessionEncKey(null);
|
await this.setSessionEncKey(null);
|
||||||
await this.localStorage.remove(keys.sessionKey);
|
await this.localStorage.remove(this.sessionKey);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return JSON.parse(sessionJson);
|
return JSON.parse(sessionJson);
|
||||||
@@ -119,9 +153,9 @@ export class LocalBackedSessionStorageService extends AbstractMemoryStorageServi
|
|||||||
// Make sure we're storing the jsonified version of the session
|
// Make sure we're storing the jsonified version of the session
|
||||||
const jsonSession = JSON.parse(JSON.stringify(session));
|
const jsonSession = JSON.parse(JSON.stringify(session));
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
await this.localStorage.remove(keys.sessionKey);
|
await this.localStorage.remove(this.sessionKey);
|
||||||
} else {
|
} else {
|
||||||
await this.localStorage.save(keys.sessionKey, jsonSession);
|
await this.localStorage.save(this.sessionKey, jsonSession);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,13 +164,13 @@ export class LocalBackedSessionStorageService extends AbstractMemoryStorageServi
|
|||||||
const encSession = await this.encryptService.encrypt(jsonSession, key);
|
const encSession = await this.encryptService.encrypt(jsonSession, key);
|
||||||
|
|
||||||
if (encSession == null) {
|
if (encSession == null) {
|
||||||
return await this.localStorage.remove(keys.sessionKey);
|
return await this.localStorage.remove(this.sessionKey);
|
||||||
}
|
}
|
||||||
await this.localStorage.save(keys.sessionKey, encSession.encryptedString);
|
await this.localStorage.save(this.sessionKey, encSession.encryptedString);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSessionEncKey(): Promise<SymmetricCryptoKey> {
|
async getSessionEncKey(): Promise<SymmetricCryptoKey> {
|
||||||
let storedKey = await this.sessionStorage.get<SymmetricCryptoKey>(keys.encKey);
|
let storedKey = await this.sessionStorage.get<SymmetricCryptoKey>(this.encKey);
|
||||||
if (storedKey == null || Object.keys(storedKey).length == 0) {
|
if (storedKey == null || Object.keys(storedKey).length == 0) {
|
||||||
const generatedKey = await this.keyGenerationService.createKeyWithPurpose(
|
const generatedKey = await this.keyGenerationService.createKeyWithPurpose(
|
||||||
128,
|
128,
|
||||||
@@ -153,9 +187,9 @@ export class LocalBackedSessionStorageService extends AbstractMemoryStorageServi
|
|||||||
|
|
||||||
async setSessionEncKey(input: SymmetricCryptoKey): Promise<void> {
|
async setSessionEncKey(input: SymmetricCryptoKey): Promise<void> {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
await this.sessionStorage.remove(keys.encKey);
|
await this.sessionStorage.remove(this.encKey);
|
||||||
} else {
|
} else {
|
||||||
await this.sessionStorage.save(keys.encKey, input);
|
await this.sessionStorage.save(this.encKey, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { BrowserApi } from "../platform/browser/browser-api";
|
|||||||
import { ZonedMessageListenerService } from "../platform/browser/zoned-message-listener.service";
|
import { ZonedMessageListenerService } from "../platform/browser/zoned-message-listener.service";
|
||||||
import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";
|
import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";
|
||||||
import { ForegroundPlatformUtilsService } from "../platform/services/platform-utils/foreground-platform-utils.service";
|
import { ForegroundPlatformUtilsService } from "../platform/services/platform-utils/foreground-platform-utils.service";
|
||||||
|
import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service";
|
||||||
|
|
||||||
import { routerTransition } from "./app-routing.animations";
|
import { routerTransition } from "./app-routing.animations";
|
||||||
import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component";
|
import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component";
|
||||||
@@ -37,6 +38,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private stateService: BrowserStateService,
|
private stateService: BrowserStateService,
|
||||||
|
private vaultBrowserStateService: VaultBrowserStateService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private platformUtilsService: ForegroundPlatformUtilsService,
|
private platformUtilsService: ForegroundPlatformUtilsService,
|
||||||
@@ -140,7 +142,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(window as any).bitwardenPopupMainMessageListener = bitwardenPopupMainMessageListener;
|
(self as any).bitwardenPopupMainMessageListener = bitwardenPopupMainMessageListener;
|
||||||
this.browserMessagingApi.messageListener("app.component", bitwardenPopupMainMessageListener);
|
this.browserMessagingApi.messageListener("app.component", bitwardenPopupMainMessageListener);
|
||||||
|
|
||||||
// eslint-disable-next-line rxjs/no-async-subscribe
|
// eslint-disable-next-line rxjs/no-async-subscribe
|
||||||
@@ -227,8 +229,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.stateService.setBrowserGroupingComponentState(null),
|
this.vaultBrowserStateService.setBrowserGroupingsComponentState(null),
|
||||||
this.stateService.setBrowserVaultItemsComponentState(null),
|
this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null),
|
||||||
this.stateService.setBrowserSendComponentState(null),
|
this.stateService.setBrowserSendComponentState(null),
|
||||||
this.stateService.setBrowserSendTypeComponentState(null),
|
this.stateService.setBrowserSendTypeComponentState(null),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { AbstractThemingService } from "@bitwarden/angular/platform/services/the
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
|
||||||
|
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
|
||||||
@@ -19,7 +18,6 @@ export class InitService {
|
|||||||
private stateService: StateServiceAbstraction,
|
private stateService: StateServiceAbstraction,
|
||||||
private logService: LogServiceAbstraction,
|
private logService: LogServiceAbstraction,
|
||||||
private themingService: AbstractThemingService,
|
private themingService: AbstractThemingService,
|
||||||
private configService: ConfigService,
|
|
||||||
@Inject(DOCUMENT) private document: Document,
|
@Inject(DOCUMENT) private document: Document,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -55,7 +53,6 @@ export class InitService {
|
|||||||
this.logService.info("Force redraw is on");
|
this.logService.info("Force redraw is on");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.configService.init();
|
|
||||||
this.setupVaultPopupHeartbeat();
|
this.setupVaultPopupHeartbeat();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
|
|
||||||
export class PopupSearchService extends SearchService {
|
export class PopupSearchService extends SearchService {
|
||||||
constructor(
|
constructor(
|
||||||
private mainSearchService: SearchService,
|
private mainSearchService: SearchService,
|
||||||
consoleLogService: ConsoleLogService,
|
logService: LogService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
) {
|
) {
|
||||||
super(consoleLogService, i18nService);
|
super(logService, i18nService);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearIndex() {
|
clearIndex() {
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
import { APP_INITIALIZER, NgModule, NgZone } from "@angular/core";
|
import { APP_INITIALIZER, NgModule, NgZone } from "@angular/core";
|
||||||
import { DomSanitizer } from "@angular/platform-browser";
|
import { DomSanitizer } from "@angular/platform-browser";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
import { ToastrService } from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
|
|
||||||
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
|
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
|
||||||
import { AngularThemingService } from "@bitwarden/angular/platform/services/theming/angular-theming.service";
|
import { AngularThemingService } from "@bitwarden/angular/platform/services/theming/angular-theming.service";
|
||||||
|
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||||
import {
|
import {
|
||||||
MEMORY_STORAGE,
|
MEMORY_STORAGE,
|
||||||
SECURE_STORAGE,
|
SECURE_STORAGE,
|
||||||
OBSERVABLE_DISK_STORAGE,
|
OBSERVABLE_DISK_STORAGE,
|
||||||
OBSERVABLE_MEMORY_STORAGE,
|
OBSERVABLE_MEMORY_STORAGE,
|
||||||
SYSTEM_THEME_OBSERVABLE,
|
SYSTEM_THEME_OBSERVABLE,
|
||||||
|
SafeInjectionToken,
|
||||||
} from "@bitwarden/angular/services/injection-tokens";
|
} from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||||
import {
|
import {
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
LoginStrategyServiceAbstraction,
|
LoginStrategyServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||||
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
@@ -28,13 +30,11 @@ import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/ab
|
|||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||||
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/services/login.service";
|
|
||||||
import {
|
import {
|
||||||
AutofillSettingsService,
|
AutofillSettingsService,
|
||||||
AutofillSettingsServiceAbstraction,
|
AutofillSettingsServiceAbstraction,
|
||||||
@@ -47,19 +47,13 @@ import {
|
|||||||
UserNotificationSettingsService,
|
UserNotificationSettingsService,
|
||||||
UserNotificationSettingsServiceAbstraction,
|
UserNotificationSettingsServiceAbstraction,
|
||||||
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/platform/abstractions/file-upload/file-upload.service";
|
|
||||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import {
|
|
||||||
LogService,
|
|
||||||
LogService as LogServiceAbstraction,
|
|
||||||
} from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
@@ -69,7 +63,6 @@ import {
|
|||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
|
||||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||||
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
||||||
@@ -82,12 +75,6 @@ import {
|
|||||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
||||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
|
||||||
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
|
||||||
import {
|
|
||||||
InternalSendService as InternalSendServiceAbstraction,
|
|
||||||
SendService,
|
|
||||||
} from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||||
import { CipherFileUploadService } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
|
import { CipherFileUploadService } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
|
||||||
@@ -103,10 +90,9 @@ import MainBackground from "../../background/main.background";
|
|||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
|
||||||
|
import { BrowserFileDownloadService } from "../../platform/popup/services/browser-file-download.service";
|
||||||
import { BrowserStateService as StateServiceAbstraction } from "../../platform/services/abstractions/browser-state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../../platform/services/abstractions/browser-state.service";
|
||||||
import { BrowserConfigService } from "../../platform/services/browser-config.service";
|
|
||||||
import { BrowserEnvironmentService } from "../../platform/services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../../platform/services/browser-environment.service";
|
||||||
import { BrowserFileDownloadService } from "../../platform/services/browser-file-download.service";
|
|
||||||
import BrowserLocalStorageService from "../../platform/services/browser-local-storage.service";
|
import BrowserLocalStorageService from "../../platform/services/browser-local-storage.service";
|
||||||
import BrowserMessagingPrivateModePopupService from "../../platform/services/browser-messaging-private-mode-popup.service";
|
import BrowserMessagingPrivateModePopupService from "../../platform/services/browser-messaging-private-mode-popup.service";
|
||||||
import BrowserMessagingService from "../../platform/services/browser-messaging.service";
|
import BrowserMessagingService from "../../platform/services/browser-messaging.service";
|
||||||
@@ -115,8 +101,8 @@ import I18nService from "../../platform/services/i18n.service";
|
|||||||
import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service";
|
import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service";
|
||||||
import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider";
|
import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider";
|
||||||
import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service";
|
import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service";
|
||||||
import { BrowserSendService } from "../../services/browser-send.service";
|
|
||||||
import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service";
|
import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service";
|
||||||
|
import { VaultBrowserStateService } from "../../vault/services/vault-browser-state.service";
|
||||||
import { VaultFilterService } from "../../vault/services/vault-filter.service";
|
import { VaultFilterService } from "../../vault/services/vault-filter.service";
|
||||||
|
|
||||||
import { DebounceNavigationService } from "./debounce-navigation.service";
|
import { DebounceNavigationService } from "./debounce-navigation.service";
|
||||||
@@ -145,99 +131,115 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
/**
|
||||||
imports: [JslibServicesModule],
|
* Provider definitions used in the ngModule.
|
||||||
declarations: [],
|
* Add your provider definition here using the safeProvider function as a wrapper. This will give you type safety.
|
||||||
providers: [
|
* If you need help please ask for it, do NOT change the type of this array.
|
||||||
InitService,
|
*/
|
||||||
DebounceNavigationService,
|
const safeProviders: SafeProvider[] = [
|
||||||
DialogService,
|
safeProvider(InitService),
|
||||||
PopupCloseWarningService,
|
safeProvider(DebounceNavigationService),
|
||||||
{
|
safeProvider(DialogService),
|
||||||
provide: APP_INITIALIZER,
|
safeProvider(PopupCloseWarningService),
|
||||||
|
safeProvider({
|
||||||
|
provide: APP_INITIALIZER as SafeInjectionToken<() => Promise<void>>,
|
||||||
useFactory: (initService: InitService) => initService.init(),
|
useFactory: (initService: InitService) => initService.init(),
|
||||||
deps: [InitService],
|
deps: [InitService],
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
}),
|
||||||
{ provide: BaseUnauthGuardService, useClass: UnauthGuardService },
|
safeProvider({
|
||||||
{
|
provide: BaseUnauthGuardService,
|
||||||
|
useClass: UnauthGuardService,
|
||||||
|
deps: [AuthServiceAbstraction, Router],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: MessagingService,
|
provide: MessagingService,
|
||||||
useFactory: () => {
|
useFactory: () => {
|
||||||
return needsBackgroundInit
|
return needsBackgroundInit
|
||||||
? new BrowserMessagingPrivateModePopupService()
|
? new BrowserMessagingPrivateModePopupService()
|
||||||
: new BrowserMessagingService();
|
: new BrowserMessagingService();
|
||||||
},
|
},
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: TwoFactorService,
|
provide: TwoFactorService,
|
||||||
useFactory: getBgService<TwoFactorService>("twoFactorService"),
|
useFactory: getBgService<TwoFactorService>("twoFactorService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: AuthServiceAbstraction,
|
provide: AuthServiceAbstraction,
|
||||||
useFactory: getBgService<AuthService>("authService"),
|
useFactory: getBgService<AuthService>("authService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: LoginStrategyServiceAbstraction,
|
provide: LoginStrategyServiceAbstraction,
|
||||||
useFactory: getBgService<LoginStrategyServiceAbstraction>("loginStrategyService"),
|
useFactory: getBgService<LoginStrategyServiceAbstraction>("loginStrategyService"),
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: SsoLoginServiceAbstraction,
|
provide: SsoLoginServiceAbstraction,
|
||||||
useFactory: getBgService<SsoLoginServiceAbstraction>("ssoLoginService"),
|
useFactory: getBgService<SsoLoginServiceAbstraction>("ssoLoginService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: SearchServiceAbstraction,
|
provide: SearchServiceAbstraction,
|
||||||
useFactory: (logService: ConsoleLogService, i18nService: I18nServiceAbstraction) => {
|
useFactory: (logService: LogService, i18nService: I18nServiceAbstraction) => {
|
||||||
return new PopupSearchService(
|
return new PopupSearchService(
|
||||||
getBgService<SearchService>("searchService")(),
|
getBgService<SearchService>("searchService")(),
|
||||||
logService,
|
logService,
|
||||||
i18nService,
|
i18nService,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
deps: [LogServiceAbstraction, I18nServiceAbstraction],
|
deps: [LogService, I18nServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: CipherFileUploadService,
|
provide: CipherFileUploadService,
|
||||||
useFactory: getBgService<CipherFileUploadService>("cipherFileUploadService"),
|
useFactory: getBgService<CipherFileUploadService>("cipherFileUploadService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{ provide: CipherService, useFactory: getBgService<CipherService>("cipherService"), deps: [] },
|
safeProvider({
|
||||||
{
|
provide: CipherService,
|
||||||
|
useFactory: getBgService<CipherService>("cipherService"),
|
||||||
|
deps: [],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: CryptoFunctionService,
|
provide: CryptoFunctionService,
|
||||||
useFactory: () => new WebCryptoFunctionService(window),
|
useFactory: () => new WebCryptoFunctionService(window),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: CollectionService,
|
provide: CollectionService,
|
||||||
useFactory: getBgService<CollectionService>("collectionService"),
|
useFactory: getBgService<CollectionService>("collectionService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: LogServiceAbstraction,
|
provide: LogService,
|
||||||
useFactory: (platformUtilsService: PlatformUtilsService) =>
|
useFactory: (platformUtilsService: PlatformUtilsService) =>
|
||||||
new ConsoleLogService(platformUtilsService.isDev()),
|
new ConsoleLogService(platformUtilsService.isDev()),
|
||||||
deps: [PlatformUtilsService],
|
deps: [PlatformUtilsService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
|
provide: EnvironmentService,
|
||||||
|
useExisting: BrowserEnvironmentService,
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: BrowserEnvironmentService,
|
provide: BrowserEnvironmentService,
|
||||||
useClass: BrowserEnvironmentService,
|
useClass: BrowserEnvironmentService,
|
||||||
deps: [LogService, StateProvider, AccountServiceAbstraction],
|
deps: [LogService, StateProvider, AccountServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: EnvironmentService,
|
provide: TotpService,
|
||||||
useExisting: BrowserEnvironmentService,
|
useFactory: getBgService<TotpService>("totpService"),
|
||||||
},
|
deps: [],
|
||||||
{ provide: TotpService, useFactory: getBgService<TotpService>("totpService"), deps: [] },
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: I18nServiceAbstraction,
|
provide: I18nServiceAbstraction,
|
||||||
useFactory: (globalStateProvider: GlobalStateProvider) => {
|
useFactory: (globalStateProvider: GlobalStateProvider) => {
|
||||||
return new I18nService(BrowserApi.getUILanguage(), globalStateProvider);
|
return new I18nService(BrowserApi.getUILanguage(), globalStateProvider);
|
||||||
},
|
},
|
||||||
deps: [GlobalStateProvider],
|
deps: [GlobalStateProvider],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: CryptoService,
|
provide: CryptoService,
|
||||||
useFactory: (encryptService: EncryptService) => {
|
useFactory: (encryptService: EncryptService) => {
|
||||||
const cryptoService = getBgService<CryptoService>("cryptoService")();
|
const cryptoService = getBgService<CryptoService>("cryptoService")();
|
||||||
@@ -245,27 +247,27 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
return cryptoService;
|
return cryptoService;
|
||||||
},
|
},
|
||||||
deps: [EncryptService],
|
deps: [EncryptService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: AuthRequestServiceAbstraction,
|
provide: AuthRequestServiceAbstraction,
|
||||||
useFactory: getBgService<AuthRequestServiceAbstraction>("authRequestService"),
|
useFactory: getBgService<AuthRequestServiceAbstraction>("authRequestService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: DeviceTrustCryptoServiceAbstraction,
|
provide: DeviceTrustCryptoServiceAbstraction,
|
||||||
useFactory: getBgService<DeviceTrustCryptoServiceAbstraction>("deviceTrustCryptoService"),
|
useFactory: getBgService<DeviceTrustCryptoServiceAbstraction>("deviceTrustCryptoService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: DevicesServiceAbstraction,
|
provide: DevicesServiceAbstraction,
|
||||||
useFactory: getBgService<DevicesServiceAbstraction>("devicesService"),
|
useFactory: getBgService<DevicesServiceAbstraction>("devicesService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: PlatformUtilsService,
|
provide: PlatformUtilsService,
|
||||||
useExisting: ForegroundPlatformUtilsService,
|
useExisting: ForegroundPlatformUtilsService,
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: ForegroundPlatformUtilsService,
|
provide: ForegroundPlatformUtilsService,
|
||||||
useClass: ForegroundPlatformUtilsService,
|
useClass: ForegroundPlatformUtilsService,
|
||||||
useFactory: (sanitizer: DomSanitizer, toastrService: ToastrService) => {
|
useFactory: (sanitizer: DomSanitizer, toastrService: ToastrService) => {
|
||||||
@@ -289,91 +291,63 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
deps: [DomSanitizer, ToastrService],
|
deps: [DomSanitizer, ToastrService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: PasswordGenerationServiceAbstraction,
|
provide: PasswordGenerationServiceAbstraction,
|
||||||
useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"),
|
useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: SendService,
|
provide: SyncService,
|
||||||
useFactory: (
|
useFactory: getBgService<SyncService>("syncService"),
|
||||||
cryptoService: CryptoService,
|
deps: [],
|
||||||
i18nService: I18nServiceAbstraction,
|
}),
|
||||||
keyGenerationService: KeyGenerationService,
|
safeProvider({
|
||||||
stateServiceAbstraction: StateServiceAbstraction,
|
|
||||||
) => {
|
|
||||||
return new BrowserSendService(
|
|
||||||
cryptoService,
|
|
||||||
i18nService,
|
|
||||||
keyGenerationService,
|
|
||||||
stateServiceAbstraction,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
deps: [CryptoService, I18nServiceAbstraction, KeyGenerationService, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: InternalSendServiceAbstraction,
|
|
||||||
useExisting: SendService,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: SendApiServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
apiService: ApiService,
|
|
||||||
fileUploadService: FileUploadService,
|
|
||||||
sendService: InternalSendServiceAbstraction,
|
|
||||||
) => {
|
|
||||||
return new SendApiService(apiService, fileUploadService, sendService);
|
|
||||||
},
|
|
||||||
deps: [ApiService, FileUploadService, InternalSendServiceAbstraction],
|
|
||||||
},
|
|
||||||
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
|
|
||||||
{
|
|
||||||
provide: DomainSettingsService,
|
provide: DomainSettingsService,
|
||||||
useClass: DefaultDomainSettingsService,
|
useClass: DefaultDomainSettingsService,
|
||||||
deps: [StateProvider],
|
deps: [StateProvider],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: AbstractStorageService,
|
provide: AbstractStorageService,
|
||||||
useClass: BrowserLocalStorageService,
|
useClass: BrowserLocalStorageService,
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: AutofillService,
|
provide: AutofillService,
|
||||||
useFactory: getBgService<AutofillService>("autofillService"),
|
useFactory: getBgService<AutofillService>("autofillService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: VaultExportServiceAbstraction,
|
provide: VaultExportServiceAbstraction,
|
||||||
useFactory: getBgService<VaultExportServiceAbstraction>("exportService"),
|
useFactory: getBgService<VaultExportServiceAbstraction>("exportService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: KeyConnectorService,
|
provide: KeyConnectorService,
|
||||||
useFactory: getBgService<KeyConnectorService>("keyConnectorService"),
|
useFactory: getBgService<KeyConnectorService>("keyConnectorService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: UserVerificationService,
|
provide: UserVerificationService,
|
||||||
useFactory: getBgService<UserVerificationService>("userVerificationService"),
|
useFactory: getBgService<UserVerificationService>("userVerificationService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: VaultTimeoutSettingsService,
|
provide: VaultTimeoutSettingsService,
|
||||||
useFactory: getBgService<VaultTimeoutSettingsService>("vaultTimeoutSettingsService"),
|
useFactory: getBgService<VaultTimeoutSettingsService>("vaultTimeoutSettingsService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: VaultTimeoutService,
|
provide: VaultTimeoutService,
|
||||||
useFactory: getBgService<VaultTimeoutService>("vaultTimeoutService"),
|
useFactory: getBgService<VaultTimeoutService>("vaultTimeoutService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: NotificationsService,
|
provide: NotificationsService,
|
||||||
useFactory: getBgService<NotificationsService>("notificationsService"),
|
useFactory: getBgService<NotificationsService>("notificationsService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: VaultFilterService,
|
provide: VaultFilterService,
|
||||||
useClass: VaultFilterService,
|
useClass: VaultFilterService,
|
||||||
deps: [
|
deps: [
|
||||||
@@ -385,31 +359,39 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
StateProvider,
|
StateProvider,
|
||||||
AccountServiceAbstraction,
|
AccountServiceAbstraction,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: SECURE_STORAGE,
|
provide: SECURE_STORAGE,
|
||||||
useExisting: AbstractStorageService, // Secure storage is not available in the browser, so we use normal storage instead and warn users when it is used.
|
useExisting: AbstractStorageService, // Secure storage is not available in the browser, so we use normal storage instead and warn users when it is used.
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: MEMORY_STORAGE,
|
provide: MEMORY_STORAGE,
|
||||||
useFactory: getBgService<AbstractStorageService>("memoryStorageService"),
|
useFactory: getBgService<AbstractStorageService>("memoryStorageService"),
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: OBSERVABLE_MEMORY_STORAGE,
|
provide: OBSERVABLE_MEMORY_STORAGE,
|
||||||
useClass: ForegroundMemoryStorageService,
|
useClass: ForegroundMemoryStorageService,
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: OBSERVABLE_DISK_STORAGE,
|
provide: OBSERVABLE_DISK_STORAGE,
|
||||||
useExisting: AbstractStorageService,
|
useExisting: AbstractStorageService,
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: VaultBrowserStateService,
|
||||||
|
useFactory: (stateProvider: StateProvider) => {
|
||||||
|
return new VaultBrowserStateService(stateProvider);
|
||||||
},
|
},
|
||||||
{
|
deps: [StateProvider],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: StateServiceAbstraction,
|
provide: StateServiceAbstraction,
|
||||||
useFactory: (
|
useFactory: (
|
||||||
storageService: AbstractStorageService,
|
storageService: AbstractStorageService,
|
||||||
secureStorageService: AbstractStorageService,
|
secureStorageService: AbstractStorageService,
|
||||||
memoryStorageService: AbstractMemoryStorageService,
|
memoryStorageService: AbstractMemoryStorageService,
|
||||||
logService: LogServiceAbstraction,
|
logService: LogService,
|
||||||
accountService: AccountServiceAbstraction,
|
accountService: AccountServiceAbstraction,
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -431,33 +413,29 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
SECURE_STORAGE,
|
SECURE_STORAGE,
|
||||||
MEMORY_STORAGE,
|
MEMORY_STORAGE,
|
||||||
LogServiceAbstraction,
|
LogService,
|
||||||
AccountServiceAbstraction,
|
AccountServiceAbstraction,
|
||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
TokenService,
|
TokenService,
|
||||||
MigrationRunner,
|
MigrationRunner,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: UsernameGenerationServiceAbstraction,
|
provide: UsernameGenerationServiceAbstraction,
|
||||||
useFactory: getBgService<UsernameGenerationServiceAbstraction>("usernameGenerationService"),
|
useFactory: getBgService<UsernameGenerationServiceAbstraction>("usernameGenerationService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: BaseStateServiceAbstraction,
|
provide: BaseStateServiceAbstraction,
|
||||||
useExisting: StateServiceAbstraction,
|
useExisting: StateServiceAbstraction,
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: FileDownloadService,
|
provide: FileDownloadService,
|
||||||
useClass: BrowserFileDownloadService,
|
useClass: BrowserFileDownloadService,
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
provide: LoginServiceAbstraction,
|
safeProvider({
|
||||||
useClass: LoginService,
|
|
||||||
deps: [StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: SYSTEM_THEME_OBSERVABLE,
|
provide: SYSTEM_THEME_OBSERVABLE,
|
||||||
useFactory: (platformUtilsService: PlatformUtilsService) => {
|
useFactory: (platformUtilsService: PlatformUtilsService) => {
|
||||||
// Safari doesn't properly handle the (prefers-color-scheme) media query in the popup window, it always returns light.
|
// Safari doesn't properly handle the (prefers-color-scheme) media query in the popup window, it always returns light.
|
||||||
@@ -471,41 +449,35 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
return AngularThemingService.createSystemThemeFromWindow(windowContext);
|
return AngularThemingService.createSystemThemeFromWindow(windowContext);
|
||||||
},
|
},
|
||||||
deps: [PlatformUtilsService],
|
deps: [PlatformUtilsService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: ConfigService,
|
|
||||||
useClass: BrowserConfigService,
|
|
||||||
deps: [
|
|
||||||
StateServiceAbstraction,
|
|
||||||
ConfigApiServiceAbstraction,
|
|
||||||
AuthServiceAbstraction,
|
|
||||||
EnvironmentService,
|
|
||||||
StateProvider,
|
|
||||||
LogService,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: FilePopoutUtilsService,
|
provide: FilePopoutUtilsService,
|
||||||
useFactory: (platformUtilsService: PlatformUtilsService) => {
|
useFactory: (platformUtilsService: PlatformUtilsService) => {
|
||||||
return new FilePopoutUtilsService(platformUtilsService);
|
return new FilePopoutUtilsService(platformUtilsService);
|
||||||
},
|
},
|
||||||
deps: [PlatformUtilsService],
|
deps: [PlatformUtilsService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: DerivedStateProvider,
|
provide: DerivedStateProvider,
|
||||||
useClass: ForegroundDerivedStateProvider,
|
useClass: ForegroundDerivedStateProvider,
|
||||||
deps: [OBSERVABLE_MEMORY_STORAGE, NgZone],
|
deps: [OBSERVABLE_MEMORY_STORAGE, NgZone],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: AutofillSettingsServiceAbstraction,
|
provide: AutofillSettingsServiceAbstraction,
|
||||||
useClass: AutofillSettingsService,
|
useClass: AutofillSettingsService,
|
||||||
deps: [StateProvider, PolicyService],
|
deps: [StateProvider, PolicyService],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: UserNotificationSettingsServiceAbstraction,
|
provide: UserNotificationSettingsServiceAbstraction,
|
||||||
useClass: UserNotificationSettingsService,
|
useClass: UserNotificationSettingsService,
|
||||||
deps: [StateProvider],
|
deps: [StateProvider],
|
||||||
},
|
}),
|
||||||
],
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [JslibServicesModule],
|
||||||
|
declarations: [],
|
||||||
|
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
|
||||||
|
providers: safeProviders,
|
||||||
})
|
})
|
||||||
export class ServicesModule {}
|
export class ServicesModule {}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Component } from "@angular/core";
|
|||||||
import { combineLatest, map } from "rxjs";
|
import { combineLatest, map } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { ButtonModule, DialogModule } from "@bitwarden/components";
|
import { ButtonModule, DialogModule } from "@bitwarden/components";
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export class AboutComponent {
|
|||||||
]).pipe(map(([serverConfig, isCloud]) => ({ serverConfig, isCloud })));
|
]).pipe(map(([serverConfig, isCloud]) => ({ serverConfig, isCloud })));
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private configService: ConfigServiceAbstraction,
|
private configService: ConfigService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import { BehaviorSubject } from "rxjs";
|
|
||||||
|
|
||||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
|
||||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
|
||||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
|
|
||||||
|
|
||||||
import { browserSession, sessionSync } from "../platform/decorators/session-sync-observable";
|
|
||||||
|
|
||||||
@browserSession
|
|
||||||
export class BrowserSendService extends SendService {
|
|
||||||
@sessionSync({ initializer: Send.fromJSON, initializeAs: "array" })
|
|
||||||
protected _sends: BehaviorSubject<Send[]>;
|
|
||||||
@sessionSync({ initializer: SendView.fromJSON, initializeAs: "array" })
|
|
||||||
protected _sendViews: BehaviorSubject<SendView[]>;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { Importer, ImportResult, ImportServiceAbstraction } from "@bitwarden/importer/core";
|
import { Importer, ImportResult, ImportServiceAbstraction } from "@bitwarden/importer/core";
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
|||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { ImportServiceAbstraction } from "@bitwarden/importer/core";
|
import { ImportServiceAbstraction } from "@bitwarden/importer/core";
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ class FilelessImporterBackground implements FilelessImporterBackgroundInterface
|
|||||||
* @param syncService - Used to trigger a full sync after the import is completed.
|
* @param syncService - Used to trigger a full sync after the import is completed.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private configService: ConfigServiceAbstraction,
|
private configService: ConfigService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private notificationBackground: NotificationBackground,
|
private notificationBackground: NotificationBackground,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Component } from "@angular/core";
|
|||||||
import { UntypedFormBuilder } from "@angular/forms";
|
import { UntypedFormBuilder } from "@angular/forms";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
|
||||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -13,6 +12,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
||||||
|
import { ExportComponent as BaseExportComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-export",
|
selector: "app-export",
|
||||||
|
|||||||
@@ -138,13 +138,23 @@
|
|||||||
attr.aria-label="{{ 'typePasskey' | i18n }} {{ fido2CredentialCreationDateValue }}"
|
attr.aria-label="{{ 'typePasskey' | i18n }} {{ fido2CredentialCreationDateValue }}"
|
||||||
>
|
>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row text-muted">
|
<div class="box-content-row box-content-row-multi text-muted" appBoxRow>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
appStopClick
|
||||||
|
(click)="removePasskey()"
|
||||||
|
appA11yTitle="{{ 'removePasskey' | i18n }}"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-fw bwi-minus-circle bwi-lg" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<div class="row-main">
|
||||||
<span class="row-label">{{ "typePasskey" | i18n }}</span>
|
<span class="row-label">{{ "typePasskey" | i18n }}</span>
|
||||||
{{ "dateCreated" | i18n }}
|
{{ "dateCreated" | i18n }}
|
||||||
{{ cipher.login.fido2Credentials[0].creationDate | date: "short" }}
|
{{ cipher.login.fido2Credentials[0].creationDate | date: "short" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
|
|||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
@@ -68,7 +68,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
sendApiService: SendApiService,
|
sendApiService: SendApiService,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
datePipe: DatePipe,
|
datePipe: DatePipe,
|
||||||
configService: ConfigServiceAbstraction,
|
configService: ConfigService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
cipherService,
|
cipherService,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
|||||||
import { BrowserGroupingsComponentState } from "../../../../models/browserGroupingsComponentState";
|
import { BrowserGroupingsComponentState } from "../../../../models/browserGroupingsComponentState";
|
||||||
import { BrowserApi } from "../../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils";
|
||||||
import { BrowserStateService } from "../../../../platform/services/abstractions/browser-state.service";
|
import { VaultBrowserStateService } from "../../../services/vault-browser-state.service";
|
||||||
import { VaultFilterService } from "../../../services/vault-filter.service";
|
import { VaultFilterService } from "../../../services/vault-filter.service";
|
||||||
|
|
||||||
const ComponentId = "VaultComponent";
|
const ComponentId = "VaultComponent";
|
||||||
@@ -84,8 +84,8 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
private browserStateService: BrowserStateService,
|
|
||||||
private vaultFilterService: VaultFilterService,
|
private vaultFilterService: VaultFilterService,
|
||||||
|
private vaultBrowserStateService: VaultBrowserStateService,
|
||||||
) {
|
) {
|
||||||
this.noFolderListSize = 100;
|
this.noFolderListSize = 100;
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
this.showLeftHeader = !(
|
this.showLeftHeader = !(
|
||||||
BrowserPopupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
|
BrowserPopupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
|
||||||
);
|
);
|
||||||
await this.browserStateService.setBrowserVaultItemsComponentState(null);
|
await this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null);
|
||||||
|
|
||||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
@@ -120,7 +120,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
const restoredScopeState = await this.restoreState();
|
const restoredScopeState = await this.restoreState();
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||||
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
||||||
this.state = await this.browserStateService.getBrowserGroupingComponentState();
|
this.state = await this.vaultBrowserStateService.getBrowserGroupingsComponentState();
|
||||||
if (this.state?.searchText) {
|
if (this.state?.searchText) {
|
||||||
this.searchText = this.state.searchText;
|
this.searchText = this.state.searchText;
|
||||||
} else if (params.searchText) {
|
} else if (params.searchText) {
|
||||||
@@ -413,11 +413,11 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
collections: this.collections,
|
collections: this.collections,
|
||||||
deletedCount: this.deletedCount,
|
deletedCount: this.deletedCount,
|
||||||
});
|
});
|
||||||
await this.browserStateService.setBrowserGroupingComponentState(this.state);
|
await this.vaultBrowserStateService.setBrowserGroupingsComponentState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async restoreState(): Promise<boolean> {
|
private async restoreState(): Promise<boolean> {
|
||||||
this.state = await this.browserStateService.getBrowserGroupingComponentState();
|
this.state = await this.vaultBrowserStateService.getBrowserGroupingsComponentState();
|
||||||
if (this.state == null) {
|
if (this.state == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
|||||||
import { BrowserComponentState } from "../../../../models/browserComponentState";
|
import { BrowserComponentState } from "../../../../models/browserComponentState";
|
||||||
import { BrowserApi } from "../../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils";
|
||||||
import { BrowserStateService } from "../../../../platform/services/abstractions/browser-state.service";
|
import { VaultBrowserStateService } from "../../../services/vault-browser-state.service";
|
||||||
import { VaultFilterService } from "../../../services/vault-filter.service";
|
import { VaultFilterService } from "../../../services/vault-filter.service";
|
||||||
|
|
||||||
const ComponentId = "VaultItemsComponent";
|
const ComponentId = "VaultItemsComponent";
|
||||||
@@ -59,7 +59,7 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn
|
|||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private broadcasterService: BroadcasterService,
|
private broadcasterService: BroadcasterService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private stateService: BrowserStateService,
|
private stateService: VaultBrowserStateService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import {
|
||||||
|
FakeAccountService,
|
||||||
|
mockAccountServiceWith,
|
||||||
|
} from "@bitwarden/common/../spec/fake-account-service";
|
||||||
|
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
|
||||||
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
|
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
||||||
|
|
||||||
|
import {
|
||||||
|
VAULT_BROWSER_COMPONENT,
|
||||||
|
VAULT_BROWSER_GROUPINGS_COMPONENT,
|
||||||
|
VaultBrowserStateService,
|
||||||
|
} from "./vault-browser-state.service";
|
||||||
|
|
||||||
|
describe("Vault Browser State Service", () => {
|
||||||
|
let stateProvider: FakeStateProvider;
|
||||||
|
|
||||||
|
let accountService: FakeAccountService;
|
||||||
|
let stateService: VaultBrowserStateService;
|
||||||
|
const mockUserId = Utils.newGuid() as UserId;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
accountService = mockAccountServiceWith(mockUserId);
|
||||||
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
|
||||||
|
stateService = new VaultBrowserStateService(stateProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getBrowserGroupingsComponentState", () => {
|
||||||
|
it("should return a BrowserGroupingsComponentState", async () => {
|
||||||
|
await stateService.setBrowserGroupingsComponentState(new BrowserGroupingsComponentState());
|
||||||
|
|
||||||
|
const actual = await stateService.getBrowserGroupingsComponentState();
|
||||||
|
|
||||||
|
expect(actual).toBeInstanceOf(BrowserGroupingsComponentState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should deserialize BrowserGroupingsComponentState", () => {
|
||||||
|
const sut = VAULT_BROWSER_GROUPINGS_COMPONENT;
|
||||||
|
|
||||||
|
const expectedState = {
|
||||||
|
deletedCount: 0,
|
||||||
|
collectionCounts: new Map<string, number>(),
|
||||||
|
folderCounts: new Map<string, number>(),
|
||||||
|
typeCounts: new Map<CipherType, number>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = sut.deserializer(
|
||||||
|
JSON.parse(JSON.stringify(expectedState)) as Jsonify<BrowserGroupingsComponentState>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getBrowserVaultItemsComponentState", () => {
|
||||||
|
it("should deserialize BrowserComponentState", () => {
|
||||||
|
const sut = VAULT_BROWSER_COMPONENT;
|
||||||
|
|
||||||
|
const expectedState = {
|
||||||
|
scrollY: 0,
|
||||||
|
searchText: "test",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = sut.deserializer(JSON.parse(JSON.stringify(expectedState)));
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a BrowserComponentState", async () => {
|
||||||
|
const componentState = new BrowserComponentState();
|
||||||
|
componentState.scrollY = 0;
|
||||||
|
componentState.searchText = "test";
|
||||||
|
|
||||||
|
await stateService.setBrowserVaultItemsComponentState(componentState);
|
||||||
|
|
||||||
|
const actual = await stateService.getBrowserVaultItemsComponentState();
|
||||||
|
expect(actual).toStrictEqual(componentState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Observable, firstValueFrom } from "rxjs";
|
||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActiveUserState,
|
||||||
|
KeyDefinition,
|
||||||
|
StateProvider,
|
||||||
|
VAULT_BROWSER_MEMORY,
|
||||||
|
} from "@bitwarden/common/platform/state";
|
||||||
|
|
||||||
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
|
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
||||||
|
|
||||||
|
export const VAULT_BROWSER_GROUPINGS_COMPONENT = new KeyDefinition<BrowserGroupingsComponentState>(
|
||||||
|
VAULT_BROWSER_MEMORY,
|
||||||
|
"vault_browser_groupings_component",
|
||||||
|
{
|
||||||
|
deserializer: (obj: Jsonify<BrowserGroupingsComponentState>) =>
|
||||||
|
BrowserGroupingsComponentState.fromJSON(obj),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const VAULT_BROWSER_COMPONENT = new KeyDefinition<BrowserComponentState>(
|
||||||
|
VAULT_BROWSER_MEMORY,
|
||||||
|
"vault_browser_component",
|
||||||
|
{
|
||||||
|
deserializer: (obj: Jsonify<BrowserComponentState>) => BrowserComponentState.fromJSON(obj),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export class VaultBrowserStateService {
|
||||||
|
vaultBrowserGroupingsComponentState$: Observable<BrowserGroupingsComponentState>;
|
||||||
|
vaultBrowserComponentState$: Observable<BrowserComponentState>;
|
||||||
|
|
||||||
|
private activeUserVaultBrowserGroupingsComponentState: ActiveUserState<BrowserGroupingsComponentState>;
|
||||||
|
private activeUserVaultBrowserComponentState: ActiveUserState<BrowserComponentState>;
|
||||||
|
|
||||||
|
constructor(protected stateProvider: StateProvider) {
|
||||||
|
this.activeUserVaultBrowserGroupingsComponentState = this.stateProvider.getActive(
|
||||||
|
VAULT_BROWSER_GROUPINGS_COMPONENT,
|
||||||
|
);
|
||||||
|
this.activeUserVaultBrowserComponentState =
|
||||||
|
this.stateProvider.getActive(VAULT_BROWSER_COMPONENT);
|
||||||
|
|
||||||
|
this.vaultBrowserGroupingsComponentState$ =
|
||||||
|
this.activeUserVaultBrowserGroupingsComponentState.state$;
|
||||||
|
this.vaultBrowserComponentState$ = this.activeUserVaultBrowserComponentState.state$;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBrowserGroupingsComponentState(): Promise<BrowserGroupingsComponentState> {
|
||||||
|
return await firstValueFrom(this.vaultBrowserGroupingsComponentState$);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setBrowserGroupingsComponentState(value: BrowserGroupingsComponentState): Promise<void> {
|
||||||
|
await this.activeUserVaultBrowserGroupingsComponentState.update(() => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBrowserVaultItemsComponentState(): Promise<BrowserComponentState> {
|
||||||
|
return await firstValueFrom(this.vaultBrowserComponentState$);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setBrowserVaultItemsComponentState(value: BrowserComponentState): Promise<void> {
|
||||||
|
await this.activeUserVaultBrowserComponentState.update(() => value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,58 +118,58 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="Name" xml:space="preserve">
|
<data name="Name" xml:space="preserve">
|
||||||
<value>Bitwarden – Free Password Manager</value>
|
<value>Bitwarden – Xestor de contrasinais gratuíto</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Summary" xml:space="preserve">
|
<data name="Summary" xml:space="preserve">
|
||||||
<value>A secure and free password manager for all of your devices</value>
|
<value>Un xestor de contrasinais seguro e gratuíto para todos os teus dispositivos</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Description" xml:space="preserve">
|
<data name="Description" xml:space="preserve">
|
||||||
<value>Bitwarden, Inc. is the parent company of 8bit Solutions LLC.
|
<value>Bitwarden, Inc. é a empresa matriz de 8bit Solutions LLC.
|
||||||
|
|
||||||
NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE.
|
NOMEADO MELLOR ADMINISTRADOR DE CONTRASINAIS POR THE VERGE, Ou.S. NEWS & WORLD REPORT, CNET E MÁS.
|
||||||
|
|
||||||
Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go.
|
Administre, almacene, protexa e comparta contrasinais ilimitados en dispositivos ilimitados desde calquera lugar. Bitwarden ofrece solucións de xestión de contrasinais de código aberto para todos, xa sexa en casa, no traballo ou en mentres estás de viaxe.
|
||||||
|
|
||||||
Generate strong, unique, and random passwords based on security requirements for every website you frequent.
|
Xere contrasinais seguros, únicas e aleatorias en función dos requisitos de seguridade de cada sitio web que frecuenta.
|
||||||
|
|
||||||
Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone.
|
Bitwarden Send transmite rapidamente información cifrada --- arquivos e texto sen formato, directamente a calquera persoa.
|
||||||
|
|
||||||
Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues.
|
Bitwarden ofrece plans Teams e Enterprise para empresas para que poida compartir contrasinais de forma segura con colegas.
|
||||||
|
|
||||||
Why Choose Bitwarden:
|
Por que elixir Bitwarden?
|
||||||
|
|
||||||
World-Class Encryption
|
Cifrado de clase mundial
|
||||||
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private.
|
Os contrasinais están protexidas con cifrado avanzado de extremo a extremo (AES-256 bits, salted hashing e PBKDF2 XA-256) para que os seus datos permanezan seguros e privados.
|
||||||
|
|
||||||
Built-in Password Generator
|
Xerador de contrasinais incorporado
|
||||||
Generate strong, unique, and random passwords based on security requirements for every website you frequent.
|
Xere contrasinais fortes, únicas e aleatorias en función dos requisitos de seguridade de cada sitio web que frecuenta.
|
||||||
|
|
||||||
Global Translations
|
Traducións Globais
|
||||||
Bitwarden translations exist in 40 languages and are growing, thanks to our global community.
|
As traducións de Bitwarden existen en 40 idiomas e están a crecer, grazas á nosa comunidade global.
|
||||||
|
|
||||||
Cross-Platform Applications
|
Aplicacións multiplataforma
|
||||||
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
|
Protexa e comparta datos confidenciais dentro da súa Caixa Forte de Bitwarden desde calquera navegador, dispositivo móbil ou sistema operativo de escritorio, e máis.
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AssetTitle" xml:space="preserve">
|
<data name="AssetTitle" xml:space="preserve">
|
||||||
<value>A secure and free password manager for all of your devices</value>
|
<value>Un xestor de contrasinais seguro e gratuíto para todos os teus dispositivos</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotSync" xml:space="preserve">
|
<data name="ScreenshotSync" xml:space="preserve">
|
||||||
<value>Sync and access your vault from multiple devices</value>
|
<value>Sincroniza e accede á túa caixa forte desde múltiples dispositivos</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotVault" xml:space="preserve">
|
<data name="ScreenshotVault" xml:space="preserve">
|
||||||
<value>Manage all your logins and passwords from a secure vault</value>
|
<value>Xestiona todos os teus usuarios e contrasinais desde unha caixa forte segura</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotAutofill" xml:space="preserve">
|
<data name="ScreenshotAutofill" xml:space="preserve">
|
||||||
<value>Quickly auto-fill your login credentials into any website that you visit</value>
|
<value>Autocompleta rapidamente os teus datos de acceso en calquera páxina web que visites</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotMenu" xml:space="preserve">
|
<data name="ScreenshotMenu" xml:space="preserve">
|
||||||
<value>Your vault is also conveniently accessible from the right-click menu</value>
|
<value>A túa caixa forte tamén é facilmente accesible desde o menú de clic dereito</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotPassword" xml:space="preserve">
|
<data name="ScreenshotPassword" xml:space="preserve">
|
||||||
<value>Automatically generate strong, random, and secure passwords</value>
|
<value>Xera automaticamente contrasinais fortes, aleatorias e seguras</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ScreenshotEdit" xml:space="preserve">
|
<data name="ScreenshotEdit" xml:space="preserve">
|
||||||
<value>Your information is managed securely using AES-256 bit encryption</value>
|
<value>A túa información é xestionada de forma segura con cifrado AES de 256 bits</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/cli",
|
"name": "@bitwarden/cli",
|
||||||
"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": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
"papaparse": "5.4.1",
|
"papaparse": "5.4.1",
|
||||||
"proper-lockfile": "4.1.2",
|
"proper-lockfile": "4.1.2",
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.1",
|
||||||
"tldts": "6.1.13",
|
"tldts": "6.1.16",
|
||||||
"zxcvbn": "4.4.2"
|
"zxcvbn": "4.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||||
import { ClientType } from "@bitwarden/common/enums";
|
import { ClientType } from "@bitwarden/common/enums";
|
||||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
import {
|
import {
|
||||||
@@ -60,6 +61,7 @@ import { GlobalState } from "@bitwarden/common/platform/models/domain/global-sta
|
|||||||
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/services/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/services/broadcaster.service";
|
||||||
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
||||||
|
import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service";
|
||||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||||
@@ -104,6 +106,7 @@ import {
|
|||||||
PasswordStrengthServiceAbstraction,
|
PasswordStrengthServiceAbstraction,
|
||||||
} from "@bitwarden/common/tools/password-strength";
|
} from "@bitwarden/common/tools/password-strength";
|
||||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
|
||||||
|
import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider";
|
||||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
|
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
@@ -131,7 +134,6 @@ import {
|
|||||||
VaultExportServiceAbstraction,
|
VaultExportServiceAbstraction,
|
||||||
} from "@bitwarden/vault-export-core";
|
} from "@bitwarden/vault-export-core";
|
||||||
|
|
||||||
import { CliConfigService } from "./platform/services/cli-config.service";
|
|
||||||
import { CliPlatformUtilsService } from "./platform/services/cli-platform-utils.service";
|
import { CliPlatformUtilsService } from "./platform/services/cli-platform-utils.service";
|
||||||
import { ConsoleLogService } from "./platform/services/console-log.service";
|
import { ConsoleLogService } from "./platform/services/console-log.service";
|
||||||
import { I18nService } from "./platform/services/i18n.service";
|
import { I18nService } from "./platform/services/i18n.service";
|
||||||
@@ -193,6 +195,7 @@ export class Main {
|
|||||||
sendProgram: SendProgram;
|
sendProgram: SendProgram;
|
||||||
logService: ConsoleLogService;
|
logService: ConsoleLogService;
|
||||||
sendService: SendService;
|
sendService: SendService;
|
||||||
|
sendStateProvider: SendStateProvider;
|
||||||
fileUploadService: FileUploadService;
|
fileUploadService: FileUploadService;
|
||||||
cipherFileUploadService: CipherFileUploadService;
|
cipherFileUploadService: CipherFileUploadService;
|
||||||
keyConnectorService: KeyConnectorService;
|
keyConnectorService: KeyConnectorService;
|
||||||
@@ -214,7 +217,7 @@ export class Main {
|
|||||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction;
|
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction;
|
||||||
authRequestService: AuthRequestService;
|
authRequestService: AuthRequestService;
|
||||||
configApiService: ConfigApiServiceAbstraction;
|
configApiService: ConfigApiServiceAbstraction;
|
||||||
configService: CliConfigService;
|
configService: ConfigService;
|
||||||
accountService: AccountService;
|
accountService: AccountService;
|
||||||
globalStateProvider: GlobalStateProvider;
|
globalStateProvider: GlobalStateProvider;
|
||||||
singleUserStateProvider: SingleUserStateProvider;
|
singleUserStateProvider: SingleUserStateProvider;
|
||||||
@@ -318,11 +321,16 @@ export class Main {
|
|||||||
this.accountService,
|
this.accountService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.keyGenerationService = new KeyGenerationService(this.cryptoFunctionService);
|
||||||
|
|
||||||
this.tokenService = new TokenService(
|
this.tokenService = new TokenService(
|
||||||
this.singleUserStateProvider,
|
this.singleUserStateProvider,
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
this.platformUtilsService.supportsSecureStorage(),
|
this.platformUtilsService.supportsSecureStorage(),
|
||||||
this.secureStorageService,
|
this.secureStorageService,
|
||||||
|
this.keyGenerationService,
|
||||||
|
this.encryptService,
|
||||||
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationRunner = new MigrationRunner(
|
const migrationRunner = new MigrationRunner(
|
||||||
@@ -343,8 +351,6 @@ export class Main {
|
|||||||
migrationRunner,
|
migrationRunner,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.keyGenerationService = new KeyGenerationService(this.cryptoFunctionService);
|
|
||||||
|
|
||||||
this.cryptoService = new CryptoService(
|
this.cryptoService = new CryptoService(
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
@@ -384,11 +390,14 @@ export class Main {
|
|||||||
|
|
||||||
this.fileUploadService = new FileUploadService(this.logService);
|
this.fileUploadService = new FileUploadService(this.logService);
|
||||||
|
|
||||||
|
this.sendStateProvider = new SendStateProvider(this.stateProvider);
|
||||||
|
|
||||||
this.sendService = new SendService(
|
this.sendService = new SendService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.stateService,
|
this.sendStateProvider,
|
||||||
|
this.encryptService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.cipherFileUploadService = new CipherFileUploadService(
|
this.cipherFileUploadService = new CipherFileUploadService(
|
||||||
@@ -423,7 +432,6 @@ export class Main {
|
|||||||
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
||||||
|
|
||||||
this.keyConnectorService = new KeyConnectorService(
|
this.keyConnectorService = new KeyConnectorService(
|
||||||
this.stateService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -431,6 +439,7 @@ export class Main {
|
|||||||
this.organizationService,
|
this.organizationService,
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
async (expired: boolean) => await this.logout(),
|
async (expired: boolean) => await this.logout(),
|
||||||
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService);
|
this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService);
|
||||||
@@ -451,11 +460,12 @@ export class Main {
|
|||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
this.stateService,
|
|
||||||
this.appIdService,
|
this.appIdService,
|
||||||
this.devicesApiService,
|
this.devicesApiService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
|
this.stateProvider,
|
||||||
|
this.secureStorageService,
|
||||||
this.userDecryptionOptionsService,
|
this.userDecryptionOptionsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -467,7 +477,7 @@ export class Main {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
||||||
this.activeUserStateProvider,
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.loginStrategyService = new LoginStrategyService(
|
this.loginStrategyService = new LoginStrategyService(
|
||||||
@@ -494,22 +504,21 @@ export class Main {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.authService = new AuthService(
|
this.authService = new AuthService(
|
||||||
|
this.accountService,
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
|
this.tokenService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.configApiService = new ConfigApiService(this.apiService, this.authService);
|
this.configApiService = new ConfigApiService(this.apiService, this.tokenService);
|
||||||
|
|
||||||
this.configService = new CliConfigService(
|
this.configService = new DefaultConfigService(
|
||||||
this.stateService,
|
|
||||||
this.configApiService,
|
this.configApiService,
|
||||||
this.authService,
|
|
||||||
this.environmentService,
|
this.environmentService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.cipherService = new CipherService(
|
this.cipherService = new CipherService(
|
||||||
@@ -710,13 +719,6 @@ export class Main {
|
|||||||
this.containerService.attachToGlobal(global);
|
this.containerService.attachToGlobal(global);
|
||||||
await this.i18nService.init();
|
await this.i18nService.init();
|
||||||
this.twoFactorService.init();
|
this.twoFactorService.init();
|
||||||
this.configService.init();
|
|
||||||
|
|
||||||
const installedVersion = await this.stateService.getInstalledVersion();
|
|
||||||
const currentVersion = await this.platformUtilsService.getApplicationVersion();
|
|
||||||
if (installedVersion == null || installedVersion !== currentVersion) {
|
|
||||||
await this.stateService.setInstalledVersion(currentVersion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import { NEVER } from "rxjs";
|
|
||||||
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
|
||||||
|
|
||||||
export class CliConfigService extends ConfigService {
|
|
||||||
// The rxjs timer uses setTimeout/setInterval under the hood, which prevents the node process from exiting
|
|
||||||
// when the command is finished. Cli should never be alive long enough to use the timer, so we disable it.
|
|
||||||
protected refreshTimer$ = NEVER;
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,7 @@ export class SendRemovePasswordCommand {
|
|||||||
try {
|
try {
|
||||||
await this.sendApiService.removePassword(id);
|
await this.sendApiService.removePassword(id);
|
||||||
|
|
||||||
const updatedSend = await this.sendService.get(id);
|
const updatedSend = await firstValueFrom(this.sendService.get$(id));
|
||||||
const decSend = await updatedSend.decrypt();
|
const decSend = await updatedSend.decrypt();
|
||||||
const env = await firstValueFrom(this.environmentService.environment$);
|
const env = await firstValueFrom(this.environmentService.environment$);
|
||||||
const webVaultUrl = env.getWebVaultUrl();
|
const webVaultUrl = env.getWebVaultUrl();
|
||||||
|
|||||||
91
apps/desktop/desktop_native/Cargo.lock
generated
91
apps/desktop/desktop_native/Cargo.lock
generated
@@ -45,9 +45,9 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arboard"
|
name = "arboard"
|
||||||
version = "3.3.0"
|
version = "3.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aafb29b107435aa276664c1db8954ac27a6e105cdad3c88287a199eb0e313c08"
|
checksum = "a2041f1943049c7978768d84e6d0fd95de98b76d6c4727b09e78ec253d29fa58"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clipboard-win",
|
"clipboard-win",
|
||||||
"log",
|
"log",
|
||||||
@@ -56,7 +56,6 @@ dependencies = [
|
|||||||
"objc_id",
|
"objc_id",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winapi",
|
|
||||||
"wl-clipboard-rs",
|
"wl-clipboard-rs",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
@@ -176,13 +175,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "4.5.0"
|
version = "5.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362"
|
checksum = "d517d4b86184dbb111d3556a10f1c8a04da7428d2987bf1081602bf11c3aa9ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"error-code",
|
"error-code",
|
||||||
"str-buf",
|
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -375,13 +372,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-code"
|
name = "error-code"
|
||||||
version = "2.3.1"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
|
checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"str-buf",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
@@ -476,12 +469,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.3.0"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
|
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -529,7 +522,7 @@ dependencies = [
|
|||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -661,12 +654,12 @@ checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.7.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"winapi",
|
"windows-targets 0.52.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -767,9 +760,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi"
|
name = "napi"
|
||||||
version = "2.13.3"
|
version = "2.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd063c93b900149304e3ba96ce5bf210cd4f81ef5eb80ded0d100df3e85a3ac0"
|
checksum = "54a63d0570e4c3e0daf7a8d380563610e159f538e20448d6c911337246f40e84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"ctor",
|
"ctor",
|
||||||
@@ -781,29 +774,29 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-build"
|
name = "napi-build"
|
||||||
version = "2.0.1"
|
version = "2.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e"
|
checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-derive"
|
name = "napi-derive"
|
||||||
version = "2.13.0"
|
version = "2.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da1c6a8fa84d549aa8708fcd062372bf8ec6e849de39016ab921067d21bde367"
|
checksum = "05bb7c37e3c1dda9312fdbe4a9fc7507fca72288ba154ec093e2d49114e727ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"napi-derive-backend",
|
"napi-derive-backend",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.38",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-derive-backend"
|
name = "napi-derive-backend"
|
||||||
version = "1.0.52"
|
version = "1.0.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20bbc7c69168d06a848f925ec5f0e0997f98e8c8d4f2cc30157f0da51c009e17"
|
checksum = "f785a8b8d7b83e925f5aa6d2ae3c159d17fe137ac368dc185bef410e7acdaeb4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -811,14 +804,14 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
"semver",
|
"semver",
|
||||||
"syn 1.0.109",
|
"syn 2.0.38",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-sys"
|
name = "napi-sys"
|
||||||
version = "2.2.3"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "166b5ef52a3ab5575047a9fe8d4a030cdd0f63c96f071cd6907674453b07bae3"
|
checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
@@ -896,9 +889,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.18.0"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_pipe"
|
name = "os_pipe"
|
||||||
@@ -1201,12 +1194,6 @@ version = "1.13.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "str-buf"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
@@ -1506,15 +1493,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-wsapoll"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1704,22 +1682,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11rb"
|
name = "x11rb"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
|
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"nix",
|
"rustix",
|
||||||
"winapi",
|
|
||||||
"winapi-wsapoll",
|
|
||||||
"x11rb-protocol",
|
"x11rb-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11rb-protocol"
|
name = "x11rb-protocol"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc"
|
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
|
||||||
dependencies = [
|
|
||||||
"nix",
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ manual_test = []
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
aes = "=0.8.4"
|
aes = "=0.8.4"
|
||||||
anyhow = "=1.0.80"
|
anyhow = "=1.0.80"
|
||||||
arboard = { version = "=3.3.0", default-features = false, features = ["wayland-data-control"] }
|
arboard = { version = "=3.3.2", default-features = false, features = ["wayland-data-control"] }
|
||||||
base64 = "=0.22.0"
|
base64 = "=0.22.0"
|
||||||
cbc = { version = "=0.1.2", features = ["alloc"] }
|
cbc = { version = "=0.1.2", features = ["alloc"] }
|
||||||
napi = { version = "=2.13.3", features = ["async"] }
|
napi = { version = "=2.16.0", features = ["async"] }
|
||||||
napi-derive = "=2.13.0"
|
napi-derive = "=2.16.0"
|
||||||
rand = "=0.8.5"
|
rand = "=0.8.5"
|
||||||
retry = "=2.0.0"
|
retry = "=2.0.0"
|
||||||
scopeguard = "=1.2.0"
|
scopeguard = "=1.2.0"
|
||||||
@@ -28,7 +28,7 @@ thiserror = "=1.0.51"
|
|||||||
typenum = "=1.17.0"
|
typenum = "=1.17.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = "=2.0.1"
|
napi-build = "=2.1.2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
widestring = "=1.0.2"
|
widestring = "=1.0.2"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"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": "2024.3.1",
|
"version": "2024.3.2",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
themeOptions: any[];
|
themeOptions: any[];
|
||||||
clearClipboardOptions: any[];
|
clearClipboardOptions: any[];
|
||||||
supportsBiometric: boolean;
|
supportsBiometric: boolean;
|
||||||
additionalBiometricSettingsText: string;
|
|
||||||
showAlwaysShowDock = false;
|
showAlwaysShowDock = false;
|
||||||
requireEnableTray = false;
|
requireEnableTray = false;
|
||||||
showDuckDuckGoIntegrationOption = false;
|
showDuckDuckGoIntegrationOption = false;
|
||||||
@@ -283,10 +282,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.showMinToTray = this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop;
|
this.showMinToTray = this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop;
|
||||||
this.showAlwaysShowDock = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
this.showAlwaysShowDock = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||||
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
|
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
|
||||||
this.additionalBiometricSettingsText =
|
|
||||||
this.biometricText === "unlockWithTouchId"
|
|
||||||
? "additionalTouchIdSettings"
|
|
||||||
: "additionalWindowsHelloSettings";
|
|
||||||
this.previousVaultTimeout = this.form.value.vaultTimeout;
|
this.previousVaultTimeout = this.form.value.vaultTimeout;
|
||||||
|
|
||||||
this.refreshTimeoutSettings$
|
this.refreshTimeoutSettings$
|
||||||
@@ -700,4 +695,15 @@ export class SettingsComponent implements OnInit {
|
|||||||
throw new Error("Unsupported platform");
|
throw new Error("Unsupported platform");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get additionalBiometricSettingsText() {
|
||||||
|
switch (this.platformUtilsService.getDevice()) {
|
||||||
|
case DeviceType.MacOsDesktop:
|
||||||
|
return "additionalTouchIdSettings";
|
||||||
|
case DeviceType.WindowsDesktop:
|
||||||
|
return "additionalWindowsHelloSettings";
|
||||||
|
default:
|
||||||
|
throw new Error("Unsupported platform");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
|||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@@ -147,7 +147,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private modalService: ModalService,
|
private modalService: ModalService,
|
||||||
private keyConnectorService: KeyConnectorService,
|
private keyConnectorService: KeyConnectorService,
|
||||||
private userVerificationService: UserVerificationService,
|
private userVerificationService: UserVerificationService,
|
||||||
private configService: ConfigServiceAbstraction,
|
private configService: ConfigService,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
private stateEventRunnerService: StateEventRunnerService,
|
private stateEventRunnerService: StateEventRunnerService,
|
||||||
@@ -265,7 +265,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.updateAppMenu();
|
this.updateAppMenu();
|
||||||
this.configService.triggerServerConfigFetch();
|
await this.configService.ensureConfigFetched();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "openSettings":
|
case "openSettings":
|
||||||
@@ -584,7 +584,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
await this.passwordGenerationService.clear(userBeingLoggedOut);
|
await this.passwordGenerationService.clear(userBeingLoggedOut);
|
||||||
await this.vaultTimeoutSettingsService.clear(userBeingLoggedOut);
|
await this.vaultTimeoutSettingsService.clear(userBeingLoggedOut);
|
||||||
await this.policyService.clear(userBeingLoggedOut);
|
await this.policyService.clear(userBeingLoggedOut);
|
||||||
await this.keyConnectorService.clear();
|
|
||||||
await this.biometricStateService.logout(userBeingLoggedOut as UserId);
|
await this.biometricStateService.logout(userBeingLoggedOut as UserId);
|
||||||
await this.providerService.save(null, userBeingLoggedOut as UserId);
|
await this.providerService.save(null, userBeingLoggedOut as UserId);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
|
|||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
|
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service";
|
import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
@@ -91,6 +92,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
|
private loginEmailService: LoginEmailServiceAbstraction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
@@ -137,7 +139,10 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
async addAccount() {
|
async addAccount() {
|
||||||
this.close();
|
this.close();
|
||||||
await this.stateService.setRememberedEmail(null);
|
|
||||||
|
this.loginEmailService.setRememberEmail(false);
|
||||||
|
await this.loginEmailService.saveEmailSettings();
|
||||||
|
|
||||||
await this.router.navigate(["/login"]);
|
await this.router.navigate(["/login"]);
|
||||||
await this.stateService.setActiveUser(null);
|
await this.stateService.setActiveUser(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.
|
|||||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
|
||||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||||
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
|
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service";
|
||||||
@@ -36,7 +35,6 @@ export class InitService {
|
|||||||
private nativeMessagingService: NativeMessagingService,
|
private nativeMessagingService: NativeMessagingService,
|
||||||
private themingService: AbstractThemingService,
|
private themingService: AbstractThemingService,
|
||||||
private encryptService: EncryptService,
|
private encryptService: EncryptService,
|
||||||
private configService: ConfigService,
|
|
||||||
@Inject(DOCUMENT) private document: Document,
|
@Inject(DOCUMENT) private document: Document,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -55,23 +53,9 @@ export class InitService {
|
|||||||
const htmlEl = this.win.document.documentElement;
|
const htmlEl = this.win.document.documentElement;
|
||||||
htmlEl.classList.add("os_" + this.platformUtilsService.getDeviceString());
|
htmlEl.classList.add("os_" + this.platformUtilsService.getDeviceString());
|
||||||
this.themingService.applyThemeChangesTo(this.document);
|
this.themingService.applyThemeChangesTo(this.document);
|
||||||
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, this.encryptService);
|
const containerService = new ContainerService(this.cryptoService, this.encryptService);
|
||||||
containerService.attachToGlobal(this.win);
|
containerService.attachToGlobal(this.win);
|
||||||
|
|
||||||
this.configService.init();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core";
|
import { APP_INITIALIZER, NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||||
import {
|
import {
|
||||||
SECURE_STORAGE,
|
SECURE_STORAGE,
|
||||||
STATE_FACTORY,
|
|
||||||
STATE_SERVICE_USE_CACHE,
|
STATE_SERVICE_USE_CACHE,
|
||||||
LOCALES_DIRECTORY,
|
LOCALES_DIRECTORY,
|
||||||
SYSTEM_LANGUAGE,
|
SYSTEM_LANGUAGE,
|
||||||
@@ -12,15 +12,15 @@ import {
|
|||||||
WINDOW,
|
WINDOW,
|
||||||
SUPPORTS_SECURE_STORAGE,
|
SUPPORTS_SECURE_STORAGE,
|
||||||
SYSTEM_THEME_OBSERVABLE,
|
SYSTEM_THEME_OBSERVABLE,
|
||||||
|
SafeInjectionToken,
|
||||||
|
STATE_FACTORY,
|
||||||
} from "@bitwarden/angular/services/injection-tokens";
|
} from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { LoginService } from "@bitwarden/common/auth/services/login.service";
|
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
@@ -77,60 +77,87 @@ import { DesktopFileDownloadService } from "./desktop-file-download.service";
|
|||||||
import { InitService } from "./init.service";
|
import { InitService } from "./init.service";
|
||||||
import { RendererCryptoFunctionService } from "./renderer-crypto-function.service";
|
import { RendererCryptoFunctionService } from "./renderer-crypto-function.service";
|
||||||
|
|
||||||
const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
const RELOAD_CALLBACK = new SafeInjectionToken<() => any>("RELOAD_CALLBACK");
|
||||||
|
|
||||||
@NgModule({
|
// Desktop has its own Account definition which must be used in its StateService
|
||||||
imports: [JslibServicesModule],
|
const DESKTOP_STATE_FACTORY = new SafeInjectionToken<StateFactory<GlobalState, Account>>(
|
||||||
declarations: [],
|
"DESKTOP_STATE_FACTORY",
|
||||||
providers: [
|
);
|
||||||
InitService,
|
|
||||||
NativeMessagingService,
|
/**
|
||||||
SearchBarService,
|
* Provider definitions used in the ngModule.
|
||||||
LoginGuard,
|
* Add your provider definition here using the safeProvider function as a wrapper. This will give you type safety.
|
||||||
DialogService,
|
* If you need help please ask for it, do NOT change the type of this array.
|
||||||
{
|
*/
|
||||||
provide: APP_INITIALIZER,
|
const safeProviders: SafeProvider[] = [
|
||||||
|
safeProvider(InitService),
|
||||||
|
safeProvider(NativeMessagingService),
|
||||||
|
safeProvider(SearchBarService),
|
||||||
|
safeProvider(LoginGuard),
|
||||||
|
safeProvider(DialogService),
|
||||||
|
safeProvider({
|
||||||
|
provide: APP_INITIALIZER as SafeInjectionToken<() => void>,
|
||||||
useFactory: (initService: InitService) => initService.init(),
|
useFactory: (initService: InitService) => initService.init(),
|
||||||
deps: [InitService],
|
deps: [InitService],
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: STATE_FACTORY,
|
provide: DESKTOP_STATE_FACTORY,
|
||||||
useValue: new StateFactory(GlobalState, Account),
|
useValue: new StateFactory(GlobalState, Account),
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
|
provide: STATE_FACTORY,
|
||||||
|
useValue: null,
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: RELOAD_CALLBACK,
|
provide: RELOAD_CALLBACK,
|
||||||
useValue: null,
|
useValue: null,
|
||||||
},
|
}),
|
||||||
{ provide: LogServiceAbstraction, useClass: ElectronLogRendererService, deps: [] },
|
safeProvider({
|
||||||
{
|
provide: LogServiceAbstraction,
|
||||||
|
useClass: ElectronLogRendererService,
|
||||||
|
deps: [],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: PlatformUtilsServiceAbstraction,
|
provide: PlatformUtilsServiceAbstraction,
|
||||||
useClass: ElectronPlatformUtilsService,
|
useClass: ElectronPlatformUtilsService,
|
||||||
deps: [I18nServiceAbstraction, MessagingServiceAbstraction],
|
deps: [I18nServiceAbstraction, MessagingServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
|
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
|
||||||
// the TokenService having to inject the PlatformUtilsService which introduces a
|
// the TokenService having to inject the PlatformUtilsService which introduces a
|
||||||
// circular dependency on Desktop only.
|
// circular dependency on Desktop only.
|
||||||
provide: SUPPORTS_SECURE_STORAGE,
|
provide: SUPPORTS_SECURE_STORAGE,
|
||||||
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
|
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: I18nServiceAbstraction,
|
provide: I18nServiceAbstraction,
|
||||||
useClass: I18nRendererService,
|
useClass: I18nRendererService,
|
||||||
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY, GlobalStateProvider],
|
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY, GlobalStateProvider],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: MessagingServiceAbstraction,
|
provide: MessagingServiceAbstraction,
|
||||||
useClass: ElectronRendererMessagingService,
|
useClass: ElectronRendererMessagingService,
|
||||||
deps: [BroadcasterServiceAbstraction],
|
deps: [BroadcasterServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{ provide: AbstractStorageService, useClass: ElectronRendererStorageService },
|
safeProvider({
|
||||||
{ provide: SECURE_STORAGE, useClass: ElectronRendererSecureStorageService },
|
provide: AbstractStorageService,
|
||||||
{ provide: MEMORY_STORAGE, useClass: MemoryStorageService },
|
useClass: ElectronRendererStorageService,
|
||||||
{ provide: OBSERVABLE_MEMORY_STORAGE, useClass: MemoryStorageServiceForStateProviders },
|
deps: [],
|
||||||
{ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService },
|
}),
|
||||||
{
|
safeProvider({
|
||||||
|
provide: SECURE_STORAGE,
|
||||||
|
useClass: ElectronRendererSecureStorageService,
|
||||||
|
deps: [],
|
||||||
|
}),
|
||||||
|
safeProvider({ provide: MEMORY_STORAGE, useClass: MemoryStorageService, deps: [] }),
|
||||||
|
safeProvider({
|
||||||
|
provide: OBSERVABLE_MEMORY_STORAGE,
|
||||||
|
useClass: MemoryStorageServiceForStateProviders,
|
||||||
|
deps: [],
|
||||||
|
}),
|
||||||
|
safeProvider({ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService }),
|
||||||
|
safeProvider({
|
||||||
provide: SystemServiceAbstraction,
|
provide: SystemServiceAbstraction,
|
||||||
useClass: SystemService,
|
useClass: SystemService,
|
||||||
deps: [
|
deps: [
|
||||||
@@ -142,8 +169,8 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
VaultTimeoutSettingsService,
|
VaultTimeoutSettingsService,
|
||||||
BiometricStateService,
|
BiometricStateService,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: StateServiceAbstraction,
|
provide: StateServiceAbstraction,
|
||||||
useClass: ElectronStateService,
|
useClass: ElectronStateService,
|
||||||
deps: [
|
deps: [
|
||||||
@@ -151,23 +178,25 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
SECURE_STORAGE,
|
SECURE_STORAGE,
|
||||||
MEMORY_STORAGE,
|
MEMORY_STORAGE,
|
||||||
LogService,
|
LogService,
|
||||||
STATE_FACTORY,
|
DESKTOP_STATE_FACTORY,
|
||||||
AccountServiceAbstraction,
|
AccountServiceAbstraction,
|
||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
TokenService,
|
TokenService,
|
||||||
MigrationRunner,
|
MigrationRunner,
|
||||||
STATE_SERVICE_USE_CACHE,
|
STATE_SERVICE_USE_CACHE,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: FileDownloadService,
|
provide: FileDownloadService,
|
||||||
useClass: DesktopFileDownloadService,
|
useClass: DesktopFileDownloadService,
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: SYSTEM_THEME_OBSERVABLE,
|
provide: SYSTEM_THEME_OBSERVABLE,
|
||||||
useFactory: () => fromIpcSystemTheme(),
|
useFactory: () => fromIpcSystemTheme(),
|
||||||
},
|
deps: [],
|
||||||
{
|
}),
|
||||||
|
safeProvider({
|
||||||
provide: EncryptedMessageHandlerService,
|
provide: EncryptedMessageHandlerService,
|
||||||
deps: [
|
deps: [
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
@@ -177,8 +206,8 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
MessagingServiceAbstraction,
|
MessagingServiceAbstraction,
|
||||||
PasswordGenerationServiceAbstraction,
|
PasswordGenerationServiceAbstraction,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: NativeMessageHandlerService,
|
provide: NativeMessageHandlerService,
|
||||||
deps: [
|
deps: [
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
@@ -187,19 +216,15 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
MessagingServiceAbstraction,
|
MessagingServiceAbstraction,
|
||||||
EncryptedMessageHandlerService,
|
EncryptedMessageHandlerService,
|
||||||
DialogService,
|
DialogService,
|
||||||
|
DesktopAutofillSettingsService,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: LoginServiceAbstraction,
|
|
||||||
useClass: LoginService,
|
|
||||||
deps: [StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: CryptoFunctionServiceAbstraction,
|
provide: CryptoFunctionServiceAbstraction,
|
||||||
useClass: RendererCryptoFunctionService,
|
useClass: RendererCryptoFunctionService,
|
||||||
deps: [WINDOW],
|
deps: [WINDOW],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: CryptoServiceAbstraction,
|
provide: CryptoServiceAbstraction,
|
||||||
useClass: ElectronCryptoService,
|
useClass: ElectronCryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
@@ -213,17 +238,21 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
StateProvider,
|
StateProvider,
|
||||||
BiometricStateService,
|
BiometricStateService,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: DesktopSettingsService,
|
provide: DesktopSettingsService,
|
||||||
useClass: DesktopSettingsService,
|
|
||||||
deps: [StateProvider],
|
deps: [StateProvider],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: DesktopAutofillSettingsService,
|
provide: DesktopAutofillSettingsService,
|
||||||
useClass: DesktopAutofillSettingsService,
|
|
||||||
deps: [StateProvider],
|
deps: [StateProvider],
|
||||||
},
|
}),
|
||||||
],
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [JslibServicesModule],
|
||||||
|
declarations: [],
|
||||||
|
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
|
||||||
|
providers: safeProviders,
|
||||||
})
|
})
|
||||||
export class ServicesModule {}
|
export class ServicesModule {}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { UntypedFormBuilder } from "@angular/forms";
|
import { UntypedFormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
|
||||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -12,6 +11,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
||||||
|
import { ExportComponent as BaseExportComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-export",
|
selector: "app-export",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user