mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
Merge branch 'main' of https://github.com/bitwarden/clients into vault/pm-10426/admin-console-add-edit
This commit is contained in:
4
.github/workflows/build-browser.yml
vendored
4
.github/workflows/build-browser.yml
vendored
@@ -114,7 +114,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -257,7 +257,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
4
.github/workflows/build-cli.yml
vendored
4
.github/workflows/build-cli.yml
vendored
@@ -93,7 +93,7 @@ jobs:
|
|||||||
awk '{print tolower($0)}')" >> $GITHUB_ENV
|
awk '{print tolower($0)}')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -171,7 +171,7 @@ jobs:
|
|||||||
choco install nasm --no-progress
|
choco install nasm --no-progress
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
14
.github/workflows/build-desktop.yml
vendored
14
.github/workflows/build-desktop.yml
vendored
@@ -143,7 +143,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -252,7 +252,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -458,7 +458,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -622,7 +622,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -839,7 +839,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -1045,7 +1045,7 @@ jobs:
|
|||||||
(github.ref == 'refs/heads/main'
|
(github.ref == 'refs/heads/main'
|
||||||
|| github.ref == 'refs/heads/rc'
|
|| github.ref == 'refs/heads/rc'
|
||||||
|| github.ref == 'refs/heads/hotfix-rc-desktop')
|
|| github.ref == 'refs/heads/hotfix-rc-desktop')
|
||||||
uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
|
uses: slackapi/slack-github-action@37ebaef184d7626c5f204ab8d3baff4262dd30f0 # v1.27.0
|
||||||
with:
|
with:
|
||||||
channel-id: C074F5UESQ0
|
channel-id: C074F5UESQ0
|
||||||
payload: |
|
payload: |
|
||||||
@@ -1084,7 +1084,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
2
.github/workflows/build-web.yml
vendored
2
.github/workflows/build-web.yml
vendored
@@ -94,7 +94,7 @@ jobs:
|
|||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
4
.github/workflows/chromatic.yml
vendored
4
.github/workflows/chromatic.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
run: npm run build-storybook:ci
|
run: npm run build-storybook:ci
|
||||||
|
|
||||||
- name: Publish to Chromatic
|
- name: Publish to Chromatic
|
||||||
uses: chromaui/action@b984808b772126a9f44b2b7737b131b68a2ede32 # v11.7.1
|
uses: chromaui/action@c883154c39671e194613be2f09ff4d17bb95f1e6 # v11.10.3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
|||||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
10
.github/workflows/release-desktop-beta.yml
vendored
10
.github/workflows/release-desktop-beta.yml
vendored
@@ -130,7 +130,7 @@ jobs:
|
|||||||
ref: ${{ needs.setup.outputs.branch-name }}
|
ref: ${{ needs.setup.outputs.branch-name }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -220,7 +220,7 @@ jobs:
|
|||||||
ref: ${{ needs.setup.outputs.branch-name }}
|
ref: ${{ needs.setup.outputs.branch-name }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -409,7 +409,7 @@ jobs:
|
|||||||
ref: ${{ needs.setup.outputs.branch-name }}
|
ref: ${{ needs.setup.outputs.branch-name }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -543,7 +543,7 @@ jobs:
|
|||||||
ref: ${{ needs.setup.outputs.branch-name }}
|
ref: ${{ needs.setup.outputs.branch-name }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
@@ -756,7 +756,7 @@ jobs:
|
|||||||
ref: ${{ needs.setup.outputs.branch-name }}
|
ref: ${{ needs.setup.outputs.branch-name }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
4
.github/workflows/scan.yml
vendored
4
.github/workflows/scan.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
- name: Scan with Checkmarx
|
- name: Scan with Checkmarx
|
||||||
uses: checkmarx/ast-github-action@1fe318de2993222574e6249750ba9000a4e2a6cd # 2.0.33
|
uses: checkmarx/ast-github-action@9fda5a4a2c297608117a5a56af424502a9192e57 # 2.0.34
|
||||||
env:
|
env:
|
||||||
INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
|
INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
|
||||||
with:
|
with:
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
--output-path . ${{ env.INCREMENTAL }}
|
--output-path . ${{ env.INCREMENTAL }}
|
||||||
|
|
||||||
- name: Upload Checkmarx results to GitHub
|
- name: Upload Checkmarx results to GitHub
|
||||||
uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6
|
uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8
|
||||||
with:
|
with:
|
||||||
sarif_file: cx_result.sarif
|
sarif_file: cx_result.sarif
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
|||||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
|||||||
2
.github/workflows/version-bump.yml
vendored
2
.github/workflows/version-bump.yml
vendored
@@ -447,7 +447,7 @@ jobs:
|
|||||||
echo "EOF" >> $GITHUB_ENV
|
echo "EOF" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Generate GH App token
|
- name: Generate GH App token
|
||||||
uses: actions/create-github-app-token@3378cda945da322a8db4b193e19d46352ebe2de5 # v1.10.4
|
uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
|
||||||
id: app-token
|
id: app-token
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.BW_GHAPP_ID }}
|
app-id: ${{ secrets.BW_GHAPP_ID }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/browser",
|
"name": "@bitwarden/browser",
|
||||||
"version": "2024.9.1",
|
"version": "2024.9.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env MANIFEST_VERSION=3 webpack",
|
"build": "cross-env MANIFEST_VERSION=3 webpack",
|
||||||
"build:mv2": "webpack",
|
"build:mv2": "webpack",
|
||||||
|
|||||||
@@ -2374,6 +2374,10 @@
|
|||||||
"message": "Are you sure you want to delete this Send?",
|
"message": "Are you sure you want to delete this Send?",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
|
"deleteSendPermanentConfirmation": {
|
||||||
|
"message": "Are you sure you want to permanently delete this Send?",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
"editSend": {
|
"editSend": {
|
||||||
"message": "Edit Send",
|
"message": "Edit Send",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
@@ -4201,6 +4205,9 @@
|
|||||||
"enableAnimations": {
|
"enableAnimations": {
|
||||||
"message": "Enable animations"
|
"message": "Enable animations"
|
||||||
},
|
},
|
||||||
|
"showAnimations": {
|
||||||
|
"message": "Show animations"
|
||||||
|
},
|
||||||
"addAccount": {
|
"addAccount": {
|
||||||
"message": "Add account"
|
"message": "Add account"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||||
|
import { parseYearMonthExpiry } from "@bitwarden/common/autofill/utils";
|
||||||
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import {
|
import {
|
||||||
@@ -1898,11 +1899,21 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
const cardView = new CardView();
|
const cardView = new CardView();
|
||||||
cardView.cardholderName = card.cardholderName || "";
|
cardView.cardholderName = card.cardholderName || "";
|
||||||
cardView.number = card.number || "";
|
cardView.number = card.number || "";
|
||||||
cardView.expMonth = card.expirationMonth || "";
|
|
||||||
cardView.expYear = card.expirationYear || "";
|
|
||||||
cardView.code = card.cvv || "";
|
cardView.code = card.cvv || "";
|
||||||
cardView.brand = card.number ? CardView.getCardBrandByPatterns(card.number) : "";
|
cardView.brand = card.number ? CardView.getCardBrandByPatterns(card.number) : "";
|
||||||
|
|
||||||
|
// If there's a combined expiration date value and no individual month or year values,
|
||||||
|
// try to parse them from the combined value
|
||||||
|
if (card.expirationDate && !card.expirationMonth && !card.expirationYear) {
|
||||||
|
const [parsedYear, parsedMonth] = parseYearMonthExpiry(card.expirationDate);
|
||||||
|
|
||||||
|
cardView.expMonth = parsedMonth || "";
|
||||||
|
cardView.expYear = parsedYear || "";
|
||||||
|
} else {
|
||||||
|
cardView.expMonth = card.expirationMonth || "";
|
||||||
|
cardView.expYear = card.expirationYear || "";
|
||||||
|
}
|
||||||
|
|
||||||
const cipherView = new CipherView();
|
const cipherView = new CipherView();
|
||||||
cipherView.name = "";
|
cipherView.name = "";
|
||||||
cipherView.folderId = null;
|
cipherView.folderId = null;
|
||||||
|
|||||||
@@ -300,8 +300,6 @@ export class CreditCardAutoFillConstants {
|
|||||||
"cb-type",
|
"cb-type",
|
||||||
];
|
];
|
||||||
|
|
||||||
static readonly CardExpiryDateDelimiters: string[] = ["/", "-", ".", " "];
|
|
||||||
|
|
||||||
// Note, these are expressions of user-guidance for the expected expiry date format to be used
|
// Note, these are expressions of user-guidance for the expected expiry date format to be used
|
||||||
static readonly CardExpiryDateFormats: CardExpiryDateFormat[] = [
|
static readonly CardExpiryDateFormats: CardExpiryDateFormat[] = [
|
||||||
// English
|
// English
|
||||||
|
|||||||
@@ -6,11 +6,15 @@ import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions
|
|||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.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 { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
import {
|
||||||
|
AutofillOverlayVisibility,
|
||||||
|
CardExpiryDateDelimiters,
|
||||||
|
} 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 { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||||
|
import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils";
|
||||||
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 { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
@@ -30,7 +34,6 @@ import { CardView } from "@bitwarden/common/vault/models/view/card.view";
|
|||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { FieldView } from "@bitwarden/common/vault/models/view/field.view";
|
import { FieldView } from "@bitwarden/common/vault/models/view/field.view";
|
||||||
import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view";
|
import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view";
|
||||||
import { normalizeExpiryYearFormat } from "@bitwarden/common/vault/utils";
|
|
||||||
|
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service";
|
import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service";
|
||||||
@@ -1397,8 +1400,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
if (expectedExpiryDateFormat) {
|
if (expectedExpiryDateFormat) {
|
||||||
const { Month, MonthShort, Year } = expiryDateFormatPatterns;
|
const { Month, MonthShort, Year } = expiryDateFormatPatterns;
|
||||||
|
|
||||||
const expiryDateDelimitersPattern =
|
const expiryDateDelimitersPattern = "\\" + CardExpiryDateDelimiters.join("\\");
|
||||||
"\\" + CreditCardAutoFillConstants.CardExpiryDateDelimiters.join("\\");
|
|
||||||
|
|
||||||
// assign the delimiter from the expected format string
|
// assign the delimiter from the expected format string
|
||||||
delimiter =
|
delimiter =
|
||||||
@@ -1450,8 +1452,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
let expectedDateFormat = null;
|
let expectedDateFormat = null;
|
||||||
let dateFormatPatterns = null;
|
let dateFormatPatterns = null;
|
||||||
|
|
||||||
const expiryDateDelimitersPattern =
|
const expiryDateDelimitersPattern = "\\" + CardExpiryDateDelimiters.join("\\");
|
||||||
"\\" + CreditCardAutoFillConstants.CardExpiryDateDelimiters.join("\\");
|
|
||||||
|
|
||||||
CreditCardAutoFillConstants.CardExpiryDateFormats.find((dateFormat) => {
|
CreditCardAutoFillConstants.CardExpiryDateFormats.find((dateFormat) => {
|
||||||
dateFormatPatterns = dateFormat;
|
dateFormatPatterns = dateFormat;
|
||||||
@@ -1489,6 +1490,8 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// @TODO if expectedDateFormat is still null, and there is a `pattern` attribute, cycle
|
||||||
|
// through generated formatted values, checking against the provided regex pattern
|
||||||
|
|
||||||
return [expectedDateFormat, dateFormatPatterns];
|
return [expectedDateFormat, dateFormatPatterns];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ export default class MainBackground {
|
|||||||
this.logService = new ConsoleLogService(isDev);
|
this.logService = new ConsoleLogService(isDev);
|
||||||
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(this.logService);
|
||||||
|
|
||||||
this.intraprocessMessagingSubject = new Subject<Message<Record<string, unknown>>>();
|
this.intraprocessMessagingSubject = new Subject<Message<Record<string, unknown>>>();
|
||||||
|
|
||||||
@@ -693,6 +693,7 @@ export default class MainBackground {
|
|||||||
|
|
||||||
this.collectionService = new CollectionService(
|
this.collectionService = new CollectionService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
@@ -803,9 +804,11 @@ export default class MainBackground {
|
|||||||
this.cipherFileUploadService,
|
this.cipherFileUploadService,
|
||||||
this.configService,
|
this.configService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
|
this.accountService,
|
||||||
);
|
);
|
||||||
this.folderService = new FolderService(
|
this.folderService = new FolderService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
@@ -977,6 +980,7 @@ export default class MainBackground {
|
|||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.accountService,
|
this.accountService,
|
||||||
);
|
);
|
||||||
@@ -986,8 +990,10 @@ export default class MainBackground {
|
|||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.kdfConfigService,
|
this.kdfConfigService,
|
||||||
|
this.accountService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.organizationVaultExportService = new OrganizationVaultExportService(
|
this.organizationVaultExportService = new OrganizationVaultExportService(
|
||||||
@@ -995,6 +1001,7 @@ export default class MainBackground {
|
|||||||
this.apiService,
|
this.apiService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
this.kdfConfigService,
|
this.kdfConfigService,
|
||||||
@@ -1098,6 +1105,7 @@ export default class MainBackground {
|
|||||||
);
|
);
|
||||||
this.nativeMessagingBackground = new NativeMessagingBackground(
|
this.nativeMessagingBackground = new NativeMessagingBackground(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.runtimeBackground,
|
this.runtimeBackground,
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
|||||||
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";
|
||||||
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -73,6 +74,7 @@ export class NativeMessagingBackground {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private runtimeBackground: RuntimeBackground,
|
private runtimeBackground: RuntimeBackground,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
@@ -227,7 +229,7 @@ export class NativeMessagingBackground {
|
|||||||
await this.secureCommunication();
|
await this.secureCommunication();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
|
return await this.encryptService.encrypt(JSON.stringify(message), this.sharedSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
getResponse(): Promise<any> {
|
getResponse(): Promise<any> {
|
||||||
@@ -273,7 +275,7 @@ export class NativeMessagingBackground {
|
|||||||
let message = rawMessage as ReceiveMessage;
|
let message = rawMessage as ReceiveMessage;
|
||||||
if (!this.platformUtilsService.isSafari()) {
|
if (!this.platformUtilsService.isSafari()) {
|
||||||
message = JSON.parse(
|
message = JSON.parse(
|
||||||
await this.cryptoService.decryptToUtf8(rawMessage as EncString, this.sharedSecret),
|
await this.encryptService.decryptToUtf8(rawMessage as EncString, this.sharedSecret),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.9.1",
|
"version": "2024.9.2",
|
||||||
"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.9.1",
|
"version": "2024.9.2",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Bitwarden Inc.",
|
"author": "Bitwarden Inc.",
|
||||||
|
|||||||
@@ -1,10 +1,67 @@
|
|||||||
import AbstractChromeStorageService from "./abstractions/abstract-chrome-storage-api.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
|
|
||||||
|
import AbstractChromeStorageService, {
|
||||||
|
SerializedValue,
|
||||||
|
} from "./abstractions/abstract-chrome-storage-api.service";
|
||||||
|
|
||||||
export default class BrowserLocalStorageService extends AbstractChromeStorageService {
|
export default class BrowserLocalStorageService extends AbstractChromeStorageService {
|
||||||
constructor() {
|
constructor(private readonly logService: LogService) {
|
||||||
super(chrome.storage.local);
|
super(chrome.storage.local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override async get<T>(key: string): Promise<T> {
|
||||||
|
return await this.getWithRetries<T>(key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getWithRetries<T>(key: string, retryNum: number): Promise<T> {
|
||||||
|
// See: https://github.com/EFForg/privacybadger/pull/2980
|
||||||
|
const MAX_RETRIES = 5;
|
||||||
|
const WAIT_TIME = 200;
|
||||||
|
|
||||||
|
const store = await this.getStore(key);
|
||||||
|
|
||||||
|
if (store == null) {
|
||||||
|
if (retryNum >= MAX_RETRIES) {
|
||||||
|
throw new Error(`Failed to get a value for key '${key}', see logs for more details.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
retryNum++;
|
||||||
|
this.logService.warning(`Retrying attempt to get value for key '${key}' in ${WAIT_TIME}ms`);
|
||||||
|
await new Promise<void>((resolve) => setTimeout(resolve, WAIT_TIME));
|
||||||
|
return await this.getWithRetries(key, retryNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a store
|
||||||
|
return this.processGetObject<T>(store[key] as T | SerializedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getStore(key: string) {
|
||||||
|
if (this.chromeStorageApi == null) {
|
||||||
|
this.logService.warning(
|
||||||
|
`chrome.storage.local was not initialized while retrieving key '${key}'.`,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<{ [key: string]: unknown }>((resolve) => {
|
||||||
|
this.chromeStorageApi.get(key, (store) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
this.logService.warning(`Failed to get value for key '${key}'`, chrome.runtime.lastError);
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store == null) {
|
||||||
|
this.logService.warning(`Store was empty while retrieving value for key '${key}'`);
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(store);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async fillBuffer() {
|
async fillBuffer() {
|
||||||
// Write 4MB of data in chrome.storage.local, log files will hold 4MB of data (by default)
|
// Write 4MB of data in chrome.storage.local, log files will hold 4MB of data (by default)
|
||||||
// before forcing a compaction. To force a compaction and have it remove previously saved data,
|
// before forcing a compaction. To force a compaction and have it remove previously saved data,
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
safeProvider({
|
safeProvider({
|
||||||
provide: AbstractStorageService,
|
provide: AbstractStorageService,
|
||||||
useClass: BrowserLocalStorageService,
|
useClass: BrowserLocalStorageService,
|
||||||
deps: [],
|
deps: [LogService],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: AutofillServiceAbstraction,
|
provide: AutofillServiceAbstraction,
|
||||||
|
|||||||
@@ -13,5 +13,14 @@
|
|||||||
<button bitButton type="submit" form="sendForm" buttonType="primary" #submitBtn>
|
<button bitButton type="submit" form="sendForm" buttonType="primary" #submitBtn>
|
||||||
{{ "save" | i18n }}
|
{{ "save" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="config?.mode !== 'add'"
|
||||||
|
type="button"
|
||||||
|
buttonType="danger"
|
||||||
|
class="tw-ml-auto bwi-lg"
|
||||||
|
bitIconButton="bwi-trash"
|
||||||
|
[bitAction]="deleteSend"
|
||||||
|
appA11yTitle="{{ 'delete' | i18n }}"
|
||||||
|
></button>
|
||||||
</popup-footer>
|
</popup-footer>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ import { map, switchMap } from "rxjs";
|
|||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||||
|
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||||
import { SendId } from "@bitwarden/common/types/guid";
|
import { SendId } from "@bitwarden/common/types/guid";
|
||||||
import { AsyncActionsModule, ButtonModule, SearchModule } from "@bitwarden/components";
|
import {
|
||||||
|
AsyncActionsModule,
|
||||||
|
ButtonModule,
|
||||||
|
DialogService,
|
||||||
|
IconButtonModule,
|
||||||
|
SearchModule,
|
||||||
|
ToastService,
|
||||||
|
} from "@bitwarden/components";
|
||||||
import {
|
import {
|
||||||
DefaultSendFormConfigService,
|
DefaultSendFormConfigService,
|
||||||
SendFormConfig,
|
SendFormConfig,
|
||||||
@@ -58,6 +66,7 @@ export type AddEditQueryParams = Partial<Record<keyof QueryParams, string>>;
|
|||||||
JslibModule,
|
JslibModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
IconButtonModule,
|
||||||
PopupPageComponent,
|
PopupPageComponent,
|
||||||
PopupHeaderComponent,
|
PopupHeaderComponent,
|
||||||
PopupFooterComponent,
|
PopupFooterComponent,
|
||||||
@@ -81,6 +90,9 @@ export class SendAddEditComponent {
|
|||||||
private location: Location,
|
private location: Location,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private addEditFormConfigService: SendFormConfigService,
|
private addEditFormConfigService: SendFormConfigService,
|
||||||
|
private sendApiService: SendApiService,
|
||||||
|
private toastService: ToastService,
|
||||||
|
private dialogService: DialogService,
|
||||||
) {
|
) {
|
||||||
this.subscribeToParams();
|
this.subscribeToParams();
|
||||||
}
|
}
|
||||||
@@ -92,6 +104,37 @@ export class SendAddEditComponent {
|
|||||||
this.location.back();
|
this.location.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteSend = async () => {
|
||||||
|
const confirmed = await this.dialogService.openSimpleDialog({
|
||||||
|
title: { key: "deleteSend" },
|
||||||
|
content: { key: "deleteSendPermanentConfirmation" },
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.sendApiService.delete(this.config.originalSend?.id);
|
||||||
|
} catch (e) {
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "error",
|
||||||
|
title: null,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.location.back();
|
||||||
|
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "success",
|
||||||
|
title: null,
|
||||||
|
message: this.i18nService.t("deletedSend"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the route query parameters and builds the configuration based on the parameters.
|
* Subscribes to the route query parameters and builds the configuration based on the parameters.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
|
import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
|
||||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||||
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
|
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
|
||||||
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
|
import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { Folder } from "@bitwarden/common/vault/models/domain/folder";
|
import { Folder } from "@bitwarden/common/vault/models/domain/folder";
|
||||||
@@ -25,6 +29,7 @@ describe("AddEditFolderDialogComponent", () => {
|
|||||||
const save = jest.fn().mockResolvedValue(null);
|
const save = jest.fn().mockResolvedValue(null);
|
||||||
const deleteFolder = jest.fn().mockResolvedValue(null);
|
const deleteFolder = jest.fn().mockResolvedValue(null);
|
||||||
const openSimpleDialog = jest.fn().mockResolvedValue(true);
|
const openSimpleDialog = jest.fn().mockResolvedValue(true);
|
||||||
|
const getUserKeyWithLegacySupport = jest.fn().mockResolvedValue("");
|
||||||
const error = jest.fn();
|
const error = jest.fn();
|
||||||
const close = jest.fn();
|
const close = jest.fn();
|
||||||
const showToast = jest.fn();
|
const showToast = jest.fn();
|
||||||
@@ -41,12 +46,29 @@ describe("AddEditFolderDialogComponent", () => {
|
|||||||
close.mockClear();
|
close.mockClear();
|
||||||
showToast.mockClear();
|
showToast.mockClear();
|
||||||
|
|
||||||
|
const userId = "" as UserId;
|
||||||
|
const accountInfo: AccountInfo = {
|
||||||
|
email: "",
|
||||||
|
emailVerified: true,
|
||||||
|
name: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [AddEditFolderDialogComponent, NoopAnimationsModule],
|
imports: [AddEditFolderDialogComponent, NoopAnimationsModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
||||||
{ provide: FolderService, useValue: { encrypt } },
|
{ provide: FolderService, useValue: { encrypt } },
|
||||||
{ provide: FolderApiServiceAbstraction, useValue: { save, delete: deleteFolder } },
|
{ provide: FolderApiServiceAbstraction, useValue: { save, delete: deleteFolder } },
|
||||||
|
{
|
||||||
|
provide: AccountService,
|
||||||
|
useValue: { activeAccount$: new BehaviorSubject({ id: userId, ...accountInfo }) },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: CryptoService,
|
||||||
|
useValue: {
|
||||||
|
getUserKeyWithLegacySupport,
|
||||||
|
},
|
||||||
|
},
|
||||||
{ provide: LogService, useValue: { error } },
|
{ provide: LogService, useValue: { error } },
|
||||||
{ provide: ToastService, useValue: { showToast } },
|
{ provide: ToastService, useValue: { showToast } },
|
||||||
{ provide: DIALOG_DATA, useValue: dialogData },
|
{ provide: DIALOG_DATA, useValue: dialogData },
|
||||||
@@ -82,7 +104,7 @@ describe("AddEditFolderDialogComponent", () => {
|
|||||||
const newFolder = new FolderView();
|
const newFolder = new FolderView();
|
||||||
newFolder.name = "New Folder";
|
newFolder.name = "New Folder";
|
||||||
|
|
||||||
expect(encrypt).toHaveBeenCalledWith(newFolder);
|
expect(encrypt).toHaveBeenCalledWith(newFolder, "");
|
||||||
expect(save).toHaveBeenCalled();
|
expect(save).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -137,10 +159,13 @@ describe("AddEditFolderDialogComponent", () => {
|
|||||||
component.folderForm.controls.name.setValue("Edited Folder");
|
component.folderForm.controls.name.setValue("Edited Folder");
|
||||||
await component.submit();
|
await component.submit();
|
||||||
|
|
||||||
expect(encrypt).toHaveBeenCalledWith({
|
expect(encrypt).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
...dialogData.editFolderConfig.folder,
|
...dialogData.editFolderConfig.folder,
|
||||||
name: "Edited Folder",
|
name: "Edited Folder",
|
||||||
});
|
},
|
||||||
|
"",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deletes the folder", async () => {
|
it("deletes the folder", async () => {
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ import {
|
|||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
|
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||||
@@ -68,6 +71,8 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit {
|
|||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private folderApiService: FolderApiServiceAbstraction,
|
private folderApiService: FolderApiServiceAbstraction,
|
||||||
|
private accountService: AccountService,
|
||||||
|
private cryptoService: CryptoService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
@@ -107,7 +112,9 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit {
|
|||||||
this.folder.name = this.folderForm.controls.name.value;
|
this.folder.name = this.folderForm.controls.name.value;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const folder = await this.folderService.encrypt(this.folder);
|
const activeUserId = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
|
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId.id);
|
||||||
|
const folder = await this.folderService.encrypt(this.folder, userKey);
|
||||||
await this.folderApiService.save(folder);
|
await this.folderApiService.save(folder);
|
||||||
|
|
||||||
this.toastService.showToast({
|
this.toastService.showToast({
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { EventType } from "@bitwarden/common/enums";
|
|||||||
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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||||
@@ -30,20 +31,19 @@ import {
|
|||||||
import { PremiumUpgradePromptService } from "../../../../../../../../libs/common/src/vault/abstractions/premium-upgrade-prompt.service";
|
import { PremiumUpgradePromptService } from "../../../../../../../../libs/common/src/vault/abstractions/premium-upgrade-prompt.service";
|
||||||
import { CipherViewComponent } from "../../../../../../../../libs/vault/src/cipher-view";
|
import { CipherViewComponent } from "../../../../../../../../libs/vault/src/cipher-view";
|
||||||
import { PopOutComponent } from "../../../../../platform/popup/components/pop-out.component";
|
import { PopOutComponent } from "../../../../../platform/popup/components/pop-out.component";
|
||||||
import { PopupFooterComponent } from "../../../../../platform/popup/layout/popup-footer.component";
|
|
||||||
import { PopupHeaderComponent } from "../../../../../platform/popup/layout/popup-header.component";
|
|
||||||
import { PopupPageComponent } from "../../../../../platform/popup/layout/popup-page.component";
|
|
||||||
import { PopupRouterCacheService } from "../../../../../platform/popup/view-cache/popup-router-cache.service";
|
import { PopupRouterCacheService } from "../../../../../platform/popup/view-cache/popup-router-cache.service";
|
||||||
import { BrowserPremiumUpgradePromptService } from "../../../services/browser-premium-upgrade-prompt.service";
|
import { BrowserPremiumUpgradePromptService } from "../../../services/browser-premium-upgrade-prompt.service";
|
||||||
import { VaultPopupAutofillService } from "../../../services/vault-popup-autofill.service";
|
import { BrowserViewPasswordHistoryService } from "../../../services/browser-view-password-history.service";
|
||||||
|
|
||||||
|
import { PopupFooterComponent } from "./../../../../../platform/popup/layout/popup-footer.component";
|
||||||
|
import { PopupHeaderComponent } from "./../../../../../platform/popup/layout/popup-header.component";
|
||||||
|
import { PopupPageComponent } from "./../../../../../platform/popup/layout/popup-page.component";
|
||||||
|
import { VaultPopupAutofillService } from "./../../../services/vault-popup-autofill.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-view-v2",
|
selector: "app-view-v2",
|
||||||
templateUrl: "view-v2.component.html",
|
templateUrl: "view-v2.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
providers: [
|
|
||||||
{ provide: PremiumUpgradePromptService, useClass: BrowserPremiumUpgradePromptService },
|
|
||||||
],
|
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
@@ -58,6 +58,10 @@ import { VaultPopupAutofillService } from "../../../services/vault-popup-autofil
|
|||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
PopOutComponent,
|
PopOutComponent,
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ViewPasswordHistoryService, useClass: BrowserViewPasswordHistoryService },
|
||||||
|
{ provide: PremiumUpgradePromptService, useClass: BrowserPremiumUpgradePromptService },
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class ViewV2Component {
|
export class ViewV2Component {
|
||||||
headerText: string;
|
headerText: string;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
|
import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
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";
|
||||||
@@ -23,7 +24,6 @@ import { CollectionService } from "@bitwarden/common/vault/abstractions/collecti
|
|||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||||
import { normalizeExpiryYearFormat } from "@bitwarden/common/vault/utils";
|
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
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 { 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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -28,6 +29,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
|||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
@@ -44,6 +46,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
|||||||
cipherService,
|
cipherService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
apiService,
|
apiService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"
|
|||||||
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 { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -80,6 +81,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro
|
|||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
auditService: AuditService,
|
auditService: AuditService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -108,6 +110,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro
|
|||||||
tokenService,
|
tokenService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
auditService,
|
auditService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { TestBed } from "@angular/core/testing";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
|
import { BrowserViewPasswordHistoryService } from "./browser-view-password-history.service";
|
||||||
|
|
||||||
|
describe("BrowserViewPasswordHistoryService", () => {
|
||||||
|
let service: BrowserViewPasswordHistoryService;
|
||||||
|
let router: MockProxy<Router>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
router = mock<Router>();
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
providers: [BrowserViewPasswordHistoryService, { provide: Router, useValue: router }],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
service = TestBed.inject(BrowserViewPasswordHistoryService);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("viewPasswordHistory", () => {
|
||||||
|
it("navigates to the password history screen", async () => {
|
||||||
|
await service.viewPasswordHistory("test");
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(["/cipher-password-history"], {
|
||||||
|
queryParams: { cipherId: "test" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { inject } from "@angular/core";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
|
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class handles the premium upgrade process for the browser extension.
|
||||||
|
*/
|
||||||
|
export class BrowserViewPasswordHistoryService implements ViewPasswordHistoryService {
|
||||||
|
private router = inject(Router);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to the password history screen.
|
||||||
|
*/
|
||||||
|
async viewPasswordHistory(cipherId: string) {
|
||||||
|
await this.router.navigate(["/cipher-password-history"], { queryParams: { cipherId } });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<popup-page>
|
<popup-page [loading]="formLoading">
|
||||||
<popup-header slot="header" [pageTitle]="'appearance' | i18n" showBackButton>
|
<popup-header slot="header" [pageTitle]="'appearance' | i18n" showBackButton>
|
||||||
<ng-container slot="end">
|
<ng-container slot="end">
|
||||||
<app-pop-out></app-pop-out>
|
<app-pop-out></app-pop-out>
|
||||||
@@ -23,10 +23,15 @@
|
|||||||
<bit-label>{{ "showNumberOfAutofillSuggestions" | i18n }}</bit-label>
|
<bit-label>{{ "showNumberOfAutofillSuggestions" | i18n }}</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
|
|
||||||
<bit-form-control disableMargin>
|
<bit-form-control>
|
||||||
<input bitCheckbox formControlName="enableFavicon" type="checkbox" />
|
<input bitCheckbox formControlName="enableFavicon" type="checkbox" />
|
||||||
<bit-label>{{ "enableFavicon" | i18n }}</bit-label>
|
<bit-label>{{ "enableFavicon" | i18n }}</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
|
|
||||||
|
<bit-form-control disableMargin>
|
||||||
|
<input bitCheckbox formControlName="enableAnimations" type="checkbox" />
|
||||||
|
<bit-label>{{ "showAnimations" | i18n }}</bit-label>
|
||||||
|
</bit-form-control>
|
||||||
</bit-card>
|
</bit-card>
|
||||||
</form>
|
</form>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { BehaviorSubject } from "rxjs";
|
|||||||
|
|
||||||
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
|
import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
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 { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
@@ -41,14 +42,17 @@ describe("AppearanceV2Component", () => {
|
|||||||
const showFavicons$ = new BehaviorSubject<boolean>(true);
|
const showFavicons$ = new BehaviorSubject<boolean>(true);
|
||||||
const enableBadgeCounter$ = new BehaviorSubject<boolean>(true);
|
const enableBadgeCounter$ = new BehaviorSubject<boolean>(true);
|
||||||
const selectedTheme$ = new BehaviorSubject<ThemeType>(ThemeType.Nord);
|
const selectedTheme$ = new BehaviorSubject<ThemeType>(ThemeType.Nord);
|
||||||
|
const enableRoutingAnimation$ = new BehaviorSubject<boolean>(true);
|
||||||
const setSelectedTheme = jest.fn().mockResolvedValue(undefined);
|
const setSelectedTheme = jest.fn().mockResolvedValue(undefined);
|
||||||
const setShowFavicons = jest.fn().mockResolvedValue(undefined);
|
const setShowFavicons = jest.fn().mockResolvedValue(undefined);
|
||||||
const setEnableBadgeCounter = jest.fn().mockResolvedValue(undefined);
|
const setEnableBadgeCounter = jest.fn().mockResolvedValue(undefined);
|
||||||
|
const setEnableRoutingAnimation = jest.fn().mockResolvedValue(undefined);
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
setSelectedTheme.mockClear();
|
setSelectedTheme.mockClear();
|
||||||
setShowFavicons.mockClear();
|
setShowFavicons.mockClear();
|
||||||
setEnableBadgeCounter.mockClear();
|
setEnableBadgeCounter.mockClear();
|
||||||
|
setEnableRoutingAnimation.mockClear();
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [AppearanceV2Component],
|
imports: [AppearanceV2Component],
|
||||||
@@ -58,11 +62,15 @@ describe("AppearanceV2Component", () => {
|
|||||||
{ provide: MessagingService, useValue: mock<MessagingService>() },
|
{ provide: MessagingService, useValue: mock<MessagingService>() },
|
||||||
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
||||||
{ provide: DomainSettingsService, useValue: { showFavicons$, setShowFavicons } },
|
{ provide: DomainSettingsService, useValue: { showFavicons$, setShowFavicons } },
|
||||||
|
{ provide: ThemeStateService, useValue: { selectedTheme$, setSelectedTheme } },
|
||||||
|
{
|
||||||
|
provide: AnimationControlService,
|
||||||
|
useValue: { enableRoutingAnimation$, setEnableRoutingAnimation },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: BadgeSettingsServiceAbstraction,
|
provide: BadgeSettingsServiceAbstraction,
|
||||||
useValue: { enableBadgeCounter$, setEnableBadgeCounter },
|
useValue: { enableBadgeCounter$, setEnableBadgeCounter },
|
||||||
},
|
},
|
||||||
{ provide: ThemeStateService, useValue: { selectedTheme$, setSelectedTheme } },
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.overrideComponent(AppearanceV2Component, {
|
.overrideComponent(AppearanceV2Component, {
|
||||||
@@ -82,6 +90,7 @@ describe("AppearanceV2Component", () => {
|
|||||||
|
|
||||||
it("populates the form with the user's current settings", () => {
|
it("populates the form with the user's current settings", () => {
|
||||||
expect(component.appearanceForm.value).toEqual({
|
expect(component.appearanceForm.value).toEqual({
|
||||||
|
enableAnimations: true,
|
||||||
enableFavicon: true,
|
enableFavicon: true,
|
||||||
enableBadgeCounter: true,
|
enableBadgeCounter: true,
|
||||||
theme: ThemeType.Nord,
|
theme: ThemeType.Nord,
|
||||||
@@ -106,5 +115,11 @@ describe("AppearanceV2Component", () => {
|
|||||||
|
|
||||||
expect(setEnableBadgeCounter).toHaveBeenCalledWith(false);
|
expect(setEnableBadgeCounter).toHaveBeenCalledWith(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("updates the animation setting", () => {
|
||||||
|
component.appearanceForm.controls.enableAnimations.setValue(false);
|
||||||
|
|
||||||
|
expect(setEnableRoutingAnimation).toHaveBeenCalledWith(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
|
import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
@@ -41,8 +42,12 @@ export class AppearanceV2Component implements OnInit {
|
|||||||
enableFavicon: false,
|
enableFavicon: false,
|
||||||
enableBadgeCounter: true,
|
enableBadgeCounter: true,
|
||||||
theme: ThemeType.System,
|
theme: ThemeType.System,
|
||||||
|
enableAnimations: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** To avoid flashes of inaccurate values, only show the form after the entire form is populated. */
|
||||||
|
formLoading = true;
|
||||||
|
|
||||||
/** Available theme options */
|
/** Available theme options */
|
||||||
themeOptions: { name: string; value: ThemeType }[];
|
themeOptions: { name: string; value: ThemeType }[];
|
||||||
|
|
||||||
@@ -53,6 +58,7 @@ export class AppearanceV2Component implements OnInit {
|
|||||||
private themeStateService: ThemeStateService,
|
private themeStateService: ThemeStateService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private destroyRef: DestroyRef,
|
private destroyRef: DestroyRef,
|
||||||
|
private animationControlService: AnimationControlService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
) {
|
) {
|
||||||
this.themeOptions = [
|
this.themeOptions = [
|
||||||
@@ -66,14 +72,20 @@ export class AppearanceV2Component implements OnInit {
|
|||||||
const enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$);
|
const enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$);
|
||||||
const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
|
const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
|
||||||
const theme = await firstValueFrom(this.themeStateService.selectedTheme$);
|
const theme = await firstValueFrom(this.themeStateService.selectedTheme$);
|
||||||
|
const enableAnimations = await firstValueFrom(
|
||||||
|
this.animationControlService.enableRoutingAnimation$,
|
||||||
|
);
|
||||||
|
|
||||||
// Set initial values for the form
|
// Set initial values for the form
|
||||||
this.appearanceForm.setValue({
|
this.appearanceForm.setValue({
|
||||||
enableFavicon,
|
enableFavicon,
|
||||||
enableBadgeCounter,
|
enableBadgeCounter,
|
||||||
theme,
|
theme,
|
||||||
|
enableAnimations,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.formLoading = false;
|
||||||
|
|
||||||
this.appearanceForm.controls.theme.valueChanges
|
this.appearanceForm.controls.theme.valueChanges
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe((newTheme) => {
|
.subscribe((newTheme) => {
|
||||||
@@ -91,6 +103,12 @@ export class AppearanceV2Component implements OnInit {
|
|||||||
.subscribe((enableBadgeCounter) => {
|
.subscribe((enableBadgeCounter) => {
|
||||||
void this.updateBadgeCounter(enableBadgeCounter);
|
void this.updateBadgeCounter(enableBadgeCounter);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.appearanceForm.controls.enableAnimations.valueChanges
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe((enableBadgeCounter) => {
|
||||||
|
void this.updateAnimations(enableBadgeCounter);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateFavicon(enableFavicon: boolean) {
|
async updateFavicon(enableFavicon: boolean) {
|
||||||
@@ -105,4 +123,8 @@ export class AppearanceV2Component implements OnInit {
|
|||||||
async saveTheme(newTheme: ThemeType) {
|
async saveTheme(newTheme: ThemeType) {
|
||||||
await this.themeStateService.setSelectedTheme(newTheme);
|
await this.themeStateService.setSelectedTheme(newTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateAnimations(enableAnimations: boolean) {
|
||||||
|
await this.animationControlService.setEnableRoutingAnimation(enableAnimations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -20,6 +22,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent implement
|
|||||||
constructor(
|
constructor(
|
||||||
folderService: FolderService,
|
folderService: FolderService,
|
||||||
folderApiService: FolderApiServiceAbstraction,
|
folderApiService: FolderApiServiceAbstraction,
|
||||||
|
accountService: AccountService,
|
||||||
|
cryptoService: CryptoService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -31,6 +35,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent implement
|
|||||||
super(
|
super(
|
||||||
folderService,
|
folderService,
|
||||||
folderApiService,
|
folderApiService,
|
||||||
|
accountService,
|
||||||
|
cryptoService,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
logService,
|
logService,
|
||||||
|
|||||||
@@ -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.9.0",
|
"version": "2024.9.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as fet from "node-fetch";
|
import * as fet from "node-fetch";
|
||||||
|
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ import { FileResponse } from "../models/response/file.response";
|
|||||||
import { CliUtils } from "../utils";
|
import { CliUtils } from "../utils";
|
||||||
|
|
||||||
export abstract class DownloadCommand {
|
export abstract class DownloadCommand {
|
||||||
constructor(protected cryptoService: CryptoService) {}
|
constructor(protected encryptService: EncryptService) {}
|
||||||
|
|
||||||
protected async saveAttachmentToFile(
|
protected async saveAttachmentToFile(
|
||||||
url: string,
|
url: string,
|
||||||
@@ -26,7 +26,7 @@ export abstract class DownloadCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const encBuf = await EncArrayBuffer.fromResponse(response);
|
const encBuf = await EncArrayBuffer.fromResponse(response);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
|
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
|
||||||
if (process.env.BW_SERVE === "true") {
|
if (process.env.BW_SERVE === "true") {
|
||||||
const res = new FileResponse(Buffer.from(decBuf), fileName);
|
const res = new FileResponse(Buffer.from(decBuf), fileName);
|
||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
|||||||
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
||||||
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
|
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
|
||||||
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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||||
@@ -25,6 +26,7 @@ export class EditCommand {
|
|||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private folderApiService: FolderApiServiceAbstraction,
|
private folderApiService: FolderApiServiceAbstraction,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
@@ -139,7 +141,10 @@ export class EditCommand {
|
|||||||
|
|
||||||
let folderView = await folder.decrypt();
|
let folderView = await folder.decrypt();
|
||||||
folderView = FolderExport.toView(req, folderView);
|
folderView = FolderExport.toView(req, folderView);
|
||||||
const encFolder = await this.folderService.encrypt(folderView);
|
|
||||||
|
const activeUserId = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
|
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId.id);
|
||||||
|
const encFolder = await this.folderService.encrypt(folderView, userKey);
|
||||||
try {
|
try {
|
||||||
await this.folderApiService.save(encFolder);
|
await this.folderApiService.save(encFolder);
|
||||||
const updatedFolder = await this.folderService.get(folder.id);
|
const updatedFolder = await this.folderService.get(folder.id);
|
||||||
@@ -187,7 +192,7 @@ export class EditCommand {
|
|||||||
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
|
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
|
||||||
);
|
);
|
||||||
const request = new CollectionRequest();
|
const request = new CollectionRequest();
|
||||||
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
request.name = (await this.encryptService.encrypt(req.name, orgKey)).encryptedString;
|
||||||
request.externalId = req.externalId;
|
request.externalId = req.externalId;
|
||||||
request.groups = groups;
|
request.groups = groups;
|
||||||
request.users = users;
|
request.users = users;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { LoginExport } from "@bitwarden/common/models/export/login.export";
|
|||||||
import { SecureNoteExport } from "@bitwarden/common/models/export/secure-note.export";
|
import { SecureNoteExport } from "@bitwarden/common/models/export/secure-note.export";
|
||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
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 { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.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";
|
||||||
@@ -56,7 +57,8 @@ export class GetCommand extends DownloadCommand {
|
|||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
private totpService: TotpService,
|
private totpService: TotpService,
|
||||||
private auditService: AuditService,
|
private auditService: AuditService,
|
||||||
cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
@@ -65,7 +67,7 @@ export class GetCommand extends DownloadCommand {
|
|||||||
private accountProfileService: BillingAccountProfileStateService,
|
private accountProfileService: BillingAccountProfileStateService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
) {
|
) {
|
||||||
super(cryptoService);
|
super(encryptService);
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||||
@@ -451,7 +453,7 @@ export class GetCommand extends DownloadCommand {
|
|||||||
|
|
||||||
const response = await this.apiService.getCollectionAccessDetails(options.organizationId, id);
|
const response = await this.apiService.getCollectionAccessDetails(options.organizationId, id);
|
||||||
const decCollection = new CollectionView(response);
|
const decCollection = new CollectionView(response);
|
||||||
decCollection.name = await this.cryptoService.decryptToUtf8(
|
decCollection.name = await this.encryptService.decryptToUtf8(
|
||||||
new EncString(response.name),
|
new EncString(response.name),
|
||||||
orgKey,
|
orgKey,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export class OssServeConfigurator {
|
|||||||
this.serviceContainer.totpService,
|
this.serviceContainer.totpService,
|
||||||
this.serviceContainer.auditService,
|
this.serviceContainer.auditService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.stateService,
|
this.serviceContainer.stateService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
@@ -79,6 +80,7 @@ export class OssServeConfigurator {
|
|||||||
this.serviceContainer.cipherService,
|
this.serviceContainer.cipherService,
|
||||||
this.serviceContainer.folderService,
|
this.serviceContainer.folderService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
this.serviceContainer.folderApiService,
|
this.serviceContainer.folderApiService,
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
@@ -89,6 +91,7 @@ export class OssServeConfigurator {
|
|||||||
this.serviceContainer.cipherService,
|
this.serviceContainer.cipherService,
|
||||||
this.serviceContainer.folderService,
|
this.serviceContainer.folderService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
this.serviceContainer.folderApiService,
|
this.serviceContainer.folderApiService,
|
||||||
this.serviceContainer.accountService,
|
this.serviceContainer.accountService,
|
||||||
@@ -150,7 +153,7 @@ export class OssServeConfigurator {
|
|||||||
this.serviceContainer.sendService,
|
this.serviceContainer.sendService,
|
||||||
this.serviceContainer.environmentService,
|
this.serviceContainer.environmentService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.encryptService,
|
||||||
);
|
);
|
||||||
this.sendEditCommand = new SendEditCommand(
|
this.sendEditCommand = new SendEditCommand(
|
||||||
this.serviceContainer.sendService,
|
this.serviceContainer.sendService,
|
||||||
|
|||||||
@@ -494,6 +494,7 @@ export class ServiceContainer {
|
|||||||
|
|
||||||
this.collectionService = new CollectionService(
|
this.collectionService = new CollectionService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
@@ -631,10 +632,12 @@ export class ServiceContainer {
|
|||||||
this.cipherFileUploadService,
|
this.cipherFileUploadService,
|
||||||
this.configService,
|
this.configService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
|
this.accountService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.folderService = new FolderService(
|
this.folderService = new FolderService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
@@ -721,6 +724,7 @@ export class ServiceContainer {
|
|||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.accountService,
|
this.accountService,
|
||||||
);
|
);
|
||||||
@@ -730,8 +734,10 @@ export class ServiceContainer {
|
|||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.kdfConfigService,
|
this.kdfConfigService,
|
||||||
|
this.accountService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.organizationExportService = new OrganizationVaultExportService(
|
this.organizationExportService = new OrganizationVaultExportService(
|
||||||
@@ -739,6 +745,7 @@ export class ServiceContainer {
|
|||||||
this.apiService,
|
this.apiService,
|
||||||
this.pinService,
|
this.pinService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
this.kdfConfigService,
|
this.kdfConfigService,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { OptionValues } from "commander";
|
|||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||||
@@ -17,9 +17,9 @@ export class SendGetCommand extends DownloadCommand {
|
|||||||
private sendService: SendService,
|
private sendService: SendService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
cryptoService: CryptoService,
|
encryptService: EncryptService,
|
||||||
) {
|
) {
|
||||||
super(cryptoService);
|
super(encryptService);
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(id: string, options: OptionValues) {
|
async run(id: string, options: OptionValues) {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { OptionValues } from "commander";
|
|||||||
import * as inquirer from "inquirer";
|
import * as inquirer from "inquirer";
|
||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
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 { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
@@ -27,14 +27,14 @@ export class SendReceiveCommand extends DownloadCommand {
|
|||||||
private sendAccessRequest: SendAccessRequest;
|
private sendAccessRequest: SendAccessRequest;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private cryptoService: CryptoService,
|
||||||
cryptoService: CryptoService,
|
encryptService: EncryptService,
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
private sendApiService: SendApiService,
|
private sendApiService: SendApiService,
|
||||||
) {
|
) {
|
||||||
super(cryptoService);
|
super(encryptService);
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(url: string, options: OptionValues): Promise<Response> {
|
async run(url: string, options: OptionValues): Promise<Response> {
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ export class SendProgram extends BaseProgram {
|
|||||||
})
|
})
|
||||||
.action(async (url: string, options: OptionValues) => {
|
.action(async (url: string, options: OptionValues) => {
|
||||||
const cmd = new SendReceiveCommand(
|
const cmd = new SendReceiveCommand(
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.cryptoFunctionService,
|
this.serviceContainer.cryptoFunctionService,
|
||||||
this.serviceContainer.platformUtilsService,
|
this.serviceContainer.platformUtilsService,
|
||||||
this.serviceContainer.environmentService,
|
this.serviceContainer.environmentService,
|
||||||
@@ -143,6 +143,7 @@ export class SendProgram extends BaseProgram {
|
|||||||
this.serviceContainer.totpService,
|
this.serviceContainer.totpService,
|
||||||
this.serviceContainer.auditService,
|
this.serviceContainer.auditService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.stateService,
|
this.serviceContainer.stateService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
@@ -187,7 +188,7 @@ export class SendProgram extends BaseProgram {
|
|||||||
this.serviceContainer.sendService,
|
this.serviceContainer.sendService,
|
||||||
this.serviceContainer.environmentService,
|
this.serviceContainer.environmentService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.encryptService,
|
||||||
);
|
);
|
||||||
const response = await cmd.run(id, options);
|
const response = await cmd.run(id, options);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
@@ -246,7 +247,7 @@ export class SendProgram extends BaseProgram {
|
|||||||
this.serviceContainer.sendService,
|
this.serviceContainer.sendService,
|
||||||
this.serviceContainer.environmentService,
|
this.serviceContainer.environmentService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.encryptService,
|
||||||
);
|
);
|
||||||
const cmd = new SendEditCommand(
|
const cmd = new SendEditCommand(
|
||||||
this.serviceContainer.sendService,
|
this.serviceContainer.sendService,
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ export class VaultProgram extends BaseProgram {
|
|||||||
this.serviceContainer.totpService,
|
this.serviceContainer.totpService,
|
||||||
this.serviceContainer.auditService,
|
this.serviceContainer.auditService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.stateService,
|
this.serviceContainer.stateService,
|
||||||
this.serviceContainer.searchService,
|
this.serviceContainer.searchService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
@@ -224,6 +225,7 @@ export class VaultProgram extends BaseProgram {
|
|||||||
this.serviceContainer.cipherService,
|
this.serviceContainer.cipherService,
|
||||||
this.serviceContainer.folderService,
|
this.serviceContainer.folderService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
this.serviceContainer.folderApiService,
|
this.serviceContainer.folderApiService,
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
@@ -272,6 +274,7 @@ export class VaultProgram extends BaseProgram {
|
|||||||
this.serviceContainer.cipherService,
|
this.serviceContainer.cipherService,
|
||||||
this.serviceContainer.folderService,
|
this.serviceContainer.folderService,
|
||||||
this.serviceContainer.cryptoService,
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.encryptService,
|
||||||
this.serviceContainer.apiService,
|
this.serviceContainer.apiService,
|
||||||
this.serviceContainer.folderApiService,
|
this.serviceContainer.folderApiService,
|
||||||
this.serviceContainer.accountService,
|
this.serviceContainer.accountService,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
|||||||
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
||||||
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
|
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
|
||||||
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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||||
@@ -31,6 +32,7 @@ export class CreateCommand {
|
|||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private folderApiService: FolderApiServiceAbstraction,
|
private folderApiService: FolderApiServiceAbstraction,
|
||||||
private accountProfileService: BillingAccountProfileStateService,
|
private accountProfileService: BillingAccountProfileStateService,
|
||||||
@@ -167,7 +169,9 @@ export class CreateCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async createFolder(req: FolderExport) {
|
private async createFolder(req: FolderExport) {
|
||||||
const folder = await this.folderService.encrypt(FolderExport.toView(req));
|
const activeAccountId = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
|
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeAccountId.id);
|
||||||
|
const folder = await this.folderService.encrypt(FolderExport.toView(req), userKey);
|
||||||
try {
|
try {
|
||||||
await this.folderApiService.save(folder);
|
await this.folderApiService.save(folder);
|
||||||
const newFolder = await this.folderService.get(folder.id);
|
const newFolder = await this.folderService.get(folder.id);
|
||||||
@@ -210,7 +214,7 @@ export class CreateCommand {
|
|||||||
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
|
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
|
||||||
);
|
);
|
||||||
const request = new CollectionRequest();
|
const request = new CollectionRequest();
|
||||||
request.name = (await this.cryptoService.encrypt(req.name, orgKey)).encryptedString;
|
request.name = (await this.encryptService.encrypt(req.name, orgKey)).encryptedString;
|
||||||
request.externalId = req.externalId;
|
request.externalId = req.externalId;
|
||||||
request.groups = groups;
|
request.groups = groups;
|
||||||
request.users = users;
|
request.users = users;
|
||||||
|
|||||||
@@ -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.9.1",
|
"version": "2024.9.2",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: NativeMessageHandlerService,
|
provide: NativeMessageHandlerService,
|
||||||
deps: [
|
deps: [
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
EncryptService,
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
MessagingServiceAbstraction,
|
MessagingServiceAbstraction,
|
||||||
EncryptedMessageHandlerService,
|
EncryptedMessageHandlerService,
|
||||||
|
|||||||
4
apps/desktop/src/package-lock.json
generated
4
apps/desktop/src/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "2024.9.1",
|
"version": "2024.9.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "2024.9.1",
|
"version": "2024.9.2",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bitwarden/desktop-napi": "file:../desktop_native/napi",
|
"@bitwarden/desktop-napi": "file:../desktop_native/napi",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"productName": "Bitwarden",
|
"productName": "Bitwarden",
|
||||||
"description": "A secure and free password manager for all of your devices.",
|
"description": "A secure and free password manager for all of your devices.",
|
||||||
"version": "2024.9.1",
|
"version": "2024.9.2",
|
||||||
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||||
"homepage": "https://bitwarden.com",
|
"homepage": "https://bitwarden.com",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { NativeMessagingVersion } from "@bitwarden/common/enums";
|
import { NativeMessagingVersion } from "@bitwarden/common/enums";
|
||||||
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 { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
@@ -31,7 +31,7 @@ export class NativeMessageHandlerService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private cryptoService: CryptoService,
|
private encryptService: EncryptService,
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private encryptedMessageHandlerService: EncryptedMessageHandlerService,
|
private encryptedMessageHandlerService: EncryptedMessageHandlerService,
|
||||||
@@ -162,7 +162,7 @@ export class NativeMessageHandlerService {
|
|||||||
payload: DecryptedCommandData,
|
payload: DecryptedCommandData,
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
): Promise<EncString> {
|
): Promise<EncString> {
|
||||||
return await this.cryptoService.encrypt(JSON.stringify(payload), key);
|
return await this.encryptService.encrypt(JSON.stringify(payload), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async decryptPayload(message: EncryptedMessage): Promise<DecryptedCommandData> {
|
private async decryptPayload(message: EncryptedMessage): Promise<DecryptedCommandData> {
|
||||||
@@ -182,7 +182,7 @@ export class NativeMessageHandlerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let decryptedResult = await this.cryptoService.decryptToUtf8(
|
let decryptedResult = await this.encryptService.decryptToUtf8(
|
||||||
message.encryptedCommand as EncString,
|
message.encryptedCommand as EncString,
|
||||||
this.ddgSharedSecret,
|
this.ddgSharedSecret,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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 { 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 { 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";
|
||||||
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
||||||
@@ -33,6 +34,7 @@ export class NativeMessagingService {
|
|||||||
constructor(
|
constructor(
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private desktopSettingService: DesktopSettingsService,
|
private desktopSettingService: DesktopSettingsService,
|
||||||
@@ -111,7 +113,7 @@ export class NativeMessagingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const message: LegacyMessage = JSON.parse(
|
const message: LegacyMessage = JSON.parse(
|
||||||
await this.cryptoService.decryptToUtf8(
|
await this.encryptService.decryptToUtf8(
|
||||||
rawMessage as EncString,
|
rawMessage as EncString,
|
||||||
SymmetricCryptoKey.fromString(await ipc.platform.ephemeralStore.getEphemeralValue(appId)),
|
SymmetricCryptoKey.fromString(await ipc.platform.ephemeralStore.getEphemeralValue(appId)),
|
||||||
),
|
),
|
||||||
@@ -224,7 +226,7 @@ export class NativeMessagingService {
|
|||||||
private async send(message: any, appId: string) {
|
private async send(message: any, appId: string) {
|
||||||
message.timestamp = Date.now();
|
message.timestamp = Date.now();
|
||||||
|
|
||||||
const encrypted = await this.cryptoService.encrypt(
|
const encrypted = await this.encryptService.encrypt(
|
||||||
JSON.stringify(message),
|
JSON.stringify(message),
|
||||||
SymmetricCryptoKey.fromString(await ipc.platform.ephemeralStore.getEphemeralValue(appId)),
|
SymmetricCryptoKey.fromString(await ipc.platform.ephemeralStore.getEphemeralValue(appId)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
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 { 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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -22,6 +23,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
|||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
@@ -36,6 +38,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
|||||||
cipherService,
|
cipherService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
apiService,
|
apiService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Component } from "@angular/core";
|
|||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -17,6 +19,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
folderService: FolderService,
|
folderService: FolderService,
|
||||||
folderApiService: FolderApiServiceAbstraction,
|
folderApiService: FolderApiServiceAbstraction,
|
||||||
|
accountService: AccountService,
|
||||||
|
cryptoService: CryptoService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
@@ -26,6 +30,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
|||||||
super(
|
super(
|
||||||
folderService,
|
folderService,
|
||||||
folderApiService,
|
folderApiService,
|
||||||
|
accountService,
|
||||||
|
cryptoService,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
logService,
|
logService,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"
|
|||||||
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 { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -48,6 +49,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro
|
|||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
auditService: AuditService,
|
auditService: AuditService,
|
||||||
broadcasterService: BroadcasterService,
|
broadcasterService: BroadcasterService,
|
||||||
@@ -72,6 +74,7 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro
|
|||||||
tokenService,
|
tokenService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
auditService,
|
auditService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/web-vault",
|
"name": "@bitwarden/web-vault",
|
||||||
"version": "2024.9.1",
|
"version": "2024.9.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:oss": "webpack",
|
"build:oss": "webpack",
|
||||||
"build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",
|
"build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
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 { 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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -26,6 +27,7 @@ export class EmergencyAccessAttachmentsComponent extends BaseAttachmentsComponen
|
|||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -40,6 +42,7 @@ export class EmergencyAccessAttachmentsComponent extends BaseAttachmentsComponen
|
|||||||
cipherService,
|
cipherService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
apiService,
|
apiService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { DisableTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/mod
|
|||||||
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request";
|
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request";
|
||||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
|
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
|
||||||
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
|
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
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";
|
||||||
@@ -127,13 +126,6 @@ export class TwoFactorAuthenticatorComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override async disableMethod() {
|
protected override async disableMethod() {
|
||||||
const twoFactorAuthenticatorTokenFeatureFlag = await this.configService.getFeatureFlag(
|
|
||||||
FeatureFlag.AuthenticatorTwoFactorToken,
|
|
||||||
);
|
|
||||||
if (twoFactorAuthenticatorTokenFeatureFlag === false) {
|
|
||||||
return super.disableMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmed = await this.dialogService.openSimpleDialog({
|
const confirmed = await this.dialogService.openSimpleDialog({
|
||||||
title: { key: "disable" },
|
title: { key: "disable" },
|
||||||
content: { key: "twoStepDisableDesc" },
|
content: { key: "twoStepDisableDesc" },
|
||||||
|
|||||||
@@ -332,20 +332,16 @@
|
|||||||
<!-- Payment info -->
|
<!-- Payment info -->
|
||||||
<ng-container *ngIf="formGroup.value.productTier !== productTypes.Free">
|
<ng-container *ngIf="formGroup.value.productTier !== productTypes.Free">
|
||||||
<h2 bitTypography="h4">{{ "paymentMethod" | i18n }}</h2>
|
<h2 bitTypography="h4">{{ "paymentMethod" | i18n }}</h2>
|
||||||
<p *ngIf="!showPayment && !deprecateStripeSourcesAPI">
|
<p *ngIf="!showPayment && (paymentSource || billing?.paymentSource)">
|
||||||
<i class="bwi bwi-fw" [ngClass]="paymentSourceClasses"></i>
|
<i class="bwi bwi-fw" [ngClass]="paymentSourceClasses"></i>
|
||||||
{{ billing?.paymentSource?.description }}
|
{{
|
||||||
<span class="ml-2 tw-text-primary-600 tw-cursor-pointer" (click)="toggleShowPayment()">{{
|
deprecateStripeSourcesAPI
|
||||||
"changePaymentMethod" | i18n
|
? paymentSource?.description
|
||||||
}}</span>
|
: billing?.paymentSource?.description
|
||||||
<a></a>
|
}}
|
||||||
</p>
|
<span class="ml-2 tw-text-primary-600 tw-cursor-pointer" (click)="toggleShowPayment()">
|
||||||
<p *ngIf="!showPayment && deprecateStripeSourcesAPI">
|
{{ "changePaymentMethod" | i18n }}
|
||||||
<i class="bwi bwi-fw" [ngClass]="paymentSourceClasses"></i>
|
</span>
|
||||||
{{ paymentSource?.description }}
|
|
||||||
<span class="ml-2 tw-text-primary-600 tw-cursor-pointer" (click)="toggleShowPayment()">{{
|
|
||||||
"changePaymentMethod" | i18n
|
|
||||||
}}</span>
|
|
||||||
<a></a>
|
<a></a>
|
||||||
</p>
|
</p>
|
||||||
<app-payment
|
<app-payment
|
||||||
|
|||||||
@@ -403,11 +403,13 @@ export class ChangePlanDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get upgradeRequiresPaymentMethod() {
|
get upgradeRequiresPaymentMethod() {
|
||||||
return (
|
const isFreeTier = this.organization?.productTierType === ProductTierType.Free;
|
||||||
this.organization?.productTierType === ProductTierType.Free &&
|
const shouldHideFree = !this.showFree;
|
||||||
!this.showFree &&
|
const hasNoPaymentSource = this.deprecateStripeSourcesAPI
|
||||||
!this.billing?.paymentSource
|
? !this.paymentSource
|
||||||
);
|
: !this.billing?.paymentSource;
|
||||||
|
|
||||||
|
return isFreeTier && shouldHideFree && hasNoPaymentSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedSecretsManagerPlan() {
|
get selectedSecretsManagerPlan() {
|
||||||
|
|||||||
@@ -23,16 +23,19 @@ import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/
|
|||||||
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
||||||
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
|
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
|
||||||
import { ProviderResponse } from "@bitwarden/common/admin-console/models/response/provider/provider.response";
|
import { ProviderResponse } from "@bitwarden/common/admin-console/models/response/provider/provider.response";
|
||||||
|
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||||
import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||||
|
import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request";
|
||||||
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
|
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
|
||||||
|
import { UpdatePaymentMethodRequest } from "@bitwarden/common/billing/models/request/update-payment-method.request";
|
||||||
import { BillingResponse } from "@bitwarden/common/billing/models/response/billing.response";
|
import { BillingResponse } from "@bitwarden/common/billing/models/response/billing.response";
|
||||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
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 { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.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 { 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
@@ -147,19 +150,20 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
|||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private logService: LogService,
|
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
private providerApiService: ProviderApiServiceAbstraction,
|
private providerApiService: ProviderApiServiceAbstraction,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
|
private billingApiService: BillingApiServiceAbstraction,
|
||||||
) {
|
) {
|
||||||
this.selfHosted = platformUtilsService.isSelfHost();
|
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -590,7 +594,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
|||||||
if (this.createOrganization) {
|
if (this.createOrganization) {
|
||||||
const orgKey = await this.cryptoService.makeOrgKey<OrgKey>();
|
const orgKey = await this.cryptoService.makeOrgKey<OrgKey>();
|
||||||
const key = orgKey[0].encryptedString;
|
const key = orgKey[0].encryptedString;
|
||||||
const collection = await this.cryptoService.encrypt(
|
const collection = await this.encryptService.encrypt(
|
||||||
this.i18nService.t("defaultCollection"),
|
this.i18nService.t("defaultCollection"),
|
||||||
orgKey[1],
|
orgKey[1],
|
||||||
);
|
);
|
||||||
@@ -658,22 +662,27 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
|||||||
this.buildSecretsManagerRequest(request);
|
this.buildSecretsManagerRequest(request);
|
||||||
|
|
||||||
if (this.upgradeRequiresPaymentMethod) {
|
if (this.upgradeRequiresPaymentMethod) {
|
||||||
let type: PaymentMethodType;
|
|
||||||
let token: string;
|
|
||||||
|
|
||||||
if (this.deprecateStripeSourcesAPI) {
|
if (this.deprecateStripeSourcesAPI) {
|
||||||
({ type, token } = await this.paymentV2Component.tokenize());
|
const updatePaymentMethodRequest = new UpdatePaymentMethodRequest();
|
||||||
|
updatePaymentMethodRequest.paymentSource = await this.paymentV2Component.tokenize();
|
||||||
|
const expandedTaxInfoUpdateRequest = new ExpandedTaxInfoUpdateRequest();
|
||||||
|
expandedTaxInfoUpdateRequest.country = this.taxComponent.country;
|
||||||
|
expandedTaxInfoUpdateRequest.postalCode = this.taxComponent.postalCode;
|
||||||
|
updatePaymentMethodRequest.taxInformation = expandedTaxInfoUpdateRequest;
|
||||||
|
await this.billingApiService.updateOrganizationPaymentMethod(
|
||||||
|
this.organizationId,
|
||||||
|
updatePaymentMethodRequest,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
[token, type] = await this.paymentComponent.createPaymentToken();
|
const [paymentToken, paymentMethodType] = await this.paymentComponent.createPaymentToken();
|
||||||
}
|
|
||||||
|
|
||||||
const paymentRequest = new PaymentRequest();
|
const paymentRequest = new PaymentRequest();
|
||||||
paymentRequest.paymentToken = token;
|
paymentRequest.paymentToken = paymentToken;
|
||||||
paymentRequest.paymentMethodType = type;
|
paymentRequest.paymentMethodType = paymentMethodType;
|
||||||
paymentRequest.country = this.taxComponent.taxFormGroup?.value.country;
|
paymentRequest.country = this.taxComponent.taxFormGroup?.value.country;
|
||||||
paymentRequest.postalCode = this.taxComponent.taxFormGroup?.value.postalCode;
|
paymentRequest.postalCode = this.taxComponent.taxFormGroup?.value.postalCode;
|
||||||
await this.organizationApiService.updatePayment(this.organizationId, paymentRequest);
|
await this.organizationApiService.updatePayment(this.organizationId, paymentRequest);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Backfill pub/priv key if necessary
|
// Backfill pub/priv key if necessary
|
||||||
if (!this.organization.hasPublicAndPrivateKeys) {
|
if (!this.organization.hasPublicAndPrivateKeys) {
|
||||||
@@ -744,7 +753,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
const providerKey = await this.cryptoService.getProviderKey(this.providerId);
|
const providerKey = await this.cryptoService.getProviderKey(this.providerId);
|
||||||
providerRequest.organizationCreateRequest.key = (
|
providerRequest.organizationCreateRequest.key = (
|
||||||
await this.cryptoService.encrypt(orgKey.key, providerKey)
|
await this.encryptService.encrypt(orgKey.key, providerKey)
|
||||||
).encryptedString;
|
).encryptedString;
|
||||||
const orgId = (
|
const orgId = (
|
||||||
await this.apiService.postProviderCreateOrganization(this.providerId, providerRequest)
|
await this.apiService.postProviderCreateOrganization(this.providerId, providerRequest)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
import { Component, Input } from "@angular/core";
|
||||||
|
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
@@ -26,7 +26,7 @@ export class SendAccessFileComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private cryptoService: CryptoService,
|
private encryptService: EncryptService,
|
||||||
private fileDownloadService: FileDownloadService,
|
private fileDownloadService: FileDownloadService,
|
||||||
private sendApiService: SendApiService,
|
private sendApiService: SendApiService,
|
||||||
) {}
|
) {}
|
||||||
@@ -62,7 +62,7 @@ export class SendAccessFileComponent {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const encBuf = await EncArrayBuffer.fromResponse(response);
|
const encBuf = await EncArrayBuffer.fromResponse(response);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, this.decKey);
|
const decBuf = await this.encryptService.decryptToBytes(encBuf, this.decKey);
|
||||||
this.fileDownloadService.download({
|
this.fileDownloadService.download({
|
||||||
fileName: this.send.file.fileName,
|
fileName: this.send.file.fileName,
|
||||||
blobData: decBuf,
|
blobData: decBuf,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Injectable } from "@angular/core";
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
||||||
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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||||
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
||||||
@@ -23,6 +24,7 @@ export class CollectionAdminService {
|
|||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -116,7 +118,7 @@ export class CollectionAdminService {
|
|||||||
const promises = collections.map(async (c) => {
|
const promises = collections.map(async (c) => {
|
||||||
const view = new CollectionAdminView();
|
const view = new CollectionAdminView();
|
||||||
view.id = c.id;
|
view.id = c.id;
|
||||||
view.name = await this.cryptoService.decryptToUtf8(new EncString(c.name), orgKey);
|
view.name = await this.encryptService.decryptToUtf8(new EncString(c.name), orgKey);
|
||||||
view.externalId = c.externalId;
|
view.externalId = c.externalId;
|
||||||
view.organizationId = c.organizationId;
|
view.organizationId = c.organizationId;
|
||||||
|
|
||||||
@@ -146,7 +148,7 @@ export class CollectionAdminService {
|
|||||||
}
|
}
|
||||||
const collection = new CollectionRequest();
|
const collection = new CollectionRequest();
|
||||||
collection.externalId = model.externalId;
|
collection.externalId = model.externalId;
|
||||||
collection.name = (await this.cryptoService.encrypt(model.name, key)).encryptedString;
|
collection.name = (await this.encryptService.encrypt(model.name, key)).encryptedString;
|
||||||
collection.groups = model.groups.map(
|
collection.groups = model.groups.map(
|
||||||
(group) =>
|
(group) =>
|
||||||
new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords, group.manage),
|
new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords, group.manage),
|
||||||
|
|||||||
@@ -8,6 +8,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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { isCardExpired } from "@bitwarden/common/autofill/utils";
|
||||||
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 { ProductTierType } from "@bitwarden/common/billing/enums";
|
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
@@ -24,7 +25,6 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde
|
|||||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { Launchable } from "@bitwarden/common/vault/interfaces/launchable";
|
import { Launchable } from "@bitwarden/common/vault/interfaces/launchable";
|
||||||
import { isCardExpired } from "@bitwarden/common/vault/utils";
|
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
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 { 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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -25,6 +26,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
|||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -39,6 +41,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
|||||||
cipherService,
|
cipherService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
apiService,
|
apiService,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||||
import { Component, Inject } from "@angular/core";
|
import { Component, Inject } from "@angular/core";
|
||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -19,6 +22,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
folderService: FolderService,
|
folderService: FolderService,
|
||||||
folderApiService: FolderApiServiceAbstraction,
|
folderApiService: FolderApiServiceAbstraction,
|
||||||
|
protected accountSerivce: AccountService,
|
||||||
|
protected cryptoService: CryptoService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
@@ -31,6 +36,8 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
|||||||
super(
|
super(
|
||||||
folderService,
|
folderService,
|
||||||
folderApiService,
|
folderApiService,
|
||||||
|
accountSerivce,
|
||||||
|
cryptoService,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
logService,
|
logService,
|
||||||
@@ -73,7 +80,9 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const folder = await this.folderService.encrypt(this.folder);
|
const activeAccountId = (await firstValueFrom(this.accountSerivce.activeAccount$)).id;
|
||||||
|
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeAccountId);
|
||||||
|
const folder = await this.folderService.encrypt(this.folder, userKey);
|
||||||
this.formPromise = this.folderApiService.save(folder);
|
this.formPromise = this.folderApiService.save(folder);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<bit-dialog dialogSize="small" background="alt">
|
||||||
|
<span bitDialogTitle>
|
||||||
|
{{ "passwordHistory" | i18n }}
|
||||||
|
</span>
|
||||||
|
<ng-container bitDialogContent>
|
||||||
|
<div *ngIf="history && history.length">
|
||||||
|
<bit-item *ngFor="let h of history">
|
||||||
|
<div class="tw-pl-3 tw-py-2">
|
||||||
|
<bit-color-password
|
||||||
|
class="tw-text-base"
|
||||||
|
[password]="h.password"
|
||||||
|
[showCount]="false"
|
||||||
|
></bit-color-password>
|
||||||
|
<div class="tw-text-sm tw-text-muted">{{ h.lastUsedDate | date: "medium" }}</div>
|
||||||
|
</div>
|
||||||
|
<ng-container slot="end">
|
||||||
|
<bit-item-action>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
aria-label="Copy"
|
||||||
|
appStopClick
|
||||||
|
(click)="copy(h.password)"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</bit-item-action>
|
||||||
|
</ng-container>
|
||||||
|
</bit-item>
|
||||||
|
</div>
|
||||||
|
<div class="no-items" *ngIf="!history || !history.length">
|
||||||
|
<p>{{ "noPasswordsInList" | i18n }}</p>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container bitDialogFooter>
|
||||||
|
<button bitButton (click)="close()" buttonType="primary" type="button">
|
||||||
|
{{ "close" | i18n }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
</bit-dialog>
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { OnInit, Inject, Component } from "@angular/core";
|
||||||
|
import { firstValueFrom, map } from "rxjs";
|
||||||
|
|
||||||
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { CipherId, UserId } from "@bitwarden/common/types/guid";
|
||||||
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { PasswordHistoryView } from "@bitwarden/common/vault/models/view/password-history.view";
|
||||||
|
import {
|
||||||
|
AsyncActionsModule,
|
||||||
|
DialogModule,
|
||||||
|
DialogService,
|
||||||
|
ToastService,
|
||||||
|
ItemModule,
|
||||||
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { SharedModule } from "../../shared/shared.module";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters for the password history dialog.
|
||||||
|
*/
|
||||||
|
export interface ViewPasswordHistoryDialogParams {
|
||||||
|
cipherId: CipherId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialog component that displays the password history for a cipher.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: "app-vault-password-history",
|
||||||
|
templateUrl: "password-history.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, AsyncActionsModule, DialogModule, ItemModule, SharedModule],
|
||||||
|
})
|
||||||
|
export class PasswordHistoryComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* The ID of the cipher to display the password history for.
|
||||||
|
*/
|
||||||
|
cipherId: CipherId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The password history for the cipher.
|
||||||
|
*/
|
||||||
|
history: PasswordHistoryView[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor for the password history dialog component.
|
||||||
|
* @param params The parameters passed to the password history dialog.
|
||||||
|
* @param cipherService The cipher service - used to get the cipher to display the password history for.
|
||||||
|
* @param platformUtilsService The platform utils service - used to copy passwords to the clipboard.
|
||||||
|
* @param i18nService The i18n service - used to translate strings.
|
||||||
|
* @param accountService The account service - used to get the active account to decrypt the cipher.
|
||||||
|
* @param win The window object - used to copy passwords to the clipboard.
|
||||||
|
* @param toastService The toast service - used to display feedback to the user when a password is copied.
|
||||||
|
* @param dialogRef The dialog reference - used to close the dialog.
|
||||||
|
**/
|
||||||
|
constructor(
|
||||||
|
@Inject(DIALOG_DATA) public params: ViewPasswordHistoryDialogParams,
|
||||||
|
protected cipherService: CipherService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected accountService: AccountService,
|
||||||
|
@Inject(WINDOW) private win: Window,
|
||||||
|
protected toastService: ToastService,
|
||||||
|
private dialogRef: DialogRef<PasswordHistoryComponent>,
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Set the cipher ID from the parameters.
|
||||||
|
*/
|
||||||
|
this.cipherId = params.cipherId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
await this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a password to the clipboard.
|
||||||
|
* @param password The password to copy.
|
||||||
|
*/
|
||||||
|
copy(password: string) {
|
||||||
|
const copyOptions = this.win != null ? { window: this.win } : undefined;
|
||||||
|
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "info",
|
||||||
|
title: "",
|
||||||
|
message: this.i18nService.t("valueCopied", this.i18nService.t("password")),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the password history dialog component.
|
||||||
|
*/
|
||||||
|
protected async init() {
|
||||||
|
const cipher = await this.cipherService.get(this.cipherId);
|
||||||
|
const activeAccount = await firstValueFrom(
|
||||||
|
this.accountService.activeAccount$.pipe(map((a: { id: string | undefined }) => a)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!activeAccount || !activeAccount.id) {
|
||||||
|
throw new Error("Active account is not available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeUserId = activeAccount.id as UserId;
|
||||||
|
const decCipher = await cipher.decrypt(
|
||||||
|
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
|
||||||
|
);
|
||||||
|
this.history = decCipher.passwordHistory == null ? [] : decCipher.passwordHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the password history dialog.
|
||||||
|
*/
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strongly typed wrapper around the dialog service to open the password history dialog.
|
||||||
|
*/
|
||||||
|
export function openPasswordHistoryDialog(
|
||||||
|
dialogService: DialogService,
|
||||||
|
config: DialogConfig<ViewPasswordHistoryDialogParams>,
|
||||||
|
) {
|
||||||
|
return dialogService.open(PasswordHistoryComponent, config);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
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";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||||
@@ -22,6 +23,7 @@ import { PremiumUpgradePromptService } from "../../../../../../libs/common/src/v
|
|||||||
import { CipherViewComponent } from "../../../../../../libs/vault/src/cipher-view/cipher-view.component";
|
import { CipherViewComponent } from "../../../../../../libs/vault/src/cipher-view/cipher-view.component";
|
||||||
import { SharedModule } from "../../shared/shared.module";
|
import { SharedModule } from "../../shared/shared.module";
|
||||||
import { WebVaultPremiumUpgradePromptService } from "../services/web-premium-upgrade-prompt.service";
|
import { WebVaultPremiumUpgradePromptService } from "../services/web-premium-upgrade-prompt.service";
|
||||||
|
import { WebViewPasswordHistoryService } from "../services/web-view-password-history.service";
|
||||||
|
|
||||||
export interface ViewCipherDialogParams {
|
export interface ViewCipherDialogParams {
|
||||||
cipher: CipherView;
|
cipher: CipherView;
|
||||||
@@ -57,6 +59,7 @@ export interface ViewCipherDialogCloseResult {
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CipherViewComponent, CommonModule, AsyncActionsModule, DialogModule, SharedModule],
|
imports: [CipherViewComponent, CommonModule, AsyncActionsModule, DialogModule, SharedModule],
|
||||||
providers: [
|
providers: [
|
||||||
|
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
||||||
{ provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService },
|
{ provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
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 { 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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -31,6 +32,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
|||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
|
encryptService: EncryptService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -45,6 +47,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
|||||||
cipherService,
|
cipherService,
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
stateService,
|
stateService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
apiService,
|
apiService,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { ActivatedRoute, Params, Router } from "@angular/router";
|
|||||||
import {
|
import {
|
||||||
BehaviorSubject,
|
BehaviorSubject,
|
||||||
combineLatest,
|
combineLatest,
|
||||||
defer,
|
|
||||||
firstValueFrom,
|
firstValueFrom,
|
||||||
lastValueFrom,
|
lastValueFrom,
|
||||||
Observable,
|
Observable,
|
||||||
@@ -303,27 +302,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||||
|
|
||||||
this.allCollectionsWithoutUnassigned$ = combineLatest([
|
this.allCollectionsWithoutUnassigned$ = this.refresh$.pipe(
|
||||||
organizationId$.pipe(switchMap((orgId) => this.collectionAdminService.getAll(orgId))),
|
switchMap(() => organizationId$),
|
||||||
defer(() => this.collectionService.getAllDecrypted()),
|
switchMap((orgId) => this.collectionAdminService.getAll(orgId)),
|
||||||
]).pipe(
|
shareReplay({ refCount: false, bufferSize: 1 }),
|
||||||
map(([adminCollections, syncCollections]) => {
|
|
||||||
const syncCollectionDict = Object.fromEntries(syncCollections.map((c) => [c.id, c]));
|
|
||||||
|
|
||||||
return adminCollections.map((collection) => {
|
|
||||||
const currentId: any = collection.id;
|
|
||||||
|
|
||||||
const match = syncCollectionDict[currentId];
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
collection.manage = match.manage;
|
|
||||||
collection.readOnly = match.readOnly;
|
|
||||||
collection.hidePasswords = match.hidePasswords;
|
|
||||||
}
|
|
||||||
return collection;
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
||||||
@@ -356,8 +338,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const allCiphers$ = organization$.pipe(
|
const allCiphers$ = combineLatest([organization$, this.refresh$]).pipe(
|
||||||
concatMap(async (organization) => {
|
switchMap(async ([organization]) => {
|
||||||
// If user swaps organization reset the addAccessToggle
|
// If user swaps organization reset the addAccessToggle
|
||||||
if (!this.showAddAccessToggle || organization) {
|
if (!this.showAddAccessToggle || organization) {
|
||||||
this.addAccessToggle(0);
|
this.addAccessToggle(0);
|
||||||
@@ -381,13 +363,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
await this.searchService.indexCiphers(ciphers, organization.id);
|
await this.searchService.indexCiphers(ciphers, organization.id);
|
||||||
return ciphers;
|
return ciphers;
|
||||||
}),
|
}),
|
||||||
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const allCipherMap$ = allCiphers$.pipe(
|
const allCipherMap$ = allCiphers$.pipe(
|
||||||
map((ciphers) => {
|
map((ciphers) => {
|
||||||
return Object.fromEntries(ciphers.map((c) => [c.id, c]));
|
return Object.fromEntries(ciphers.map((c) => [c.id, c]));
|
||||||
}),
|
}),
|
||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const nestedCollections$ = allCollections$.pipe(
|
const nestedCollections$ = allCollections$.pipe(
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Overlay } from "@angular/cdk/overlay";
|
||||||
|
import { TestBed } from "@angular/core/testing";
|
||||||
|
|
||||||
|
import { CipherId } from "@bitwarden/common/types/guid";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { openPasswordHistoryDialog } from "../individual-vault/password-history.component";
|
||||||
|
|
||||||
|
import { WebViewPasswordHistoryService } from "./web-view-password-history.service";
|
||||||
|
|
||||||
|
jest.mock("../individual-vault/password-history.component", () => ({
|
||||||
|
openPasswordHistoryDialog: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("WebViewPasswordHistoryService", () => {
|
||||||
|
let service: WebViewPasswordHistoryService;
|
||||||
|
let dialogService: DialogService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const mockDialogService = {
|
||||||
|
open: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
WebViewPasswordHistoryService,
|
||||||
|
{ provide: DialogService, useValue: mockDialogService },
|
||||||
|
Overlay,
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
service = TestBed.inject(WebViewPasswordHistoryService);
|
||||||
|
dialogService = TestBed.inject(DialogService);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("viewPasswordHistory", () => {
|
||||||
|
it("calls openPasswordHistoryDialog with the correct parameters", async () => {
|
||||||
|
const mockCipherId = "cipher-id" as CipherId;
|
||||||
|
await service.viewPasswordHistory(mockCipherId);
|
||||||
|
expect(openPasswordHistoryDialog).toHaveBeenCalledWith(dialogService, {
|
||||||
|
data: { cipherId: mockCipherId },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
|
import { CipherId } from "@bitwarden/common/types/guid";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { ViewPasswordHistoryService } from "../../../../../../libs/common/src/vault/abstractions/view-password-history.service";
|
||||||
|
import { openPasswordHistoryDialog } from "../individual-vault/password-history.component";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This service is used to display the password history dialog in the web vault.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class WebViewPasswordHistoryService implements ViewPasswordHistoryService {
|
||||||
|
constructor(private dialogService: DialogService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the password history dialog for the given cipher ID.
|
||||||
|
* @param cipherId The ID of the cipher to view the password history for.
|
||||||
|
*/
|
||||||
|
async viewPasswordHistory(cipherId: CipherId) {
|
||||||
|
openPasswordHistoryDialog(this.dialogService, { data: { cipherId } });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ export class ServiceContainer extends OssServiceContainer {
|
|||||||
this.organizationAuthRequestService = new OrganizationAuthRequestService(
|
this.organizationAuthRequestService = new OrganizationAuthRequestService(
|
||||||
this.organizationAuthRequestApiService,
|
this.organizationAuthRequestApiService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.organizationUserApiService,
|
this.organizationUserApiService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
} from "@bitwarden/admin-console/common";
|
} from "@bitwarden/admin-console/common";
|
||||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
|
|
||||||
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
||||||
@@ -16,16 +17,19 @@ import { PendingAuthRequestView } from "./pending-auth-request.view";
|
|||||||
describe("OrganizationAuthRequestService", () => {
|
describe("OrganizationAuthRequestService", () => {
|
||||||
let organizationAuthRequestApiService: MockProxy<OrganizationAuthRequestApiService>;
|
let organizationAuthRequestApiService: MockProxy<OrganizationAuthRequestApiService>;
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
|
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
|
||||||
let organizationAuthRequestService: OrganizationAuthRequestService;
|
let organizationAuthRequestService: OrganizationAuthRequestService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
organizationAuthRequestApiService = mock<OrganizationAuthRequestApiService>();
|
organizationAuthRequestApiService = mock<OrganizationAuthRequestApiService>();
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
|
encryptService = mock<EncryptService>();
|
||||||
organizationUserApiService = mock<OrganizationUserApiService>();
|
organizationUserApiService = mock<OrganizationUserApiService>();
|
||||||
organizationAuthRequestService = new OrganizationAuthRequestService(
|
organizationAuthRequestService = new OrganizationAuthRequestService(
|
||||||
organizationAuthRequestApiService,
|
organizationAuthRequestApiService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
organizationUserApiService,
|
organizationUserApiService,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
OrganizationUserResetPasswordDetailsResponse,
|
OrganizationUserResetPasswordDetailsResponse,
|
||||||
} from "@bitwarden/admin-console/common";
|
} from "@bitwarden/admin-console/common";
|
||||||
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 { 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";
|
||||||
@@ -15,6 +16,7 @@ export class OrganizationAuthRequestService {
|
|||||||
constructor(
|
constructor(
|
||||||
private organizationAuthRequestApiService: OrganizationAuthRequestApiService,
|
private organizationAuthRequestApiService: OrganizationAuthRequestApiService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
|
private encryptService: EncryptService,
|
||||||
private organizationUserApiService: OrganizationUserApiService,
|
private organizationUserApiService: OrganizationUserApiService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -109,7 +111,7 @@ export class OrganizationAuthRequestService {
|
|||||||
|
|
||||||
// Decrypt Organization's encrypted Private Key with org key
|
// Decrypt Organization's encrypted Private Key with org key
|
||||||
const orgSymKey = await this.cryptoService.getOrgKey(organizationId);
|
const orgSymKey = await this.cryptoService.getOrgKey(organizationId);
|
||||||
const decOrgPrivateKey = await this.cryptoService.decryptToBytes(
|
const decOrgPrivateKey = await this.encryptService.decryptToBytes(
|
||||||
new EncString(encryptedOrgPrivateKey),
|
new EncString(encryptedOrgPrivateKey),
|
||||||
orgSymKey,
|
orgSymKey,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { PendingAuthRequestView } from "@bitwarden/bit-common/admin-console/auth
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
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 { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.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";
|
||||||
@@ -30,7 +31,12 @@ import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module";
|
|||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: OrganizationAuthRequestService,
|
provide: OrganizationAuthRequestService,
|
||||||
deps: [OrganizationAuthRequestApiService, CryptoService, OrganizationUserApiService],
|
deps: [
|
||||||
|
OrganizationAuthRequestApiService,
|
||||||
|
CryptoService,
|
||||||
|
EncryptService,
|
||||||
|
OrganizationUserApiService,
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
] satisfies SafeProvider[],
|
] satisfies SafeProvider[],
|
||||||
imports: [SharedModule, NoItemsModule, LooseComponentsModule],
|
imports: [SharedModule, NoItemsModule, LooseComponentsModule],
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class WebProviderService {
|
|||||||
const orgKey = await this.cryptoService.getOrgKey(organizationId);
|
const orgKey = await this.cryptoService.getOrgKey(organizationId);
|
||||||
const providerKey = await this.cryptoService.getProviderKey(providerId);
|
const providerKey = await this.cryptoService.getProviderKey(providerId);
|
||||||
|
|
||||||
const encryptedOrgKey = await this.cryptoService.encrypt(orgKey.key, providerKey);
|
const encryptedOrgKey = await this.encryptService.encrypt(orgKey.key, providerKey);
|
||||||
|
|
||||||
const request = new ProviderAddOrganizationRequest();
|
const request = new ProviderAddOrganizationRequest();
|
||||||
request.organizationId = organizationId;
|
request.organizationId = organizationId;
|
||||||
|
|||||||
@@ -449,6 +449,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
fileUploadService: CipherFileUploadServiceAbstraction,
|
fileUploadService: CipherFileUploadServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
stateProvider: StateProvider,
|
stateProvider: StateProvider,
|
||||||
|
accountService: AccountServiceAbstraction,
|
||||||
) =>
|
) =>
|
||||||
new CipherService(
|
new CipherService(
|
||||||
cryptoService,
|
cryptoService,
|
||||||
@@ -463,6 +464,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
fileUploadService,
|
fileUploadService,
|
||||||
configService,
|
configService,
|
||||||
stateProvider,
|
stateProvider,
|
||||||
|
accountService,
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
@@ -477,6 +479,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
CipherFileUploadServiceAbstraction,
|
CipherFileUploadServiceAbstraction,
|
||||||
ConfigService,
|
ConfigService,
|
||||||
StateProvider,
|
StateProvider,
|
||||||
|
AccountServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
@@ -484,6 +487,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
useClass: FolderService,
|
useClass: FolderService,
|
||||||
deps: [
|
deps: [
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
CipherServiceAbstraction,
|
CipherServiceAbstraction,
|
||||||
StateProvider,
|
StateProvider,
|
||||||
@@ -527,7 +531,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
safeProvider({
|
safeProvider({
|
||||||
provide: CollectionServiceAbstraction,
|
provide: CollectionServiceAbstraction,
|
||||||
useClass: CollectionService,
|
useClass: CollectionService,
|
||||||
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, StateProvider],
|
deps: [CryptoServiceAbstraction, EncryptService, I18nServiceAbstraction, StateProvider],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: EnvironmentService,
|
provide: EnvironmentService,
|
||||||
@@ -785,6 +789,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
CollectionServiceAbstraction,
|
CollectionServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
PinServiceAbstraction,
|
PinServiceAbstraction,
|
||||||
AccountServiceAbstraction,
|
AccountServiceAbstraction,
|
||||||
],
|
],
|
||||||
@@ -797,8 +802,10 @@ const safeProviders: SafeProvider[] = [
|
|||||||
CipherServiceAbstraction,
|
CipherServiceAbstraction,
|
||||||
PinServiceAbstraction,
|
PinServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
KdfConfigServiceAbstraction,
|
KdfConfigServiceAbstraction,
|
||||||
|
AccountServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
@@ -809,6 +816,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
PinServiceAbstraction,
|
PinServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
CollectionServiceAbstraction,
|
CollectionServiceAbstraction,
|
||||||
KdfConfigServiceAbstraction,
|
KdfConfigServiceAbstraction,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
|||||||
import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
|
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
@@ -36,7 +37,6 @@ import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"
|
|||||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||||
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||||
import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view";
|
import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view";
|
||||||
import { normalizeExpiryYearFormat } from "@bitwarden/common/vault/utils";
|
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||||
|
|
||||||
@@ -329,6 +329,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
this.cipher.card.expYear = normalizeExpiryYearFormat(this.cipher.card.expYear);
|
this.cipher.card.expYear = normalizeExpiryYearFormat(this.cipher.card.expYear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim whitespace from the TOTP field
|
||||||
|
if (this.cipher.type === this.cipherType.Login && this.cipher.login.totp) {
|
||||||
|
this.cipher.login.totp = this.cipher.login.totp.trim();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.cipher.name == null || this.cipher.name === "") {
|
if (this.cipher.name == null || this.cipher.name === "") {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
|||||||
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 { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -40,6 +41,7 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
protected cipherService: CipherService,
|
protected cipherService: CipherService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected cryptoService: CryptoService,
|
protected cryptoService: CryptoService,
|
||||||
|
protected encryptService: EncryptService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected apiService: ApiService,
|
protected apiService: ApiService,
|
||||||
protected win: Window,
|
protected win: Window,
|
||||||
@@ -178,7 +180,7 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
attachment.key != null
|
attachment.key != null
|
||||||
? attachment.key
|
? attachment.key
|
||||||
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
|
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
|
||||||
this.fileDownloadService.download({
|
this.fileDownloadService.download({
|
||||||
fileName: attachment.fileName,
|
fileName: attachment.fileName,
|
||||||
blobData: decBuf,
|
blobData: decBuf,
|
||||||
@@ -249,7 +251,7 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
attachment.key != null
|
attachment.key != null
|
||||||
? attachment.key
|
? attachment.key
|
||||||
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
|
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
|
||||||
const activeUserId = await firstValueFrom(
|
const activeUserId = await firstValueFrom(
|
||||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
import { Validators, FormBuilder } from "@angular/forms";
|
import { Validators, FormBuilder } from "@angular/forms";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -29,6 +32,8 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
protected folderService: FolderService,
|
protected folderService: FolderService,
|
||||||
protected folderApiService: FolderApiServiceAbstraction,
|
protected folderApiService: FolderApiServiceAbstraction,
|
||||||
|
protected accountService: AccountService,
|
||||||
|
protected cryptoService: CryptoService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
@@ -52,7 +57,9 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const folder = await this.folderService.encrypt(this.folder);
|
const activeAccountId = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
|
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeAccountId.id);
|
||||||
|
const folder = await this.folderService.encrypt(this.folder, userKey);
|
||||||
this.formPromise = this.folderApiService.save(folder);
|
this.formPromise = this.folderApiService.save(folder);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { EventType } from "@bitwarden/common/enums";
|
|||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.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 { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.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";
|
||||||
@@ -87,6 +88,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
protected tokenService: TokenService,
|
protected tokenService: TokenService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected cryptoService: CryptoService,
|
protected cryptoService: CryptoService,
|
||||||
|
protected encryptService: EncryptService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected auditService: AuditService,
|
protected auditService: AuditService,
|
||||||
protected win: Window,
|
protected win: Window,
|
||||||
@@ -442,7 +444,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
attachment.key != null
|
attachment.key != null
|
||||||
? attachment.key
|
? attachment.key
|
||||||
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, key);
|
const decBuf = await this.encryptService.decryptToBytes(encBuf, key);
|
||||||
this.fileDownloadService.download({
|
this.fileDownloadService.download({
|
||||||
fileName: attachment.fileName,
|
fileName: attachment.fileName,
|
||||||
blobData: decBuf,
|
blobData: decBuf,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -37,6 +38,7 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
let cache: AuthRequestLoginStrategyData;
|
let cache: AuthRequestLoginStrategyData;
|
||||||
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
let appIdService: MockProxy<AppIdService>;
|
let appIdService: MockProxy<AppIdService>;
|
||||||
@@ -101,6 +103,7 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -104,6 +105,7 @@ describe("LoginStrategy", () => {
|
|||||||
|
|
||||||
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
let appIdService: MockProxy<AppIdService>;
|
let appIdService: MockProxy<AppIdService>;
|
||||||
@@ -128,6 +130,7 @@ describe("LoginStrategy", () => {
|
|||||||
|
|
||||||
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
|
encryptService = mock<EncryptService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
appIdService = mock<AppIdService>();
|
appIdService = mock<AppIdService>();
|
||||||
@@ -156,6 +159,7 @@ describe("LoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
@@ -467,6 +471,7 @@ describe("LoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action
|
|||||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -66,6 +67,7 @@ export abstract class LoginStrategy {
|
|||||||
protected accountService: AccountService,
|
protected accountService: AccountService,
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||||
protected cryptoService: CryptoService,
|
protected cryptoService: CryptoService,
|
||||||
|
protected encryptService: EncryptService,
|
||||||
protected apiService: ApiService,
|
protected apiService: ApiService,
|
||||||
protected tokenService: TokenService,
|
protected tokenService: TokenService,
|
||||||
protected appIdService: AppIdService,
|
protected appIdService: AppIdService,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -63,6 +64,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
|
|
||||||
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
let appIdService: MockProxy<AppIdService>;
|
let appIdService: MockProxy<AppIdService>;
|
||||||
@@ -88,6 +90,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
|
|
||||||
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
|
encryptService = mock<EncryptService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
appIdService = mock<AppIdService>();
|
appIdService = mock<AppIdService>();
|
||||||
@@ -127,6 +130,7 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action
|
|||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
@@ -44,6 +45,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
let masterPasswordService: FakeMasterPasswordService;
|
let masterPasswordService: FakeMasterPasswordService;
|
||||||
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
let appIdService: MockProxy<AppIdService>;
|
let appIdService: MockProxy<AppIdService>;
|
||||||
@@ -78,6 +80,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
masterPasswordService = new FakeMasterPasswordService();
|
masterPasswordService = new FakeMasterPasswordService();
|
||||||
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
|
encryptService = mock<EncryptService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
appIdService = mock<AppIdService>();
|
appIdService = mock<AppIdService>();
|
||||||
@@ -125,6 +128,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 {
|
import {
|
||||||
Environment,
|
Environment,
|
||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
@@ -39,6 +40,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
let masterPasswordService: FakeMasterPasswordService;
|
let masterPasswordService: FakeMasterPasswordService;
|
||||||
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
let appIdService: MockProxy<AppIdService>;
|
let appIdService: MockProxy<AppIdService>;
|
||||||
@@ -99,6 +101,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
|||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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 { 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";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -37,6 +38,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
let masterPasswordService: FakeMasterPasswordService;
|
let masterPasswordService: FakeMasterPasswordService;
|
||||||
|
|
||||||
let cryptoService!: MockProxy<CryptoService>;
|
let cryptoService!: MockProxy<CryptoService>;
|
||||||
|
let encryptService!: MockProxy<EncryptService>;
|
||||||
let apiService!: MockProxy<ApiService>;
|
let apiService!: MockProxy<ApiService>;
|
||||||
let tokenService!: MockProxy<TokenService>;
|
let tokenService!: MockProxy<TokenService>;
|
||||||
let appIdService!: MockProxy<AppIdService>;
|
let appIdService!: MockProxy<AppIdService>;
|
||||||
@@ -79,6 +81,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
masterPasswordService = new FakeMasterPasswordService();
|
masterPasswordService = new FakeMasterPasswordService();
|
||||||
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
|
encryptService = mock<EncryptService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
appIdService = mock<AppIdService>();
|
appIdService = mock<AppIdService>();
|
||||||
@@ -103,6 +106,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
accountService,
|
accountService,
|
||||||
masterPasswordService,
|
masterPasswordService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
encryptService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
appIdService,
|
appIdService,
|
||||||
@@ -221,7 +225,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
const mockUserKeyArray: Uint8Array = randomBytes(32);
|
const mockUserKeyArray: Uint8Array = randomBytes(32);
|
||||||
const mockUserKey = new SymmetricCryptoKey(mockUserKeyArray) as UserKey;
|
const mockUserKey = new SymmetricCryptoKey(mockUserKeyArray) as UserKey;
|
||||||
|
|
||||||
cryptoService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
|
encryptService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
|
||||||
cryptoService.rsaDecrypt.mockResolvedValue(mockUserKeyArray);
|
cryptoService.rsaDecrypt.mockResolvedValue(mockUserKeyArray);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@@ -235,8 +239,8 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
userId,
|
userId,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(cryptoService.decryptToBytes).toHaveBeenCalledTimes(1);
|
expect(encryptService.decryptToBytes).toHaveBeenCalledTimes(1);
|
||||||
expect(cryptoService.decryptToBytes).toHaveBeenCalledWith(
|
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(
|
||||||
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedPrivateKey,
|
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedPrivateKey,
|
||||||
webAuthnCredentials.prfKey,
|
webAuthnCredentials.prfKey,
|
||||||
);
|
);
|
||||||
@@ -268,7 +272,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(cryptoService.decryptToBytes).not.toHaveBeenCalled();
|
expect(encryptService.decryptToBytes).not.toHaveBeenCalled();
|
||||||
expect(cryptoService.rsaDecrypt).not.toHaveBeenCalled();
|
expect(cryptoService.rsaDecrypt).not.toHaveBeenCalled();
|
||||||
expect(cryptoService.setUserKey).not.toHaveBeenCalled();
|
expect(cryptoService.setUserKey).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -303,7 +307,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(idTokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(idTokenResponse);
|
||||||
|
|
||||||
cryptoService.decryptToBytes.mockResolvedValue(null);
|
encryptService.decryptToBytes.mockResolvedValue(null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decrypt prf encrypted private key
|
// decrypt prf encrypted private key
|
||||||
const privateKey = await this.cryptoService.decryptToBytes(
|
const privateKey = await this.encryptService.decryptToBytes(
|
||||||
webAuthnPrfOption.encryptedPrivateKey,
|
webAuthnPrfOption.encryptedPrivateKey,
|
||||||
credentials.prfKey,
|
credentials.prfKey,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -317,6 +317,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
this.accountService,
|
this.accountService,
|
||||||
this.masterPasswordService,
|
this.masterPasswordService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
this.encryptService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
this.appIdService,
|
this.appIdService,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { firstValueFrom, map, Observable } from "rxjs";
|
|||||||
|
|
||||||
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
|
|
||||||
import { FeatureFlag } from "../../enums/feature-flag.enum";
|
|
||||||
import { AppIdService } from "../../platform/abstractions/app-id.service";
|
import { AppIdService } from "../../platform/abstractions/app-id.service";
|
||||||
import { ConfigService } from "../../platform/abstractions/config/config.service";
|
import { ConfigService } from "../../platform/abstractions/config/config.service";
|
||||||
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
|
||||||
@@ -334,9 +333,6 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async recordDeviceTrustLoss(): Promise<void> {
|
async recordDeviceTrustLoss(): Promise<void> {
|
||||||
if (!(await this.configService.getFeatureFlag(FeatureFlag.DeviceTrustLogging))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const deviceIdentifier = await this.appIdService.getAppId();
|
const deviceIdentifier = await this.appIdService.getAppId();
|
||||||
await this.devicesApiService.postDeviceTrustLoss(deviceIdentifier);
|
await this.devicesApiService.postDeviceTrustLoss(deviceIdentifier);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,3 +109,5 @@ export type ExtensionCommandType = (typeof ExtensionCommand)[keyof typeof Extens
|
|||||||
export const CLEAR_NOTIFICATION_LOGIN_DATA_DURATION = 60 * 1000; // 1 minute
|
export const CLEAR_NOTIFICATION_LOGIN_DATA_DURATION = 60 * 1000; // 1 minute
|
||||||
|
|
||||||
export const MAX_DEEP_QUERY_RECURSION_DEPTH = 4;
|
export const MAX_DEEP_QUERY_RECURSION_DEPTH = 4;
|
||||||
|
|
||||||
|
export * from "./match-patterns";
|
||||||
|
|||||||
26
libs/common/src/autofill/constants/match-patterns.ts
Normal file
26
libs/common/src/autofill/constants/match-patterns.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export const CardExpiryDateDelimiters: string[] = ["/", "-", ".", " "];
|
||||||
|
|
||||||
|
// `CardExpiryDateDelimiters` is not intended solely for regex consumption,
|
||||||
|
// so we need to format it here
|
||||||
|
export const ExpiryDateDelimitersPattern =
|
||||||
|
"\\" +
|
||||||
|
CardExpiryDateDelimiters.join("\\")
|
||||||
|
// replace space character with the regex whitespace character class
|
||||||
|
.replace(" ", "s");
|
||||||
|
|
||||||
|
export const MonthPattern = "(([1]{1}[0-2]{1})|(0?[1-9]{1}))";
|
||||||
|
|
||||||
|
// Because we're dealing with expiry dates, we assume the year will be in current or next century (as of 2024)
|
||||||
|
export const ExpiryFullYearPattern = "2[0-1]{1}\\d{2}";
|
||||||
|
|
||||||
|
export const DelimiterPatternExpression = new RegExp(`[${ExpiryDateDelimitersPattern}]`, "g");
|
||||||
|
|
||||||
|
export const IrrelevantExpiryCharactersPatternExpression = new RegExp(
|
||||||
|
// "nor digits" to ensure numbers are removed from guidance pattern, which aren't covered by ^\w
|
||||||
|
`[^\\d${ExpiryDateDelimitersPattern}]`,
|
||||||
|
"g",
|
||||||
|
);
|
||||||
|
|
||||||
|
export const MonthPatternExpression = new RegExp(`^${MonthPattern}$`);
|
||||||
|
|
||||||
|
export const ExpiryFullYearPatternExpression = new RegExp(`^${ExpiryFullYearPattern}$`);
|
||||||
284
libs/common/src/autofill/utils.spec.ts
Normal file
284
libs/common/src/autofill/utils.spec.ts
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
import {
|
||||||
|
normalizeExpiryYearFormat,
|
||||||
|
isCardExpired,
|
||||||
|
parseYearMonthExpiry,
|
||||||
|
} from "@bitwarden/common/autofill/utils";
|
||||||
|
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
|
||||||
|
|
||||||
|
function getExpiryYearValueFormats(currentCentury: string) {
|
||||||
|
return [
|
||||||
|
[-12, `${currentCentury}12`],
|
||||||
|
[0, `${currentCentury}00`],
|
||||||
|
[2043, "2043"], // valid year with a length of four should be taken directly
|
||||||
|
[24, `${currentCentury}24`],
|
||||||
|
[3054, "3054"], // valid year with a length of four should be taken directly
|
||||||
|
[31423524543, `${currentCentury}43`],
|
||||||
|
[4, `${currentCentury}04`],
|
||||||
|
[null, null],
|
||||||
|
[undefined, null],
|
||||||
|
["-12", `${currentCentury}12`],
|
||||||
|
["", null],
|
||||||
|
["0", `${currentCentury}00`],
|
||||||
|
["00", `${currentCentury}00`],
|
||||||
|
["000", `${currentCentury}00`],
|
||||||
|
["0000", `${currentCentury}00`],
|
||||||
|
["00000", `${currentCentury}00`],
|
||||||
|
["0234234", `${currentCentury}34`],
|
||||||
|
["04", `${currentCentury}04`],
|
||||||
|
["2043", "2043"], // valid year with a length of four should be taken directly
|
||||||
|
["24", `${currentCentury}24`],
|
||||||
|
["3054", "3054"], // valid year with a length of four should be taken directly
|
||||||
|
["31423524543", `${currentCentury}43`],
|
||||||
|
["4", `${currentCentury}04`],
|
||||||
|
["aaaa", null],
|
||||||
|
["adgshsfhjsdrtyhsrth", null],
|
||||||
|
["agdredg42grg35grrr. ea3534@#^145345ag$%^ -_#$rdg ", `${currentCentury}45`],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("normalizeExpiryYearFormat", () => {
|
||||||
|
const currentCentury = `${new Date().getFullYear()}`.slice(0, 2);
|
||||||
|
|
||||||
|
const expiryYearValueFormats = getExpiryYearValueFormats(currentCentury);
|
||||||
|
|
||||||
|
expiryYearValueFormats.forEach(([inputValue, expectedValue]) => {
|
||||||
|
it(`should return '${expectedValue}' when '${inputValue}' is passed`, () => {
|
||||||
|
const formattedValue = normalizeExpiryYearFormat(inputValue);
|
||||||
|
|
||||||
|
expect(formattedValue).toEqual(expectedValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("in the year 3107", () => {
|
||||||
|
const theDistantFuture = new Date(Date.UTC(3107, 1, 1));
|
||||||
|
jest.spyOn(Date, "now").mockReturnValue(theDistantFuture.valueOf());
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.useFakeTimers({ advanceTimers: true });
|
||||||
|
jest.setSystemTime(theDistantFuture);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentCentury = `${new Date(Date.now()).getFullYear()}`.slice(0, 2);
|
||||||
|
expect(currentCentury).toBe("31");
|
||||||
|
|
||||||
|
const expiryYearValueFormats = getExpiryYearValueFormats(currentCentury);
|
||||||
|
|
||||||
|
expiryYearValueFormats.forEach(([inputValue, expectedValue]) => {
|
||||||
|
it(`should return '${expectedValue}' when '${inputValue}' is passed`, () => {
|
||||||
|
const formattedValue = normalizeExpiryYearFormat(inputValue);
|
||||||
|
|
||||||
|
expect(formattedValue).toEqual(expectedValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
jest.clearAllTimers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function getCardExpiryDateValues() {
|
||||||
|
const currentDate = new Date();
|
||||||
|
|
||||||
|
const currentYear = currentDate.getFullYear();
|
||||||
|
|
||||||
|
// `Date` months are zero-indexed, our expiry date month inputs are one-indexed
|
||||||
|
const currentMonth = currentDate.getMonth() + 1;
|
||||||
|
|
||||||
|
return [
|
||||||
|
[null, null, false], // no month, no year
|
||||||
|
[undefined, undefined, false], // no month, no year, invalid values
|
||||||
|
["", "", false], // no month, no year, invalid values
|
||||||
|
["12", "agdredg42grg35grrr. ea3534@#^145345ag$%^ -_#$rdg ", false], // invalid values
|
||||||
|
["0", `${currentYear}`, true], // invalid month
|
||||||
|
["0", `${currentYear - 1}`, true], // invalid 0 month
|
||||||
|
["00", `${currentYear + 1}`, false], // invalid 0 month
|
||||||
|
[`${currentMonth}`, "0000", true], // current month, in the year 2000
|
||||||
|
[null, `${currentYear}`.slice(-2), false], // no month, this year
|
||||||
|
[null, `${currentYear - 1}`.slice(-2), true], // no month, last year
|
||||||
|
["1", null, false], // no year, January
|
||||||
|
["1", `${currentYear - 1}`, true], // January last year
|
||||||
|
["13", `${currentYear}`, false], // 12 + 1 is Feb. in the next year (Date is zero-indexed)
|
||||||
|
[`${currentMonth + 36}`, `${currentYear - 1}`, true], // even though the month value would put the date 3 years into the future when calculated with `Date`, an explicit year in the past indicates the card is expired
|
||||||
|
[`${currentMonth}`, `${currentYear}`, false], // this year, this month (not expired until the month is over)
|
||||||
|
[`${currentMonth}`, `${currentYear}`.slice(-2), false], // This month, this year (not expired until the month is over)
|
||||||
|
[`${currentMonth - 1}`, `${currentYear}`, true], // last month
|
||||||
|
[`${currentMonth - 1}`, `${currentYear + 1}`, false], // 11 months from now
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("isCardExpired", () => {
|
||||||
|
const expiryYearValueFormats = getCardExpiryDateValues();
|
||||||
|
|
||||||
|
expiryYearValueFormats.forEach(
|
||||||
|
([inputMonth, inputYear, expectedValue]: [string | null, string | null, boolean]) => {
|
||||||
|
it(`should return ${expectedValue} when the card expiry month is ${inputMonth} and the card expiry year is ${inputYear}`, () => {
|
||||||
|
const testCardView = new CardView();
|
||||||
|
testCardView.expMonth = inputMonth;
|
||||||
|
testCardView.expYear = inputYear;
|
||||||
|
|
||||||
|
const cardIsExpired = isCardExpired(testCardView);
|
||||||
|
|
||||||
|
expect(cardIsExpired).toBe(expectedValue);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const combinedDateTestValues = [
|
||||||
|
" 2024 / 05 ",
|
||||||
|
"05 2024",
|
||||||
|
"05 2024", // Tab whitespace character
|
||||||
|
"05 2024", // Em Quad
|
||||||
|
"05 2024", // Em Space
|
||||||
|
"05 2024", // En Quad
|
||||||
|
"05 2024", // En Space
|
||||||
|
"05 2024", // Figure Space
|
||||||
|
"05 2024", // Four-Per-Em Space
|
||||||
|
"05 2024", // Hair Space
|
||||||
|
"05 2024", // Ideographic Space
|
||||||
|
"05 2024", // Medium Mathematical Space
|
||||||
|
"05 2024", // No-Break Space
|
||||||
|
"05 2024", // ogham space mark
|
||||||
|
"05 2024", // Punctuation Space
|
||||||
|
"05 2024", // Six-Per-Em Space
|
||||||
|
"05 2024", // Thin Space
|
||||||
|
"05 2024", // Three-Per-Em Space
|
||||||
|
"05 24",
|
||||||
|
"05-2024",
|
||||||
|
"05-24",
|
||||||
|
"05.2024",
|
||||||
|
"05.24",
|
||||||
|
"05/2024",
|
||||||
|
"05/24",
|
||||||
|
"052024",
|
||||||
|
"0524",
|
||||||
|
"2024 05",
|
||||||
|
"2024 5",
|
||||||
|
"2024-05",
|
||||||
|
"2024-5",
|
||||||
|
"2024.05",
|
||||||
|
"2024.5",
|
||||||
|
"2024/05",
|
||||||
|
"2024/5",
|
||||||
|
"202405",
|
||||||
|
"20245",
|
||||||
|
"24 05",
|
||||||
|
"24 5",
|
||||||
|
"24-05",
|
||||||
|
"24-5",
|
||||||
|
"24.05",
|
||||||
|
"24.5",
|
||||||
|
"24/05",
|
||||||
|
"24/5",
|
||||||
|
"2405",
|
||||||
|
"5 2024",
|
||||||
|
"5 24",
|
||||||
|
"5-2024",
|
||||||
|
"5-24",
|
||||||
|
"5.2024",
|
||||||
|
"5.24",
|
||||||
|
"5/2024",
|
||||||
|
"5/24",
|
||||||
|
"52024",
|
||||||
|
];
|
||||||
|
const expectedParsedValue = ["2024", "5"];
|
||||||
|
describe("parseYearMonthExpiry", () => {
|
||||||
|
it('returns "null" expiration year and month values when a value of "" is passed', () => {
|
||||||
|
expect(parseYearMonthExpiry("")).toStrictEqual([null, null]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns "null" expiration year and month values when a value of "/" is passed', () => {
|
||||||
|
expect(parseYearMonthExpiry("/")).toStrictEqual([null, null]);
|
||||||
|
});
|
||||||
|
|
||||||
|
combinedDateTestValues.forEach((combinedDate) => {
|
||||||
|
it(`returns an expiration year value of "${expectedParsedValue[0]}" and month value of "${expectedParsedValue[1]}" when a value of "${combinedDate}" is passed`, () => {
|
||||||
|
expect(parseYearMonthExpiry(combinedDate)).toStrictEqual(expectedParsedValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an expiration year value of "2002" and month value of "2" when a value of "022" is passed', () => {
|
||||||
|
expect(parseYearMonthExpiry("022")).toStrictEqual(["2002", "2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an expiration year value of "2002" and month value of "2" when a value of "202" is passed', () => {
|
||||||
|
expect(parseYearMonthExpiry("202")).toStrictEqual(["2002", "2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an expiration year value of "2002" and month value of "1" when a value of "1/2/3/4" is passed', () => {
|
||||||
|
expect(parseYearMonthExpiry("1/2/3/4")).toStrictEqual(["2002", "1"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns valid expiration year and month values when a value of "198" is passed', () => {
|
||||||
|
// This static value will cause the test to fail in 2098
|
||||||
|
const testValue = "198";
|
||||||
|
const parsedValue = parseYearMonthExpiry(testValue);
|
||||||
|
|
||||||
|
expect(parsedValue[0]).toHaveLength(4);
|
||||||
|
expect(parsedValue[1]).toMatch(/^[\d]{1,2}$/);
|
||||||
|
|
||||||
|
expect(parsedValue).toStrictEqual(["2098", "1"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ambiguous input cases: we use try/catch for these cases as a workaround to accept either
|
||||||
|
// outcome (both are valid interpretations) in the event of any future code changes.
|
||||||
|
describe("ambiguous input cases", () => {
|
||||||
|
it('returns valid expiration year and month values when a value of "111" is passed', () => {
|
||||||
|
const testValue = "111";
|
||||||
|
const parsedValue = parseYearMonthExpiry(testValue);
|
||||||
|
|
||||||
|
expect(parsedValue[0]).toHaveLength(4);
|
||||||
|
expect(parsedValue[1]).toMatch(/^[\d]{1,2}$/);
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(parsedValue).toStrictEqual(["2011", "1"]);
|
||||||
|
} catch {
|
||||||
|
expect(parsedValue).toStrictEqual(["2001", "11"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns valid expiration year and month values when a value of "212" is passed', () => {
|
||||||
|
const testValue = "212";
|
||||||
|
const parsedValue = parseYearMonthExpiry(testValue);
|
||||||
|
|
||||||
|
expect(parsedValue[0]).toHaveLength(4);
|
||||||
|
expect(parsedValue[1]).toMatch(/^[\d]{1,2}$/);
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(parsedValue).toStrictEqual(["2012", "2"]);
|
||||||
|
} catch {
|
||||||
|
expect(parsedValue).toStrictEqual(["2021", "2"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns valid expiration year and month values when a value of "245" is passed', () => {
|
||||||
|
const testValue = "245";
|
||||||
|
const parsedValue = parseYearMonthExpiry(testValue);
|
||||||
|
|
||||||
|
expect(parsedValue[0]).toHaveLength(4);
|
||||||
|
expect(parsedValue[1]).toMatch(/^[\d]{1,2}$/);
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(parsedValue).toStrictEqual(["2045", "2"]);
|
||||||
|
} catch {
|
||||||
|
expect(parsedValue).toStrictEqual(["2024", "5"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns valid expiration year and month values when a value of "524" is passed', () => {
|
||||||
|
const testValue = "524";
|
||||||
|
const parsedValue = parseYearMonthExpiry(testValue);
|
||||||
|
|
||||||
|
expect(parsedValue[0]).toHaveLength(4);
|
||||||
|
expect(parsedValue[1]).toMatch(/^[\d]{1,2}$/);
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(parsedValue).toStrictEqual(["2024", "5"]);
|
||||||
|
} catch {
|
||||||
|
expect(parsedValue).toStrictEqual(["2052", "4"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
307
libs/common/src/autofill/utils.ts
Normal file
307
libs/common/src/autofill/utils.ts
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import {
|
||||||
|
DelimiterPatternExpression,
|
||||||
|
ExpiryFullYearPattern,
|
||||||
|
ExpiryFullYearPatternExpression,
|
||||||
|
IrrelevantExpiryCharactersPatternExpression,
|
||||||
|
MonthPatternExpression,
|
||||||
|
} from "@bitwarden/common/autofill/constants";
|
||||||
|
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
|
||||||
|
|
||||||
|
type NonZeroIntegers = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
||||||
|
type Year = `${NonZeroIntegers}${NonZeroIntegers}${0 | NonZeroIntegers}${0 | NonZeroIntegers}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a string or number value and returns a string value formatted as a valid 4-digit year
|
||||||
|
*
|
||||||
|
* @param {(string | number)} yearInput
|
||||||
|
* @return {*} {(Year | null)}
|
||||||
|
*/
|
||||||
|
export function normalizeExpiryYearFormat(yearInput: string | number): Year | null {
|
||||||
|
// The input[type="number"] is returning a number, convert it to a string
|
||||||
|
// An empty field returns null, avoid casting `"null"` to a string
|
||||||
|
const yearInputIsEmpty = yearInput == null || yearInput === "";
|
||||||
|
let expirationYear = yearInputIsEmpty ? null : `${yearInput}`;
|
||||||
|
|
||||||
|
// Exit early if year is already formatted correctly or empty
|
||||||
|
if (yearInputIsEmpty || /^[1-9]{1}\d{3}$/.test(expirationYear)) {
|
||||||
|
return expirationYear as Year;
|
||||||
|
}
|
||||||
|
|
||||||
|
expirationYear = expirationYear
|
||||||
|
// For safety, because even input[type="number"] will allow decimals
|
||||||
|
.replace(/[^\d]/g, "")
|
||||||
|
// remove any leading zero padding (leave the last leading zero if it ends the string)
|
||||||
|
.replace(/^[0]+(?=.)/, "");
|
||||||
|
|
||||||
|
if (expirationYear === "") {
|
||||||
|
expirationYear = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// given the context of payment card expiry, a year character length of 3, or over 4
|
||||||
|
// is more likely to be a mistake than an intentional value for the far past or far future.
|
||||||
|
if (expirationYear && expirationYear.length !== 4) {
|
||||||
|
const paddedYear = ("00" + expirationYear).slice(-2);
|
||||||
|
const currentCentury = `${new Date().getFullYear()}`.slice(0, 2);
|
||||||
|
|
||||||
|
expirationYear = currentCentury + paddedYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expirationYear as Year | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a cipher card view and returns "true" if the month and year affirmativey indicate
|
||||||
|
* the card is expired.
|
||||||
|
*
|
||||||
|
* @param {CardView} cipherCard
|
||||||
|
* @return {*} {boolean}
|
||||||
|
*/
|
||||||
|
export function isCardExpired(cipherCard: CardView): boolean {
|
||||||
|
if (cipherCard) {
|
||||||
|
const { expMonth = null, expYear = null } = cipherCard;
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const normalizedYear = normalizeExpiryYearFormat(expYear);
|
||||||
|
|
||||||
|
// If the card year is before the current year, don't bother checking the month
|
||||||
|
if (normalizedYear && parseInt(normalizedYear, 10) < now.getFullYear()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedYear && expMonth) {
|
||||||
|
const parsedMonthInteger = parseInt(expMonth, 10);
|
||||||
|
|
||||||
|
const parsedMonth = isNaN(parsedMonthInteger)
|
||||||
|
? 0
|
||||||
|
: // Add a month floor of 0 to protect against an invalid low month value of "0" or negative integers
|
||||||
|
Math.max(
|
||||||
|
// `Date` months are zero-indexed
|
||||||
|
parsedMonthInteger - 1,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsedYear = parseInt(normalizedYear, 10);
|
||||||
|
|
||||||
|
// First day of the next month minus one, to get last day of the card month
|
||||||
|
const cardExpiry = new Date(parsedYear, parsedMonth + 1, 0);
|
||||||
|
|
||||||
|
return cardExpiry < now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to split a string into date segments on the basis of expected formats and delimiter symbols.
|
||||||
|
*
|
||||||
|
* @param {string} combinedExpiryValue
|
||||||
|
* @return {*} {string[]}
|
||||||
|
*/
|
||||||
|
function splitCombinedDateValues(combinedExpiryValue: string): string[] {
|
||||||
|
let sanitizedValue = combinedExpiryValue
|
||||||
|
.replace(IrrelevantExpiryCharactersPatternExpression, "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Do this after initial value replace to avoid identifying leading whitespace as delimiter
|
||||||
|
const parsedDelimiter = sanitizedValue.match(DelimiterPatternExpression)?.[0] || null;
|
||||||
|
|
||||||
|
let dateParts = [sanitizedValue];
|
||||||
|
|
||||||
|
if (parsedDelimiter?.length) {
|
||||||
|
// If the parsed delimiter is a whitespace character, assign 's' (character class) instead
|
||||||
|
const delimiterPattern = /\s/.test(parsedDelimiter) ? "\\s" : "\\" + parsedDelimiter;
|
||||||
|
|
||||||
|
sanitizedValue = sanitizedValue
|
||||||
|
// Remove all other delimiter characters not identified as the delimiter
|
||||||
|
.replace(new RegExp(`[^\\d${delimiterPattern}]`, "g"), "")
|
||||||
|
// Also de-dupe the delimiter character
|
||||||
|
.replace(new RegExp(`[${delimiterPattern}]{2,}`, "g"), parsedDelimiter);
|
||||||
|
|
||||||
|
dateParts = sanitizedValue.split(parsedDelimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
dateParts
|
||||||
|
// remove values that have no length
|
||||||
|
.filter((splitValue) => splitValue?.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an array of split card expiry date parts,
|
||||||
|
* returns an array of those values ordered by year then month
|
||||||
|
*
|
||||||
|
* @param {string[]} splitDateInput
|
||||||
|
* @return {*} {([string | null, string | null])}
|
||||||
|
*/
|
||||||
|
function parseDelimitedYearMonthExpiry([firstPart, secondPart]: string[]): [string, string] {
|
||||||
|
// Conditionals here are structured to avoid unnecessary evaluations and are ordered
|
||||||
|
// from more authoritative checks to checks yielding increasingly inferred conclusions
|
||||||
|
|
||||||
|
// If a 4-digit value is found (when there are multiple parts), it can't be month
|
||||||
|
if (ExpiryFullYearPatternExpression.test(firstPart)) {
|
||||||
|
return [firstPart, secondPart];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a 4-digit value is found (when there are multiple parts), it can't be month
|
||||||
|
if (ExpiryFullYearPatternExpression.test(secondPart)) {
|
||||||
|
return [secondPart, firstPart];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a two digit value that doesn't match against month pattern, assume it's a year
|
||||||
|
if (/\d{2}/.test(firstPart) && !MonthPatternExpression.test(firstPart)) {
|
||||||
|
return [firstPart, secondPart];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a two digit value that doesn't match against month pattern, assume it's a year
|
||||||
|
if (/\d{2}/.test(secondPart) && !MonthPatternExpression.test(secondPart)) {
|
||||||
|
return [secondPart, firstPart];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values are too ambiguous (e.g. "12/09"). For the most part,
|
||||||
|
// a month-looking value likely is, at the time of writing (year 2024).
|
||||||
|
let parsedYear = firstPart;
|
||||||
|
let parsedMonth = secondPart;
|
||||||
|
|
||||||
|
if (MonthPatternExpression.test(firstPart)) {
|
||||||
|
parsedYear = secondPart;
|
||||||
|
parsedMonth = firstPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [parsedYear, parsedMonth];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a single string of integers, attempts to identify card expiry date portions within
|
||||||
|
* and return values ordered by year then month
|
||||||
|
*
|
||||||
|
* @param {string} dateInput
|
||||||
|
* @return {*} {([string | null, string | null])}
|
||||||
|
*/
|
||||||
|
function parseNonDelimitedYearMonthExpiry(dateInput: string): [string | null, string | null] {
|
||||||
|
if (dateInput.length > 4) {
|
||||||
|
// e.g.
|
||||||
|
// "052024"
|
||||||
|
// "202405"
|
||||||
|
// "20245"
|
||||||
|
// "52024"
|
||||||
|
|
||||||
|
// If the value is over 5-characters long, it likely has a full year format in it
|
||||||
|
const [parsedYear, parsedMonth] = dateInput
|
||||||
|
.split(new RegExp(`(?=${ExpiryFullYearPattern})|(?<=${ExpiryFullYearPattern})`, "g"))
|
||||||
|
.sort((current: string, next: string) => (current.length > next.length ? -1 : 1));
|
||||||
|
|
||||||
|
return [parsedYear, parsedMonth];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateInput.length === 4) {
|
||||||
|
// e.g.
|
||||||
|
// "0524"
|
||||||
|
// "2405"
|
||||||
|
|
||||||
|
// If the `sanitizedFirstPart` value is a length of 4, it must be split in half, since
|
||||||
|
// neither a year or month will be represented with three characters
|
||||||
|
const splitFirstPartFirstHalf = dateInput.slice(0, 2);
|
||||||
|
const splitFirstPartSecondHalf = dateInput.slice(-2);
|
||||||
|
|
||||||
|
let parsedYear = splitFirstPartSecondHalf;
|
||||||
|
let parsedMonth = splitFirstPartFirstHalf;
|
||||||
|
|
||||||
|
// If the first part doesn't match a month pattern, assume it's a year
|
||||||
|
if (!MonthPatternExpression.test(splitFirstPartFirstHalf)) {
|
||||||
|
parsedYear = splitFirstPartFirstHalf;
|
||||||
|
parsedMonth = splitFirstPartSecondHalf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [parsedYear, parsedMonth];
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g.
|
||||||
|
// "245"
|
||||||
|
// "202"
|
||||||
|
// "212"
|
||||||
|
// "022"
|
||||||
|
// "111"
|
||||||
|
|
||||||
|
// A valid year representation here must be two characters so try to find it first.
|
||||||
|
|
||||||
|
let parsedYear = null;
|
||||||
|
let parsedMonth = null;
|
||||||
|
|
||||||
|
// Split if there is a digit with a leading zero
|
||||||
|
const splitFirstPartOnLeadingZero = dateInput.split(/(?<=0[1-9]{1})|(?=0[1-9]{1})/);
|
||||||
|
|
||||||
|
// Assume a leading zero indicates a month in ambiguous cases (e.g. "202"), since we're
|
||||||
|
// dealing with expiry dates and the next two-digit year with a leading zero will be 2100
|
||||||
|
if (splitFirstPartOnLeadingZero.length > 1) {
|
||||||
|
parsedYear = splitFirstPartOnLeadingZero[0];
|
||||||
|
parsedMonth = splitFirstPartOnLeadingZero[1];
|
||||||
|
|
||||||
|
if (splitFirstPartOnLeadingZero[0].startsWith("0")) {
|
||||||
|
parsedMonth = splitFirstPartOnLeadingZero[0];
|
||||||
|
parsedYear = splitFirstPartOnLeadingZero[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Here, a year has to be two-digits, and a month can't be more than one, so assume the first two digits that are greater than the current year is the year representation.
|
||||||
|
parsedYear = dateInput.slice(0, 2);
|
||||||
|
parsedMonth = dateInput.slice(-1);
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const normalizedParsedYear = parseInt(normalizeExpiryYearFormat(parsedYear), 10);
|
||||||
|
const normalizedParsedYearAlternative = parseInt(
|
||||||
|
normalizeExpiryYearFormat(dateInput.slice(-2)),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (normalizedParsedYear < currentYear && normalizedParsedYearAlternative >= currentYear) {
|
||||||
|
parsedYear = dateInput.slice(-2);
|
||||||
|
parsedMonth = dateInput.slice(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [parsedYear, parsedMonth];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to parse year and month parts of a combined expiry date value.
|
||||||
|
*
|
||||||
|
* @param {string} combinedExpiryValue
|
||||||
|
* @return {*} {([string | null, string | null])}
|
||||||
|
*/
|
||||||
|
export function parseYearMonthExpiry(combinedExpiryValue: string): [Year | null, string | null] {
|
||||||
|
let parsedYear = null;
|
||||||
|
let parsedMonth = null;
|
||||||
|
|
||||||
|
const dateParts = splitCombinedDateValues(combinedExpiryValue);
|
||||||
|
|
||||||
|
if (dateParts.length < 1) {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitizedFirstPart =
|
||||||
|
dateParts[0]?.replace(IrrelevantExpiryCharactersPatternExpression, "") || "";
|
||||||
|
const sanitizedSecondPart =
|
||||||
|
dateParts[1]?.replace(IrrelevantExpiryCharactersPatternExpression, "") || "";
|
||||||
|
|
||||||
|
// If there is only one date part, no delimiter was found in the passed value
|
||||||
|
if (dateParts.length === 1) {
|
||||||
|
[parsedYear, parsedMonth] = parseNonDelimitedYearMonthExpiry(sanitizedFirstPart);
|
||||||
|
}
|
||||||
|
// There are multiple date parts
|
||||||
|
else {
|
||||||
|
[parsedYear, parsedMonth] = parseDelimitedYearMonthExpiry([
|
||||||
|
sanitizedFirstPart,
|
||||||
|
sanitizedSecondPart,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedParsedYear = normalizeExpiryYearFormat(parsedYear);
|
||||||
|
const normalizedParsedMonth = parsedMonth?.replace(/^0+/, "").slice(0, 2);
|
||||||
|
|
||||||
|
// Set "empty" values to null
|
||||||
|
parsedYear = normalizedParsedYear?.length ? normalizedParsedYear : null;
|
||||||
|
parsedMonth = normalizedParsedMonth?.length ? normalizedParsedMonth : null;
|
||||||
|
|
||||||
|
return [parsedYear, parsedMonth];
|
||||||
|
}
|
||||||
@@ -24,8 +24,6 @@ export enum FeatureFlag {
|
|||||||
VaultBulkManagementAction = "vault-bulk-management-action",
|
VaultBulkManagementAction = "vault-bulk-management-action",
|
||||||
AC2828_ProviderPortalMembersPage = "AC-2828_provider-portal-members-page",
|
AC2828_ProviderPortalMembersPage = "AC-2828_provider-portal-members-page",
|
||||||
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
||||||
DeviceTrustLogging = "pm-8285-device-trust-logging",
|
|
||||||
AuthenticatorTwoFactorToken = "authenticator-2fa-token",
|
|
||||||
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
||||||
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
||||||
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
||||||
@@ -69,8 +67,6 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.VaultBulkManagementAction]: FALSE,
|
[FeatureFlag.VaultBulkManagementAction]: FALSE,
|
||||||
[FeatureFlag.AC2828_ProviderPortalMembersPage]: FALSE,
|
[FeatureFlag.AC2828_ProviderPortalMembersPage]: FALSE,
|
||||||
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
||||||
[FeatureFlag.DeviceTrustLogging]: FALSE,
|
|
||||||
[FeatureFlag.AuthenticatorTwoFactorToken]: FALSE,
|
|
||||||
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
||||||
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
||||||
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
UserPublicKey,
|
UserPublicKey,
|
||||||
} from "../../types/key";
|
} from "../../types/key";
|
||||||
import { KeySuffixOptions, HashPurpose } from "../enums";
|
import { KeySuffixOptions, HashPurpose } from "../enums";
|
||||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
|
||||||
import { EncString } from "../models/domain/enc-string";
|
import { EncString } from "../models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
@@ -373,37 +372,6 @@ export abstract class CryptoService {
|
|||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
*/
|
*/
|
||||||
abstract clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: string): Promise<void>;
|
abstract clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: string): Promise<void>;
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.encrypt
|
|
||||||
*/
|
|
||||||
abstract encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString>;
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.encryptToBytes
|
|
||||||
*/
|
|
||||||
abstract encryptToBytes(
|
|
||||||
plainValue: Uint8Array,
|
|
||||||
key?: SymmetricCryptoKey,
|
|
||||||
): Promise<EncArrayBuffer>;
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToBytes
|
|
||||||
*/
|
|
||||||
abstract decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array>;
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToUtf8
|
|
||||||
*/
|
|
||||||
abstract decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string>;
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToBytes
|
|
||||||
*/
|
|
||||||
abstract decryptFromBytes(
|
|
||||||
encBuffer: EncArrayBuffer,
|
|
||||||
key: SymmetricCryptoKey,
|
|
||||||
): Promise<Uint8Array>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all the keys needed for decrypting Ciphers
|
* Retrieves all the keys needed for decrypting Ciphers
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import { StateService } from "../abstractions/state.service";
|
|||||||
import { KeySuffixOptions, HashPurpose, EncryptionType } from "../enums";
|
import { KeySuffixOptions, HashPurpose, EncryptionType } from "../enums";
|
||||||
import { convertValues } from "../misc/convert-values";
|
import { convertValues } from "../misc/convert-values";
|
||||||
import { EFFLongWordList } from "../misc/wordlist";
|
import { EFFLongWordList } from "../misc/wordlist";
|
||||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
|
||||||
import { EncString, EncryptedString } from "../models/domain/enc-string";
|
import { EncString, EncryptedString } from "../models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
import { ActiveUserState, StateProvider } from "../state";
|
import { ActiveUserState, StateProvider } from "../state";
|
||||||
@@ -859,58 +858,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --DEPRECATED METHODS--
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.encrypt
|
|
||||||
*/
|
|
||||||
async encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString> {
|
|
||||||
key ||= await this.getUserKeyWithLegacySupport();
|
|
||||||
return await this.encryptService.encrypt(plainValue, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.encryptToBytes
|
|
||||||
*/
|
|
||||||
async encryptToBytes(plainValue: Uint8Array, key?: SymmetricCryptoKey): Promise<EncArrayBuffer> {
|
|
||||||
key ||= await this.getUserKeyWithLegacySupport();
|
|
||||||
return this.encryptService.encryptToBytes(plainValue, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToBytes
|
|
||||||
*/
|
|
||||||
async decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array> {
|
|
||||||
key ||= await this.getUserKeyWithLegacySupport();
|
|
||||||
return this.encryptService.decryptToBytes(encString, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToUtf8
|
|
||||||
*/
|
|
||||||
async decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string> {
|
|
||||||
key ||= await this.getUserKeyWithLegacySupport();
|
|
||||||
return await this.encryptService.decryptToUtf8(encString, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
|
||||||
* and then call encryptService.decryptToBytes
|
|
||||||
*/
|
|
||||||
async decryptFromBytes(encBuffer: EncArrayBuffer, key: SymmetricCryptoKey): Promise<Uint8Array> {
|
|
||||||
if (encBuffer == null) {
|
|
||||||
throw new Error("No buffer provided for decryption.");
|
|
||||||
}
|
|
||||||
|
|
||||||
key ||= await this.getUserKeyWithLegacySupport();
|
|
||||||
|
|
||||||
return this.encryptService.decryptToBytes(encBuffer, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
userKey$(userId: UserId): Observable<UserKey> {
|
userKey$(userId: UserId): Observable<UserKey> {
|
||||||
return this.stateProvider.getUser(userId, USER_KEY).state$;
|
return this.stateProvider.getUser(userId, USER_KEY).state$;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user