mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 08:43:33 +00:00
Merge master into merge/feature/org-admin-refresh (using imerge)
This commit is contained in:
@@ -86,7 +86,7 @@
|
|||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"zones": [
|
"zones": [
|
||||||
// Do not allow angular/node/electron code to be imported into common
|
// Do not allow angular/node code to be imported into common
|
||||||
{
|
{
|
||||||
"target": "./libs/common/**/*",
|
"target": "./libs/common/**/*",
|
||||||
"from": "./libs/angular/**/*"
|
"from": "./libs/angular/**/*"
|
||||||
@@ -94,10 +94,6 @@
|
|||||||
{
|
{
|
||||||
"target": "./libs/common/**/*",
|
"target": "./libs/common/**/*",
|
||||||
"from": "./libs/node/**/*"
|
"from": "./libs/node/**/*"
|
||||||
},
|
|
||||||
{
|
|
||||||
"target": "./libs/common/**/*",
|
|
||||||
"from": "./libs/electron/**/*"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -131,12 +127,6 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/node/*", "src/**/*"] }]
|
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/node/*", "src/**/*"] }]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["libs/electron/src/**/*.ts"],
|
|
||||||
"rules": {
|
|
||||||
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/electron/*", "src/**/*"] }]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
84
.github/whitelist-capital-letters.txt
vendored
84
.github/whitelist-capital-letters.txt
vendored
@@ -4,14 +4,10 @@
|
|||||||
./apps/browser/src/safari/desktop/Base.lproj
|
./apps/browser/src/safari/desktop/Base.lproj
|
||||||
./apps/browser/src/services/vaultTimeout
|
./apps/browser/src/services/vaultTimeout
|
||||||
./apps/browser/store/windows/Assets
|
./apps/browser/store/windows/Assets
|
||||||
./apps/desktop/src/models/nativeMessaging
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessagePayloads
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses
|
|
||||||
./libs/common/spec/misc/logInStrategies
|
./libs/common/spec/misc/logInStrategies
|
||||||
./libs/common/src/abstractions/fileDownload
|
./libs/common/src/abstractions/fileDownload
|
||||||
./libs/common/src/abstractions/userVerification
|
./libs/common/src/abstractions/userVerification
|
||||||
./libs/common/src/abstractions/vaultTimeout
|
./libs/common/src/abstractions/vaultTimeout
|
||||||
./libs/common/src/emailForwarders
|
|
||||||
./libs/common/src/misc/logInStrategies
|
./libs/common/src/misc/logInStrategies
|
||||||
./libs/common/src/services/userVerification
|
./libs/common/src/services/userVerification
|
||||||
./libs/common/src/services/vaultTimeout
|
./libs/common/src/services/vaultTimeout
|
||||||
@@ -112,12 +108,6 @@
|
|||||||
./libs/common/src/enums/nativeMessagingVersion.ts
|
./libs/common/src/enums/nativeMessagingVersion.ts
|
||||||
./libs/common/src/enums/cipherRepromptType.ts
|
./libs/common/src/enums/cipherRepromptType.ts
|
||||||
./libs/common/src/enums/organizationUserType.ts
|
./libs/common/src/enums/organizationUserType.ts
|
||||||
./libs/common/src/emailForwarders/fastmailForwarder.ts
|
|
||||||
./libs/common/src/emailForwarders/duckDuckGoForwarder.ts
|
|
||||||
./libs/common/src/emailForwarders/firefoxRelayForwarder.ts
|
|
||||||
./libs/common/src/emailForwarders/anonAddyForwarder.ts
|
|
||||||
./libs/common/src/emailForwarders/simpleLoginForwarder.ts
|
|
||||||
./libs/common/src/emailForwarders/forwarderOptions.ts
|
|
||||||
./libs/common/src/factories/accountFactory.ts
|
./libs/common/src/factories/accountFactory.ts
|
||||||
./libs/common/src/factories/globalStateFactory.ts
|
./libs/common/src/factories/globalStateFactory.ts
|
||||||
./libs/common/src/factories/stateFactory.ts
|
./libs/common/src/factories/stateFactory.ts
|
||||||
@@ -162,27 +152,6 @@
|
|||||||
./libs/common/src/services/bitwardenFileUpload.service.ts
|
./libs/common/src/services/bitwardenFileUpload.service.ts
|
||||||
./libs/common/src/services/webCryptoFunction.service.ts
|
./libs/common/src/services/webCryptoFunction.service.ts
|
||||||
./libs/common/src/interfaces/IEncrypted.ts
|
./libs/common/src/interfaces/IEncrypted.ts
|
||||||
./libs/node/spec/cli/consoleLog.service.spec.ts
|
|
||||||
./libs/node/src/cli/models/response/baseResponse.ts
|
|
||||||
./libs/node/src/cli/models/response/stringResponse.ts
|
|
||||||
./libs/node/src/cli/models/response/fileResponse.ts
|
|
||||||
./libs/node/src/cli/models/response/messageResponse.ts
|
|
||||||
./libs/node/src/cli/models/response/listResponse.ts
|
|
||||||
./libs/node/src/cli/baseProgram.ts
|
|
||||||
./libs/node/src/cli/services/consoleLog.service.ts
|
|
||||||
./libs/node/src/cli/services/cliPlatformUtils.service.ts
|
|
||||||
./libs/node/src/services/nodeApi.service.ts
|
|
||||||
./libs/node/src/services/lowdbStorage.service.ts
|
|
||||||
./libs/electron/spec/services/electronLog.service.spec.ts
|
|
||||||
./libs/electron/src/baseMenu.ts
|
|
||||||
./libs/electron/src/services/electronLog.service.ts
|
|
||||||
./libs/electron/src/services/electronStorage.service.ts
|
|
||||||
./libs/electron/src/services/electronRendererMessaging.service.ts
|
|
||||||
./libs/electron/src/services/electronMainMessaging.service.ts
|
|
||||||
./libs/electron/src/services/electronPlatformUtils.service.ts
|
|
||||||
./libs/electron/src/services/electronRendererStorage.service.ts
|
|
||||||
./libs/electron/src/services/electronCrypto.service.ts
|
|
||||||
./libs/electron/src/services/electronRendererSecureStorage.service.ts
|
|
||||||
./README.md
|
./README.md
|
||||||
./LICENSE_BITWARDEN.txt
|
./LICENSE_BITWARDEN.txt
|
||||||
./CONTRIBUTING.md
|
./CONTRIBUTING.md
|
||||||
@@ -197,64 +166,11 @@
|
|||||||
./apps/desktop/resources/appx/StoreLogo.png
|
./apps/desktop/resources/appx/StoreLogo.png
|
||||||
./apps/desktop/resources/appx/Wide310x150Logo.png
|
./apps/desktop/resources/appx/Wide310x150Logo.png
|
||||||
./apps/desktop/resources/appx/Square44x44Logo.png
|
./apps/desktop/resources/appx/Square44x44Logo.png
|
||||||
./apps/desktop/native-messaging-test-runner/src/ipcService.ts
|
|
||||||
./apps/desktop/native-messaging-test-runner/src/nativeMessageService.ts
|
|
||||||
./apps/desktop/native-messaging-test-runner/src/logUtils.ts
|
|
||||||
./apps/desktop/README.md
|
./apps/desktop/README.md
|
||||||
./apps/desktop/desktop_native/Cargo.toml
|
./apps/desktop/desktop_native/Cargo.toml
|
||||||
./apps/desktop/desktop_native/Cargo.lock
|
./apps/desktop/desktop_native/Cargo.lock
|
||||||
./apps/desktop/src/app/services/desktopFileDownloadService.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/unencryptedCommand.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessage.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/legacyMessageWrapper.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/unencryptedMessage.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/unencryptedMessageResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedCommand.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/successStatusResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/generateResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/failureStatusResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/cannotDecryptErrorResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/userStatusErrorResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/accountStatusResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/encryptedMessageResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessageResponses/cipherResponse.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/decryptedCommandData.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/messageCommon.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/legacyMessage.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessagePayloads/credentialUpdatePayload.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessagePayloads/passwordGeneratePayload.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessagePayloads/credentialCreatePayload.ts
|
|
||||||
./apps/desktop/src/models/nativeMessaging/encryptedMessagePayloads/credentialRetrievePayload.ts
|
|
||||||
./apps/desktop/src/main/desktopCredentialStorageListener.ts
|
|
||||||
./apps/desktop/src/main/powerMonitor.main.ts
|
|
||||||
./apps/desktop/src/main/nativeMessaging.main.ts
|
|
||||||
./apps/desktop/src/services/passwordReprompt.service.ts
|
|
||||||
./apps/desktop/src/services/encryptedMessageHandlerService.ts
|
|
||||||
./apps/desktop/src/services/nativeMessaging.service.ts
|
|
||||||
./apps/desktop/src/services/nativeMessageHandler.service.ts
|
|
||||||
./apps/cli/stores/chocolatey/tools/VERIFICATION.txt
|
./apps/cli/stores/chocolatey/tools/VERIFICATION.txt
|
||||||
./apps/cli/README.md
|
./apps/cli/README.md
|
||||||
./apps/cli/src/models/response/sendFileResponse.ts
|
|
||||||
./apps/cli/src/models/response/organizationCollectionResponse.ts
|
|
||||||
./apps/cli/src/models/response/collectionResponse.ts
|
|
||||||
./apps/cli/src/models/response/templateResponse.ts
|
|
||||||
./apps/cli/src/models/response/passwordHistoryResponse.ts
|
|
||||||
./apps/cli/src/models/response/folderResponse.ts
|
|
||||||
./apps/cli/src/models/response/loginResponse.ts
|
|
||||||
./apps/cli/src/models/response/sendAccessResponse.ts
|
|
||||||
./apps/cli/src/models/response/sendResponse.ts
|
|
||||||
./apps/cli/src/models/response/cipherResponse.ts
|
|
||||||
./apps/cli/src/models/response/organizationResponse.ts
|
|
||||||
./apps/cli/src/models/response/organizationUserResponse.ts
|
|
||||||
./apps/cli/src/models/response/sendTextResponse.ts
|
|
||||||
./apps/cli/src/models/response/attachmentResponse.ts
|
|
||||||
./apps/cli/src/models/selectionReadOnly.ts
|
|
||||||
./apps/cli/src/models/request/organizationCollectionRequest.ts
|
|
||||||
./apps/cli/src/commands/convertToKeyConnector.command.ts
|
|
||||||
./apps/cli/src/commands/send/removePassword.command.ts
|
|
||||||
./apps/cli/src/services/lowdbStorage.service.ts
|
|
||||||
./apps/cli/src/services/nodeEnvSecureStorage.service.ts
|
|
||||||
./apps/browser/README.md
|
./apps/browser/README.md
|
||||||
./apps/browser/store/windows/AppxManifest.xml
|
./apps/browser/store/windows/AppxManifest.xml
|
||||||
./apps/browser/src/background/nativeMessaging.background.ts
|
./apps/browser/src/background/nativeMessaging.background.ts
|
||||||
|
|||||||
4
.github/workflows/build-browser.yml
vendored
4
.github/workflows/build-browser.yml
vendored
@@ -63,8 +63,8 @@ jobs:
|
|||||||
repo_url=https://github.com/$GITHUB_REPOSITORY.git
|
repo_url=https://github.com/$GITHUB_REPOSITORY.git
|
||||||
adj_build_num=${GITHUB_SHA:0:7}
|
adj_build_num=${GITHUB_SHA:0:7}
|
||||||
|
|
||||||
echo "::set-output name=repo_url::$repo_url"
|
echo "repo_url=$repo_url" >> $GITHUB_OUTPUT
|
||||||
echo "::set-output name=adj_build_number::$adj_build_num"
|
echo "adj_build_number=$adj_build_num" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
|
||||||
locales-test:
|
locales-test:
|
||||||
|
|||||||
4
.github/workflows/build-cli.yml
vendored
4
.github/workflows/build-cli.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
|||||||
id: retrieve-version
|
id: retrieve-version
|
||||||
run: |
|
run: |
|
||||||
PKG_VERSION=$(jq -r .version package.json)
|
PKG_VERSION=$(jq -r .version package.json)
|
||||||
echo "::set-output name=package_version::$PKG_VERSION"
|
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
|
||||||
cli:
|
cli:
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
- setup
|
- setup
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
_WIN_PKG_FETCH_VERSION: 16.15.0
|
_WIN_PKG_FETCH_VERSION: 16.16.0
|
||||||
_WIN_PKG_VERSION: 3.4
|
_WIN_PKG_VERSION: 3.4
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
|||||||
18
.github/workflows/build-desktop.yml
vendored
18
.github/workflows/build-desktop.yml
vendored
@@ -87,29 +87,29 @@ jobs:
|
|||||||
id: retrieve-version
|
id: retrieve-version
|
||||||
run: |
|
run: |
|
||||||
PKG_VERSION=$(jq -r .version src/package.json)
|
PKG_VERSION=$(jq -r .version src/package.json)
|
||||||
echo "::set-output name=package_version::$PKG_VERSION"
|
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Increment Version
|
- name: Increment Version
|
||||||
id: increment-version
|
id: increment-version
|
||||||
run: |
|
run: |
|
||||||
BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
|
BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
|
||||||
echo "Setting build number to $BUILD_NUMBER"
|
echo "Setting build number to $BUILD_NUMBER"
|
||||||
echo "::set-output name=build_number::$BUILD_NUMBER"
|
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Get Version Channel
|
- name: Get Version Channel
|
||||||
id: release-channel
|
id: release-channel
|
||||||
run: |
|
run: |
|
||||||
case "${{ steps.retrieve-version.outputs.package_version }}" in
|
case "${{ steps.retrieve-version.outputs.package_version }}" in
|
||||||
*"alpha"*)
|
*"alpha"*)
|
||||||
echo "::set-output name=channel::alpha"
|
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||||
echo "[!] We do not yet support 'alpha'"
|
echo "[!] We do not yet support 'alpha'"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
*"beta"*)
|
*"beta"*)
|
||||||
echo "::set-output name=channel::beta"
|
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "::set-output name=channel::latest"
|
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -117,15 +117,15 @@ jobs:
|
|||||||
id: branch-check
|
id: branch-check
|
||||||
run: |
|
run: |
|
||||||
if [[ $(git ls-remote --heads origin rc) ]]; then
|
if [[ $(git ls-remote --heads origin rc) ]]; then
|
||||||
echo "::set-output name=rc_branch_exists::1"
|
echo "rc_branch_exists=1" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "::set-output name=rc_branch_exists::0"
|
echo "rc_branch_exists=0" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $(git ls-remote --heads origin hotfix-rc-desktop) ]]; then
|
if [[ $(git ls-remote --heads origin hotfix-rc-desktop) ]]; then
|
||||||
echo "::set-output name=hotfix_branch_exists::1"
|
echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "::set-output name=hotfix_branch_exists::0"
|
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/build-web.yml
vendored
6
.github/workflows/build-web.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Get GitHub sha as version
|
- name: Get GitHub sha as version
|
||||||
id: version
|
id: version
|
||||||
run: echo "::set-output name=value::${GITHUB_SHA:0:7}"
|
run: echo "value=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
build-artifacts:
|
build-artifacts:
|
||||||
name: Build artifacts
|
name: Build artifacts
|
||||||
@@ -112,7 +112,7 @@ jobs:
|
|||||||
if: matrix.name == 'cloud-QA'
|
if: matrix.name == 'cloud-QA'
|
||||||
run: |
|
run: |
|
||||||
VERSION=$( jq -r ".version" package.json)
|
VERSION=$( jq -r ".version" package.json)
|
||||||
jq --arg version "$VERSION - ${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp
|
jq --arg version "$VERSION+${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp
|
||||||
mv package.json.tmp package.json
|
mv package.json.tmp package.json
|
||||||
|
|
||||||
- name: Build ${{ matrix.name }}
|
- name: Build ${{ matrix.name }}
|
||||||
@@ -303,7 +303,7 @@ jobs:
|
|||||||
IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION
|
IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "::set-output name=value::$IMAGE_TAG"
|
echo "value=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Tag image
|
- name: Tag image
|
||||||
env:
|
env:
|
||||||
|
|||||||
10
.github/workflows/release-desktop-beta.yml
vendored
10
.github/workflows/release-desktop-beta.yml
vendored
@@ -60,22 +60,22 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
|
BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
|
||||||
echo "Setting build number to $BUILD_NUMBER"
|
echo "Setting build number to $BUILD_NUMBER"
|
||||||
echo "::set-output name=build_number::$BUILD_NUMBER"
|
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Get Version Channel
|
- name: Get Version Channel
|
||||||
id: release-channel
|
id: release-channel
|
||||||
run: |
|
run: |
|
||||||
case "${{ steps.version.outputs.version }}" in
|
case "${{ steps.version.outputs.version }}" in
|
||||||
*"alpha"*)
|
*"alpha"*)
|
||||||
echo "::set-output name=channel::alpha"
|
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||||
echo "[!] We do not yet support 'alpha'"
|
echo "[!] We do not yet support 'alpha'"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
*"beta"*)
|
*"beta"*)
|
||||||
echo "::set-output name=channel::beta"
|
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "::set-output name=channel::latest"
|
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
|
|
||||||
git push -u origin $branch_name
|
git push -u origin $branch_name
|
||||||
|
|
||||||
echo "::set-output name=branch-name::$branch_name"
|
echo "branch-name=$branch_name" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
name: Linux Build
|
name: Linux Build
|
||||||
|
|||||||
23
.github/workflows/release-desktop.yml
vendored
23
.github/workflows/release-desktop.yml
vendored
@@ -29,6 +29,16 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
default: true
|
default: true
|
||||||
type: boolean
|
type: boolean
|
||||||
|
electron_publish:
|
||||||
|
description: 'Publish electron to S3 bucket'
|
||||||
|
required: true
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
github_release:
|
||||||
|
description: 'Publish github release'
|
||||||
|
required: true
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -70,15 +80,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
case "${{ steps.version.outputs.version }}" in
|
case "${{ steps.version.outputs.version }}" in
|
||||||
*"alpha"*)
|
*"alpha"*)
|
||||||
echo "::set-output name=channel::alpha"
|
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||||
echo "[!] We do not yet support 'alpha'"
|
echo "[!] We do not yet support 'alpha'"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
*"beta"*)
|
*"beta"*)
|
||||||
echo "::set-output name=channel::beta"
|
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "::set-output name=channel::latest"
|
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -136,6 +146,7 @@ jobs:
|
|||||||
run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive
|
run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive
|
||||||
|
|
||||||
- name: Set staged rollout percentage
|
- name: Set staged rollout percentage
|
||||||
|
if: ${{ github.event.inputs.electron_publish }}
|
||||||
env:
|
env:
|
||||||
RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }}
|
RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }}
|
||||||
ROLLOUT_PCT: ${{ github.event.inputs.rollout_percentage }}
|
ROLLOUT_PCT: ${{ github.event.inputs.rollout_percentage }}
|
||||||
@@ -145,7 +156,7 @@ jobs:
|
|||||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-mac.yml
|
echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-mac.yml
|
||||||
|
|
||||||
- name: Publish artifacts to S3
|
- name: Publish artifacts to S3
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' && github.event.inputs.electron_publish }}
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }}
|
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
|
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
|
||||||
@@ -159,7 +170,7 @@ jobs:
|
|||||||
--quiet
|
--quiet
|
||||||
|
|
||||||
- name: Publish artifacts to R2
|
- name: Publish artifacts to R2
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' && github.event.inputs.electron_publish }}
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }}
|
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }}
|
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }}
|
||||||
@@ -175,7 +186,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09
|
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09
|
||||||
if: ${{ steps.release-channel.outputs.channel == 'latest' && github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ steps.release-channel.outputs.channel == 'latest' && github.event.inputs.release_type != 'Dry Run' && github.event.inputs.github_release }}
|
||||||
env:
|
env:
|
||||||
PKG_VERSION: ${{ steps.version.outputs.version }}
|
PKG_VERSION: ${{ steps.version.outputs.version }}
|
||||||
RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }}
|
RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }}
|
||||||
|
|||||||
38
.github/workflows/staged-rollout-desktop.yml
vendored
38
.github/workflows/staged-rollout-desktop.yml
vendored
@@ -54,20 +54,6 @@ jobs:
|
|||||||
r2-electron-bucket-name,
|
r2-electron-bucket-name,
|
||||||
cf-prod-account"
|
cf-prod-account"
|
||||||
|
|
||||||
- name: Download channel update info files from S3
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
|
|
||||||
AWS_DEFAULT_REGION: 'us-west-2'
|
|
||||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
|
||||||
run: |
|
|
||||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . \
|
|
||||||
--quiet
|
|
||||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-linux.yml . \
|
|
||||||
--quiet
|
|
||||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-mac.yml . \
|
|
||||||
--quiet
|
|
||||||
|
|
||||||
- name: Download channel update info files from R2
|
- name: Download channel update info files from R2
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }}
|
AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }}
|
||||||
@@ -99,7 +85,7 @@ jobs:
|
|||||||
echo
|
echo
|
||||||
echo "If you want to pull a staged release because it hasn’t gone well, you must increment the version \
|
echo "If you want to pull a staged release because it hasn’t gone well, you must increment the version \
|
||||||
number higher than your broken release. Because some of your users will be on the broken 1.0.1, \
|
number higher than your broken release. Because some of your users will be on the broken 1.0.1, \
|
||||||
releasing a new 1.0.1 would result in them staying on a broken version.”
|
releasing a new 1.0.1 would result in them staying on a broken version."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -118,10 +104,14 @@ jobs:
|
|||||||
AWS_DEFAULT_REGION: 'us-west-2'
|
AWS_DEFAULT_REGION: 'us-west-2'
|
||||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
||||||
run: |
|
run: |
|
||||||
aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \
|
aws s3 cp latest.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
--include "latest*.yml" \
|
--acl "public-read"
|
||||||
--acl "public-read" \
|
|
||||||
--quiet
|
aws s3 cp latest-linux.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
|
--acl "public-read"
|
||||||
|
|
||||||
|
aws s3 cp latest-mac.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
|
--acl "public-read"
|
||||||
|
|
||||||
- name: Publish channel update info files to R2
|
- name: Publish channel update info files to R2
|
||||||
env:
|
env:
|
||||||
@@ -131,7 +121,11 @@ jobs:
|
|||||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }}
|
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }}
|
||||||
CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }}
|
CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }}
|
||||||
run: |
|
run: |
|
||||||
aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \
|
aws s3 cp latest.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
--include "latest*.yml" \
|
--endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com
|
||||||
--quiet \
|
|
||||||
|
aws s3 cp latest-linux.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
|
--endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com
|
||||||
|
|
||||||
|
aws s3 cp latest-mac.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||||
--endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com
|
--endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com
|
||||||
|
|||||||
2
.github/workflows/version-auto-bump.yml
vendored
2
.github/workflows/version-auto-bump.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
|
|
||||||
NEW_VER=$CURR_MAJOR.$NEW_PATCH
|
NEW_VER=$CURR_MAJOR.$NEW_PATCH
|
||||||
echo "New Version: $NEW_VER"
|
echo "New Version: $NEW_VER"
|
||||||
echo "::set-output name=new-version::$NEW_VER"
|
echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
trigger_version_bump:
|
trigger_version_bump:
|
||||||
name: "Trigger desktop version bump workflow"
|
name: "Trigger desktop version bump workflow"
|
||||||
|
|||||||
9
.github/workflows/version-bump.yml
vendored
9
.github/workflows/version-bump.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
|||||||
VERSION: ${{ github.event.inputs.version_number }}
|
VERSION: ${{ github.event.inputs.version_number }}
|
||||||
run: |
|
run: |
|
||||||
CLIENT=$(python -c "print('$CLIENT_NAME'.lower())")
|
CLIENT=$(python -c "print('$CLIENT_NAME'.lower())")
|
||||||
echo "::set-output name=client::$CLIENT"
|
echo "client=$CLIENT" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
git switch -c ${CLIENT}_version_bump_${VERSION}
|
git switch -c ${CLIENT}_version_bump_${VERSION}
|
||||||
|
|
||||||
@@ -131,9 +131,9 @@ jobs:
|
|||||||
id: version-changed
|
id: version-changed
|
||||||
run: |
|
run: |
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
echo "::set-output name=changes_to_commit::TRUE"
|
echo "changes_to_commit=TRUE" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "::set-output name=changes_to_commit::FALSE"
|
echo "changes_to_commit=FALSE" >> $GITHUB_OUTPUT
|
||||||
echo "No changes to commit!";
|
echo "No changes to commit!";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -142,8 +142,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CLIENT: ${{ steps.branch.outputs.client }}
|
CLIENT: ${{ steps.branch.outputs.client }}
|
||||||
VERSION: ${{ github.event.inputs.version_number }}
|
VERSION: ${{ github.event.inputs.version_number }}
|
||||||
run: |
|
run: git commit -m "Bumped ${CLIENT} version to ${VERSION}" -a
|
||||||
git commit -m "Bumped ${CLIENT} version to ${VERSION}" -a
|
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ module.exports = {
|
|||||||
"../libs/components/src/**/*.stories.@(js|jsx|ts|tsx)",
|
"../libs/components/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||||
"../apps/web/src/**/*.stories.mdx",
|
"../apps/web/src/**/*.stories.mdx",
|
||||||
"../apps/web/src/**/*.stories.@(js|jsx|ts|tsx)",
|
"../apps/web/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||||
|
"../bitwarden_license/bit-web/src/**/*.stories.mdx",
|
||||||
|
"../bitwarden_license/bit-web/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||||
],
|
],
|
||||||
addons: [
|
addons: [
|
||||||
"@storybook/addon-links",
|
"@storybook/addon-links",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
This repository houses all Bitwarden client applications except the [Mobile application](https://github.com/bitwarden/mobile).
|
This repository houses all Bitwarden client applications except the [Mobile application](https://github.com/bitwarden/mobile).
|
||||||
|
|
||||||
Please refer to the [Clients section](https://contributing.bitwarden.com/clients/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
Please refer to the [Clients section](https://contributing.bitwarden.com/getting-started/clients/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
||||||
|
|
||||||
## Related projects:
|
## Related projects:
|
||||||
|
|
||||||
|
|||||||
@@ -19,4 +19,4 @@ The Bitwarden browser extension is written using the Web Extension API and Angul
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Please refer to the [Browser section](https://contributing.bitwarden.com/clients/browser/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
Please refer to the [Browser section](https://contributing.bitwarden.com/getting-started/clients/browser/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
||||||
|
|||||||
@@ -482,7 +482,7 @@
|
|||||||
"message": "الاسم مطلوب."
|
"message": "الاسم مطلوب."
|
||||||
},
|
},
|
||||||
"addedFolder": {
|
"addedFolder": {
|
||||||
"message": "Folder added"
|
"message": "أُضيف المجلد"
|
||||||
},
|
},
|
||||||
"changeMasterPass": {
|
"changeMasterPass": {
|
||||||
"message": "تغيير كلمة المرور الرئيسية"
|
"message": "تغيير كلمة المرور الرئيسية"
|
||||||
@@ -494,7 +494,7 @@
|
|||||||
"message": "تسجيل الدخول بخطوتين يجعل حسابك أكثر أمنا من خلال مطالبتك بالتحقق من تسجيل الدخول باستخدام جهاز آخر مثل مفتاح الأمان، تطبيق المصادقة، الرسائل القصيرة، المكالمة الهاتفية، أو البريد الإلكتروني. يمكن تمكين تسجيل الدخول بخطوتين على خزنة الويب bitwarden.com. هل تريد زيارة الموقع الآن؟"
|
"message": "تسجيل الدخول بخطوتين يجعل حسابك أكثر أمنا من خلال مطالبتك بالتحقق من تسجيل الدخول باستخدام جهاز آخر مثل مفتاح الأمان، تطبيق المصادقة، الرسائل القصيرة، المكالمة الهاتفية، أو البريد الإلكتروني. يمكن تمكين تسجيل الدخول بخطوتين على خزنة الويب bitwarden.com. هل تريد زيارة الموقع الآن؟"
|
||||||
},
|
},
|
||||||
"editedFolder": {
|
"editedFolder": {
|
||||||
"message": "Folder saved"
|
"message": "حُفظ المجلد"
|
||||||
},
|
},
|
||||||
"deleteFolderConfirmation": {
|
"deleteFolderConfirmation": {
|
||||||
"message": "هل أنت متأكد من حذف هذا المجلّد؟"
|
"message": "هل أنت متأكد من حذف هذا المجلّد؟"
|
||||||
@@ -521,7 +521,7 @@
|
|||||||
"message": "عنوان الـ URI"
|
"message": "عنوان الـ URI"
|
||||||
},
|
},
|
||||||
"uriPosition": {
|
"uriPosition": {
|
||||||
"message": "URI $POSITION$",
|
"message": "رابط $POSITION$",
|
||||||
"description": "A listing of URIs. Ex: URI 1, URI 2, URI 3, etc.",
|
"description": "A listing of URIs. Ex: URI 1, URI 2, URI 3, etc.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"position": {
|
"position": {
|
||||||
@@ -571,13 +571,13 @@
|
|||||||
"description": "This is the folder for uncategorized items"
|
"description": "This is the folder for uncategorized items"
|
||||||
},
|
},
|
||||||
"enableAddLoginNotification": {
|
"enableAddLoginNotification": {
|
||||||
"message": "Ask to add login"
|
"message": "اطلب إضافة تسجيل الدخول"
|
||||||
},
|
},
|
||||||
"addLoginNotificationDesc": {
|
"addLoginNotificationDesc": {
|
||||||
"message": "Ask to add an item if one isn't found in your vault."
|
"message": "اطلب إضافة عنصر إذا لم يُعثر عليه في خزنتك."
|
||||||
},
|
},
|
||||||
"showCardsCurrentTab": {
|
"showCardsCurrentTab": {
|
||||||
"message": "Show cards on Tab page"
|
"message": "أظهر البطاقات في صفحة التبويبات"
|
||||||
},
|
},
|
||||||
"showCardsCurrentTabDesc": {
|
"showCardsCurrentTabDesc": {
|
||||||
"message": "List card items on the Tab page for easy auto-fill."
|
"message": "List card items on the Tab page for easy auto-fill."
|
||||||
|
|||||||
@@ -153,7 +153,7 @@
|
|||||||
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
||||||
},
|
},
|
||||||
"yourAccountsFingerprint": {
|
"yourAccountsFingerprint": {
|
||||||
"message": "Fráze otisku prstu vašeho účtu",
|
"message": "Fráze otisku vašeho účtu",
|
||||||
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
||||||
},
|
},
|
||||||
"twoStepLogin": {
|
"twoStepLogin": {
|
||||||
@@ -606,7 +606,7 @@
|
|||||||
"message": "Zeptat se na aktualizaci existujícího přihlášení"
|
"message": "Zeptat se na aktualizaci existujícího přihlášení"
|
||||||
},
|
},
|
||||||
"changedPasswordNotificationDesc": {
|
"changedPasswordNotificationDesc": {
|
||||||
"message": "Ask to update a login's password when a change is detected on a website."
|
"message": "Dotázat se na aktualizaci hesla pro přihlášení, pokud je na webové stránce zjištěno použití jiného hesla."
|
||||||
},
|
},
|
||||||
"notificationChangeDesc": {
|
"notificationChangeDesc": {
|
||||||
"message": "Chcete aktualizovat toto heslo v Bitwarden?"
|
"message": "Chcete aktualizovat toto heslo v Bitwarden?"
|
||||||
@@ -618,7 +618,7 @@
|
|||||||
"message": "Zobrazit v kontextovém menu"
|
"message": "Zobrazit v kontextovém menu"
|
||||||
},
|
},
|
||||||
"contextMenuItemDesc": {
|
"contextMenuItemDesc": {
|
||||||
"message": "Use a secondary click to access password generation and matching logins for the website. "
|
"message": "Použijte pravé tlačítko pro přístup k vytvoření hesla a odpovídajícímu přihlášení pro tuto stránku. "
|
||||||
},
|
},
|
||||||
"defaultUriMatchDetection": {
|
"defaultUriMatchDetection": {
|
||||||
"message": "Výchozí zjišťování shody URI",
|
"message": "Výchozí zjišťování shody URI",
|
||||||
@@ -1043,10 +1043,10 @@
|
|||||||
"message": "Zobrazit rozeznatelný obrázek vedle každého přihlášení."
|
"message": "Zobrazit rozeznatelný obrázek vedle každého přihlášení."
|
||||||
},
|
},
|
||||||
"enableBadgeCounter": {
|
"enableBadgeCounter": {
|
||||||
"message": "Show badge counter"
|
"message": "Zobrazovat počet uložených přihlašovacích údajů na stránce"
|
||||||
},
|
},
|
||||||
"badgeCounterDesc": {
|
"badgeCounterDesc": {
|
||||||
"message": "Zobrazit počet přihlašovacích údajů pro aktuální webovou stránku."
|
"message": "Zobrazit počet přihlašovacích údajů pro aktuální webovou stránku na ikoně rozšíření prohlížeče."
|
||||||
},
|
},
|
||||||
"cardholderName": {
|
"cardholderName": {
|
||||||
"message": "Jméno držitele karty"
|
"message": "Jméno držitele karty"
|
||||||
@@ -1632,7 +1632,7 @@
|
|||||||
"message": "Odstraněné heslo"
|
"message": "Odstraněné heslo"
|
||||||
},
|
},
|
||||||
"deletedSend": {
|
"deletedSend": {
|
||||||
"message": "Smazaný Send",
|
"message": "Send odstraněn",
|
||||||
"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."
|
||||||
},
|
},
|
||||||
"sendLink": {
|
"sendLink": {
|
||||||
@@ -1899,10 +1899,10 @@
|
|||||||
"message": "Vypršel časový limit relace. Vraťte se prosím zpět a zkuste se znovu přihlásit."
|
"message": "Vypršel časový limit relace. Vraťte se prosím zpět a zkuste se znovu přihlásit."
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultTitle": {
|
"exportingPersonalVaultTitle": {
|
||||||
"message": "Exporting individual vault"
|
"message": "Export mého trezoru"
|
||||||
},
|
},
|
||||||
"exportingPersonalVaultDescription": {
|
"exportingPersonalVaultDescription": {
|
||||||
"message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.",
|
"message": "Budou exportovány pouze položky trezoru spojené s účtem $EMAIL$. Nebudou zahrnuty položky trezoru v organizaci.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"email": {
|
"email": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -1970,16 +1970,16 @@
|
|||||||
"message": "API klíč"
|
"message": "API klíč"
|
||||||
},
|
},
|
||||||
"ssoKeyConnectorError": {
|
"ssoKeyConnectorError": {
|
||||||
"message": "Key connector error: make sure key connector is available and working correctly."
|
"message": "Chyba Key Connector: ujistěte se, že je Key Connector k dispozici a funguje správně."
|
||||||
},
|
},
|
||||||
"premiumSubcriptionRequired": {
|
"premiumSubcriptionRequired": {
|
||||||
"message": "Vyžadováno prémiové předplatné"
|
"message": "Vyžadováno prémiové předplatné"
|
||||||
},
|
},
|
||||||
"organizationIsDisabled": {
|
"organizationIsDisabled": {
|
||||||
"message": "Organization suspended."
|
"message": "Organizace je deaktivována."
|
||||||
},
|
},
|
||||||
"disabledOrganizationFilterError": {
|
"disabledOrganizationFilterError": {
|
||||||
"message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance."
|
"message": "K položkám v deaktivované organizaci nemáte přístup. Požádejte o pomoc vlastníka organizace."
|
||||||
},
|
},
|
||||||
"cardBrandMir": {
|
"cardBrandMir": {
|
||||||
"message": "Mir"
|
"message": "Mir"
|
||||||
@@ -2000,19 +2000,19 @@
|
|||||||
"message": "Klikněte zde"
|
"message": "Klikněte zde"
|
||||||
},
|
},
|
||||||
"environmentEditedReset": {
|
"environmentEditedReset": {
|
||||||
"message": "to reset to pre-configured settings"
|
"message": "pro obnovení do přednastavených nastavení"
|
||||||
},
|
},
|
||||||
"serverVersion": {
|
"serverVersion": {
|
||||||
"message": "Verze serveru"
|
"message": "Verze serveru"
|
||||||
},
|
},
|
||||||
"selfHosted": {
|
"selfHosted": {
|
||||||
"message": "Self-hosted"
|
"message": "Vlastní hosting"
|
||||||
},
|
},
|
||||||
"thirdParty": {
|
"thirdParty": {
|
||||||
"message": "Third-party"
|
"message": "Tretí strana"
|
||||||
},
|
},
|
||||||
"thirdPartyServerMessage": {
|
"thirdPartyServerMessage": {
|
||||||
"message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.",
|
"message": "Připojeno k serveru třetí strany $SERVERNAME$. Ověřte chyby připojením na oficiální server nebo nahlaste problém správci serveru.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"servername": {
|
"servername": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
"message": "My vault"
|
"message": "My vault"
|
||||||
},
|
},
|
||||||
"allVaults": {
|
"allVaults": {
|
||||||
"message": "All Vaults"
|
"message": "All vaults"
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
"message": "Tools"
|
"message": "Tools"
|
||||||
@@ -92,13 +92,13 @@
|
|||||||
"message": "Auto-fill"
|
"message": "Auto-fill"
|
||||||
},
|
},
|
||||||
"generatePasswordCopied": {
|
"generatePasswordCopied": {
|
||||||
"message": "Generate Password (and Copy)"
|
"message": "Generate password (copied)"
|
||||||
},
|
},
|
||||||
"copyElementIdentifier": {
|
"copyElementIdentifier": {
|
||||||
"message": "Copy Custom Field Name"
|
"message": "Copy custom field name"
|
||||||
},
|
},
|
||||||
"noMatchingLogins": {
|
"noMatchingLogins": {
|
||||||
"message": "No matching logins."
|
"message": "No matching logins"
|
||||||
},
|
},
|
||||||
"unlockVaultMenu": {
|
"unlockVaultMenu": {
|
||||||
"message": "Unlock your vault"
|
"message": "Unlock your vault"
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"message": "Uusi pääsalasanasi ei täytä käytännön määrittämiä vaatimuksia."
|
"message": "Uusi pääsalasanasi ei täytä käytännön määrittämiä vaatimuksia."
|
||||||
},
|
},
|
||||||
"acceptPolicies": {
|
"acceptPolicies": {
|
||||||
"message": "Valitsemalla tämän ruudun hyväksyt seuraavat:"
|
"message": "Valitsemalla tämän hyväksyt seuraavat:"
|
||||||
},
|
},
|
||||||
"acceptPoliciesRequired": {
|
"acceptPoliciesRequired": {
|
||||||
"message": "Palveluehtoja ja tietosuojakäytäntöä ei ole vahvistettu."
|
"message": "Palveluehtoja ja tietosuojakäytäntöä ei ole vahvistettu."
|
||||||
|
|||||||
@@ -577,16 +577,16 @@
|
|||||||
"message": "La \"Notification de demande d'ajout d'identifiant\" apparait automatiquement pour vous demander d'enregistrer dans votre coffre les identifiants que vous utilisez pour la première fois."
|
"message": "La \"Notification de demande d'ajout d'identifiant\" apparait automatiquement pour vous demander d'enregistrer dans votre coffre les identifiants que vous utilisez pour la première fois."
|
||||||
},
|
},
|
||||||
"showCardsCurrentTab": {
|
"showCardsCurrentTab": {
|
||||||
"message": "Show cards on Tab page"
|
"message": "Afficher les cartes sur la page de l'onglet"
|
||||||
},
|
},
|
||||||
"showCardsCurrentTabDesc": {
|
"showCardsCurrentTabDesc": {
|
||||||
"message": "List card items on the Tab page for easy auto-fill."
|
"message": "Lister les éléments de la carte sur la page de l'onglet pour faciliter le remplissage automatique."
|
||||||
},
|
},
|
||||||
"showIdentitiesCurrentTab": {
|
"showIdentitiesCurrentTab": {
|
||||||
"message": "Show identities on Tab page"
|
"message": "Afficher les identités sur la page Onglet courant"
|
||||||
},
|
},
|
||||||
"showIdentitiesCurrentTabDesc": {
|
"showIdentitiesCurrentTabDesc": {
|
||||||
"message": "List identity items on the Tab page for easy auto-fill."
|
"message": "Lister les éléments d'identité sur la page de l'onglet pour faciliter le remplissage automatique."
|
||||||
},
|
},
|
||||||
"clearClipboard": {
|
"clearClipboard": {
|
||||||
"message": "Effacer le presse-papiers",
|
"message": "Effacer le presse-papiers",
|
||||||
@@ -618,7 +618,7 @@
|
|||||||
"message": "Afficher les options du menu contextuel"
|
"message": "Afficher les options du menu contextuel"
|
||||||
},
|
},
|
||||||
"contextMenuItemDesc": {
|
"contextMenuItemDesc": {
|
||||||
"message": "Use a secondary click to access password generation and matching logins for the website. "
|
"message": "Utilisez un clic secondaire pour accéder à la génération de mots de passe et les identifiants correspondants pour le site Web. "
|
||||||
},
|
},
|
||||||
"defaultUriMatchDetection": {
|
"defaultUriMatchDetection": {
|
||||||
"message": "Détection de correspondance URI par défaut",
|
"message": "Détection de correspondance URI par défaut",
|
||||||
@@ -816,7 +816,7 @@
|
|||||||
"message": "Si une clé d'authentification est rattachée à votre identifiant, alors le code de vérification TOTP est automatiquement copié dans le presse-papiers lorsque vous renseignez l'identifiant."
|
"message": "Si une clé d'authentification est rattachée à votre identifiant, alors le code de vérification TOTP est automatiquement copié dans le presse-papiers lorsque vous renseignez l'identifiant."
|
||||||
},
|
},
|
||||||
"enableAutoBiometricsPrompt": {
|
"enableAutoBiometricsPrompt": {
|
||||||
"message": "Ask for biometrics on launch"
|
"message": "Demander la biométrie au lancement"
|
||||||
},
|
},
|
||||||
"premiumRequired": {
|
"premiumRequired": {
|
||||||
"message": "Version Premium requise"
|
"message": "Version Premium requise"
|
||||||
@@ -1043,10 +1043,10 @@
|
|||||||
"message": "Afficher une image reconnaissable à côté de chaque identifiant."
|
"message": "Afficher une image reconnaissable à côté de chaque identifiant."
|
||||||
},
|
},
|
||||||
"enableBadgeCounter": {
|
"enableBadgeCounter": {
|
||||||
"message": "Show badge counter"
|
"message": "Afficher le compteur de badge"
|
||||||
},
|
},
|
||||||
"badgeCounterDesc": {
|
"badgeCounterDesc": {
|
||||||
"message": "Indicate how many logins you have for the current web page."
|
"message": "Indique le nombre d'identifiants que vous avez pour la page web actuelle."
|
||||||
},
|
},
|
||||||
"cardholderName": {
|
"cardholderName": {
|
||||||
"message": "Nom du titulaire de la carte"
|
"message": "Nom du titulaire de la carte"
|
||||||
@@ -2000,19 +2000,19 @@
|
|||||||
"message": "Cliquez ici"
|
"message": "Cliquez ici"
|
||||||
},
|
},
|
||||||
"environmentEditedReset": {
|
"environmentEditedReset": {
|
||||||
"message": "to reset to pre-configured settings"
|
"message": "pour réinitialiser aux paramètres par défaut"
|
||||||
},
|
},
|
||||||
"serverVersion": {
|
"serverVersion": {
|
||||||
"message": "Server version"
|
"message": "Version du serveur"
|
||||||
},
|
},
|
||||||
"selfHosted": {
|
"selfHosted": {
|
||||||
"message": "Auto-hébergé"
|
"message": "Auto-hébergé"
|
||||||
},
|
},
|
||||||
"thirdParty": {
|
"thirdParty": {
|
||||||
"message": "Third-party"
|
"message": "Tierce partie"
|
||||||
},
|
},
|
||||||
"thirdPartyServerMessage": {
|
"thirdPartyServerMessage": {
|
||||||
"message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.",
|
"message": "Connecté à l'implémentation du serveur tiers, $SERVERNAME$. Veuillez contrôler les bugs en utilisant le serveur officiel, ou rapportez-les au serveur tiers.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"servername": {
|
"servername": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2021,7 +2021,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lastSeenOn": {
|
"lastSeenOn": {
|
||||||
"message": "last seen on: $DATE$",
|
"message": "vu pour la dernière fois le : $DATE$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"date": {
|
"date": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -2030,10 +2030,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loginWithMasterPassword": {
|
"loginWithMasterPassword": {
|
||||||
"message": "Log in with master password"
|
"message": "Connectez-vous avec le mot de passe maître"
|
||||||
},
|
},
|
||||||
"loggingInAs": {
|
"loggingInAs": {
|
||||||
"message": "Logging in as"
|
"message": "Connexion en tant que"
|
||||||
},
|
},
|
||||||
"notYou": {
|
"notYou": {
|
||||||
"message": "Ce n'est pas vous ?"
|
"message": "Ce n'est pas vous ?"
|
||||||
@@ -2042,6 +2042,6 @@
|
|||||||
"message": "Êtes-vous nouveau ici ?"
|
"message": "Êtes-vous nouveau ici ?"
|
||||||
},
|
},
|
||||||
"rememberEmail": {
|
"rememberEmail": {
|
||||||
"message": "Remember email"
|
"message": "Se souvenir de l'e-mail"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2042,6 +2042,6 @@
|
|||||||
"message": "Jesteś tu nowy(a)?"
|
"message": "Jesteś tu nowy(a)?"
|
||||||
},
|
},
|
||||||
"rememberEmail": {
|
"rememberEmail": {
|
||||||
"message": "Zapamiętaj email"
|
"message": "Zapamiętaj adres e-mail"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -642,7 +642,7 @@
|
|||||||
"description": "Light color"
|
"description": "Light color"
|
||||||
},
|
},
|
||||||
"solarizedDark": {
|
"solarizedDark": {
|
||||||
"message": "Солнечная темная",
|
"message": "Solarized dark",
|
||||||
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
|
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
|
||||||
},
|
},
|
||||||
"exportVault": {
|
"exportVault": {
|
||||||
@@ -921,7 +921,7 @@
|
|||||||
"message": "Коды подтверждения будут отправлены вам по электронной почте."
|
"message": "Коды подтверждения будут отправлены вам по электронной почте."
|
||||||
},
|
},
|
||||||
"selfHostedEnvironment": {
|
"selfHostedEnvironment": {
|
||||||
"message": "Окружение собственного хостинга"
|
"message": "Окружение пользовательского хостинга"
|
||||||
},
|
},
|
||||||
"selfHostedEnvironmentFooter": {
|
"selfHostedEnvironmentFooter": {
|
||||||
"message": "Укажите URL Bitwarden на вашем сервере."
|
"message": "Укажите URL Bitwarden на вашем сервере."
|
||||||
@@ -1396,7 +1396,7 @@
|
|||||||
"message": "Действие по тайм-ауту хранилища"
|
"message": "Действие по тайм-ауту хранилища"
|
||||||
},
|
},
|
||||||
"lock": {
|
"lock": {
|
||||||
"message": "Заблокировать",
|
"message": "Блокировка",
|
||||||
"description": "Verb form: to make secure or inaccesible by"
|
"description": "Verb form: to make secure or inaccesible by"
|
||||||
},
|
},
|
||||||
"trash": {
|
"trash": {
|
||||||
|
|||||||
@@ -53,13 +53,13 @@
|
|||||||
"message": "Zavihek"
|
"message": "Zavihek"
|
||||||
},
|
},
|
||||||
"vault": {
|
"vault": {
|
||||||
"message": "Sef"
|
"message": "Trezor"
|
||||||
},
|
},
|
||||||
"myVault": {
|
"myVault": {
|
||||||
"message": "Moj trezor"
|
"message": "Moj trezor"
|
||||||
},
|
},
|
||||||
"allVaults": {
|
"allVaults": {
|
||||||
"message": "All vaults"
|
"message": "Vsi trezorji"
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
"message": "Orodja"
|
"message": "Orodja"
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
"message": "Nobenih ujemajočih prijav."
|
"message": "Nobenih ujemajočih prijav."
|
||||||
},
|
},
|
||||||
"unlockVaultMenu": {
|
"unlockVaultMenu": {
|
||||||
"message": "Unlock your vault"
|
"message": "Odkleni svoj trezor"
|
||||||
},
|
},
|
||||||
"loginToVaultMenu": {
|
"loginToVaultMenu": {
|
||||||
"message": "Log in to your vault"
|
"message": "Log in to your vault"
|
||||||
@@ -131,10 +131,10 @@
|
|||||||
"message": "Send a verification code to your email"
|
"message": "Send a verification code to your email"
|
||||||
},
|
},
|
||||||
"sendCode": {
|
"sendCode": {
|
||||||
"message": "Send code"
|
"message": "Pošlji kodo"
|
||||||
},
|
},
|
||||||
"codeSent": {
|
"codeSent": {
|
||||||
"message": "Code sent"
|
"message": "Koda poslana"
|
||||||
},
|
},
|
||||||
"verificationCode": {
|
"verificationCode": {
|
||||||
"message": "Verifikacijska koda"
|
"message": "Verifikacijska koda"
|
||||||
@@ -242,10 +242,10 @@
|
|||||||
"message": "Lowercase (a-z)"
|
"message": "Lowercase (a-z)"
|
||||||
},
|
},
|
||||||
"numbers": {
|
"numbers": {
|
||||||
"message": "Numbers (0-9)"
|
"message": "Številke (0-9)"
|
||||||
},
|
},
|
||||||
"specialCharacters": {
|
"specialCharacters": {
|
||||||
"message": "Special characters (!@#$%^&*)"
|
"message": "Posebni znaki (!@#$%^&*)"
|
||||||
},
|
},
|
||||||
"numWords": {
|
"numWords": {
|
||||||
"message": "Število besed"
|
"message": "Število besed"
|
||||||
@@ -864,7 +864,7 @@
|
|||||||
"message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab."
|
"message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab."
|
||||||
},
|
},
|
||||||
"webAuthnNewTabOpen": {
|
"webAuthnNewTabOpen": {
|
||||||
"message": "Open new tab"
|
"message": "Odpri nov zavihek"
|
||||||
},
|
},
|
||||||
"webAuthnAuthenticate": {
|
"webAuthnAuthenticate": {
|
||||||
"message": "Authenticate WebAuthn"
|
"message": "Authenticate WebAuthn"
|
||||||
@@ -879,10 +879,10 @@
|
|||||||
"message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)."
|
"message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)."
|
||||||
},
|
},
|
||||||
"twoStepOptions": {
|
"twoStepOptions": {
|
||||||
"message": "Two-step login options"
|
"message": "Možnosti dvostopenjske prijave"
|
||||||
},
|
},
|
||||||
"recoveryCodeDesc": {
|
"recoveryCodeDesc": {
|
||||||
"message": "Lost access to all of your two-factor providers? Use your recovery code to turn off all two-factor providers from your account."
|
"message": "Ste izgubili dostop do vseh vaših ponudnikov dvostopenjske prijave? Uporabite svojo kodo za obnovitev in tako onemogočite dvostopenjsko prijavo v svoj račun."
|
||||||
},
|
},
|
||||||
"recoveryCodeTitle": {
|
"recoveryCodeTitle": {
|
||||||
"message": "Koda za obnovitev"
|
"message": "Koda za obnovitev"
|
||||||
@@ -927,7 +927,7 @@
|
|||||||
"message": "Specify the base URL of your on-premises hosted Bitwarden installation."
|
"message": "Specify the base URL of your on-premises hosted Bitwarden installation."
|
||||||
},
|
},
|
||||||
"customEnvironment": {
|
"customEnvironment": {
|
||||||
"message": "Custom environment"
|
"message": "Okolje po meri"
|
||||||
},
|
},
|
||||||
"customEnvironmentFooter": {
|
"customEnvironmentFooter": {
|
||||||
"message": "For advanced users. You can specify the base URL of each service independently."
|
"message": "For advanced users. You can specify the base URL of each service independently."
|
||||||
@@ -993,7 +993,7 @@
|
|||||||
"message": "Generate and copy a new random password to the clipboard"
|
"message": "Generate and copy a new random password to the clipboard"
|
||||||
},
|
},
|
||||||
"commandLockVaultDesc": {
|
"commandLockVaultDesc": {
|
||||||
"message": "Lock the vault"
|
"message": "Zakleni trezor"
|
||||||
},
|
},
|
||||||
"privateModeWarning": {
|
"privateModeWarning": {
|
||||||
"message": "Private mode support is experimental and some features are limited."
|
"message": "Private mode support is experimental and some features are limited."
|
||||||
@@ -1002,10 +1002,10 @@
|
|||||||
"message": "Custom fields"
|
"message": "Custom fields"
|
||||||
},
|
},
|
||||||
"copyValue": {
|
"copyValue": {
|
||||||
"message": "Copy value"
|
"message": "Kopiraj vrednost"
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"message": "Value"
|
"message": "Vrednost"
|
||||||
},
|
},
|
||||||
"newCustomField": {
|
"newCustomField": {
|
||||||
"message": "New custom field"
|
"message": "New custom field"
|
||||||
@@ -1020,7 +1020,7 @@
|
|||||||
"message": "Skrito"
|
"message": "Skrito"
|
||||||
},
|
},
|
||||||
"cfTypeBoolean": {
|
"cfTypeBoolean": {
|
||||||
"message": "Boolean"
|
"message": "Logična vrednost"
|
||||||
},
|
},
|
||||||
"cfTypeLinked": {
|
"cfTypeLinked": {
|
||||||
"message": "Linked",
|
"message": "Linked",
|
||||||
@@ -1133,7 +1133,7 @@
|
|||||||
"message": "Priimek"
|
"message": "Priimek"
|
||||||
},
|
},
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "Full name"
|
"message": "Polno ime"
|
||||||
},
|
},
|
||||||
"identityName": {
|
"identityName": {
|
||||||
"message": "Ime identitete"
|
"message": "Ime identitete"
|
||||||
@@ -1190,22 +1190,22 @@
|
|||||||
"message": "Prijave"
|
"message": "Prijave"
|
||||||
},
|
},
|
||||||
"typeSecureNote": {
|
"typeSecureNote": {
|
||||||
"message": "Secure note"
|
"message": "Varni zapisek"
|
||||||
},
|
},
|
||||||
"typeCard": {
|
"typeCard": {
|
||||||
"message": "Card"
|
"message": "Kartica"
|
||||||
},
|
},
|
||||||
"typeIdentity": {
|
"typeIdentity": {
|
||||||
"message": "Identity"
|
"message": "Identiteta"
|
||||||
},
|
},
|
||||||
"passwordHistory": {
|
"passwordHistory": {
|
||||||
"message": "Password history"
|
"message": "Zgodovina gesel"
|
||||||
},
|
},
|
||||||
"back": {
|
"back": {
|
||||||
"message": "Back"
|
"message": "Nazaj"
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"message": "Collections"
|
"message": "Zbirke"
|
||||||
},
|
},
|
||||||
"favorites": {
|
"favorites": {
|
||||||
"message": "Priljubljeno"
|
"message": "Priljubljeno"
|
||||||
@@ -1226,7 +1226,7 @@
|
|||||||
"message": "Prijave"
|
"message": "Prijave"
|
||||||
},
|
},
|
||||||
"secureNotes": {
|
"secureNotes": {
|
||||||
"message": "Secure notes"
|
"message": "Varni zapiski"
|
||||||
},
|
},
|
||||||
"clear": {
|
"clear": {
|
||||||
"message": "Počisti",
|
"message": "Počisti",
|
||||||
@@ -1285,15 +1285,15 @@
|
|||||||
"description": "Toggle the display of the URIs of the currently open tabs in the browser."
|
"description": "Toggle the display of the URIs of the currently open tabs in the browser."
|
||||||
},
|
},
|
||||||
"currentUri": {
|
"currentUri": {
|
||||||
"message": "Current URI",
|
"message": "Trenutni URI",
|
||||||
"description": "The URI of one of the current open tabs in the browser."
|
"description": "The URI of one of the current open tabs in the browser."
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"message": "Organization",
|
"message": "Organizacija",
|
||||||
"description": "An entity of multiple related people (ex. a team or business organization)."
|
"description": "An entity of multiple related people (ex. a team or business organization)."
|
||||||
},
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"message": "Types"
|
"message": "Tipi"
|
||||||
},
|
},
|
||||||
"allItems": {
|
"allItems": {
|
||||||
"message": "All items"
|
"message": "All items"
|
||||||
@@ -1302,13 +1302,13 @@
|
|||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Odstrani"
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"message": "Default"
|
"message": "Privzeto"
|
||||||
},
|
},
|
||||||
"dateUpdated": {
|
"dateUpdated": {
|
||||||
"message": "Updated",
|
"message": "Posodobljeno",
|
||||||
"description": "ex. Date this item was updated"
|
"description": "ex. Date this item was updated"
|
||||||
},
|
},
|
||||||
"dateCreated": {
|
"dateCreated": {
|
||||||
@@ -1329,25 +1329,25 @@
|
|||||||
"message": "There are no collections to list."
|
"message": "There are no collections to list."
|
||||||
},
|
},
|
||||||
"ownership": {
|
"ownership": {
|
||||||
"message": "Ownership"
|
"message": "Lastništvo"
|
||||||
},
|
},
|
||||||
"whoOwnsThisItem": {
|
"whoOwnsThisItem": {
|
||||||
"message": "Who owns this item?"
|
"message": "Who owns this item?"
|
||||||
},
|
},
|
||||||
"strong": {
|
"strong": {
|
||||||
"message": "Strong",
|
"message": "Močno",
|
||||||
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
|
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
|
||||||
},
|
},
|
||||||
"good": {
|
"good": {
|
||||||
"message": "Good",
|
"message": "Dobro",
|
||||||
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
|
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
|
||||||
},
|
},
|
||||||
"weak": {
|
"weak": {
|
||||||
"message": "Weak",
|
"message": "Šibko",
|
||||||
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
|
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
|
||||||
},
|
},
|
||||||
"weakMasterPassword": {
|
"weakMasterPassword": {
|
||||||
"message": "Weak master password"
|
"message": "Šibko glavno geslo"
|
||||||
},
|
},
|
||||||
"weakMasterPasswordDesc": {
|
"weakMasterPasswordDesc": {
|
||||||
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
|
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
|
||||||
@@ -1357,19 +1357,19 @@
|
|||||||
"description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device."
|
"description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device."
|
||||||
},
|
},
|
||||||
"unlockWithPin": {
|
"unlockWithPin": {
|
||||||
"message": "Unlock with PIN"
|
"message": "Odkleni s PIN kodo"
|
||||||
},
|
},
|
||||||
"setYourPinCode": {
|
"setYourPinCode": {
|
||||||
"message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application."
|
"message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application."
|
||||||
},
|
},
|
||||||
"pinRequired": {
|
"pinRequired": {
|
||||||
"message": "PIN code is required."
|
"message": "Potrebna je PIN koda."
|
||||||
},
|
},
|
||||||
"invalidPin": {
|
"invalidPin": {
|
||||||
"message": "Invalid PIN code."
|
"message": "Nepravilna PIN koda."
|
||||||
},
|
},
|
||||||
"unlockWithBiometrics": {
|
"unlockWithBiometrics": {
|
||||||
"message": "Unlock with biometrics"
|
"message": "Prijava z biometriko"
|
||||||
},
|
},
|
||||||
"awaitDesktop": {
|
"awaitDesktop": {
|
||||||
"message": "Awaiting confirmation from desktop"
|
"message": "Awaiting confirmation from desktop"
|
||||||
@@ -1387,7 +1387,7 @@
|
|||||||
"message": "Clone item"
|
"message": "Clone item"
|
||||||
},
|
},
|
||||||
"clone": {
|
"clone": {
|
||||||
"message": "Clone"
|
"message": "Kloniraj"
|
||||||
},
|
},
|
||||||
"passwordGeneratorPolicyInEffect": {
|
"passwordGeneratorPolicyInEffect": {
|
||||||
"message": "One or more organization policies are affecting your generator settings."
|
"message": "One or more organization policies are affecting your generator settings."
|
||||||
@@ -1396,15 +1396,15 @@
|
|||||||
"message": "Vault timeout action"
|
"message": "Vault timeout action"
|
||||||
},
|
},
|
||||||
"lock": {
|
"lock": {
|
||||||
"message": "Lock",
|
"message": "Zakleni",
|
||||||
"description": "Verb form: to make secure or inaccesible by"
|
"description": "Verb form: to make secure or inaccesible by"
|
||||||
},
|
},
|
||||||
"trash": {
|
"trash": {
|
||||||
"message": "Trash",
|
"message": "Koš",
|
||||||
"description": "Noun: a special folder to hold deleted items"
|
"description": "Noun: a special folder to hold deleted items"
|
||||||
},
|
},
|
||||||
"searchTrash": {
|
"searchTrash": {
|
||||||
"message": "Search trash"
|
"message": "Preišči koš"
|
||||||
},
|
},
|
||||||
"permanentlyDeleteItem": {
|
"permanentlyDeleteItem": {
|
||||||
"message": "Permanently delete item"
|
"message": "Permanently delete item"
|
||||||
@@ -1440,7 +1440,7 @@
|
|||||||
"message": "Item auto-filled "
|
"message": "Item auto-filled "
|
||||||
},
|
},
|
||||||
"setMasterPassword": {
|
"setMasterPassword": {
|
||||||
"message": "Set master password"
|
"message": "Nastavi glavno geslo"
|
||||||
},
|
},
|
||||||
"masterPasswordPolicyInEffect": {
|
"masterPasswordPolicyInEffect": {
|
||||||
"message": "One or more organization policies require your master password to meet the following requirements:"
|
"message": "One or more organization policies require your master password to meet the following requirements:"
|
||||||
@@ -1494,13 +1494,13 @@
|
|||||||
"message": "Terms of Service"
|
"message": "Terms of Service"
|
||||||
},
|
},
|
||||||
"privacyPolicy": {
|
"privacyPolicy": {
|
||||||
"message": "Privacy Policy"
|
"message": "Pravilnik o zasebnosti"
|
||||||
},
|
},
|
||||||
"hintEqualsPassword": {
|
"hintEqualsPassword": {
|
||||||
"message": "Your password hint cannot be the same as your password."
|
"message": "Your password hint cannot be the same as your password."
|
||||||
},
|
},
|
||||||
"ok": {
|
"ok": {
|
||||||
"message": "Ok"
|
"message": "V redu"
|
||||||
},
|
},
|
||||||
"desktopSyncVerificationTitle": {
|
"desktopSyncVerificationTitle": {
|
||||||
"message": "Desktop sync verification"
|
"message": "Desktop sync verification"
|
||||||
@@ -1584,7 +1584,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"send": {
|
"send": {
|
||||||
"message": "Send",
|
"message": "Pošlji",
|
||||||
"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."
|
||||||
},
|
},
|
||||||
"searchSends": {
|
"searchSends": {
|
||||||
@@ -1596,10 +1596,10 @@
|
|||||||
"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."
|
||||||
},
|
},
|
||||||
"sendTypeText": {
|
"sendTypeText": {
|
||||||
"message": "Text"
|
"message": "Besedilo"
|
||||||
},
|
},
|
||||||
"sendTypeFile": {
|
"sendTypeFile": {
|
||||||
"message": "File"
|
"message": "Datoteka"
|
||||||
},
|
},
|
||||||
"allSends": {
|
"allSends": {
|
||||||
"message": "All Sends",
|
"message": "All Sends",
|
||||||
@@ -1610,7 +1610,7 @@
|
|||||||
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
||||||
},
|
},
|
||||||
"expired": {
|
"expired": {
|
||||||
"message": "Expired"
|
"message": "Poteklo"
|
||||||
},
|
},
|
||||||
"pendingDeletion": {
|
"pendingDeletion": {
|
||||||
"message": "Pending deletion"
|
"message": "Pending deletion"
|
||||||
@@ -1626,7 +1626,7 @@
|
|||||||
"message": "Remove Password"
|
"message": "Remove Password"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"message": "Delete"
|
"message": "Izbriši"
|
||||||
},
|
},
|
||||||
"removedPassword": {
|
"removedPassword": {
|
||||||
"message": "Password removed"
|
"message": "Password removed"
|
||||||
@@ -1636,11 +1636,11 @@
|
|||||||
"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."
|
||||||
},
|
},
|
||||||
"sendLink": {
|
"sendLink": {
|
||||||
"message": "Send link",
|
"message": "Pošlji povezavo",
|
||||||
"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."
|
||||||
},
|
},
|
||||||
"disabled": {
|
"disabled": {
|
||||||
"message": "Disabled"
|
"message": "Onemogočeno"
|
||||||
},
|
},
|
||||||
"removePasswordConfirmation": {
|
"removePasswordConfirmation": {
|
||||||
"message": "Are you sure you want to remove the password?"
|
"message": "Are you sure you want to remove the password?"
|
||||||
@@ -1683,10 +1683,10 @@
|
|||||||
"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."
|
||||||
},
|
},
|
||||||
"oneDay": {
|
"oneDay": {
|
||||||
"message": "1 day"
|
"message": "1 dan"
|
||||||
},
|
},
|
||||||
"days": {
|
"days": {
|
||||||
"message": "$DAYS$ days",
|
"message": "$DAYS$ dni",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"days": {
|
"days": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -1835,10 +1835,10 @@
|
|||||||
"message": "In order to complete logging in with SSO, please set a master password to access and protect your vault."
|
"message": "In order to complete logging in with SSO, please set a master password to access and protect your vault."
|
||||||
},
|
},
|
||||||
"hours": {
|
"hours": {
|
||||||
"message": "Hours"
|
"message": "Ur"
|
||||||
},
|
},
|
||||||
"minutes": {
|
"minutes": {
|
||||||
"message": "Minutes"
|
"message": "Minut"
|
||||||
},
|
},
|
||||||
"vaultTimeoutPolicyInEffect": {
|
"vaultTimeoutPolicyInEffect": {
|
||||||
"message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)",
|
"message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)",
|
||||||
@@ -1911,7 +1911,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"message": "Error"
|
"message": "Napaka"
|
||||||
},
|
},
|
||||||
"regenerateUsername": {
|
"regenerateUsername": {
|
||||||
"message": "Regenerate username"
|
"message": "Regenerate username"
|
||||||
@@ -1936,13 +1936,13 @@
|
|||||||
"message": "Use your domain's configured catch-all inbox."
|
"message": "Use your domain's configured catch-all inbox."
|
||||||
},
|
},
|
||||||
"random": {
|
"random": {
|
||||||
"message": "Random"
|
"message": "Naključno"
|
||||||
},
|
},
|
||||||
"randomWord": {
|
"randomWord": {
|
||||||
"message": "Random word"
|
"message": "Naključna beseda"
|
||||||
},
|
},
|
||||||
"websiteName": {
|
"websiteName": {
|
||||||
"message": "Website name"
|
"message": "Ime spletne strani"
|
||||||
},
|
},
|
||||||
"whatWouldYouLikeToGenerate": {
|
"whatWouldYouLikeToGenerate": {
|
||||||
"message": "What would you like to generate?"
|
"message": "What would you like to generate?"
|
||||||
@@ -1997,13 +1997,13 @@
|
|||||||
"message": "Settings have been edited"
|
"message": "Settings have been edited"
|
||||||
},
|
},
|
||||||
"environmentEditedClick": {
|
"environmentEditedClick": {
|
||||||
"message": "Click here"
|
"message": "Kliknite tukaj"
|
||||||
},
|
},
|
||||||
"environmentEditedReset": {
|
"environmentEditedReset": {
|
||||||
"message": "to reset to pre-configured settings"
|
"message": "to reset to pre-configured settings"
|
||||||
},
|
},
|
||||||
"serverVersion": {
|
"serverVersion": {
|
||||||
"message": "Server version"
|
"message": "Verzija strežnika"
|
||||||
},
|
},
|
||||||
"selfHosted": {
|
"selfHosted": {
|
||||||
"message": "Self-hosted"
|
"message": "Self-hosted"
|
||||||
@@ -2036,12 +2036,12 @@
|
|||||||
"message": "Logging in as"
|
"message": "Logging in as"
|
||||||
},
|
},
|
||||||
"notYou": {
|
"notYou": {
|
||||||
"message": "Not you?"
|
"message": "Niste vi?"
|
||||||
},
|
},
|
||||||
"newAroundHere": {
|
"newAroundHere": {
|
||||||
"message": "New around here?"
|
"message": "New around here?"
|
||||||
},
|
},
|
||||||
"rememberEmail": {
|
"rememberEmail": {
|
||||||
"message": "Remember email"
|
"message": "Zapomni si e-pošto"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2012,7 +2012,7 @@
|
|||||||
"message": "Трећа страна"
|
"message": "Трећа страна"
|
||||||
},
|
},
|
||||||
"thirdPartyServerMessage": {
|
"thirdPartyServerMessage": {
|
||||||
"message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.",
|
"message": "Повезан са имплементацијом сервера треће стране, $SERVERNAME$. Проверите грешке користећи званични сервер или их пријавите серверу треће стране.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"servername": {
|
"servername": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
|
|||||||
@@ -53,13 +53,13 @@
|
|||||||
"message": "แท็บ"
|
"message": "แท็บ"
|
||||||
},
|
},
|
||||||
"vault": {
|
"vault": {
|
||||||
"message": "Vault"
|
"message": "ตู้นิรภัย"
|
||||||
},
|
},
|
||||||
"myVault": {
|
"myVault": {
|
||||||
"message": "My Vault"
|
"message": "My Vault"
|
||||||
},
|
},
|
||||||
"allVaults": {
|
"allVaults": {
|
||||||
"message": "All vaults"
|
"message": "ตู้นิรภัยทั้งหมด"
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
"message": "เครื่องมือ"
|
"message": "เครื่องมือ"
|
||||||
@@ -95,16 +95,16 @@
|
|||||||
"message": "Generate Password (copied)"
|
"message": "Generate Password (copied)"
|
||||||
},
|
},
|
||||||
"copyElementIdentifier": {
|
"copyElementIdentifier": {
|
||||||
"message": "Copy custom field name"
|
"message": "คัดลอกชื่อของช่องที่กำหนดเอง"
|
||||||
},
|
},
|
||||||
"noMatchingLogins": {
|
"noMatchingLogins": {
|
||||||
"message": "ไม่พบข้อมูลล็อกอินที่ตรงกัน"
|
"message": "ไม่พบข้อมูลล็อกอินที่ตรงกัน"
|
||||||
},
|
},
|
||||||
"unlockVaultMenu": {
|
"unlockVaultMenu": {
|
||||||
"message": "Unlock your vault"
|
"message": "ปลดล็อกกตู้นิรภัยของคุณ"
|
||||||
},
|
},
|
||||||
"loginToVaultMenu": {
|
"loginToVaultMenu": {
|
||||||
"message": "Log in to your vault"
|
"message": "ลงชื่อเข้าใช้ตู้นิรภัยของคุณ"
|
||||||
},
|
},
|
||||||
"autoFillInfo": {
|
"autoFillInfo": {
|
||||||
"message": "ไม่พบข้อมูลล็อกอินเพื่อใช้กรอกข้อมูลอัตโนมัติ สำหรับแท็บปัจจุบันของเบราว์เซอร์"
|
"message": "ไม่พบข้อมูลล็อกอินเพื่อใช้กรอกข้อมูลอัตโนมัติ สำหรับแท็บปัจจุบันของเบราว์เซอร์"
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
||||||
},
|
},
|
||||||
"yourAccountsFingerprint": {
|
"yourAccountsFingerprint": {
|
||||||
"message": "Your account's fingerprint phrase",
|
"message": "ข้อความลายนิ้วมือของบัญชีของคุณ",
|
||||||
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
|
||||||
},
|
},
|
||||||
"twoStepLogin": {
|
"twoStepLogin": {
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
"description": "Short for 'Password Generator'."
|
"description": "Short for 'Password Generator'."
|
||||||
},
|
},
|
||||||
"passGenInfo": {
|
"passGenInfo": {
|
||||||
"message": "Automatically generate strong, unique passwords for your logins."
|
"message": "สร้างรหัสผ่านที่รัดกุมและไม่ซ้ำใครโดยอัตโนมัติสำหรับการเข้าสู่ระบบของคุณ"
|
||||||
},
|
},
|
||||||
"bitWebVault": {
|
"bitWebVault": {
|
||||||
"message": "bitwarden Web Vault"
|
"message": "bitwarden Web Vault"
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
"message": "รหัสผ่าน"
|
"message": "รหัสผ่าน"
|
||||||
},
|
},
|
||||||
"passphrase": {
|
"passphrase": {
|
||||||
"message": "Passphrase"
|
"message": "ข้อความรหัสผ่าน"
|
||||||
},
|
},
|
||||||
"favorite": {
|
"favorite": {
|
||||||
"message": "รายการโปรด"
|
"message": "รายการโปรด"
|
||||||
@@ -333,10 +333,10 @@
|
|||||||
"message": "Rate the Extension"
|
"message": "Rate the Extension"
|
||||||
},
|
},
|
||||||
"rateExtensionDesc": {
|
"rateExtensionDesc": {
|
||||||
"message": "Please consider helping us out with a good review!"
|
"message": "โปรดพิจารณา ช่วยเราด้วยการตรวจสอบที่ดี!"
|
||||||
},
|
},
|
||||||
"browserNotSupportClipboard": {
|
"browserNotSupportClipboard": {
|
||||||
"message": "Your web browser does not support easy clipboard copying. Copy it manually instead."
|
"message": "เว็บเบราว์เซอร์ของคุณไม่รองรับการคัดลอกคลิปบอร์ดอย่างง่าย คัดลอกด้วยตนเองแทน"
|
||||||
},
|
},
|
||||||
"verifyIdentity": {
|
"verifyIdentity": {
|
||||||
"message": "ยืนยันตัวตน"
|
"message": "ยืนยันตัวตน"
|
||||||
@@ -424,22 +424,22 @@
|
|||||||
"message": "ที่อยู่อีเมลไม่ถูกต้อง"
|
"message": "ที่อยู่อีเมลไม่ถูกต้อง"
|
||||||
},
|
},
|
||||||
"masterPasswordRequired": {
|
"masterPasswordRequired": {
|
||||||
"message": "Master password is required."
|
"message": "ต้องใช้รหัสผ่านหลัก"
|
||||||
},
|
},
|
||||||
"confirmMasterPasswordRequired": {
|
"confirmMasterPasswordRequired": {
|
||||||
"message": "Master password retype is required."
|
"message": "ต้องพิมพ์รหัสผ่านหลักอีกครั้ง"
|
||||||
},
|
},
|
||||||
"masterPasswordMinlength": {
|
"masterPasswordMinlength": {
|
||||||
"message": "Master password must be at least 8 characters long."
|
"message": "รหัสผ่านหลักต้องมีความยาวอย่างน้อย 8 ตัวอักษร"
|
||||||
},
|
},
|
||||||
"masterPassDoesntMatch": {
|
"masterPassDoesntMatch": {
|
||||||
"message": "Master password confirmation does not match."
|
"message": "การยืนยันรหัสผ่านหลักไม่ตรงกัน"
|
||||||
},
|
},
|
||||||
"newAccountCreated": {
|
"newAccountCreated": {
|
||||||
"message": "Your new account has been created! You may now log in."
|
"message": "บัญชีใหม่ของคุณถูกสร้างขึ้นแล้ว! ตอนนี้คุณสามารถเข้าสู่ระบบ"
|
||||||
},
|
},
|
||||||
"masterPassSent": {
|
"masterPassSent": {
|
||||||
"message": "We've sent you an email with your master password hint."
|
"message": "เราได้ส่งอีเมลพร้อมคำใบ้รหัสผ่านหลักของคุณออกไปแล้ว"
|
||||||
},
|
},
|
||||||
"verificationCodeRequired": {
|
"verificationCodeRequired": {
|
||||||
"message": "ต้องระบุโค้ดยืนยัน"
|
"message": "ต้องระบุโค้ดยืนยัน"
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
"message": "Edited Folder"
|
"message": "Edited Folder"
|
||||||
},
|
},
|
||||||
"deleteFolderConfirmation": {
|
"deleteFolderConfirmation": {
|
||||||
"message": "Are you sure you want to delete this folder?"
|
"message": "คุณแน่ใจหรือไม่ว่าต้องการลบโฟลเดอร์นี้"
|
||||||
},
|
},
|
||||||
"deletedFolder": {
|
"deletedFolder": {
|
||||||
"message": "ลบโฟลเดอร์แล้ว"
|
"message": "ลบโฟลเดอร์แล้ว"
|
||||||
@@ -506,7 +506,7 @@
|
|||||||
"message": "Getting Started Tutorial"
|
"message": "Getting Started Tutorial"
|
||||||
},
|
},
|
||||||
"gettingStartedTutorialVideo": {
|
"gettingStartedTutorialVideo": {
|
||||||
"message": "Watch our getting started tutorial to learn how to get the most out of the browser extension."
|
"message": "ดูบทช่วยสอนการเริ่มต้นของเราเพื่อเรียนรู้วิธีใช้ประโยชน์สูงสุดจากส่วนขยายเบราว์เซอร์"
|
||||||
},
|
},
|
||||||
"syncingComplete": {
|
"syncingComplete": {
|
||||||
"message": "การซิงก์เสร็จสมบูรณ์"
|
"message": "การซิงก์เสร็จสมบูรณ์"
|
||||||
@@ -552,48 +552,48 @@
|
|||||||
"message": "คุณต้องการเขียนทับรหัสผ่านปัจจุบันใช่หรือไม่?"
|
"message": "คุณต้องการเขียนทับรหัสผ่านปัจจุบันใช่หรือไม่?"
|
||||||
},
|
},
|
||||||
"overwriteUsername": {
|
"overwriteUsername": {
|
||||||
"message": "Overwrite username"
|
"message": "เขียนทับชื่อผู้ใช้"
|
||||||
},
|
},
|
||||||
"overwriteUsernameConfirmation": {
|
"overwriteUsernameConfirmation": {
|
||||||
"message": "Are you sure you want to overwrite the current username?"
|
"message": "คุณแน่ใจหรือไม่ว่าต้องการเขียนทับชื่อผู้ใช้ปัจจุบัน"
|
||||||
},
|
},
|
||||||
"searchFolder": {
|
"searchFolder": {
|
||||||
"message": "ค้นหาในโพลเดอร์"
|
"message": "ค้นหาในโพลเดอร์"
|
||||||
},
|
},
|
||||||
"searchCollection": {
|
"searchCollection": {
|
||||||
"message": "Search collection"
|
"message": "คอลเลกชันการค้นหา"
|
||||||
},
|
},
|
||||||
"searchType": {
|
"searchType": {
|
||||||
"message": "Search type"
|
"message": "ประเภทการค้นหา"
|
||||||
},
|
},
|
||||||
"noneFolder": {
|
"noneFolder": {
|
||||||
"message": "No Folder",
|
"message": "No Folder",
|
||||||
"description": "This is the folder for uncategorized items"
|
"description": "This is the folder for uncategorized items"
|
||||||
},
|
},
|
||||||
"enableAddLoginNotification": {
|
"enableAddLoginNotification": {
|
||||||
"message": "Ask to add login"
|
"message": "ถามเพื่อให้เพิ่มการเข้าสู่ระบบ"
|
||||||
},
|
},
|
||||||
"addLoginNotificationDesc": {
|
"addLoginNotificationDesc": {
|
||||||
"message": "The \"Add Login Notification\" automatically prompts you to save new logins to your vault whenever you log into them for the first time."
|
"message": "The \"Add Login Notification\" automatically prompts you to save new logins to your vault whenever you log into them for the first time."
|
||||||
},
|
},
|
||||||
"showCardsCurrentTab": {
|
"showCardsCurrentTab": {
|
||||||
"message": "Show cards on Tab page"
|
"message": "แสดงการ์ดบนหน้าแท็บ"
|
||||||
},
|
},
|
||||||
"showCardsCurrentTabDesc": {
|
"showCardsCurrentTabDesc": {
|
||||||
"message": "List card items on the Tab page for easy auto-fill."
|
"message": "บัตรรายการในหน้าแท็บเพื่อให้ป้อนอัตโนมัติได้ง่าย"
|
||||||
},
|
},
|
||||||
"showIdentitiesCurrentTab": {
|
"showIdentitiesCurrentTab": {
|
||||||
"message": "Show identities on Tab page"
|
"message": "แสดงตัวตนบนหน้าแท็บ"
|
||||||
},
|
},
|
||||||
"showIdentitiesCurrentTabDesc": {
|
"showIdentitiesCurrentTabDesc": {
|
||||||
"message": "List identity items on the Tab page for easy auto-fill."
|
"message": "แสดงรายการข้อมูลประจำตัวในหน้าแท็บเพื่อให้ป้อนอัตโนมัติได้ง่าย"
|
||||||
},
|
},
|
||||||
"clearClipboard": {
|
"clearClipboard": {
|
||||||
"message": "ล้างคลิปบอร์ด",
|
"message": "ล้างคลิปบอร์ด",
|
||||||
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
||||||
},
|
},
|
||||||
"clearClipboardDesc": {
|
"clearClipboardDesc": {
|
||||||
"message": "Automatically clear copied values from your clipboard.",
|
"message": "ล้างค่าที่คัดลอกโดยอัตโนมัติจากคลิปบอร์ดของคุณ",
|
||||||
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
||||||
},
|
},
|
||||||
"notificationAddDesc": {
|
"notificationAddDesc": {
|
||||||
@@ -603,7 +603,7 @@
|
|||||||
"message": "Yes, Save Now"
|
"message": "Yes, Save Now"
|
||||||
},
|
},
|
||||||
"enableChangedPasswordNotification": {
|
"enableChangedPasswordNotification": {
|
||||||
"message": "Ask to update existing login"
|
"message": "ขอให้ปรับปรุงการเข้าสู่ระบบที่มีอยู่"
|
||||||
},
|
},
|
||||||
"changedPasswordNotificationDesc": {
|
"changedPasswordNotificationDesc": {
|
||||||
"message": "Ask to update a login's password when a change is detected on a website."
|
"message": "Ask to update a login's password when a change is detected on a website."
|
||||||
@@ -615,17 +615,17 @@
|
|||||||
"message": "Yes, Update Now"
|
"message": "Yes, Update Now"
|
||||||
},
|
},
|
||||||
"enableContextMenuItem": {
|
"enableContextMenuItem": {
|
||||||
"message": "Show context menu options"
|
"message": "แสดงตัวเลือกเมนูบริบท"
|
||||||
},
|
},
|
||||||
"contextMenuItemDesc": {
|
"contextMenuItemDesc": {
|
||||||
"message": "Use a secondary click to access password generation and matching logins for the website. "
|
"message": "ใช้การคลิกสำรองเพื่อเข้าถึงการสร้างรหัสผ่านและการเข้าสู่ระบบที่ตรงกันสำหรับเว็บไซต์ "
|
||||||
},
|
},
|
||||||
"defaultUriMatchDetection": {
|
"defaultUriMatchDetection": {
|
||||||
"message": "Default URI match detection",
|
"message": "การตรวจจับการจับคู่ URI เริ่มต้น",
|
||||||
"description": "Default URI match detection for auto-fill."
|
"description": "Default URI match detection for auto-fill."
|
||||||
},
|
},
|
||||||
"defaultUriMatchDetectionDesc": {
|
"defaultUriMatchDetectionDesc": {
|
||||||
"message": "Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill."
|
"message": "เลือกวิธีเริ่มต้นในการจัดการการตรวจหาการจับคู่ URI สำหรับการเข้าสู่ระบบเมื่อดำเนินการต่างๆ เช่น การป้อนอัตโนมัติ"
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"message": "ธีม"
|
"message": "ธีม"
|
||||||
@@ -656,31 +656,31 @@
|
|||||||
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
||||||
},
|
},
|
||||||
"confirmVaultExport": {
|
"confirmVaultExport": {
|
||||||
"message": "Confirm vault export"
|
"message": "ยืนยันการส่งออกตู้นิรภัย"
|
||||||
},
|
},
|
||||||
"exportWarningDesc": {
|
"exportWarningDesc": {
|
||||||
"message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it."
|
"message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it."
|
||||||
},
|
},
|
||||||
"encExportKeyWarningDesc": {
|
"encExportKeyWarningDesc": {
|
||||||
"message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file."
|
"message": "การส่งออกนี้เข้ารหัสข้อมูลของคุณโดยใช้คีย์เข้ารหัสของบัญชีของคุณ หากคุณเคยหมุนเวียนคีย์เข้ารหัสของบัญชี คุณควรส่งออกอีกครั้ง เนื่องจากคุณจะไม่สามารถถอดรหัสไฟล์ส่งออกนี้ได้"
|
||||||
},
|
},
|
||||||
"encExportAccountWarningDesc": {
|
"encExportAccountWarningDesc": {
|
||||||
"message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account."
|
"message": "คีย์การเข้ารหัสบัญชีจะไม่ซ้ำกันสำหรับบัญชีผู้ใช้ Bitwarden แต่ละบัญชี ดังนั้นคุณจึงไม่สามารถนำเข้าการส่งออกที่เข้ารหัสไปยังบัญชีอื่นได้"
|
||||||
},
|
},
|
||||||
"exportMasterPassword": {
|
"exportMasterPassword": {
|
||||||
"message": "Enter your master password to export your vault data."
|
"message": "ป้อนรหัสผ่านหลักของคุณเพื่อส่งออกข้อมูลตู้นิรภัยของคุณ"
|
||||||
},
|
},
|
||||||
"shared": {
|
"shared": {
|
||||||
"message": "แชร์แล้ว"
|
"message": "แชร์แล้ว"
|
||||||
},
|
},
|
||||||
"learnOrg": {
|
"learnOrg": {
|
||||||
"message": "Learn about organizations"
|
"message": "เรียนรู้เกี่ยวกับองค์กร"
|
||||||
},
|
},
|
||||||
"learnOrgConfirmation": {
|
"learnOrgConfirmation": {
|
||||||
"message": "Bitwarden allows you to share your vault items with others by using an organization. Would you like to visit the bitwarden.com website to learn more?"
|
"message": "Bitwarden อนุญาตให้คุณแชร์รายการตู้นิรภัยของคุณกับผู้อื่นโดยใช้องค์กร คุณต้องการเยี่ยมชมเว็บไซต์ bitwarden.com เพื่อเรียนรู้เพิ่มเติมหรือไม่?"
|
||||||
},
|
},
|
||||||
"moveToOrganization": {
|
"moveToOrganization": {
|
||||||
"message": "Move to organization"
|
"message": "ย้ายไปยังแบบองค์กร"
|
||||||
},
|
},
|
||||||
"share": {
|
"share": {
|
||||||
"message": "แชร์"
|
"message": "แชร์"
|
||||||
@@ -699,10 +699,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"moveToOrgDesc": {
|
"moveToOrgDesc": {
|
||||||
"message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved."
|
"message": "เลือกองค์กรที่คุณต้องการย้ายรายการนี้ไป การย้ายไปยังองค์กรจะโอนความเป็นเจ้าของรายการไปยังองค์กรนั้น คุณจะไม่ได้เป็นเจ้าของโดยตรงของรายการนี้อีกต่อไปเมื่อมีการย้ายแล้ว"
|
||||||
},
|
},
|
||||||
"learnMore": {
|
"learnMore": {
|
||||||
"message": "Learn more"
|
"message": "เรียนรู้เพิ่มเติม"
|
||||||
},
|
},
|
||||||
"authenticatorKeyTotp": {
|
"authenticatorKeyTotp": {
|
||||||
"message": "Authenticator Key (TOTP)"
|
"message": "Authenticator Key (TOTP)"
|
||||||
@@ -747,7 +747,7 @@
|
|||||||
"message": "Feature Unavailable"
|
"message": "Feature Unavailable"
|
||||||
},
|
},
|
||||||
"updateKey": {
|
"updateKey": {
|
||||||
"message": "You cannot use this feature until you update your encryption key."
|
"message": "คุณไม่สามารถใช้คุณลักษณะนี้ได้จนกว่าคุณจะปรับปรุงคีย์การเข้ารหัสลับของคุณ"
|
||||||
},
|
},
|
||||||
"premiumMembership": {
|
"premiumMembership": {
|
||||||
"message": "Premium Membership"
|
"message": "Premium Membership"
|
||||||
@@ -756,28 +756,28 @@
|
|||||||
"message": "Manage Membership"
|
"message": "Manage Membership"
|
||||||
},
|
},
|
||||||
"premiumManageAlert": {
|
"premiumManageAlert": {
|
||||||
"message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?"
|
"message": "คุณสามารถจัดการการเป็นสมาชิกของคุณได้ที่ bitwarden.com web vault คุณต้องการเข้าชมเว็บไซต์ตอนนี้หรือไม่?"
|
||||||
},
|
},
|
||||||
"premiumRefresh": {
|
"premiumRefresh": {
|
||||||
"message": "Refresh Membership"
|
"message": "Refresh Membership"
|
||||||
},
|
},
|
||||||
"premiumNotCurrentMember": {
|
"premiumNotCurrentMember": {
|
||||||
"message": "You are not currently a Premium member."
|
"message": "คุณยังไม่ได้เป็นสมาชิกพรีเมียม"
|
||||||
},
|
},
|
||||||
"premiumSignUpAndGet": {
|
"premiumSignUpAndGet": {
|
||||||
"message": "Sign up for a Premium membership and get:"
|
"message": "สมัครสมาชิกพรีเมี่ยมและรับ:"
|
||||||
},
|
},
|
||||||
"ppremiumSignUpStorage": {
|
"ppremiumSignUpStorage": {
|
||||||
"message": "1 GB of encrypted file storage."
|
"message": "1 GB of encrypted file storage."
|
||||||
},
|
},
|
||||||
"ppremiumSignUpTwoStep": {
|
"ppremiumSignUpTwoStep": {
|
||||||
"message": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo."
|
"message": "ตัวเลือกการเข้าสู่ระบบแบบสองขั้นตอนเพิ่มเติม เช่น YubiKey, FIDO U2F และ Duo"
|
||||||
},
|
},
|
||||||
"ppremiumSignUpReports": {
|
"ppremiumSignUpReports": {
|
||||||
"message": "Password hygiene, account health, and data breach reports to keep your vault safe."
|
"message": "สุขอนามัยของรหัสผ่าน ความสมบูรณ์ของบัญชี และรายงานการละเมิดข้อมูลเพื่อให้ตู้นิรภัยของคุณปลอดภัย"
|
||||||
},
|
},
|
||||||
"ppremiumSignUpTotp": {
|
"ppremiumSignUpTotp": {
|
||||||
"message": "TOTP verification code (2FA) generator for logins in your vault."
|
"message": "ตัวสร้างรหัสยืนยัน TOTP (2FA) สำหรับการเข้าสู่ระบบในตู้นิรภัยของคุณ"
|
||||||
},
|
},
|
||||||
"ppremiumSignUpSupport": {
|
"ppremiumSignUpSupport": {
|
||||||
"message": "Priority customer support."
|
"message": "Priority customer support."
|
||||||
@@ -1055,7 +1055,7 @@
|
|||||||
"message": "หมายเลข"
|
"message": "หมายเลข"
|
||||||
},
|
},
|
||||||
"brand": {
|
"brand": {
|
||||||
"message": "Brand"
|
"message": "แบรนด์"
|
||||||
},
|
},
|
||||||
"expirationMonth": {
|
"expirationMonth": {
|
||||||
"message": "Expiration Month"
|
"message": "Expiration Month"
|
||||||
@@ -1133,7 +1133,7 @@
|
|||||||
"message": "Last Name"
|
"message": "Last Name"
|
||||||
},
|
},
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "Full name"
|
"message": "ชื่อเต็ม"
|
||||||
},
|
},
|
||||||
"identityName": {
|
"identityName": {
|
||||||
"message": "Identity Name"
|
"message": "Identity Name"
|
||||||
@@ -1181,7 +1181,7 @@
|
|||||||
"message": "ประเทศ"
|
"message": "ประเทศ"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"message": "Type"
|
"message": "ชนิด"
|
||||||
},
|
},
|
||||||
"typeLogin": {
|
"typeLogin": {
|
||||||
"message": "ล็อกอิน"
|
"message": "ล็อกอิน"
|
||||||
@@ -1205,35 +1205,35 @@
|
|||||||
"message": "ย้อนกลับ"
|
"message": "ย้อนกลับ"
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"message": "Collections"
|
"message": "คอลเลกชัน"
|
||||||
},
|
},
|
||||||
"favorites": {
|
"favorites": {
|
||||||
"message": "รายการโปรด"
|
"message": "รายการโปรด"
|
||||||
},
|
},
|
||||||
"popOutNewWindow": {
|
"popOutNewWindow": {
|
||||||
"message": "Pop out to a new window"
|
"message": "เปิดหน้าต่างใหม่"
|
||||||
},
|
},
|
||||||
"refresh": {
|
"refresh": {
|
||||||
"message": "Refresh"
|
"message": "รีเฟรช"
|
||||||
},
|
},
|
||||||
"cards": {
|
"cards": {
|
||||||
"message": "Cards"
|
"message": "บัตร"
|
||||||
},
|
},
|
||||||
"identities": {
|
"identities": {
|
||||||
"message": "Identities"
|
"message": "ข้อมูลระบุตัวตน"
|
||||||
},
|
},
|
||||||
"logins": {
|
"logins": {
|
||||||
"message": "Logins"
|
"message": "เข้าสู่ระบบ"
|
||||||
},
|
},
|
||||||
"secureNotes": {
|
"secureNotes": {
|
||||||
"message": "Secure Notes"
|
"message": "Secure Notes"
|
||||||
},
|
},
|
||||||
"clear": {
|
"clear": {
|
||||||
"message": "Clear",
|
"message": "ลบทิ้ง",
|
||||||
"description": "To clear something out. example: To clear browser history."
|
"description": "To clear something out. example: To clear browser history."
|
||||||
},
|
},
|
||||||
"checkPassword": {
|
"checkPassword": {
|
||||||
"message": "Check if password has been exposed."
|
"message": "ตรวจสอบว่ารหัสผ่านถูกเปิดเผยหรือไม่"
|
||||||
},
|
},
|
||||||
"passwordExposed": {
|
"passwordExposed": {
|
||||||
"message": "This password has been exposed in data breaches. You should change it.",
|
"message": "This password has been exposed in data breaches. You should change it.",
|
||||||
@@ -1245,28 +1245,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"passwordSafe": {
|
"passwordSafe": {
|
||||||
"message": "This password was not found in any known data breaches. It should be safe to use."
|
"message": "ไม่พบรหัสผ่านนี้ในการละเมิดข้อมูลที่มี ควรใช้อย่างปลอดภัย"
|
||||||
},
|
},
|
||||||
"baseDomain": {
|
"baseDomain": {
|
||||||
"message": "Base domain",
|
"message": "โดเมนพื้นฐาน",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
"message": "Domain name",
|
"message": "ชื่อโดเมน",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"message": "Host",
|
"message": "โฮสต์",
|
||||||
"description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'."
|
"description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'."
|
||||||
},
|
},
|
||||||
"exact": {
|
"exact": {
|
||||||
"message": "Exact"
|
"message": "ถูกต้อง"
|
||||||
},
|
},
|
||||||
"startsWith": {
|
"startsWith": {
|
||||||
"message": "Starts with"
|
"message": "เริ่มต้นด้วย"
|
||||||
},
|
},
|
||||||
"regEx": {
|
"regEx": {
|
||||||
"message": "Regular expression",
|
"message": "นิพจน์ทั่วไป",
|
||||||
"description": "A programming term, also known as 'RegEx'."
|
"description": "A programming term, also known as 'RegEx'."
|
||||||
},
|
},
|
||||||
"matchDetection": {
|
"matchDetection": {
|
||||||
@@ -1274,14 +1274,14 @@
|
|||||||
"description": "URI match detection for auto-fill."
|
"description": "URI match detection for auto-fill."
|
||||||
},
|
},
|
||||||
"defaultMatchDetection": {
|
"defaultMatchDetection": {
|
||||||
"message": "Default match detection",
|
"message": "การตรวจจับการจับคู่เริ่มต้น",
|
||||||
"description": "Default URI match detection for auto-fill."
|
"description": "Default URI match detection for auto-fill."
|
||||||
},
|
},
|
||||||
"toggleOptions": {
|
"toggleOptions": {
|
||||||
"message": "Toggle Options"
|
"message": "Toggle Options"
|
||||||
},
|
},
|
||||||
"toggleCurrentUris": {
|
"toggleCurrentUris": {
|
||||||
"message": "Toggle current URIs",
|
"message": "สลับ URI ปัจจุบัน",
|
||||||
"description": "Toggle the display of the URIs of the currently open tabs in the browser."
|
"description": "Toggle the display of the URIs of the currently open tabs in the browser."
|
||||||
},
|
},
|
||||||
"currentUri": {
|
"currentUri": {
|
||||||
@@ -1293,26 +1293,26 @@
|
|||||||
"description": "An entity of multiple related people (ex. a team or business organization)."
|
"description": "An entity of multiple related people (ex. a team or business organization)."
|
||||||
},
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"message": "Types"
|
"message": "ชนิด"
|
||||||
},
|
},
|
||||||
"allItems": {
|
"allItems": {
|
||||||
"message": "รายการทั้งหมด"
|
"message": "รายการทั้งหมด"
|
||||||
},
|
},
|
||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "ไม่มีรหัสผ่านที่จะแสดง"
|
||||||
},
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "ลบ"
|
"message": "ลบ"
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"message": "Default"
|
"message": "ค่าเริ่มต้น"
|
||||||
},
|
},
|
||||||
"dateUpdated": {
|
"dateUpdated": {
|
||||||
"message": "อัปเดตแล้ว",
|
"message": "อัปเดตแล้ว",
|
||||||
"description": "ex. Date this item was updated"
|
"description": "ex. Date this item was updated"
|
||||||
},
|
},
|
||||||
"dateCreated": {
|
"dateCreated": {
|
||||||
"message": "Created",
|
"message": "สร้างเมื่อ",
|
||||||
"description": "ex. Date this item was created"
|
"description": "ex. Date this item was created"
|
||||||
},
|
},
|
||||||
"datePasswordUpdated": {
|
"datePasswordUpdated": {
|
||||||
@@ -1320,13 +1320,13 @@
|
|||||||
"description": "ex. Date this password was updated"
|
"description": "ex. Date this password was updated"
|
||||||
},
|
},
|
||||||
"neverLockWarning": {
|
"neverLockWarning": {
|
||||||
"message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected."
|
"message": "คุณแน่ใจหรือไม่ว่าต้องการใช้ตัวเลือก \"ไม่เคย\" การตั้งค่าตัวเลือกการล็อกเป็น \"ไม่\" จะเก็บคีย์เข้ารหัสของห้องนิรภัยไว้ในอุปกรณ์ของคุณ หากคุณใช้ตัวเลือกนี้ คุณควรตรวจสอบให้แน่ใจว่าคุณปกป้องอุปกรณ์ของคุณอย่างเหมาะสม"
|
||||||
},
|
},
|
||||||
"noOrganizationsList": {
|
"noOrganizationsList": {
|
||||||
"message": "You do not belong to any organizations. Organizations allow you to securely share items with other users."
|
"message": "You do not belong to any organizations. Organizations allow you to securely share items with other users."
|
||||||
},
|
},
|
||||||
"noCollectionsInList": {
|
"noCollectionsInList": {
|
||||||
"message": "There are no collections to list."
|
"message": "ไม่มีคอลเลกชันที่จะแสดง"
|
||||||
},
|
},
|
||||||
"ownership": {
|
"ownership": {
|
||||||
"message": "เจ้าของ"
|
"message": "เจ้าของ"
|
||||||
@@ -1350,7 +1350,7 @@
|
|||||||
"message": "Weak Master Password"
|
"message": "Weak Master Password"
|
||||||
},
|
},
|
||||||
"weakMasterPasswordDesc": {
|
"weakMasterPasswordDesc": {
|
||||||
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
|
"message": "รหัสผ่านหลักที่คุณเลือกนั้นไม่รัดกุม คุณควรใช้รหัสผ่านหลักที่รัดกุม (หรือวลีรหัสผ่าน) เพื่อปกป้องบัญชี Bitwarden ของคุณอย่างเหมาะสม คุณแน่ใจหรือไม่ว่าต้องการใช้รหัสผ่านหลักนี้"
|
||||||
},
|
},
|
||||||
"pin": {
|
"pin": {
|
||||||
"message": "PIN",
|
"message": "PIN",
|
||||||
@@ -1369,31 +1369,31 @@
|
|||||||
"message": "PIN ไม่ถูกต้อง"
|
"message": "PIN ไม่ถูกต้อง"
|
||||||
},
|
},
|
||||||
"unlockWithBiometrics": {
|
"unlockWithBiometrics": {
|
||||||
"message": "Unlock with biometrics"
|
"message": "ปลดล็อกด้วยไบโอเมตริก"
|
||||||
},
|
},
|
||||||
"awaitDesktop": {
|
"awaitDesktop": {
|
||||||
"message": "Awaiting confirmation from desktop"
|
"message": "Awaiting confirmation from desktop"
|
||||||
},
|
},
|
||||||
"awaitDesktopDesc": {
|
"awaitDesktopDesc": {
|
||||||
"message": "Please confirm using biometrics in the Bitwarden desktop application to set up biometrics for browser."
|
"message": "โปรดยืนยันการใช้ไบโอเมตริกในแอปพลิเคชันเดสก์ท็อป Bitwarden เพื่อตั้งค่าไบโอเมตริกสำหรับเบราว์เซอร์"
|
||||||
},
|
},
|
||||||
"lockWithMasterPassOnRestart": {
|
"lockWithMasterPassOnRestart": {
|
||||||
"message": "Lock with master password on browser restart"
|
"message": "ล็อคด้วยรหัสผ่านหลักเมื่อรีสตาร์ทเบราว์เซอร์"
|
||||||
},
|
},
|
||||||
"selectOneCollection": {
|
"selectOneCollection": {
|
||||||
"message": "You must select at least one collection."
|
"message": "คุณต้องเลือกอย่างน้อยหนึ่งคอลเลกชัน"
|
||||||
},
|
},
|
||||||
"cloneItem": {
|
"cloneItem": {
|
||||||
"message": "Clone item"
|
"message": "โคลนรายการ"
|
||||||
},
|
},
|
||||||
"clone": {
|
"clone": {
|
||||||
"message": "Clone"
|
"message": "โคลน"
|
||||||
},
|
},
|
||||||
"passwordGeneratorPolicyInEffect": {
|
"passwordGeneratorPolicyInEffect": {
|
||||||
"message": "One or more organization policies are affecting your generator settings."
|
"message": "นโยบายองค์กรอย่างน้อยหนึ่งนโยบายส่งผลต่อการตั้งค่าตัวสร้างของคุณ"
|
||||||
},
|
},
|
||||||
"vaultTimeoutAction": {
|
"vaultTimeoutAction": {
|
||||||
"message": "Vault timeout action"
|
"message": "การดำเนินการหลังหมดเวลาล็อคตู้เซฟ"
|
||||||
},
|
},
|
||||||
"lock": {
|
"lock": {
|
||||||
"message": "ล็อก",
|
"message": "ล็อก",
|
||||||
@@ -1407,46 +1407,46 @@
|
|||||||
"message": "ค้นหาในถังขยะ"
|
"message": "ค้นหาในถังขยะ"
|
||||||
},
|
},
|
||||||
"permanentlyDeleteItem": {
|
"permanentlyDeleteItem": {
|
||||||
"message": "Permanently delete item"
|
"message": "ลบรายการอย่างถาวร"
|
||||||
},
|
},
|
||||||
"permanentlyDeleteItemConfirmation": {
|
"permanentlyDeleteItemConfirmation": {
|
||||||
"message": "Are you sure you want to permanently delete this item?"
|
"message": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการนี้อย่างถาวร?"
|
||||||
},
|
},
|
||||||
"permanentlyDeletedItem": {
|
"permanentlyDeletedItem": {
|
||||||
"message": "Item permanently deleted"
|
"message": "ลบรายการอย่างถาวรแล้ว"
|
||||||
},
|
},
|
||||||
"restoreItem": {
|
"restoreItem": {
|
||||||
"message": "Restore item"
|
"message": "กู้คืนรายการ"
|
||||||
},
|
},
|
||||||
"restoreItemConfirmation": {
|
"restoreItemConfirmation": {
|
||||||
"message": "Are you sure you want to restore this item?"
|
"message": "คุณแน่ใจหรือไม่ว่าต้องการกู้คืนรายการนี้"
|
||||||
},
|
},
|
||||||
"restoredItem": {
|
"restoredItem": {
|
||||||
"message": "Item restored"
|
"message": "คืนค่ารายการแล้ว"
|
||||||
},
|
},
|
||||||
"vaultTimeoutLogOutConfirmation": {
|
"vaultTimeoutLogOutConfirmation": {
|
||||||
"message": "Logging out will remove all access to your vault and requires online authentication after the timeout period. Are you sure you want to use this setting?"
|
"message": "การออกจากระบบจะลบการเข้าถึงตู้นิรภัยของคุณทั้งหมด และต้องมีการตรวจสอบสิทธิ์ออนไลน์หลังจากหมดเวลา คุณแน่ใจหรือไม่ว่าต้องการใช้การตั้งค่านี้"
|
||||||
},
|
},
|
||||||
"vaultTimeoutLogOutConfirmationTitle": {
|
"vaultTimeoutLogOutConfirmationTitle": {
|
||||||
"message": "Timeout action confirmation"
|
"message": "การยืนยันการดำเนินการหมดเวลา"
|
||||||
},
|
},
|
||||||
"autoFillAndSave": {
|
"autoFillAndSave": {
|
||||||
"message": "Auto-fill and save"
|
"message": "กรอกอัตโนมัติและบันทึก"
|
||||||
},
|
},
|
||||||
"autoFillSuccessAndSavedUri": {
|
"autoFillSuccessAndSavedUri": {
|
||||||
"message": "Item auto-filled and URI saved"
|
"message": "เติมรายการอัตโนมัติและบันทึก URI แล้ว"
|
||||||
},
|
},
|
||||||
"autoFillSuccess": {
|
"autoFillSuccess": {
|
||||||
"message": "Item auto-filled "
|
"message": "รายการเติมอัตโนมัติ "
|
||||||
},
|
},
|
||||||
"setMasterPassword": {
|
"setMasterPassword": {
|
||||||
"message": "ตั้งรหัสผ่านหลัก"
|
"message": "ตั้งรหัสผ่านหลัก"
|
||||||
},
|
},
|
||||||
"masterPasswordPolicyInEffect": {
|
"masterPasswordPolicyInEffect": {
|
||||||
"message": "One or more organization policies require your master password to meet the following requirements:"
|
"message": "นโยบายองค์กรอย่างน้อยหนึ่งนโยบายกำหนดให้รหัสผ่านหลักของคุณเป็นไปตามข้อกำหนดต่อไปนี้:"
|
||||||
},
|
},
|
||||||
"policyInEffectMinComplexity": {
|
"policyInEffectMinComplexity": {
|
||||||
"message": "Minimum complexity score of $SCORE$",
|
"message": "คะแนนความซับซ้อนขั้นต่ำ $SCORE$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"score": {
|
"score": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@@ -1482,7 +1482,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"masterPasswordPolicyRequirementsNotMet": {
|
"masterPasswordPolicyRequirementsNotMet": {
|
||||||
"message": "Your new master password does not meet the policy requirements."
|
"message": "รหัสผ่านหลักใหม่ของคุณไม่เป็นไปตามข้อกำหนดของนโยบาย"
|
||||||
},
|
},
|
||||||
"acceptPolicies": {
|
"acceptPolicies": {
|
||||||
"message": "By checking this box you agree to the following:"
|
"message": "By checking this box you agree to the following:"
|
||||||
|
|||||||
@@ -2039,7 +2039,7 @@
|
|||||||
"message": "不是你?"
|
"message": "不是你?"
|
||||||
},
|
},
|
||||||
"newAroundHere": {
|
"newAroundHere": {
|
||||||
"message": "新建在这里?"
|
"message": "初来乍到吗?"
|
||||||
},
|
},
|
||||||
"rememberEmail": {
|
"rememberEmail": {
|
||||||
"message": "记住电子邮件地址"
|
"message": "记住电子邮件地址"
|
||||||
|
|||||||
@@ -2039,7 +2039,7 @@
|
|||||||
"message": "不是您嗎?"
|
"message": "不是您嗎?"
|
||||||
},
|
},
|
||||||
"newAroundHere": {
|
"newAroundHere": {
|
||||||
"message": "New around here?"
|
"message": "第一次使用?"
|
||||||
},
|
},
|
||||||
"rememberEmail": {
|
"rememberEmail": {
|
||||||
"message": "記住電子郵件地址"
|
"message": "記住電子郵件地址"
|
||||||
|
|||||||
66
apps/browser/src/alarms/alarm-state.ts
Normal file
66
apps/browser/src/alarms/alarm-state.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
|
import { clearClipboardAlarmName } from "../clipboard";
|
||||||
|
|
||||||
|
export const alarmKeys = [clearClipboardAlarmName] as const;
|
||||||
|
export type AlarmKeys = typeof alarmKeys[number];
|
||||||
|
|
||||||
|
type AlarmState = { [T in AlarmKeys]: number | undefined };
|
||||||
|
|
||||||
|
const alarmState: AlarmState = {
|
||||||
|
clearClipboard: null,
|
||||||
|
//TODO once implemented vaultTimeout: null;
|
||||||
|
//TODO once implemented checkNotifications: null;
|
||||||
|
//TODO once implemented (if necessary) processReload: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the set alarm time (planned execution) for a give an commandName {@link AlarmState}
|
||||||
|
* @param commandName A command that has been previously registered with {@link AlarmState}
|
||||||
|
* @returns {Promise<number>} null or Unix epoch timestamp when the alarm action is supposed to execute
|
||||||
|
* @example
|
||||||
|
* // getAlarmTime(clearClipboard)
|
||||||
|
*/
|
||||||
|
export async function getAlarmTime(commandName: AlarmKeys): Promise<number> {
|
||||||
|
let alarmTime: number;
|
||||||
|
if (BrowserApi.manifestVersion == 3) {
|
||||||
|
const fromSessionStore = await chrome.storage.session.get(commandName);
|
||||||
|
alarmTime = fromSessionStore[commandName];
|
||||||
|
} else {
|
||||||
|
alarmTime = alarmState[commandName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return alarmTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an action that should execute after the given time has passed
|
||||||
|
* @param commandName A command that has been previously registered with {@link AlarmState}
|
||||||
|
* @param delay_ms The number of ms from now in which the command should execute from
|
||||||
|
* @example
|
||||||
|
* // setAlarmTime(clearClipboard, 5000) register the clearClipboard action which will execute when at least 5 seconds from now have passed
|
||||||
|
*/
|
||||||
|
export async function setAlarmTime(commandName: AlarmKeys, delay_ms: number): Promise<void> {
|
||||||
|
if (!delay_ms || delay_ms === 0) {
|
||||||
|
await this.clearAlarmTime(commandName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = Date.now() + delay_ms;
|
||||||
|
await setAlarmTimeInternal(commandName, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the time currently set for a given command
|
||||||
|
* @param commandName A command that has been previously registered with {@link AlarmState}
|
||||||
|
*/
|
||||||
|
export async function clearAlarmTime(commandName: AlarmKeys): Promise<void> {
|
||||||
|
await setAlarmTimeInternal(commandName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setAlarmTimeInternal(commandName: AlarmKeys, time: number): Promise<void> {
|
||||||
|
if (BrowserApi.manifestVersion == 3) {
|
||||||
|
await chrome.storage.session.set({ [commandName]: time });
|
||||||
|
} else {
|
||||||
|
alarmState[commandName] = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
apps/browser/src/alarms/on-alarm-listener.ts
Normal file
26
apps/browser/src/alarms/on-alarm-listener.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { ClearClipboard, clearClipboardAlarmName } from "../clipboard";
|
||||||
|
|
||||||
|
import { alarmKeys, clearAlarmTime, getAlarmTime } from "./alarm-state";
|
||||||
|
|
||||||
|
export const onAlarmListener = async (alarm: chrome.alarms.Alarm) => {
|
||||||
|
alarmKeys.forEach(async (key) => {
|
||||||
|
const executionTime = await getAlarmTime(key);
|
||||||
|
if (!executionTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDate = Date.now();
|
||||||
|
if (executionTime > currentDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await clearAlarmTime(key);
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case clearClipboardAlarmName:
|
||||||
|
ClearClipboard.run();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
29
apps/browser/src/alarms/register-alarms.ts
Normal file
29
apps/browser/src/alarms/register-alarms.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const NUMBER_OF_ALARMS = 6;
|
||||||
|
|
||||||
|
export function registerAlarms() {
|
||||||
|
alarmsToBeCreated(NUMBER_OF_ALARMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates staggered alarms that periodically (1min) raise OnAlarm events. The staggering is calculated based on the numnber of alarms passed in.
|
||||||
|
* @param numberOfAlarms Number of named alarms, that shall be registered
|
||||||
|
* @example
|
||||||
|
* // alarmsToBeCreated(2) results in 2 alarms separated by 30 seconds
|
||||||
|
* @example
|
||||||
|
* // alarmsToBeCreated(4) results in 4 alarms separated by 15 seconds
|
||||||
|
* @example
|
||||||
|
* // alarmsToBeCreated(6) results in 6 alarms separated by 10 seconds
|
||||||
|
* @example
|
||||||
|
* // alarmsToBeCreated(60) results in 60 alarms separated by 1 second
|
||||||
|
*/
|
||||||
|
function alarmsToBeCreated(numberOfAlarms: number): void {
|
||||||
|
const oneMinuteInMs = 60 * 1000;
|
||||||
|
const offset = oneMinuteInMs / numberOfAlarms;
|
||||||
|
|
||||||
|
let calculatedWhen: number = Date.now() + offset;
|
||||||
|
|
||||||
|
for (let index = 0; index < numberOfAlarms; index++) {
|
||||||
|
chrome.alarms.create(`bw_alarm${index}`, { periodInMinutes: 1, when: calculatedWhen });
|
||||||
|
calculatedWhen += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { onAlarmListener } from "./alarms/on-alarm-listener";
|
||||||
|
import { registerAlarms } from "./alarms/register-alarms";
|
||||||
import MainBackground from "./background/main.background";
|
import MainBackground from "./background/main.background";
|
||||||
import { BrowserApi } from "./browser/browserApi";
|
import { BrowserApi } from "./browser/browserApi";
|
||||||
import { ClearClipboard } from "./clipboard";
|
|
||||||
import { onCommandListener } from "./listeners/onCommandListener";
|
import { onCommandListener } from "./listeners/onCommandListener";
|
||||||
import { onInstallListener } from "./listeners/onInstallListener";
|
import { onInstallListener } from "./listeners/onInstallListener";
|
||||||
import { UpdateBadge } from "./listeners/update-badge";
|
import { UpdateBadge } from "./listeners/update-badge";
|
||||||
@@ -9,13 +10,12 @@ const manifestV3MessageListeners: ((
|
|||||||
serviceCache: Record<string, unknown>,
|
serviceCache: Record<string, unknown>,
|
||||||
message: { command: string }
|
message: { command: string }
|
||||||
) => void | Promise<void>)[] = [UpdateBadge.messageListener];
|
) => void | Promise<void>)[] = [UpdateBadge.messageListener];
|
||||||
type AlarmAction = (executionTime: Date, serviceCache: Record<string, unknown>) => void;
|
|
||||||
|
|
||||||
const AlarmActions: AlarmAction[] = [ClearClipboard.run];
|
|
||||||
|
|
||||||
if (BrowserApi.manifestVersion === 3) {
|
if (BrowserApi.manifestVersion === 3) {
|
||||||
chrome.commands.onCommand.addListener(onCommandListener);
|
chrome.commands.onCommand.addListener(onCommandListener);
|
||||||
chrome.runtime.onInstalled.addListener(onInstallListener);
|
chrome.runtime.onInstalled.addListener(onInstallListener);
|
||||||
|
chrome.alarms.onAlarm.addListener(onAlarmListener);
|
||||||
|
registerAlarms();
|
||||||
chrome.tabs.onActivated.addListener(UpdateBadge.tabsOnActivatedListener);
|
chrome.tabs.onActivated.addListener(UpdateBadge.tabsOnActivatedListener);
|
||||||
chrome.tabs.onReplaced.addListener(UpdateBadge.tabsOnReplacedListener);
|
chrome.tabs.onReplaced.addListener(UpdateBadge.tabsOnReplacedListener);
|
||||||
chrome.tabs.onUpdated.addListener(UpdateBadge.tabsOnUpdatedListener);
|
chrome.tabs.onUpdated.addListener(UpdateBadge.tabsOnUpdatedListener);
|
||||||
@@ -26,14 +26,6 @@ if (BrowserApi.manifestVersion === 3) {
|
|||||||
listener(serviceCache, message);
|
listener(serviceCache, message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
chrome.alarms.onAlarm.addListener((_alarm) => {
|
|
||||||
const executionTime = new Date();
|
|
||||||
const serviceCache = {};
|
|
||||||
|
|
||||||
for (const alarmAction of AlarmActions) {
|
|
||||||
alarmAction(executionTime, serviceCache);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
||||||
bitwardenMain.bootstrap().then(() => {
|
bitwardenMain.bootstrap().then(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||||
@@ -24,7 +24,7 @@ export default class ContextMenusBackground {
|
|||||||
private passwordGenerationService: PasswordGenerationService,
|
private passwordGenerationService: PasswordGenerationService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private eventService: EventService,
|
private eventCollectionService: EventCollectionService,
|
||||||
private totpService: TotpService
|
private totpService: TotpService
|
||||||
) {
|
) {
|
||||||
this.contextMenus = chrome.contextMenus;
|
this.contextMenus = chrome.contextMenus;
|
||||||
@@ -124,7 +124,7 @@ export default class ContextMenusBackground {
|
|||||||
this.platformUtilsService.copyToClipboard(cipher.login.username, { window: window });
|
this.platformUtilsService.copyToClipboard(cipher.login.username, { window: window });
|
||||||
} else if (info.parentMenuItemId === "copy-password") {
|
} else if (info.parentMenuItemId === "copy-password") {
|
||||||
this.platformUtilsService.copyToClipboard(cipher.login.password, { window: window });
|
this.platformUtilsService.copyToClipboard(cipher.login.password, { window: window });
|
||||||
this.eventService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id);
|
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id);
|
||||||
} else if (info.parentMenuItemId === "copy-totp") {
|
} else if (info.parentMenuItemId === "copy-totp") {
|
||||||
const totpValue = await this.totpService.getCode(cipher.login.totp);
|
const totpValue = await this.totpService.getCode(cipher.login.totp);
|
||||||
this.platformUtilsService.copyToClipboard(totpValue, { window: window });
|
this.platformUtilsService.copyToClipboard(totpValue, { window: window });
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||||
|
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
const IdleInterval = 60 * 5; // 5 minutes
|
const IdleInterval = 60 * 5; // 5 minutes
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ export default class IdleBackground {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
private vaultTimeoutService: VaultTimeoutService,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private notificationsService: NotificationsService
|
private notificationsService: NotificationsService
|
||||||
) {
|
) {
|
||||||
this.idle = chrome.idle || (browser != null ? browser.idle : null);
|
this.idle = chrome.idle || (browser != null ? browser.idle : null);
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/co
|
|||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
|
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||||
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
||||||
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
|
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
|
||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction";
|
||||||
@@ -17,7 +18,7 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarde
|
|||||||
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
|
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
|
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
|
||||||
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
|
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
|
||||||
import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
import { InternalOrganizationService as InternalOrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||||
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
|
||||||
@@ -54,21 +55,19 @@ import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service
|
|||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
|
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
|
||||||
import { EventService } from "@bitwarden/common/services/event.service";
|
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
|
||||||
|
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
|
||||||
import { ExportService } from "@bitwarden/common/services/export.service";
|
import { ExportService } from "@bitwarden/common/services/export.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
||||||
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
|
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
|
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
|
||||||
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
|
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
|
||||||
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
|
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
|
|
||||||
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
|
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
|
||||||
import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service";
|
import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
|
|
||||||
import { ProviderService } from "@bitwarden/common/services/provider.service";
|
import { ProviderService } from "@bitwarden/common/services/provider.service";
|
||||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
import { SendService } from "@bitwarden/common/services/send.service";
|
import { SendService } from "@bitwarden/common/services/send.service";
|
||||||
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
|
||||||
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
|
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
|
||||||
import { SyncService } from "@bitwarden/common/services/sync/sync.service";
|
import { SyncService } from "@bitwarden/common/services/sync/sync.service";
|
||||||
import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service";
|
import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service";
|
||||||
@@ -89,19 +88,22 @@ import { UpdateBadge } from "../listeners/update-badge";
|
|||||||
import { Account } from "../models/account";
|
import { Account } from "../models/account";
|
||||||
import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
||||||
import { AutofillService as AutofillServiceAbstraction } from "../services/abstractions/autofill.service";
|
import { AutofillService as AutofillServiceAbstraction } from "../services/abstractions/autofill.service";
|
||||||
import { StateService as StateServiceAbstraction } from "../services/abstractions/state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../services/abstractions/browser-state.service";
|
||||||
import AutofillService from "../services/autofill.service";
|
import AutofillService from "../services/autofill.service";
|
||||||
import { BrowserEnvironmentService } from "../services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../services/browser-environment.service";
|
||||||
|
import { BrowserFolderService } from "../services/browser-folder.service";
|
||||||
|
import { BrowserOrganizationService } from "../services/browser-organization.service";
|
||||||
|
import { BrowserPolicyService } from "../services/browser-policy.service";
|
||||||
|
import { BrowserSettingsService } from "../services/browser-settings.service";
|
||||||
|
import { BrowserStateService } from "../services/browser-state.service";
|
||||||
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
||||||
import BrowserLocalStorageService from "../services/browserLocalStorage.service";
|
import BrowserLocalStorageService from "../services/browserLocalStorage.service";
|
||||||
import BrowserMessagingService from "../services/browserMessaging.service";
|
import BrowserMessagingService from "../services/browserMessaging.service";
|
||||||
import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service";
|
import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service";
|
||||||
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
||||||
import { FolderService } from "../services/folders/folder.service";
|
|
||||||
import I18nService from "../services/i18n.service";
|
import I18nService from "../services/i18n.service";
|
||||||
import { KeyGenerationService } from "../services/keyGeneration.service";
|
import { KeyGenerationService } from "../services/keyGeneration.service";
|
||||||
import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service";
|
import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service";
|
||||||
import { StateService } from "../services/state.service";
|
|
||||||
import { VaultFilterService } from "../services/vaultFilter.service";
|
import { VaultFilterService } from "../services/vaultFilter.service";
|
||||||
import VaultTimeoutService from "../services/vaultTimeout/vaultTimeout.service";
|
import VaultTimeoutService from "../services/vaultTimeout/vaultTimeout.service";
|
||||||
|
|
||||||
@@ -148,12 +150,13 @@ export default class MainBackground {
|
|||||||
stateService: StateServiceAbstraction;
|
stateService: StateServiceAbstraction;
|
||||||
stateMigrationService: StateMigrationService;
|
stateMigrationService: StateMigrationService;
|
||||||
systemService: SystemServiceAbstraction;
|
systemService: SystemServiceAbstraction;
|
||||||
eventService: EventServiceAbstraction;
|
eventCollectionService: EventCollectionServiceAbstraction;
|
||||||
|
eventUploadService: EventUploadServiceAbstraction;
|
||||||
policyService: InternalPolicyServiceAbstraction;
|
policyService: InternalPolicyServiceAbstraction;
|
||||||
popupUtilsService: PopupUtilsService;
|
popupUtilsService: PopupUtilsService;
|
||||||
sendService: SendServiceAbstraction;
|
sendService: SendServiceAbstraction;
|
||||||
fileUploadService: FileUploadServiceAbstraction;
|
fileUploadService: FileUploadServiceAbstraction;
|
||||||
organizationService: OrganizationServiceAbstraction;
|
organizationService: InternalOrganizationServiceAbstraction;
|
||||||
providerService: ProviderServiceAbstraction;
|
providerService: ProviderServiceAbstraction;
|
||||||
keyConnectorService: KeyConnectorServiceAbstraction;
|
keyConnectorService: KeyConnectorServiceAbstraction;
|
||||||
userVerificationService: UserVerificationServiceAbstraction;
|
userVerificationService: UserVerificationServiceAbstraction;
|
||||||
@@ -227,7 +230,7 @@ export default class MainBackground {
|
|||||||
this.secureStorageService,
|
this.secureStorageService,
|
||||||
new StateFactory(GlobalState, Account)
|
new StateFactory(GlobalState, Account)
|
||||||
);
|
);
|
||||||
this.stateService = new StateService(
|
this.stateService = new BrowserStateService(
|
||||||
this.storageService,
|
this.storageService,
|
||||||
this.secureStorageService,
|
this.secureStorageService,
|
||||||
this.memoryStorageService,
|
this.memoryStorageService,
|
||||||
@@ -282,7 +285,7 @@ export default class MainBackground {
|
|||||||
this.appIdService,
|
this.appIdService,
|
||||||
(expired: boolean) => this.logout(expired)
|
(expired: boolean) => this.logout(expired)
|
||||||
);
|
);
|
||||||
this.settingsService = new SettingsService(this.stateService);
|
this.settingsService = new BrowserSettingsService(this.stateService);
|
||||||
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
|
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
|
||||||
this.cipherService = new CipherService(
|
this.cipherService = new CipherService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
@@ -295,7 +298,7 @@ export default class MainBackground {
|
|||||||
this.stateService,
|
this.stateService,
|
||||||
this.encryptService
|
this.encryptService
|
||||||
);
|
);
|
||||||
this.folderService = new FolderService(
|
this.folderService = new BrowserFolderService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
@@ -317,8 +320,8 @@ export default class MainBackground {
|
|||||||
this.stateService
|
this.stateService
|
||||||
);
|
);
|
||||||
this.syncNotifierService = new SyncNotifierService();
|
this.syncNotifierService = new SyncNotifierService();
|
||||||
this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService);
|
this.organizationService = new BrowserOrganizationService(this.stateService);
|
||||||
this.policyService = new PolicyService(this.stateService, this.organizationService);
|
this.policyService = new BrowserPolicyService(this.stateService, this.organizationService);
|
||||||
this.policyApiService = new PolicyApiService(
|
this.policyApiService = new PolicyApiService(
|
||||||
this.policyService,
|
this.policyService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
@@ -409,15 +412,19 @@ export default class MainBackground {
|
|||||||
this.stateService,
|
this.stateService,
|
||||||
this.providerService,
|
this.providerService,
|
||||||
this.folderApiService,
|
this.folderApiService,
|
||||||
this.syncNotifierService,
|
this.organizationService,
|
||||||
logoutCallback
|
logoutCallback
|
||||||
);
|
);
|
||||||
this.eventService = new EventService(
|
this.eventUploadService = new EventUploadService(
|
||||||
this.apiService,
|
this.apiService,
|
||||||
|
this.stateService,
|
||||||
|
this.logService
|
||||||
|
);
|
||||||
|
this.eventCollectionService = new EventCollectionService(
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.logService,
|
this.organizationService,
|
||||||
this.organizationService
|
this.eventUploadService
|
||||||
);
|
);
|
||||||
this.passwordGenerationService = new PasswordGenerationService(
|
this.passwordGenerationService = new PasswordGenerationService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
@@ -429,7 +436,7 @@ export default class MainBackground {
|
|||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.totpService,
|
this.totpService,
|
||||||
this.eventService,
|
this.eventCollectionService,
|
||||||
this.logService
|
this.logService
|
||||||
);
|
);
|
||||||
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
|
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
|
||||||
@@ -532,7 +539,7 @@ export default class MainBackground {
|
|||||||
this.passwordGenerationService,
|
this.passwordGenerationService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
this.authService,
|
this.authService,
|
||||||
this.eventService,
|
this.eventCollectionService,
|
||||||
this.totpService
|
this.totpService
|
||||||
);
|
);
|
||||||
this.idleBackground = new IdleBackground(
|
this.idleBackground = new IdleBackground(
|
||||||
@@ -560,7 +567,7 @@ export default class MainBackground {
|
|||||||
|
|
||||||
await (this.vaultTimeoutService as VaultTimeoutService).init(true);
|
await (this.vaultTimeoutService as VaultTimeoutService).init(true);
|
||||||
await (this.i18nService as I18nService).init();
|
await (this.i18nService as I18nService).init();
|
||||||
await (this.eventService as EventService).init(true);
|
await (this.eventUploadService as EventUploadService).init(true);
|
||||||
await this.runtimeBackground.init();
|
await this.runtimeBackground.init();
|
||||||
await this.notificationBackground.init();
|
await this.notificationBackground.init();
|
||||||
await this.commandsBackground.init();
|
await this.commandsBackground.init();
|
||||||
@@ -626,10 +633,9 @@ export default class MainBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async logout(expired: boolean, userId?: string) {
|
async logout(expired: boolean, userId?: string) {
|
||||||
await this.eventService.uploadEvents(userId);
|
await this.eventUploadService.uploadEvents(userId);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.eventService.clearEvents(userId),
|
|
||||||
this.syncService.setLastSync(new Date(0), userId),
|
this.syncService.setLastSync(new Date(0), userId),
|
||||||
this.cryptoService.clearKeys(userId),
|
this.cryptoService.clearKeys(userId),
|
||||||
this.settingsService.clear(userId),
|
this.settingsService.clear(userId),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { LoginView } from "@bitwarden/common/models/view/login.view";
|
|||||||
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import AddChangePasswordQueueMessage from "./models/addChangePasswordQueueMessage";
|
import AddChangePasswordQueueMessage from "./models/addChangePasswordQueueMessage";
|
||||||
import AddLoginQueueMessage from "./models/addLoginQueueMessage";
|
import AddLoginQueueMessage from "./models/addLoginQueueMessage";
|
||||||
@@ -33,7 +33,7 @@ export default class NotificationBackground {
|
|||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private stateService: StateService
|
private stateService: BrowserStateService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { AutofillService as AbstractAutoFillService } from "../../services/abstr
|
|||||||
import AutofillService from "../../services/autofill.service";
|
import AutofillService from "../../services/autofill.service";
|
||||||
|
|
||||||
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
||||||
import { EventServiceInitOptions, eventServiceFactory } from "./event-service.factory";
|
import {
|
||||||
|
EventCollectionServiceInitOptions,
|
||||||
|
eventCollectionServiceFactory,
|
||||||
|
} from "./event-collection-service.factory";
|
||||||
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||||
@@ -14,7 +17,7 @@ export type AutoFillServiceInitOptions = AutoFillServiceOptions &
|
|||||||
CipherServiceInitOptions &
|
CipherServiceInitOptions &
|
||||||
StateServiceInitOptions &
|
StateServiceInitOptions &
|
||||||
TotpServiceInitOptions &
|
TotpServiceInitOptions &
|
||||||
EventServiceInitOptions &
|
EventCollectionServiceInitOptions &
|
||||||
LogServiceInitOptions;
|
LogServiceInitOptions;
|
||||||
|
|
||||||
export function autofillServiceFactory(
|
export function autofillServiceFactory(
|
||||||
@@ -30,7 +33,7 @@ export function autofillServiceFactory(
|
|||||||
await cipherServiceFactory(cache, opts),
|
await cipherServiceFactory(cache, opts),
|
||||||
await stateServiceFactory(cache, opts),
|
await stateServiceFactory(cache, opts),
|
||||||
await totpServiceFactory(cache, opts),
|
await totpServiceFactory(cache, opts),
|
||||||
await eventServiceFactory(cache, opts),
|
await eventCollectionServiceFactory(cache, opts),
|
||||||
await logServiceFactory(cache, opts)
|
await logServiceFactory(cache, opts)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { EventCollectionService as AbstractEventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
|
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
|
||||||
|
|
||||||
|
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
||||||
|
import {
|
||||||
|
eventUploadServiceFactory,
|
||||||
|
EventUploadServiceInitOptions,
|
||||||
|
} from "./event-upload-service.factory";
|
||||||
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
|
import {
|
||||||
|
organizationServiceFactory,
|
||||||
|
OrganizationServiceInitOptions,
|
||||||
|
} from "./organization-service.factory";
|
||||||
|
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||||
|
|
||||||
|
type EventCollectionServiceOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type EventCollectionServiceInitOptions = EventCollectionServiceOptions &
|
||||||
|
CipherServiceInitOptions &
|
||||||
|
StateServiceInitOptions &
|
||||||
|
OrganizationServiceInitOptions &
|
||||||
|
EventUploadServiceInitOptions;
|
||||||
|
|
||||||
|
export function eventCollectionServiceFactory(
|
||||||
|
cache: { eventCollectionService?: AbstractEventCollectionService } & CachedServices,
|
||||||
|
opts: EventCollectionServiceInitOptions
|
||||||
|
): Promise<AbstractEventCollectionService> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"eventCollectionService",
|
||||||
|
opts,
|
||||||
|
async () =>
|
||||||
|
new EventCollectionService(
|
||||||
|
await cipherServiceFactory(cache, opts),
|
||||||
|
await stateServiceFactory(cache, opts),
|
||||||
|
await organizationServiceFactory(cache, opts),
|
||||||
|
await eventUploadServiceFactory(cache, opts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import { EventService as AbstractEventService } from "@bitwarden/common/abstractions/event.service";
|
|
||||||
import { EventService } from "@bitwarden/common/services/event.service";
|
|
||||||
|
|
||||||
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
|
||||||
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
|
||||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
|
||||||
import {
|
|
||||||
organizationServiceFactory,
|
|
||||||
OrganizationServiceInitOptions,
|
|
||||||
} from "./organization-service.factory";
|
|
||||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
|
||||||
|
|
||||||
type EventServiceOptions = FactoryOptions;
|
|
||||||
|
|
||||||
export type EventServiceInitOptions = EventServiceOptions &
|
|
||||||
ApiServiceInitOptions &
|
|
||||||
CipherServiceInitOptions &
|
|
||||||
StateServiceInitOptions &
|
|
||||||
LogServiceInitOptions &
|
|
||||||
OrganizationServiceInitOptions;
|
|
||||||
|
|
||||||
export function eventServiceFactory(
|
|
||||||
cache: { eventService?: AbstractEventService } & CachedServices,
|
|
||||||
opts: EventServiceInitOptions
|
|
||||||
): Promise<AbstractEventService> {
|
|
||||||
return factory(
|
|
||||||
cache,
|
|
||||||
"eventService",
|
|
||||||
opts,
|
|
||||||
async () =>
|
|
||||||
new EventService(
|
|
||||||
await apiServiceFactory(cache, opts),
|
|
||||||
await cipherServiceFactory(cache, opts),
|
|
||||||
await stateServiceFactory(cache, opts),
|
|
||||||
await logServiceFactory(cache, opts),
|
|
||||||
await organizationServiceFactory(cache, opts)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { EventUploadService as AbstractEventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||||
|
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
|
||||||
|
|
||||||
|
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
||||||
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
|
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||||
|
|
||||||
|
type EventUploadServiceOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type EventUploadServiceInitOptions = EventUploadServiceOptions &
|
||||||
|
ApiServiceInitOptions &
|
||||||
|
StateServiceInitOptions &
|
||||||
|
LogServiceInitOptions;
|
||||||
|
|
||||||
|
export function eventUploadServiceFactory(
|
||||||
|
cache: { eventUploadService?: AbstractEventUploadService } & CachedServices,
|
||||||
|
opts: EventUploadServiceInitOptions
|
||||||
|
): Promise<AbstractEventUploadService> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"eventUploadService",
|
||||||
|
opts,
|
||||||
|
async () =>
|
||||||
|
new EventUploadService(
|
||||||
|
await apiServiceFactory(cache, opts),
|
||||||
|
await stateServiceFactory(cache, opts),
|
||||||
|
await logServiceFactory(cache, opts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { FolderService as AbstractFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
import { FolderService as AbstractFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
||||||
|
|
||||||
import { FolderService } from "../../services/folders/folder.service";
|
import { BrowserFolderService } from "../../services/browser-folder.service";
|
||||||
|
|
||||||
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory";
|
||||||
import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory";
|
import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory";
|
||||||
@@ -28,7 +28,7 @@ export function folderServiceFactory(
|
|||||||
"folderService",
|
"folderService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new FolderService(
|
new BrowserFolderService(
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await cipherServiceFactory(cache, opts),
|
await cipherServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||||
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
|
|
||||||
|
import { BrowserOrganizationService } from "../../services/browser-organization.service";
|
||||||
|
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||||
import {
|
|
||||||
syncNotifierServiceFactory,
|
|
||||||
SyncNotifierServiceInitOptions,
|
|
||||||
} from "./sync-notifier-service.factory";
|
|
||||||
|
|
||||||
type OrganizationServiceFactoryOptions = FactoryOptions;
|
type OrganizationServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions &
|
export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions &
|
||||||
SyncNotifierServiceInitOptions &
|
|
||||||
StateServiceInitOptions;
|
StateServiceInitOptions;
|
||||||
|
|
||||||
export function organizationServiceFactory(
|
export function organizationServiceFactory(
|
||||||
@@ -22,10 +18,6 @@ export function organizationServiceFactory(
|
|||||||
cache,
|
cache,
|
||||||
"organizationService",
|
"organizationService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () => new BrowserOrganizationService(await stateServiceFactory(cache, opts))
|
||||||
new OrganizationService(
|
|
||||||
await stateServiceFactory(cache, opts),
|
|
||||||
await syncNotifierServiceFactory(cache, opts)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PolicyService as AbstractPolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService as AbstractPolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
|
|
||||||
|
import { BrowserPolicyService } from "../../services/browser-policy.service";
|
||||||
|
|
||||||
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
import {
|
import {
|
||||||
@@ -26,7 +27,7 @@ export function policyServiceFactory(
|
|||||||
"policyService",
|
"policyService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new PolicyService(
|
new BrowserPolicyService(
|
||||||
await stateServiceFactory(cache, opts),
|
await stateServiceFactory(cache, opts),
|
||||||
await organizationServiceFactory(cache, opts)
|
await organizationServiceFactory(cache, opts)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { SettingsService as AbstractSettingsService } from "@bitwarden/common/abstractions/settings.service";
|
import { SettingsService as AbstractSettingsService } from "@bitwarden/common/abstractions/settings.service";
|
||||||
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
|
||||||
|
import { BrowserSettingsService } from "../../services/browser-settings.service";
|
||||||
|
|
||||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||||
@@ -16,6 +17,6 @@ export function settingsServiceFactory(
|
|||||||
cache,
|
cache,
|
||||||
"settingsService",
|
"settingsService",
|
||||||
opts,
|
opts,
|
||||||
async () => new SettingsService(await stateServiceFactory(cache, opts))
|
async () => new BrowserSettingsService(await stateServiceFactory(cache, opts))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
|||||||
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
||||||
|
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { StateService } from "../../services/state.service";
|
import { BrowserStateService } from "../../services/browser-state.service";
|
||||||
|
|
||||||
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
@@ -34,15 +34,15 @@ export type StateServiceInitOptions = StateServiceFactoryOptions &
|
|||||||
StateMigrationServiceInitOptions;
|
StateMigrationServiceInitOptions;
|
||||||
|
|
||||||
export async function stateServiceFactory(
|
export async function stateServiceFactory(
|
||||||
cache: { stateService?: StateService } & CachedServices,
|
cache: { stateService?: BrowserStateService } & CachedServices,
|
||||||
opts: StateServiceInitOptions
|
opts: StateServiceInitOptions
|
||||||
): Promise<StateService> {
|
): Promise<BrowserStateService> {
|
||||||
const service = await factory(
|
const service = await factory(
|
||||||
cache,
|
cache,
|
||||||
"stateService",
|
"stateService",
|
||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
await new StateService(
|
await new BrowserStateService(
|
||||||
await diskStorageServiceFactory(cache, opts),
|
await diskStorageServiceFactory(cache, opts),
|
||||||
await secureStorageServiceFactory(cache, opts),
|
await secureStorageServiceFactory(cache, opts),
|
||||||
await memoryStorageServiceFactory(cache, opts),
|
await memoryStorageServiceFactory(cache, opts),
|
||||||
|
|||||||
39
apps/browser/src/clipboard/clear-clipboard.spec.ts
Normal file
39
apps/browser/src/clipboard/clear-clipboard.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
|
|
||||||
|
import { ClearClipboard } from "./clear-clipboard";
|
||||||
|
|
||||||
|
describe("clearClipboard", () => {
|
||||||
|
describe("run", () => {
|
||||||
|
it("Does not clear clipboard when no active tabs are retrieved", async () => {
|
||||||
|
jest.spyOn(BrowserApi, "getActiveTabs").mockResolvedValue([] as any);
|
||||||
|
|
||||||
|
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
|
||||||
|
|
||||||
|
await ClearClipboard.run();
|
||||||
|
|
||||||
|
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).not.toHaveBeenCalledWith(1, {
|
||||||
|
command: "clearClipboard",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Sends a message to the content script to clear the clipboard", async () => {
|
||||||
|
jest.spyOn(BrowserApi, "getActiveTabs").mockResolvedValue([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
] as any);
|
||||||
|
|
||||||
|
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
|
||||||
|
|
||||||
|
await ClearClipboard.run();
|
||||||
|
|
||||||
|
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledWith(1, {
|
||||||
|
command: "clearClipboard",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import { mock, MockProxy } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
|
||||||
|
|
||||||
import { ClearClipboard } from "./clear-clipboard";
|
|
||||||
import { getClearClipboardTime, setClearClipboardTime } from "./clipboard-state";
|
|
||||||
|
|
||||||
jest.mock("./clipboard-state", () => {
|
|
||||||
return {
|
|
||||||
getClearClipboardTime: jest.fn(),
|
|
||||||
setClearClipboardTime: jest.fn(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getClearClipboardTimeMock = getClearClipboardTime as jest.Mock;
|
|
||||||
const setClearClipboardTimeMock = setClearClipboardTime as jest.Mock;
|
|
||||||
|
|
||||||
describe("clearClipboard", () => {
|
|
||||||
describe("run", () => {
|
|
||||||
let stateService: MockProxy<StateService>;
|
|
||||||
let serviceCache: Record<string, unknown>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
stateService = mock<StateService>();
|
|
||||||
serviceCache = {
|
|
||||||
stateService: stateService,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("has a clear time that is past execution time", async () => {
|
|
||||||
const executionTime = new Date(2022, 1, 1, 12);
|
|
||||||
const clearTime = new Date(2022, 1, 1, 12, 1);
|
|
||||||
|
|
||||||
jest.spyOn(BrowserApi, "getActiveTabs").mockResolvedValue([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
] as any);
|
|
||||||
|
|
||||||
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
|
|
||||||
|
|
||||||
getClearClipboardTimeMock.mockResolvedValue(clearTime.getTime());
|
|
||||||
|
|
||||||
await ClearClipboard.run(executionTime, serviceCache);
|
|
||||||
|
|
||||||
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledWith(1, {
|
|
||||||
command: "clearClipboard",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("has a clear time before execution time", async () => {
|
|
||||||
const executionTime = new Date(2022, 1, 1, 12);
|
|
||||||
const clearTime = new Date(2022, 1, 1, 11);
|
|
||||||
|
|
||||||
setClearClipboardTimeMock.mockResolvedValue(clearTime.getTime());
|
|
||||||
|
|
||||||
await ClearClipboard.run(executionTime, serviceCache);
|
|
||||||
|
|
||||||
expect(jest.spyOn(BrowserApi, "getActiveTabs")).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("has an undefined clearTime", async () => {
|
|
||||||
const executionTime = new Date(2022, 1, 1);
|
|
||||||
|
|
||||||
getClearClipboardTimeMock.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
await ClearClipboard.run(executionTime, serviceCache);
|
|
||||||
|
|
||||||
expect(jest.spyOn(BrowserApi, "getActiveTabs")).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,43 +1,15 @@
|
|||||||
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
|
||||||
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
|
||||||
|
|
||||||
import { stateServiceFactory } from "../background/service_factories/state-service.factory";
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { Account } from "../models/account";
|
|
||||||
|
|
||||||
import { getClearClipboardTime } from "./clipboard-state";
|
export const clearClipboardAlarmName = "clearClipboard";
|
||||||
|
|
||||||
export class ClearClipboard {
|
export class ClearClipboard {
|
||||||
static async run(executionTime: Date, serviceCache: Record<string, unknown>) {
|
/**
|
||||||
const stateFactory = new StateFactory(GlobalState, Account);
|
We currently rely on an active tab with an injected content script (`../content/misc-utils.ts`) to clear the clipboard via `window.navigator.clipboard.writeText(text)`
|
||||||
const stateService = await stateServiceFactory(serviceCache, {
|
|
||||||
cryptoFunctionServiceOptions: {
|
|
||||||
win: self,
|
|
||||||
},
|
|
||||||
encryptServiceOptions: {
|
|
||||||
logMacFailures: false,
|
|
||||||
},
|
|
||||||
logServiceOptions: {
|
|
||||||
isDev: false,
|
|
||||||
},
|
|
||||||
stateMigrationServiceOptions: {
|
|
||||||
stateFactory: stateFactory,
|
|
||||||
},
|
|
||||||
stateServiceOptions: {
|
|
||||||
stateFactory: stateFactory,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const clearClipboardTime = await getClearClipboardTime(stateService);
|
|
||||||
|
|
||||||
if (!clearClipboardTime) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clearClipboardTime < executionTime.getTime()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
With https://bugs.chromium.org/p/chromium/issues/detail?id=1160302 it was said that service workers,
|
||||||
|
would have access to the clipboard api and then we could migrate to a simpler solution
|
||||||
|
*/
|
||||||
|
static async run() {
|
||||||
const activeTabs = await BrowserApi.getActiveTabs();
|
const activeTabs = await BrowserApi.getActiveTabs();
|
||||||
if (!activeTabs || activeTabs.length === 0) {
|
if (!activeTabs || activeTabs.length === 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
const clearClipboardStorageKey = "clearClipboardTime";
|
const clearClipboardStorageKey = "clearClipboardTime";
|
||||||
export const getClearClipboardTime = async (stateService: StateService) => {
|
export const getClearClipboardTime = async (stateService: BrowserStateService) => {
|
||||||
return await stateService.getFromSessionMemory<number>(clearClipboardStorageKey);
|
return await stateService.getFromSessionMemory<number>(clearClipboardStorageKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setClearClipboardTime = async (stateService: StateService, time: number) => {
|
export const setClearClipboardTime = async (stateService: BrowserStateService, time: number) => {
|
||||||
await stateService.setInSessionMemory(clearClipboardStorageKey, time);
|
await stateService.setInSessionMemory(clearClipboardStorageKey, time);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,30 +2,30 @@ import { mock, MockProxy } from "jest-mock-extended";
|
|||||||
|
|
||||||
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
||||||
|
|
||||||
|
import { setAlarmTime } from "../alarms/alarm-state";
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { setClearClipboardTime } from "./clipboard-state";
|
import { clearClipboardAlarmName } from "./clear-clipboard";
|
||||||
import { GeneratePasswordToClipboardCommand } from "./generate-password-to-clipboard-command";
|
import { GeneratePasswordToClipboardCommand } from "./generate-password-to-clipboard-command";
|
||||||
|
|
||||||
jest.mock("./clipboard-state", () => {
|
jest.mock("../alarms/alarm-state", () => {
|
||||||
return {
|
return {
|
||||||
getClearClipboardTime: jest.fn(),
|
setAlarmTime: jest.fn(),
|
||||||
setClearClipboardTime: jest.fn(),
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const setClearClipboardTimeMock = setClearClipboardTime as jest.Mock;
|
const setAlarmTimeMock = setAlarmTime as jest.Mock;
|
||||||
|
|
||||||
describe("GeneratePasswordToClipboardCommand", () => {
|
describe("GeneratePasswordToClipboardCommand", () => {
|
||||||
let passwordGenerationService: MockProxy<PasswordGenerationService>;
|
let passwordGenerationService: MockProxy<PasswordGenerationService>;
|
||||||
let stateService: MockProxy<StateService>;
|
let stateService: MockProxy<BrowserStateService>;
|
||||||
|
|
||||||
let sut: GeneratePasswordToClipboardCommand;
|
let sut: GeneratePasswordToClipboardCommand;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
passwordGenerationService = mock<PasswordGenerationService>();
|
passwordGenerationService = mock<PasswordGenerationService>();
|
||||||
stateService = mock<StateService>();
|
stateService = mock<BrowserStateService>();
|
||||||
|
|
||||||
passwordGenerationService.getOptions.mockResolvedValue([{ length: 8 }, {} as any]);
|
passwordGenerationService.getOptions.mockResolvedValue([{ length: 8 }, {} as any]);
|
||||||
|
|
||||||
@@ -53,9 +53,9 @@ describe("GeneratePasswordToClipboardCommand", () => {
|
|||||||
text: "PASSWORD",
|
text: "PASSWORD",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(setClearClipboardTimeMock).toHaveBeenCalledTimes(1);
|
expect(setAlarmTimeMock).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(setClearClipboardTimeMock).toHaveBeenCalledWith(stateService, expect.any(Number));
|
expect(setAlarmTimeMock).toHaveBeenCalledWith(clearClipboardAlarmName, expect.any(Number));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not have clear clipboard value", async () => {
|
it("does not have clear clipboard value", async () => {
|
||||||
@@ -70,7 +70,7 @@ describe("GeneratePasswordToClipboardCommand", () => {
|
|||||||
text: "PASSWORD",
|
text: "PASSWORD",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(setClearClipboardTimeMock).not.toHaveBeenCalled();
|
expect(setAlarmTimeMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
||||||
|
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { setAlarmTime } from "../alarms/alarm-state";
|
||||||
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { setClearClipboardTime } from "./clipboard-state";
|
import { clearClipboardAlarmName } from "./clear-clipboard";
|
||||||
import { copyToClipboard } from "./copy-to-clipboard-command";
|
import { copyToClipboard } from "./copy-to-clipboard-command";
|
||||||
|
|
||||||
export class GeneratePasswordToClipboardCommand {
|
export class GeneratePasswordToClipboardCommand {
|
||||||
constructor(
|
constructor(
|
||||||
private passwordGenerationService: PasswordGenerationService,
|
private passwordGenerationService: PasswordGenerationService,
|
||||||
private stateService: StateService
|
private stateService: BrowserStateService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async generatePasswordToClipboard(tab: chrome.tabs.Tab) {
|
async generatePasswordToClipboard(tab: chrome.tabs.Tab) {
|
||||||
@@ -20,7 +21,7 @@ export class GeneratePasswordToClipboardCommand {
|
|||||||
const clearClipboard = await this.stateService.getClearClipboard();
|
const clearClipboard = await this.stateService.getClearClipboard();
|
||||||
|
|
||||||
if (clearClipboard != null) {
|
if (clearClipboard != null) {
|
||||||
await setClearClipboardTime(this.stateService, Date.now() + clearClipboard * 1000);
|
await setAlarmTime(clearClipboardAlarmName, clearClipboard * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
import { StateService } from "../../services/state.service";
|
import { BrowserStateService } from "../../services/browser-state.service";
|
||||||
|
|
||||||
import { browserSession } from "./browser-session.decorator";
|
import { browserSession } from "./browser-session.decorator";
|
||||||
import { SessionStorable } from "./session-storable";
|
import { SessionStorable } from "./session-storable";
|
||||||
@@ -22,25 +22,25 @@ describe("browserSession decorator", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should create if StateService is a constructor argument", () => {
|
it("should create if StateService is a constructor argument", () => {
|
||||||
const stateService = Object.create(StateService.prototype, {});
|
const stateService = Object.create(BrowserStateService.prototype, {});
|
||||||
|
|
||||||
@browserSession
|
@browserSession
|
||||||
class TestClass {
|
class TestClass {
|
||||||
constructor(private stateService: StateService) {}
|
constructor(private stateService: BrowserStateService) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(new TestClass(stateService)).toBeDefined();
|
expect(new TestClass(stateService)).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("interaction with @sessionSync decorator", () => {
|
describe("interaction with @sessionSync decorator", () => {
|
||||||
let stateService: StateService;
|
let stateService: BrowserStateService;
|
||||||
|
|
||||||
@browserSession
|
@browserSession
|
||||||
class TestClass {
|
class TestClass {
|
||||||
@sessionSync({ initializer: (s: string) => s })
|
@sessionSync({ initializer: (s: string) => s })
|
||||||
private behaviorSubject = new BehaviorSubject("");
|
private behaviorSubject = new BehaviorSubject("");
|
||||||
|
|
||||||
constructor(private stateService: StateService) {}
|
constructor(private stateService: BrowserStateService) {}
|
||||||
|
|
||||||
fromJSON(json: any) {
|
fromJSON(json: any) {
|
||||||
this.behaviorSubject.next(json);
|
this.behaviorSubject.next(json);
|
||||||
@@ -48,7 +48,7 @@ describe("browserSession decorator", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
stateService = Object.create(StateService.prototype, {}) as StateService;
|
stateService = Object.create(BrowserStateService.prototype, {}) as BrowserStateService;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create a session syncer", () => {
|
it("should create a session syncer", () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Constructor } from "type-fest";
|
import { Constructor } from "type-fest";
|
||||||
|
|
||||||
import { StateService } from "../../services/state.service";
|
import { BrowserStateService } from "../../services/browser-state.service";
|
||||||
|
|
||||||
import { SessionStorable } from "./session-storable";
|
import { SessionStorable } from "./session-storable";
|
||||||
import { SessionSyncer } from "./session-syncer";
|
import { SessionSyncer } from "./session-syncer";
|
||||||
@@ -22,7 +22,13 @@ export function browserSession<TCtor extends Constructor<any>>(constructor: TCto
|
|||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
// Require state service to be injected
|
// Require state service to be injected
|
||||||
const stateService = args.find((arg) => arg instanceof StateService);
|
const stateService: BrowserStateService = [this as any]
|
||||||
|
.concat(args)
|
||||||
|
.find(
|
||||||
|
(arg) =>
|
||||||
|
typeof arg.setInSessionMemory === "function" &&
|
||||||
|
typeof arg.getFromSessionMemory === "function"
|
||||||
|
);
|
||||||
if (!stateService) {
|
if (!stateService) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot decorate ${constructor.name} with browserSession, Browser's StateService must be injected`
|
`Cannot decorate ${constructor.name} with browserSession, Browser's StateService must be injected`
|
||||||
@@ -38,7 +44,7 @@ export function browserSession<TCtor extends Constructor<any>>(constructor: TCto
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSyncer(metadata: SyncedItemMetadata, stateService: StateService) {
|
buildSyncer(metadata: SyncedItemMetadata, stateService: BrowserStateService) {
|
||||||
const syncer = new SessionSyncer((this as any)[metadata.propertyKey], stateService, metadata);
|
const syncer = new SessionSyncer((this as any)[metadata.propertyKey], stateService, metadata);
|
||||||
syncer.init();
|
syncer.init();
|
||||||
return syncer;
|
return syncer;
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ describe("sessionSync decorator", () => {
|
|||||||
class TestClass {
|
class TestClass {
|
||||||
@sessionSync({ ctor: ctor, initializer: initializer })
|
@sessionSync({ ctor: ctor, initializer: initializer })
|
||||||
private testProperty = new BehaviorSubject("");
|
private testProperty = new BehaviorSubject("");
|
||||||
|
@sessionSync({ ctor: ctor, initializer: initializer, initializeAs: "array" })
|
||||||
|
private secondTestProperty = new BehaviorSubject("");
|
||||||
|
|
||||||
complete() {
|
complete() {
|
||||||
this.testProperty.complete();
|
this.testProperty.complete();
|
||||||
|
this.secondTestProperty.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,11 +22,40 @@ describe("sessionSync decorator", () => {
|
|||||||
expect((testClass as any).__syncedItemMetadata).toEqual([
|
expect((testClass as any).__syncedItemMetadata).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
propertyKey: "testProperty",
|
propertyKey: "testProperty",
|
||||||
sessionKey: "TestClass_testProperty",
|
sessionKey: "testProperty_0",
|
||||||
ctor: ctor,
|
ctor: ctor,
|
||||||
initializer: initializer,
|
initializer: initializer,
|
||||||
}),
|
}),
|
||||||
testClass.complete(),
|
expect.objectContaining({
|
||||||
|
propertyKey: "secondTestProperty",
|
||||||
|
sessionKey: "secondTestProperty_1",
|
||||||
|
ctor: ctor,
|
||||||
|
initializer: initializer,
|
||||||
|
initializeAs: "array",
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
testClass.complete();
|
||||||
|
});
|
||||||
|
|
||||||
|
class TestClass2 {
|
||||||
|
@sessionSync({ ctor: ctor, initializer: initializer })
|
||||||
|
private testProperty = new BehaviorSubject("");
|
||||||
|
|
||||||
|
complete() {
|
||||||
|
this.testProperty.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should maintain sessionKey index count for other test classes", () => {
|
||||||
|
const testClass = new TestClass2();
|
||||||
|
expect((testClass as any).__syncedItemMetadata).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
propertyKey: "testProperty",
|
||||||
|
sessionKey: "testProperty_2",
|
||||||
|
ctor: ctor,
|
||||||
|
initializer: initializer,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
testClass.complete();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { SessionStorable } from "./session-storable";
|
import { SessionStorable } from "./session-storable";
|
||||||
|
import { InitializeOptions } from "./sync-item-metadata";
|
||||||
|
|
||||||
class BuildOptions<T> {
|
class BuildOptions<T, TJson = Jsonify<T>> {
|
||||||
ctor?: new () => T;
|
ctor?: new () => T;
|
||||||
initializer?: (keyValuePair: Jsonify<T>) => T;
|
initializer?: (keyValuePair: TJson) => T;
|
||||||
initializeAsArray? = false;
|
initializeAs?: InitializeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to ensure uniqueness for each synced observable
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A decorator used to indicate the BehaviorSubject should be synced for this browser session across all contexts.
|
* A decorator used to indicate the BehaviorSubject should be synced for this browser session across all contexts.
|
||||||
*
|
*
|
||||||
@@ -20,10 +24,10 @@ class BuildOptions<T> {
|
|||||||
* @param buildOptions
|
* @param buildOptions
|
||||||
* Builders for the value, requires either a constructor (ctor) for your BehaviorSubject type or an
|
* Builders for the value, requires either a constructor (ctor) for your BehaviorSubject type or an
|
||||||
* initializer function that takes a key value pair representation of the BehaviorSubject data
|
* initializer function that takes a key value pair representation of the BehaviorSubject data
|
||||||
* and returns your instantiated BehaviorSubject value. `initializeAsArray can optionally be used to indicate
|
* and returns your instantiated BehaviorSubject value. `initializeAs can optionally be used to indicate
|
||||||
* the provided initializer function should be used to build an array of values. For example,
|
* the provided initializer function should be used to build an array of values. For example,
|
||||||
* ```ts
|
* ```ts
|
||||||
* \@sessionSync({ initializer: Foo.fromJSON, initializeAsArray: true })
|
* \@sessionSync({ initializer: Foo.fromJSON, initializeAs: 'array' })
|
||||||
* ```
|
* ```
|
||||||
* is equivalent to
|
* is equivalent to
|
||||||
* ```
|
* ```
|
||||||
@@ -43,10 +47,10 @@ export function sessionSync<T>(buildOptions: BuildOptions<T>) {
|
|||||||
|
|
||||||
p.__syncedItemMetadata.push({
|
p.__syncedItemMetadata.push({
|
||||||
propertyKey,
|
propertyKey,
|
||||||
sessionKey: `${prototype.constructor.name}_${propertyKey}`,
|
sessionKey: `${propertyKey}_${index++}`,
|
||||||
ctor: buildOptions.ctor,
|
ctor: buildOptions.ctor,
|
||||||
initializer: buildOptions.initializer,
|
initializer: buildOptions.initializer,
|
||||||
initializeAsArray: buildOptions.initializeAsArray,
|
initializeAs: buildOptions.initializeAs ?? "object",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { awaitAsync, awaitAsync as flushAsyncObservables } from "@bitwarden/angular/../test-utils";
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject, ReplaySubject } from "rxjs";
|
||||||
|
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { SessionSyncer } from "./session-syncer";
|
import { SessionSyncer } from "./session-syncer";
|
||||||
import { SyncedItemMetadata } from "./sync-item-metadata";
|
import { SyncedItemMetadata } from "./sync-item-metadata";
|
||||||
@@ -10,8 +11,13 @@ import { SyncedItemMetadata } from "./sync-item-metadata";
|
|||||||
describe("session syncer", () => {
|
describe("session syncer", () => {
|
||||||
const propertyKey = "behaviorSubject";
|
const propertyKey = "behaviorSubject";
|
||||||
const sessionKey = "Test__" + propertyKey;
|
const sessionKey = "Test__" + propertyKey;
|
||||||
const metaData = { propertyKey, sessionKey, initializer: (s: string) => s };
|
const metaData: SyncedItemMetadata = {
|
||||||
let stateService: MockProxy<StateService>;
|
propertyKey,
|
||||||
|
sessionKey,
|
||||||
|
initializer: (s: string) => s,
|
||||||
|
initializeAs: "object",
|
||||||
|
};
|
||||||
|
let stateService: MockProxy<BrowserStateService>;
|
||||||
let sut: SessionSyncer;
|
let sut: SessionSyncer;
|
||||||
let behaviorSubject: BehaviorSubject<string>;
|
let behaviorSubject: BehaviorSubject<string>;
|
||||||
|
|
||||||
@@ -23,7 +29,8 @@ describe("session syncer", () => {
|
|||||||
manifest_version: 3,
|
manifest_version: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
stateService = mock<StateService>();
|
stateService = mock<BrowserStateService>();
|
||||||
|
stateService.hasInSessionMemory.mockResolvedValue(false);
|
||||||
sut = new SessionSyncer(behaviorSubject, stateService, metaData);
|
sut = new SessionSyncer(behaviorSubject, stateService, metaData);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,53 +41,87 @@ describe("session syncer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("constructor", () => {
|
describe("constructor", () => {
|
||||||
it("should throw if behaviorSubject is not an instance of BehaviorSubject", () => {
|
it("should throw if subject is not an instance of Subject", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new SessionSyncer({} as any, stateService, null);
|
new SessionSyncer({} as any, stateService, null);
|
||||||
}).toThrowError("behaviorSubject must be an instance of BehaviorSubject");
|
}).toThrowError("subject must inherit from Subject");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create if either ctor or initializer is provided", () => {
|
it("should create if either ctor or initializer is provided", () => {
|
||||||
expect(
|
expect(
|
||||||
new SessionSyncer(behaviorSubject, stateService, { propertyKey, sessionKey, ctor: String })
|
new SessionSyncer(behaviorSubject, stateService, {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey,
|
||||||
|
ctor: String,
|
||||||
|
initializeAs: "object",
|
||||||
|
})
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
expect(
|
expect(
|
||||||
new SessionSyncer(behaviorSubject, stateService, {
|
new SessionSyncer(behaviorSubject, stateService, {
|
||||||
propertyKey,
|
propertyKey,
|
||||||
sessionKey,
|
sessionKey,
|
||||||
initializer: (s: any) => s,
|
initializer: (s: any) => s,
|
||||||
|
initializeAs: "object",
|
||||||
})
|
})
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
});
|
});
|
||||||
it("should throw if neither ctor or initializer is provided", () => {
|
it("should throw if neither ctor or initializer is provided", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new SessionSyncer(behaviorSubject, stateService, { propertyKey, sessionKey });
|
new SessionSyncer(behaviorSubject, stateService, {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey,
|
||||||
|
initializeAs: "object",
|
||||||
|
});
|
||||||
}).toThrowError("ctor or initializer must be provided");
|
}).toThrowError("ctor or initializer must be provided");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("manifest v2 init", () => {
|
describe("init", () => {
|
||||||
let observeSpy: jest.SpyInstance;
|
it("should ignore all updates currently in a ReplaySubject's buffer", () => {
|
||||||
let listenForUpdatesSpy: jest.SpyInstance;
|
const replaySubject = new ReplaySubject<string>(Infinity);
|
||||||
|
replaySubject.next("1");
|
||||||
beforeEach(() => {
|
replaySubject.next("2");
|
||||||
observeSpy = jest.spyOn(behaviorSubject, "subscribe").mockReturnThis();
|
replaySubject.next("3");
|
||||||
listenForUpdatesSpy = jest.spyOn(BrowserApi, "messageListener").mockReturnValue();
|
sut = new SessionSyncer(replaySubject, stateService, metaData);
|
||||||
jest.spyOn(chrome.runtime, "getManifest").mockReturnValue({
|
// block observing the subject
|
||||||
name: "bitwarden-test",
|
jest.spyOn(sut as any, "observe").mockImplementation();
|
||||||
version: "0.0.0",
|
|
||||||
manifest_version: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
sut.init();
|
sut.init();
|
||||||
|
|
||||||
|
expect(sut["ignoreNUpdates"]).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not start observing", () => {
|
it("should ignore BehaviorSubject's initial value", () => {
|
||||||
expect(observeSpy).not.toHaveBeenCalled();
|
const behaviorSubject = new BehaviorSubject<string>("initial");
|
||||||
|
sut = new SessionSyncer(behaviorSubject, stateService, metaData);
|
||||||
|
// block observing the subject
|
||||||
|
jest.spyOn(sut as any, "observe").mockImplementation();
|
||||||
|
|
||||||
|
sut.init();
|
||||||
|
|
||||||
|
expect(sut["ignoreNUpdates"]).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not start listening", () => {
|
it("should grab an initial value from storage if it exists", async () => {
|
||||||
expect(listenForUpdatesSpy).not.toHaveBeenCalled();
|
stateService.hasInSessionMemory.mockResolvedValue(true);
|
||||||
|
//Block a call to update
|
||||||
|
const updateSpy = jest.spyOn(sut as any, "update").mockImplementation();
|
||||||
|
|
||||||
|
sut.init();
|
||||||
|
await awaitAsync();
|
||||||
|
|
||||||
|
expect(updateSpy).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not grab an initial value from storage if it does not exist", async () => {
|
||||||
|
stateService.hasInSessionMemory.mockResolvedValue(false);
|
||||||
|
//Block a call to update
|
||||||
|
const updateSpy = jest.spyOn(sut as any, "update").mockImplementation();
|
||||||
|
|
||||||
|
sut.init();
|
||||||
|
await awaitAsync();
|
||||||
|
|
||||||
|
expect(updateSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -146,6 +187,7 @@ describe("session syncer", () => {
|
|||||||
stateService.getFromSessionMemory.mockResolvedValue("test");
|
stateService.getFromSessionMemory.mockResolvedValue("test");
|
||||||
|
|
||||||
await sut.updateFromMessage({ command: `${sessionKey}_update`, id: "different_id" });
|
await sut.updateFromMessage({ command: `${sessionKey}_update`, id: "different_id" });
|
||||||
|
await flushAsyncObservables();
|
||||||
|
|
||||||
expect(stateService.getFromSessionMemory).toHaveBeenCalledTimes(1);
|
expect(stateService.getFromSessionMemory).toHaveBeenCalledTimes(1);
|
||||||
expect(stateService.getFromSessionMemory).toHaveBeenCalledWith(sessionKey, builder);
|
expect(stateService.getFromSessionMemory).toHaveBeenCalledWith(sessionKey, builder);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { BehaviorSubject, concatMap, Subscription } from "rxjs";
|
import { BehaviorSubject, concatMap, ReplaySubject, Subject, Subscription } from "rxjs";
|
||||||
|
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
|
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { SyncedItemMetadata } from "./sync-item-metadata";
|
import { SyncedItemMetadata } from "./sync-item-metadata";
|
||||||
|
|
||||||
@@ -11,16 +11,16 @@ export class SessionSyncer {
|
|||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
id = Utils.newGuid();
|
id = Utils.newGuid();
|
||||||
|
|
||||||
// everyone gets the same initial values
|
// ignore initial values
|
||||||
private ignoreNextUpdate = true;
|
private ignoreNUpdates = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private behaviorSubject: BehaviorSubject<any>,
|
private subject: Subject<any>,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private metaData: SyncedItemMetadata
|
private metaData: SyncedItemMetadata
|
||||||
) {
|
) {
|
||||||
if (!(behaviorSubject instanceof BehaviorSubject)) {
|
if (!(subject instanceof Subject)) {
|
||||||
throw new Error("behaviorSubject must be an instance of BehaviorSubject");
|
throw new Error("subject must inherit from Subject");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metaData.ctor == null && metaData.initializer == null) {
|
if (metaData.ctor == null && metaData.initializer == null) {
|
||||||
@@ -29,11 +29,26 @@ export class SessionSyncer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (BrowserApi.manifestVersion !== 3) {
|
switch (this.subject.constructor) {
|
||||||
return;
|
case ReplaySubject:
|
||||||
|
// ignore all updates currently in the buffer
|
||||||
|
this.ignoreNUpdates = (this.subject as any)._buffer.length;
|
||||||
|
break;
|
||||||
|
case BehaviorSubject:
|
||||||
|
this.ignoreNUpdates = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.observe();
|
this.observe();
|
||||||
|
// must be synchronous
|
||||||
|
this.stateService.hasInSessionMemory(this.metaData.sessionKey).then((hasInSessionMemory) => {
|
||||||
|
if (hasInSessionMemory) {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.listenForUpdates();
|
this.listenForUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,11 +56,11 @@ export class SessionSyncer {
|
|||||||
// This may be a memory leak.
|
// This may be a memory leak.
|
||||||
// There is no good time to unsubscribe from this observable. Hopefully Manifest V3 clears memory from temporary
|
// There is no good time to unsubscribe from this observable. Hopefully Manifest V3 clears memory from temporary
|
||||||
// contexts. If so, this is handled by destruction of the context.
|
// contexts. If so, this is handled by destruction of the context.
|
||||||
this.subscription = this.behaviorSubject
|
this.subscription = this.subject
|
||||||
.pipe(
|
.pipe(
|
||||||
concatMap(async (next) => {
|
concatMap(async (next) => {
|
||||||
if (this.ignoreNextUpdate) {
|
if (this.ignoreNUpdates > 0) {
|
||||||
this.ignoreNextUpdate = false;
|
this.ignoreNUpdates -= 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.updateSession(next);
|
await this.updateSession(next);
|
||||||
@@ -66,10 +81,14 @@ export class SessionSyncer {
|
|||||||
if (message.command != this.updateMessageCommand || message.id === this.id) {
|
if (message.command != this.updateMessageCommand || message.id === this.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
async update() {
|
||||||
const builder = SyncedItemMetadata.builder(this.metaData);
|
const builder = SyncedItemMetadata.builder(this.metaData);
|
||||||
const value = await this.stateService.getFromSessionMemory(this.metaData.sessionKey, builder);
|
const value = await this.stateService.getFromSessionMemory(this.metaData.sessionKey, builder);
|
||||||
this.ignoreNextUpdate = true;
|
this.ignoreNUpdates = 1;
|
||||||
this.behaviorSubject.next(value);
|
this.subject.next(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateSession(value: any) {
|
private async updateSession(value: any) {
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
|
export type InitializeOptions = "array" | "record" | "object";
|
||||||
|
|
||||||
export class SyncedItemMetadata {
|
export class SyncedItemMetadata {
|
||||||
propertyKey: string;
|
propertyKey: string;
|
||||||
sessionKey: string;
|
sessionKey: string;
|
||||||
ctor?: new () => any;
|
ctor?: new () => any;
|
||||||
initializer?: (keyValuePair: any) => any;
|
initializer?: (keyValuePair: any) => any;
|
||||||
initializeAsArray?: boolean;
|
initializeAs: InitializeOptions;
|
||||||
|
|
||||||
static builder(metadata: SyncedItemMetadata): (o: any) => any {
|
static builder(metadata: SyncedItemMetadata): (o: any) => any {
|
||||||
const itemBuilder =
|
const itemBuilder =
|
||||||
metadata.initializer != null
|
metadata.initializer != null
|
||||||
? metadata.initializer
|
? metadata.initializer
|
||||||
: (o: any) => Object.assign(new metadata.ctor(), o);
|
: (o: any) => Object.assign(new metadata.ctor(), o);
|
||||||
if (metadata.initializeAsArray) {
|
if (metadata.initializeAs === "array") {
|
||||||
return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o));
|
return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o));
|
||||||
|
} else if (metadata.initializeAs === "record") {
|
||||||
|
return (keyValuePair: any) => {
|
||||||
|
const record: Record<any, any> = {};
|
||||||
|
for (const key in keyValuePair) {
|
||||||
|
record[key] = itemBuilder(keyValuePair[key]);
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return (keyValuePair: any) => itemBuilder(keyValuePair);
|
return (keyValuePair: any) => itemBuilder(keyValuePair);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,32 +8,60 @@ describe("builder", () => {
|
|||||||
const ctor = TestClass;
|
const ctor = TestClass;
|
||||||
|
|
||||||
it("should use initializer if provided", () => {
|
it("should use initializer if provided", () => {
|
||||||
const metadata = { propertyKey, sessionKey: key, initializer };
|
const metadata: SyncedItemMetadata = {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey: key,
|
||||||
|
initializer,
|
||||||
|
initializeAs: "object",
|
||||||
|
};
|
||||||
const builder = SyncedItemMetadata.builder(metadata);
|
const builder = SyncedItemMetadata.builder(metadata);
|
||||||
expect(builder({})).toBe("used initializer");
|
expect(builder({})).toBe("used initializer");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should use ctor if initializer is not provided", () => {
|
it("should use ctor if initializer is not provided", () => {
|
||||||
const metadata = { propertyKey, sessionKey: key, ctor };
|
const metadata: SyncedItemMetadata = {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey: key,
|
||||||
|
ctor,
|
||||||
|
initializeAs: "object",
|
||||||
|
};
|
||||||
const builder = SyncedItemMetadata.builder(metadata);
|
const builder = SyncedItemMetadata.builder(metadata);
|
||||||
expect(builder({})).toBeInstanceOf(TestClass);
|
expect(builder({})).toBeInstanceOf(TestClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should prefer initializer over ctor", () => {
|
it("should prefer initializer over ctor", () => {
|
||||||
const metadata = { propertyKey, sessionKey: key, ctor, initializer };
|
const metadata: SyncedItemMetadata = {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey: key,
|
||||||
|
ctor,
|
||||||
|
initializer,
|
||||||
|
initializeAs: "object",
|
||||||
|
};
|
||||||
const builder = SyncedItemMetadata.builder(metadata);
|
const builder = SyncedItemMetadata.builder(metadata);
|
||||||
expect(builder({})).toBe("used initializer");
|
expect(builder({})).toBe("used initializer");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should honor initialize as array", () => {
|
it("should honor initialize as array", () => {
|
||||||
const metadata = {
|
const metadata: SyncedItemMetadata = {
|
||||||
propertyKey,
|
propertyKey,
|
||||||
sessionKey: key,
|
sessionKey: key,
|
||||||
initializer: initializer,
|
initializer: initializer,
|
||||||
initializeAsArray: true,
|
initializeAs: "array",
|
||||||
};
|
};
|
||||||
const builder = SyncedItemMetadata.builder(metadata);
|
const builder = SyncedItemMetadata.builder(metadata);
|
||||||
expect(builder([{}])).toBeInstanceOf(Array);
|
expect(builder([{}])).toBeInstanceOf(Array);
|
||||||
expect(builder([{}])[0]).toBe("used initializer");
|
expect(builder([{}])[0]).toBe("used initializer");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should honor initialize as record", () => {
|
||||||
|
const metadata: SyncedItemMetadata = {
|
||||||
|
propertyKey,
|
||||||
|
sessionKey: key,
|
||||||
|
initializer: initializer,
|
||||||
|
initializeAs: "record",
|
||||||
|
};
|
||||||
|
const builder = SyncedItemMetadata.builder(metadata);
|
||||||
|
expect(builder({ key: "" })).toBeInstanceOf(Object);
|
||||||
|
expect(builder({ key: "" })).toStrictEqual({ key: "used initializer" });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { searchServiceFactory } from "../background/service_factories/search-ser
|
|||||||
import { stateServiceFactory } from "../background/service_factories/state-service.factory";
|
import { stateServiceFactory } from "../background/service_factories/state-service.factory";
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { Account } from "../models/account";
|
import { Account } from "../models/account";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
||||||
|
|
||||||
export type BadgeOptions = {
|
export type BadgeOptions = {
|
||||||
@@ -25,7 +25,7 @@ export type BadgeOptions = {
|
|||||||
|
|
||||||
export class UpdateBadge {
|
export class UpdateBadge {
|
||||||
private authService: AuthService;
|
private authService: AuthService;
|
||||||
private stateService: StateService;
|
private stateService: BrowserStateService;
|
||||||
private cipherService: CipherService;
|
private cipherService: CipherService;
|
||||||
private badgeAction: typeof chrome.action;
|
private badgeAction: typeof chrome.action;
|
||||||
private sidebarAction: OperaSidebarAction | FirefoxSidebarAction;
|
private sidebarAction: OperaSidebarAction | FirefoxSidebarAction;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account as BaseAccount,
|
Account as BaseAccount,
|
||||||
AccountSettings as BaseAccountSettings,
|
AccountSettings as BaseAccountSettings,
|
||||||
@@ -9,6 +11,14 @@ import { BrowserSendComponentState } from "./browserSendComponentState";
|
|||||||
|
|
||||||
export class AccountSettings extends BaseAccountSettings {
|
export class AccountSettings extends BaseAccountSettings {
|
||||||
vaultTimeout = -1; // On Restart
|
vaultTimeout = -1; // On Restart
|
||||||
|
|
||||||
|
static fromJSON(json: Jsonify<AccountSettings>): AccountSettings {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new AccountSettings(), json, super.fromJSON(json));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Account extends BaseAccount {
|
export class Account extends BaseAccount {
|
||||||
@@ -29,4 +39,18 @@ export class Account extends BaseAccount {
|
|||||||
this.ciphers = init?.ciphers ?? new BrowserComponentState();
|
this.ciphers = init?.ciphers ?? new BrowserComponentState();
|
||||||
this.sendType = init?.sendType ?? new BrowserComponentState();
|
this.sendType = init?.sendType ?? new BrowserComponentState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: Jsonify<Account>): Account {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new Account({}), json, super.fromJSON(json), {
|
||||||
|
settings: AccountSettings.fromJSON(json.settings),
|
||||||
|
groupings: BrowserGroupingsComponentState.fromJSON(json.groupings),
|
||||||
|
send: BrowserSendComponentState.fromJSON(json.send),
|
||||||
|
ciphers: BrowserComponentState.fromJSON(json.ciphers),
|
||||||
|
sendType: BrowserComponentState.fromJSON(json.sendType),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
export class BrowserComponentState {
|
export class BrowserComponentState {
|
||||||
scrollY: number;
|
scrollY: number;
|
||||||
searchText: string;
|
searchText: string;
|
||||||
|
|
||||||
|
static fromJSON(json: Jsonify<BrowserComponentState>) {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new BrowserComponentState(), json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
||||||
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
|
||||||
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
|
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
|
||||||
import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
||||||
|
import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify";
|
||||||
|
|
||||||
import { BrowserComponentState } from "./browserComponentState";
|
import { BrowserComponentState } from "./browserComponentState";
|
||||||
|
|
||||||
@@ -15,4 +17,28 @@ export class BrowserGroupingsComponentState extends BrowserComponentState {
|
|||||||
folders: FolderView[];
|
folders: FolderView[];
|
||||||
collections: CollectionView[];
|
collections: CollectionView[];
|
||||||
deletedCount: number;
|
deletedCount: number;
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return Utils.merge(this, {
|
||||||
|
collectionCounts: Utils.mapToRecord(this.collectionCounts),
|
||||||
|
folderCounts: Utils.mapToRecord(this.folderCounts),
|
||||||
|
typeCounts: Utils.mapToRecord(this.typeCounts),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: DeepJsonify<BrowserGroupingsComponentState>) {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new BrowserGroupingsComponentState(), json, {
|
||||||
|
favoriteCiphers: json.favoriteCiphers?.map((c) => CipherView.fromJSON(c)),
|
||||||
|
noFolderCiphers: json.noFolderCiphers?.map((c) => CipherView.fromJSON(c)),
|
||||||
|
ciphers: json.ciphers?.map((c) => CipherView.fromJSON(c)),
|
||||||
|
collectionCounts: Utils.recordToMap(json.collectionCounts),
|
||||||
|
folderCounts: Utils.recordToMap(json.folderCounts),
|
||||||
|
typeCounts: Utils.recordToMap(json.typeCounts),
|
||||||
|
folders: json.folders?.map((f) => FolderView.fromJSON(f)),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
import { SendType } from "@bitwarden/common/enums/sendType";
|
import { SendType } from "@bitwarden/common/enums/sendType";
|
||||||
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { SendView } from "@bitwarden/common/models/view/send.view";
|
import { SendView } from "@bitwarden/common/models/view/send.view";
|
||||||
|
import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify";
|
||||||
|
|
||||||
import { BrowserComponentState } from "./browserComponentState";
|
import { BrowserComponentState } from "./browserComponentState";
|
||||||
|
|
||||||
export class BrowserSendComponentState extends BrowserComponentState {
|
export class BrowserSendComponentState extends BrowserComponentState {
|
||||||
sends: SendView[];
|
sends: SendView[];
|
||||||
typeCounts: Map<SendType, number>;
|
typeCounts: Map<SendType, number>;
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return Utils.merge(this, {
|
||||||
|
typeCounts: Utils.mapToRecord(this.typeCounts),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: DeepJsonify<BrowserSendComponentState>) {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(new BrowserSendComponentState(), json, {
|
||||||
|
sends: json.sends?.map((s) => SendView.fromJSON(s)),
|
||||||
|
typeCounts: Utils.recordToMap(json.typeCounts),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,13 +39,10 @@
|
|||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<div class="box-content-row-flex">
|
<div class="box-content-row-flex">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<label for="masterPassword"
|
<label for="masterPassword">
|
||||||
>{{ "masterPass" | i18n }}
|
{{ "masterPass" | i18n }}
|
||||||
<strong
|
<strong class="sub-label text-{{ color }}" *ngIf="text">
|
||||||
class="sub-label text-{{ passwordStrengthComponent?.masterPasswordScoreColor }}"
|
{{ text }}
|
||||||
*ngIf="passwordStrengthComponent?.masterPasswordScoreText"
|
|
||||||
>
|
|
||||||
{{ passwordStrengthComponent?.masterPasswordScoreText }}
|
|
||||||
</strong>
|
</strong>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -86,7 +86,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="selectedProviderType === providerType.WebAuthn && !webAuthnNewTab">
|
<ng-container *ngIf="selectedProviderType === providerType.WebAuthn && !webAuthnNewTab">
|
||||||
<div id="web-authn-frame"><iframe id="webauthn_iframe" [allow]="webAuthnAllow"></iframe></div>
|
<div id="web-authn-frame">
|
||||||
|
<iframe id="webauthn_iframe" [attr.allow]="webAuthnAllow"></iframe>
|
||||||
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ import { SyncComponent } from "./settings/sync.component";
|
|||||||
import { TabsComponent } from "./tabs.component";
|
import { TabsComponent } from "./tabs.component";
|
||||||
import { AddEditComponent } from "./vault/add-edit.component";
|
import { AddEditComponent } from "./vault/add-edit.component";
|
||||||
import { AttachmentsComponent } from "./vault/attachments.component";
|
import { AttachmentsComponent } from "./vault/attachments.component";
|
||||||
import { CiphersComponent } from "./vault/ciphers.component";
|
|
||||||
import { CollectionsComponent } from "./vault/collections.component";
|
import { CollectionsComponent } from "./vault/collections.component";
|
||||||
import { CurrentTabComponent } from "./vault/current-tab.component";
|
import { CurrentTabComponent } from "./vault/current-tab.component";
|
||||||
import { PasswordHistoryComponent } from "./vault/password-history.component";
|
import { PasswordHistoryComponent } from "./vault/password-history.component";
|
||||||
import { ShareComponent } from "./vault/share.component";
|
import { ShareComponent } from "./vault/share.component";
|
||||||
import { VaultFilterComponent } from "./vault/vault-filter.component";
|
import { VaultFilterComponent } from "./vault/vault-filter.component";
|
||||||
|
import { VaultItemsComponent } from "./vault/vault-items.component";
|
||||||
import { ViewComponent } from "./vault/view.component";
|
import { ViewComponent } from "./vault/view.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
@@ -120,7 +120,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "ciphers",
|
path: "ciphers",
|
||||||
component: CiphersComponent,
|
component: VaultItemsComponent,
|
||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard],
|
||||||
data: { state: "ciphers" },
|
data: { state: "ciphers" },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { BrowserStateService } from "../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { routerTransition } from "./app-routing.animations";
|
import { routerTransition } from "./app-routing.animations";
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
@@ -276,7 +276,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.stateService.setBrowserGroupingComponentState(null),
|
this.stateService.setBrowserGroupingComponentState(null),
|
||||||
this.stateService.setBrowserCipherComponentState(null),
|
this.stateService.setBrowserVaultItemsComponentState(null),
|
||||||
this.stateService.setBrowserSendComponentState(null),
|
this.stateService.setBrowserSendComponentState(null),
|
||||||
this.stateService.setBrowserSendTypeComponentState(null),
|
this.stateService.setBrowserSendTypeComponentState(null),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ import { TabsComponent } from "./tabs.component";
|
|||||||
import { AddEditCustomFieldsComponent } from "./vault/add-edit-custom-fields.component";
|
import { AddEditCustomFieldsComponent } from "./vault/add-edit-custom-fields.component";
|
||||||
import { AddEditComponent } from "./vault/add-edit.component";
|
import { AddEditComponent } from "./vault/add-edit.component";
|
||||||
import { AttachmentsComponent } from "./vault/attachments.component";
|
import { AttachmentsComponent } from "./vault/attachments.component";
|
||||||
import { CiphersComponent } from "./vault/ciphers.component";
|
|
||||||
import { CollectionsComponent } from "./vault/collections.component";
|
import { CollectionsComponent } from "./vault/collections.component";
|
||||||
import { CurrentTabComponent } from "./vault/current-tab.component";
|
import { CurrentTabComponent } from "./vault/current-tab.component";
|
||||||
import { PasswordHistoryComponent } from "./vault/password-history.component";
|
import { PasswordHistoryComponent } from "./vault/password-history.component";
|
||||||
import { ShareComponent } from "./vault/share.component";
|
import { ShareComponent } from "./vault/share.component";
|
||||||
import { VaultFilterComponent } from "./vault/vault-filter.component";
|
import { VaultFilterComponent } from "./vault/vault-filter.component";
|
||||||
|
import { VaultItemsComponent } from "./vault/vault-items.component";
|
||||||
import { VaultSelectComponent } from "./vault/vault-select.component";
|
import { VaultSelectComponent } from "./vault/vault-select.component";
|
||||||
import { ViewCustomFieldsComponent } from "./vault/view-custom-fields.component";
|
import { ViewCustomFieldsComponent } from "./vault/view-custom-fields.component";
|
||||||
import { ViewComponent } from "./vault/view.component";
|
import { ViewComponent } from "./vault/view.component";
|
||||||
@@ -200,7 +200,7 @@ registerLocaleData(localeZhTw, "zh-TW");
|
|||||||
AppComponent,
|
AppComponent,
|
||||||
AttachmentsComponent,
|
AttachmentsComponent,
|
||||||
CipherRowComponent,
|
CipherRowComponent,
|
||||||
CiphersComponent,
|
VaultItemsComponent,
|
||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
CurrentTabComponent,
|
CurrentTabComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||||
|
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service";
|
import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
@@ -27,7 +27,7 @@ export class ActionButtonsComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private eventService: EventService,
|
private eventCollectionService: EventCollectionService,
|
||||||
private totpService: TotpService,
|
private totpService: TotpService,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private passwordRepromptService: PasswordRepromptService
|
private passwordRepromptService: PasswordRepromptService
|
||||||
@@ -68,9 +68,12 @@ export class ActionButtonsComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (typeI18nKey === "password" || typeI18nKey === "verificationCodeTotp") {
|
if (typeI18nKey === "password" || typeI18nKey === "verificationCodeTotp") {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, cipher.id);
|
this.eventCollectionService.collect(
|
||||||
|
EventType.Cipher_ClientToggledHiddenFieldVisible,
|
||||||
|
cipher.id
|
||||||
|
);
|
||||||
} else if (typeI18nKey === "securityCode") {
|
} else if (typeI18nKey === "securityCode") {
|
||||||
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, cipher.id);
|
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedCardCode, cipher.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,11 +57,11 @@
|
|||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
|
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
|
||||||
(click)="regenerate()"
|
(click)="regenerate()"
|
||||||
[disabled]="form.loading"
|
[disabled]="$any(form).loading"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg bwi-generate"
|
class="bwi bwi-lg bwi-generate"
|
||||||
[ngClass]="form.loading ? 'bwi-spin' : ''"
|
[ngClass]="$any(form).loading ? 'bwi-spin' : ''"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -320,22 +320,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="usernameOptions.type === 'forwarded'">
|
<div class="box" *ngIf="usernameOptions.type === 'forwarded'">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" role="radiogroup" aria-labelledby="forwardTypeHeading">
|
<div class="box-content-row" role="listbox" aria-labelledby="forwardTypeHeading">
|
||||||
<label id="forwardTypeHeading" class="radio-header">{{ "service" | i18n }}</label>
|
<label id="forwardTypeHeading">{{ "service" | i18n }}</label>
|
||||||
<div class="radio-group text-default" appBoxRow *ngFor="let o of forwardOptions">
|
<select
|
||||||
<input
|
id="ForwardTypeDropdown"
|
||||||
type="radio"
|
name="ForwardType"
|
||||||
[(ngModel)]="usernameOptions.forwardedService"
|
[(ngModel)]="usernameOptions.forwardedService"
|
||||||
name="ForwardType"
|
(change)="saveUsernameOptions()"
|
||||||
id="forwardtype_{{ o.value }}"
|
>
|
||||||
[value]="o.value"
|
<option *ngFor="let o of forwardOptions" [ngValue]="o.value" role="option">
|
||||||
(change)="saveUsernameOptions()"
|
|
||||||
[checked]="usernameOptions.forwardedService === o.value"
|
|
||||||
/>
|
|
||||||
<label for="forwardtype_{{ o.value }}">
|
|
||||||
{{ o.name }}
|
{{ o.name }}
|
||||||
</label>
|
</option>
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="usernameOptions.forwardedService === 'simplelogin'">
|
<ng-container *ngIf="usernameOptions.forwardedService === 'simplelogin'">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
@@ -355,7 +351,7 @@
|
|||||||
<input
|
<input
|
||||||
id="duckduckgo-apikey"
|
id="duckduckgo-apikey"
|
||||||
type="password"
|
type="password"
|
||||||
name="DuckDudkGoApiKey"
|
name="DuckDuckGoApiKey"
|
||||||
[(ngModel)]="usernameOptions.forwardedDuckDuckGoToken"
|
[(ngModel)]="usernameOptions.forwardedDuckDuckGoToken"
|
||||||
(blur)="saveUsernameOptions()"
|
(blur)="saveUsernameOptions()"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -432,6 +432,12 @@ app-vault-view .box-footer {
|
|||||||
user-select: auto;
|
user-select: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tweak for inconsistent line heights in cipher view */
|
||||||
|
.box-footer button,
|
||||||
|
.box-footer a {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Workaround for slow performance on external monitors on Chrome + MacOS
|
// Workaround for slow performance on external monitors on Chrome + MacOS
|
||||||
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
|
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
|
||||||
@keyframes redraw {
|
@keyframes redraw {
|
||||||
|
|||||||
@@ -305,8 +305,11 @@
|
|||||||
>
|
>
|
||||||
<div class="row-main text-danger">
|
<div class="row-main text-danger">
|
||||||
<div class="icon text-danger" aria-hidden="true">
|
<div class="icon text-danger" aria-hidden="true">
|
||||||
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="deleteBtn.loading"></i>
|
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="$any(deleteBtn).loading"></i>
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw" [hidden]="!deleteBtn.loading"></i>
|
<i
|
||||||
|
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||||
|
[hidden]="!$any(deleteBtn).loading"
|
||||||
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<span>{{ "deleteSend" | i18n }}</span>
|
<span>{{ "deleteSend" | i18n }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
|
|||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { SendService } from "@bitwarden/common/abstractions/send.service";
|
import { SendService } from "@bitwarden/common/abstractions/send.service";
|
||||||
|
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
import { PopupUtilsService } from "../services/popup-utils.service";
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -33,7 +33,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
stateService: StateService,
|
stateService: BrowserStateService,
|
||||||
messagingService: MessagingService,
|
messagingService: MessagingService,
|
||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { SendType } from "@bitwarden/common/enums/sendType";
|
|||||||
import { SendView } from "@bitwarden/common/models/view/send.view";
|
import { SendView } from "@bitwarden/common/models/view/send.view";
|
||||||
|
|
||||||
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
import { PopupUtilsService } from "../services/popup-utils.service";
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
const ComponentId = "SendComponent";
|
const ComponentId = "SendComponent";
|
||||||
@@ -42,7 +42,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
|||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
searchService: SearchService,
|
searchService: SearchService,
|
||||||
private popupUtils: PopupUtilsService,
|
private popupUtils: PopupUtilsService,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
@@ -165,12 +165,12 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async saveState() {
|
private async saveState() {
|
||||||
this.state = {
|
this.state = Object.assign(new BrowserSendComponentState(), {
|
||||||
scrollY: this.popupUtils.getContentScrollY(window),
|
scrollY: this.popupUtils.getContentScrollY(window),
|
||||||
searchText: this.searchText,
|
searchText: this.searchText,
|
||||||
sends: this.sends,
|
sends: this.sends,
|
||||||
typeCounts: this.typeCounts,
|
typeCounts: this.typeCounts,
|
||||||
};
|
});
|
||||||
await this.stateService.setBrowserSendComponentState(this.state);
|
await this.stateService.setBrowserSendComponentState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { SendType } from "@bitwarden/common/enums/sendType";
|
|||||||
import { SendView } from "@bitwarden/common/models/view/send.view";
|
import { SendView } from "@bitwarden/common/models/view/send.view";
|
||||||
|
|
||||||
import { BrowserComponentState } from "../../models/browserComponentState";
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
import { PopupUtilsService } from "../services/popup-utils.service";
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
const ComponentId = "SendTypeComponent";
|
const ComponentId = "SendTypeComponent";
|
||||||
@@ -41,7 +41,7 @@ export class SendTypeComponent extends BaseSendComponent {
|
|||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
searchService: SearchService,
|
searchService: SearchService,
|
||||||
private popupUtils: PopupUtilsService,
|
private popupUtils: PopupUtilsService,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
|
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../../services/abstractions/browser-state.service";
|
||||||
|
|
||||||
import { PopupUtilsService } from "./popup-utils.service";
|
import { PopupUtilsService } from "./popup-utils.service";
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import { CollectionService } from "@bitwarden/common/abstractions/collection.ser
|
|||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
|
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||||
import { ExportService } from "@bitwarden/common/abstractions/export.service";
|
import { ExportService } from "@bitwarden/common/abstractions/export.service";
|
||||||
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service";
|
||||||
@@ -38,6 +39,7 @@ import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abs
|
|||||||
import { SendService } from "@bitwarden/common/abstractions/send.service";
|
import { SendService } from "@bitwarden/common/abstractions/send.service";
|
||||||
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
||||||
import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/abstractions/state.service";
|
import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/abstractions/state.service";
|
||||||
|
import { StateMigrationService } from "@bitwarden/common/abstractions/stateMigration.service";
|
||||||
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
||||||
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
||||||
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
||||||
@@ -47,6 +49,8 @@ import { UserVerificationService } from "@bitwarden/common/abstractions/userVeri
|
|||||||
import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||||
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
||||||
import { AuthService } from "@bitwarden/common/services/auth.service";
|
import { AuthService } from "@bitwarden/common/services/auth.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
import { LoginService } from "@bitwarden/common/services/login.service";
|
import { LoginService } from "@bitwarden/common/services/login.service";
|
||||||
@@ -54,9 +58,14 @@ import { SearchService } from "@bitwarden/common/services/search.service";
|
|||||||
|
|
||||||
import MainBackground from "../../background/main.background";
|
import MainBackground from "../../background/main.background";
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
|
import { Account } from "../../models/account";
|
||||||
import { AutofillService } from "../../services/abstractions/autofill.service";
|
import { AutofillService } from "../../services/abstractions/autofill.service";
|
||||||
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../../services/abstractions/browser-state.service";
|
||||||
import { BrowserEnvironmentService } from "../../services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../../services/browser-environment.service";
|
||||||
|
import { BrowserOrganizationService } from "../../services/browser-organization.service";
|
||||||
|
import { BrowserPolicyService } from "../../services/browser-policy.service";
|
||||||
|
import { BrowserSettingsService } from "../../services/browser-settings.service";
|
||||||
|
import { BrowserStateService } from "../../services/browser-state.service";
|
||||||
import { BrowserFileDownloadService } from "../../services/browserFileDownloadService";
|
import { BrowserFileDownloadService } from "../../services/browserFileDownloadService";
|
||||||
import BrowserMessagingService from "../../services/browserMessaging.service";
|
import BrowserMessagingService from "../../services/browserMessaging.service";
|
||||||
import BrowserMessagingPrivateModePopupService from "../../services/browserMessagingPrivateModePopup.service";
|
import BrowserMessagingPrivateModePopupService from "../../services/browserMessagingPrivateModePopup.service";
|
||||||
@@ -187,11 +196,25 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
{ provide: TokenService, useFactory: getBgService<TokenService>("tokenService"), deps: [] },
|
{ provide: TokenService, useFactory: getBgService<TokenService>("tokenService"), deps: [] },
|
||||||
{ provide: I18nService, useFactory: getBgService<I18nService>("i18nService"), deps: [] },
|
{ provide: I18nService, useFactory: getBgService<I18nService>("i18nService"), deps: [] },
|
||||||
{ provide: CryptoService, useFactory: getBgService<CryptoService>("cryptoService"), deps: [] },
|
{ provide: CryptoService, useFactory: getBgService<CryptoService>("cryptoService"), deps: [] },
|
||||||
{ provide: EventService, useFactory: getBgService<EventService>("eventService"), deps: [] },
|
{
|
||||||
|
provide: EventUploadService,
|
||||||
|
useFactory: getBgService<EventUploadService>("eventUploadService"),
|
||||||
|
deps: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: EventCollectionService,
|
||||||
|
useFactory: getBgService<EventCollectionService>("eventCollectionService"),
|
||||||
|
deps: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: PolicyService,
|
provide: PolicyService,
|
||||||
useFactory: getBgService<PolicyService>("policyService"),
|
useFactory: (
|
||||||
deps: [],
|
stateService: StateServiceAbstraction,
|
||||||
|
organizationService: OrganizationService
|
||||||
|
) => {
|
||||||
|
return new BrowserPolicyService(stateService, organizationService);
|
||||||
|
},
|
||||||
|
deps: [StateServiceAbstraction, OrganizationService],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: PolicyApiServiceAbstraction,
|
provide: PolicyApiServiceAbstraction,
|
||||||
@@ -212,8 +235,10 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
|
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
|
||||||
{
|
{
|
||||||
provide: SettingsService,
|
provide: SettingsService,
|
||||||
useFactory: getBgService<SettingsService>("settingsService"),
|
useFactory: (stateService: StateServiceAbstraction) => {
|
||||||
deps: [],
|
return new BrowserSettingsService(stateService);
|
||||||
|
},
|
||||||
|
deps: [StateServiceAbstraction],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: AbstractStorageService,
|
provide: AbstractStorageService,
|
||||||
@@ -261,8 +286,10 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
||||||
{
|
{
|
||||||
provide: OrganizationService,
|
provide: OrganizationService,
|
||||||
useFactory: getBgService<OrganizationService>("organizationService"),
|
useFactory: (stateService: StateServiceAbstraction) => {
|
||||||
deps: [],
|
return new BrowserOrganizationService(stateService);
|
||||||
|
},
|
||||||
|
deps: [StateServiceAbstraction],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: VaultFilterService,
|
provide: VaultFilterService,
|
||||||
@@ -293,10 +320,36 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
useFactory: getBgService<AbstractStorageService>("memoryStorageService"),
|
useFactory: getBgService<AbstractStorageService>("memoryStorageService"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: StateServiceAbstraction,
|
provide: StateMigrationService,
|
||||||
useFactory: getBgService<StateServiceAbstraction>("stateService"),
|
useFactory: getBgService<StateMigrationService>("stateMigrationService"),
|
||||||
deps: [],
|
deps: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: StateServiceAbstraction,
|
||||||
|
useFactory: (
|
||||||
|
storageService: AbstractStorageService,
|
||||||
|
secureStorageService: AbstractStorageService,
|
||||||
|
memoryStorageService: AbstractStorageService,
|
||||||
|
logService: LogServiceAbstraction,
|
||||||
|
stateMigrationService: StateMigrationService
|
||||||
|
) => {
|
||||||
|
return new BrowserStateService(
|
||||||
|
storageService,
|
||||||
|
secureStorageService,
|
||||||
|
memoryStorageService,
|
||||||
|
logService,
|
||||||
|
stateMigrationService,
|
||||||
|
new StateFactory(GlobalState, Account)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
deps: [
|
||||||
|
AbstractStorageService,
|
||||||
|
SECURE_STORAGE,
|
||||||
|
MEMORY_STORAGE,
|
||||||
|
LogServiceAbstraction,
|
||||||
|
StateMigrationService,
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: UsernameGenerationService,
|
provide: UsernameGenerationService,
|
||||||
useFactory: getBgService<UsernameGenerationService>("usernameGenerationService"),
|
useFactory: getBgService<UsernameGenerationService>("usernameGenerationService"),
|
||||||
@@ -317,17 +370,19 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: AbstractThemingService,
|
provide: AbstractThemingService,
|
||||||
useFactory: () => {
|
useFactory: (
|
||||||
|
stateService: StateServiceAbstraction,
|
||||||
|
platformUtilsService: PlatformUtilsService
|
||||||
|
) => {
|
||||||
return new ThemingService(
|
return new ThemingService(
|
||||||
getBgService<StateServiceAbstraction>("stateService")(),
|
stateService,
|
||||||
// Safari doesn't properly handle the (prefers-color-scheme) media query in the popup window, it always returns light.
|
// Safari doesn't properly handle the (prefers-color-scheme) media query in the popup window, it always returns light.
|
||||||
// In Safari we have to use the background page instead, which comes with limitations like not dynamically changing the extension theme when the system theme is changed.
|
// In Safari we have to use the background page instead, which comes with limitations like not dynamically changing the extension theme when the system theme is changed.
|
||||||
getBgService<PlatformUtilsService>("platformUtilsService")().isSafari()
|
platformUtilsService.isSafari() ? getBgService<Window>("backgroundWindow")() : window,
|
||||||
? getBgService<Window>("backgroundWindow")()
|
|
||||||
: window,
|
|
||||||
document
|
document
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
deps: [StateServiceAbstraction, PlatformUtilsService],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Router } from "@angular/router";
|
|||||||
|
|
||||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component";
|
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component";
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { ExportService } from "@bitwarden/common/abstractions/export.service";
|
import { ExportService } from "@bitwarden/common/abstractions/export.service";
|
||||||
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
@@ -23,7 +23,7 @@ export class ExportComponent extends BaseExportComponent {
|
|||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
exportService: ExportService,
|
exportService: ExportService,
|
||||||
eventService: EventService,
|
eventCollectionService: EventCollectionService,
|
||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
@@ -36,7 +36,7 @@ export class ExportComponent extends BaseExportComponent {
|
|||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
exportService,
|
exportService,
|
||||||
eventService,
|
eventCollectionService,
|
||||||
policyService,
|
policyService,
|
||||||
window,
|
window,
|
||||||
logService,
|
logService,
|
||||||
|
|||||||
@@ -40,8 +40,11 @@
|
|||||||
>
|
>
|
||||||
<div class="row-main text-danger">
|
<div class="row-main text-danger">
|
||||||
<div class="icon text-danger" aria-hidden="true">
|
<div class="icon text-danger" aria-hidden="true">
|
||||||
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="deleteBtn.loading"></i>
|
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="$any(deleteBtn).loading"></i>
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw" [hidden]="!deleteBtn.loading"></i>
|
<i
|
||||||
|
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||||
|
[hidden]="!$any(deleteBtn).loading"
|
||||||
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<span>{{ "deleteFolder" | i18n }}</span>
|
<span>{{ "deleteFolder" | i18n }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,14 +49,14 @@
|
|||||||
#refreshBtn
|
#refreshBtn
|
||||||
type="button"
|
type="button"
|
||||||
(click)="refresh()"
|
(click)="refresh()"
|
||||||
[disabled]="refreshBtn.loading"
|
[disabled]="$any(refreshBtn).loading"
|
||||||
[appApiAction]="refreshPromise"
|
[appApiAction]="refreshPromise"
|
||||||
class="btn link block"
|
class="btn link block"
|
||||||
>
|
>
|
||||||
<span [hidden]="refreshBtn.loading">{{ "premiumRefresh" | i18n }}</span>
|
<span [hidden]="$any(refreshBtn).loading">{{ "premiumRefresh" | i18n }}</span>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||||
[hidden]="!refreshBtn.loading"
|
[hidden]="!$any(refreshBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -17,11 +17,15 @@
|
|||||||
class="btn block primary"
|
class="btn block primary"
|
||||||
(click)="sync()"
|
(click)="sync()"
|
||||||
#syncBtn
|
#syncBtn
|
||||||
[disabled]="syncBtn.loading"
|
[disabled]="$any(syncBtn).loading"
|
||||||
[appApiAction]="syncPromise"
|
[appApiAction]="syncPromise"
|
||||||
>
|
>
|
||||||
<span [hidden]="syncBtn.loading">{{ "syncVaultNow" | i18n }}</span>
|
<span [hidden]="$any(syncBtn).loading">{{ "syncVaultNow" | i18n }}</span>
|
||||||
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!syncBtn.loading" aria-hidden="true"></i>
|
<i
|
||||||
|
class="bwi bwi-spinner bwi-lg bwi-spin"
|
||||||
|
[hidden]="!$any(syncBtn).loading"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
</button>
|
</button>
|
||||||
<p class="text-center text-muted small">{{ "lastSync" | i18n }} {{ lastSync }}</p>
|
<p class="text-center text-muted small">{{ "lastSync" | i18n }} {{ lastSync }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -81,8 +81,8 @@
|
|||||||
[(ngModel)]="f.value"
|
[(ngModel)]="f.value"
|
||||||
*ngIf="f.type === fieldType.Boolean"
|
*ngIf="f.type === fieldType.Boolean"
|
||||||
appTrueFalseValue
|
appTrueFalseValue
|
||||||
trueValue="true"
|
[trueValue]="true"
|
||||||
falseValue="false"
|
[falseValue]="false"
|
||||||
attr.aria-describedby="fieldName{{ i }}"
|
attr.aria-describedby="fieldName{{ i }}"
|
||||||
[readonly]="!cipher.edit && editMode"
|
[readonly]="!cipher.edit && editMode"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { AddEditCustomFieldsComponent as BaseAddEditCustomFieldsComponent } from "@bitwarden/angular/components/add-edit-custom-fields.component";
|
import { AddEditCustomFieldsComponent as BaseAddEditCustomFieldsComponent } from "@bitwarden/angular/components/add-edit-custom-fields.component";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -9,7 +9,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
templateUrl: "add-edit-custom-fields.component.html",
|
templateUrl: "add-edit-custom-fields.component.html",
|
||||||
})
|
})
|
||||||
export class AddEditCustomFieldsComponent extends BaseAddEditCustomFieldsComponent {
|
export class AddEditCustomFieldsComponent extends BaseAddEditCustomFieldsComponent {
|
||||||
constructor(i18nService: I18nService, eventService: EventService) {
|
constructor(i18nService: I18nService, eventCollectionService: EventCollectionService) {
|
||||||
super(i18nService, eventService);
|
super(i18nService, eventCollectionService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,17 +88,17 @@
|
|||||||
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
||||||
(click)="checkPassword()"
|
(click)="checkPassword()"
|
||||||
[appApiAction]="checkPasswordPromise"
|
[appApiAction]="checkPasswordPromise"
|
||||||
[disabled]="checkPasswordBtn.loading"
|
[disabled]="$any(checkPasswordBtn).loading"
|
||||||
*ngIf="cipher.viewPassword"
|
*ngIf="cipher.viewPassword"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg bwi-check-circle"
|
class="bwi bwi-lg bwi-check-circle"
|
||||||
[hidden]="checkPasswordBtn.loading"
|
[hidden]="$any(checkPasswordBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg bwi-spinner bwi-spin"
|
class="bwi bwi-lg bwi-spinner bwi-spin"
|
||||||
[hidden]="!checkPasswordBtn.loading"
|
[hidden]="!$any(checkPasswordBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -487,7 +487,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
name="Login.Uris[{{ i }}].Uri"
|
name="Login.Uris[{{ i }}].Uri"
|
||||||
[(ngModel)]="u.uri"
|
[(ngModel)]="u.uri"
|
||||||
[hidden]="u.showUriOptionsInput === true"
|
[hidden]="$any(u).showUriOptionsInput === true"
|
||||||
placeholder="{{ 'ex' | i18n }} https://google.com"
|
placeholder="{{ 'ex' | i18n }} https://google.com"
|
||||||
inputmode="url"
|
inputmode="url"
|
||||||
appInputVerbatim
|
appInputVerbatim
|
||||||
@@ -500,7 +500,7 @@
|
|||||||
id="currentUris{{ i }}"
|
id="currentUris{{ i }}"
|
||||||
name="Login.Uris[{{ i }}].CurrentUris"
|
name="Login.Uris[{{ i }}].CurrentUris"
|
||||||
[(ngModel)]="u.uri"
|
[(ngModel)]="u.uri"
|
||||||
[hidden]="!u.showCurrentUris"
|
[hidden]="!$any(u).showCurrentUris"
|
||||||
>
|
>
|
||||||
<option [ngValue]="null">-- {{ "select" | i18n }} --</option>
|
<option [ngValue]="null">-- {{ "select" | i18n }} --</option>
|
||||||
<option *ngFor="let u of currentUris" [ngValue]="u">{{ u }}</option>
|
<option *ngFor="let u of currentUris" [ngValue]="u">{{ u }}</option>
|
||||||
@@ -512,7 +512,9 @@
|
|||||||
id="loginUriMatch{{ i }}"
|
id="loginUriMatch{{ i }}"
|
||||||
name="Login.Uris[{{ i }}].Match"
|
name="Login.Uris[{{ i }}].Match"
|
||||||
[(ngModel)]="u.match"
|
[(ngModel)]="u.match"
|
||||||
[hidden]="u.showOptions === false || (u.showOptions == null && u.match == null)"
|
[hidden]="
|
||||||
|
$any(u).showOptions === false || ($any(u).showOptions == null && u.match == null)
|
||||||
|
"
|
||||||
(change)="loginUriMatchChanged(u)"
|
(change)="loginUriMatchChanged(u)"
|
||||||
>
|
>
|
||||||
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{ o.name }}</option>
|
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{ o.name }}</option>
|
||||||
@@ -526,7 +528,7 @@
|
|||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleCurrentUris' | i18n }}"
|
appA11yTitle="{{ 'toggleCurrentUris' | i18n }}"
|
||||||
(click)="toggleUriInput(u)"
|
(click)="toggleUriInput(u)"
|
||||||
[attr.aria-pressed]="u.showCurrentUris === true"
|
[attr.aria-pressed]="$any(u).showCurrentUris === true"
|
||||||
>
|
>
|
||||||
<i aria-hidden="true" class="bwi bwi-lg bwi-list"></i>
|
<i aria-hidden="true" class="bwi bwi-lg bwi-list"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -536,7 +538,7 @@
|
|||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleOptions' | i18n }}"
|
appA11yTitle="{{ 'toggleOptions' | i18n }}"
|
||||||
(click)="toggleUriOptions(u)"
|
(click)="toggleUriOptions(u)"
|
||||||
[attr.aria-pressed]="u.showOptions === true"
|
[attr.aria-pressed]="$any(u).showOptions === true"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -695,7 +697,7 @@
|
|||||||
<input
|
<input
|
||||||
id="collection_{{ i }}"
|
id="collection_{{ i }}"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
[(ngModel)]="c.checked"
|
[(ngModel)]="$any(c).checked"
|
||||||
name="Collection[{{ i }}].Checked"
|
name="Collection[{{ i }}].Checked"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -713,8 +715,11 @@
|
|||||||
>
|
>
|
||||||
<div class="row-main text-danger">
|
<div class="row-main text-danger">
|
||||||
<div class="icon text-danger" aria-hidden="true">
|
<div class="icon text-danger" aria-hidden="true">
|
||||||
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="deleteBtn.loading"></i>
|
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="$any(deleteBtn).loading"></i>
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw" [hidden]="!deleteBtn.loading"></i>
|
<i
|
||||||
|
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||||
|
[hidden]="!$any(deleteBtn).loading"
|
||||||
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<span>{{ "deleteItem" | i18n }}</span>
|
<span>{{ "deleteItem" | i18n }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/com
|
|||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
@@ -46,7 +46,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
eventService: EventService,
|
eventCollectionService: EventCollectionService,
|
||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
private popupUtilsService: PopupUtilsService,
|
private popupUtilsService: PopupUtilsService,
|
||||||
organizationService: OrganizationService,
|
organizationService: OrganizationService,
|
||||||
@@ -62,7 +62,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
stateService,
|
stateService,
|
||||||
collectionService,
|
collectionService,
|
||||||
messagingService,
|
messagingService,
|
||||||
eventService,
|
eventCollectionService,
|
||||||
policyService,
|
policyService,
|
||||||
logService,
|
logService,
|
||||||
passwordRepromptService,
|
passwordRepromptService,
|
||||||
|
|||||||
@@ -37,16 +37,16 @@
|
|||||||
(click)="delete(a)"
|
(click)="delete(a)"
|
||||||
#deleteBtn
|
#deleteBtn
|
||||||
[appApiAction]="deletePromises[a.id]"
|
[appApiAction]="deletePromises[a.id]"
|
||||||
[disabled]="deleteBtn.loading"
|
[disabled]="$any(deleteBtn).loading"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-trash bwi-lg bwi-fw"
|
class="bwi bwi-trash bwi-lg bwi-fw"
|
||||||
[hidden]="deleteBtn.loading"
|
[hidden]="$any(deleteBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||||
[hidden]="!deleteBtn.loading"
|
[hidden]="!$any(deleteBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<input
|
<input
|
||||||
id="collection_{{ i }}"
|
id="collection_{{ i }}"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
[(ngModel)]="c.checked"
|
[(ngModel)]="$any(c).checked"
|
||||||
name="Collection[{{ i }}].Checked"
|
name="Collection[{{ i }}].Checked"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async load() {
|
protected async load() {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.tab = await BrowserApi.getTabFromCurrentWindow();
|
this.tab = await BrowserApi.getTabFromCurrentWindow();
|
||||||
if (this.tab != null) {
|
if (this.tab != null) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
|||||||
|
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
import { VaultFilterService } from "../../services/vaultFilter.service";
|
import { VaultFilterService } from "../../services/vaultFilter.service";
|
||||||
import { PopupUtilsService } from "../services/popup-utils.service";
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private location: Location,
|
private location: Location,
|
||||||
private browserStateService: StateService,
|
private browserStateService: BrowserStateService,
|
||||||
private vaultFilterService: VaultFilterService
|
private vaultFilterService: VaultFilterService
|
||||||
) {
|
) {
|
||||||
this.noFolderListSize = 100;
|
this.noFolderListSize = 100;
|
||||||
@@ -94,7 +94,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
this.showLeftHeader = !(
|
this.showLeftHeader = !(
|
||||||
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
|
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
|
||||||
);
|
);
|
||||||
await this.browserStateService.setBrowserCipherComponentState(null);
|
await this.browserStateService.setBrowserVaultItemsComponentState(null);
|
||||||
|
|
||||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||||
this.ngZone.run(async () => {
|
this.ngZone.run(async () => {
|
||||||
@@ -373,7 +373,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async saveState() {
|
private async saveState() {
|
||||||
this.state = {
|
this.state = Object.assign(new BrowserGroupingsComponentState(), {
|
||||||
scrollY: this.popupUtils.getContentScrollY(window),
|
scrollY: this.popupUtils.getContentScrollY(window),
|
||||||
searchText: this.searchText,
|
searchText: this.searchText,
|
||||||
favoriteCiphers: this.favoriteCiphers,
|
favoriteCiphers: this.favoriteCiphers,
|
||||||
@@ -385,7 +385,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
|||||||
folders: this.folders,
|
folders: this.folders,
|
||||||
collections: this.collections,
|
collections: this.collections,
|
||||||
deletedCount: this.deletedCount,
|
deletedCount: this.deletedCount,
|
||||||
};
|
});
|
||||||
await this.browserStateService.setBrowserGroupingComponentState(this.state);
|
await this.browserStateService.setBrowserGroupingComponentState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angula
|
|||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { CiphersComponent as BaseCiphersComponent } from "@bitwarden/angular/components/ciphers.component";
|
import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/components/vault-items.component";
|
||||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
@@ -21,17 +21,17 @@ import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
|||||||
|
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
import { BrowserComponentState } from "../../models/browserComponentState";
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
import { StateService } from "../../services/abstractions/state.service";
|
import { BrowserStateService } from "../../services/abstractions/browser-state.service";
|
||||||
import { VaultFilterService } from "../../services/vaultFilter.service";
|
import { VaultFilterService } from "../../services/vaultFilter.service";
|
||||||
import { PopupUtilsService } from "../services/popup-utils.service";
|
import { PopupUtilsService } from "../services/popup-utils.service";
|
||||||
|
|
||||||
const ComponentId = "CiphersComponent";
|
const ComponentId = "VaultItemsComponent";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-vault-ciphers",
|
selector: "app-vault-items",
|
||||||
templateUrl: "ciphers.component.html",
|
templateUrl: "vault-items.component.html",
|
||||||
})
|
})
|
||||||
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
|
export class VaultItemsComponent extends BaseVaultItemsComponent implements OnInit, OnDestroy {
|
||||||
groupingTitle: string;
|
groupingTitle: string;
|
||||||
state: BrowserComponentState;
|
state: BrowserComponentState;
|
||||||
folderId: string = null;
|
folderId: string = null;
|
||||||
@@ -60,7 +60,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private broadcasterService: BroadcasterService,
|
private broadcasterService: BroadcasterService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private popupUtils: PopupUtilsService,
|
private popupUtils: PopupUtilsService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
@@ -82,7 +82,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||||
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
||||||
if (this.applySavedState) {
|
if (this.applySavedState) {
|
||||||
this.state = await this.stateService.getBrowserCipherComponentState();
|
this.state = await this.stateService.getBrowserVaultItemsComponentState();
|
||||||
if (this.state?.searchText) {
|
if (this.state?.searchText) {
|
||||||
this.searchText = this.state.searchText;
|
this.searchText = this.state.searchText;
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await this.stateService.setBrowserCipherComponentState(null);
|
await this.stateService.setBrowserVaultItemsComponentState(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||||
@@ -291,6 +291,6 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
scrollY: this.popupUtils.getContentScrollY(window, this.scrollingContainer),
|
scrollY: this.popupUtils.getContentScrollY(window, this.scrollingContainer),
|
||||||
searchText: this.searchText,
|
searchText: this.searchText,
|
||||||
};
|
};
|
||||||
await this.stateService.setBrowserCipherComponentState(this.state);
|
await this.stateService.setBrowserVaultItemsComponentState(this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,11 +27,7 @@
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
>
|
>
|
||||||
<button
|
<button appStopClick (click)="selectAllVaults()">
|
||||||
appStopClick
|
|
||||||
(click)="selectAllVaults()"
|
|
||||||
[ngClass]="{ active: !myVaultOnly && !selectOrganizationId }"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
|
||||||
{{ "allVaults" | i18n }}
|
{{ "allVaults" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
@@ -60,7 +56,7 @@
|
|||||||
<i
|
<i
|
||||||
*ngIf="!organization.enabled"
|
*ngIf="!organization.enabled"
|
||||||
class="bwi bwi-fw bwi-exclamation-triangle text-danger"
|
class="bwi bwi-fw bwi-exclamation-triangle text-danger"
|
||||||
aria-label="{{ 'organizationIsDisabled' | i18n }}"
|
attr.aria-label="{{ 'organizationIsDisabled' | i18n }}"
|
||||||
appA11yTitle="{{ 'organizationIsDisabled' | i18n }}"
|
appA11yTitle="{{ 'organizationIsDisabled' | i18n }}"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { ViewCustomFieldsComponent as BaseViewCustomFieldsComponent } from "@bitwarden/angular/components/view-custom-fields.component";
|
import { ViewCustomFieldsComponent as BaseViewCustomFieldsComponent } from "@bitwarden/angular/components/view-custom-fields.component";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-vault-view-custom-fields",
|
selector: "app-vault-view-custom-fields",
|
||||||
templateUrl: "view-custom-fields.component.html",
|
templateUrl: "view-custom-fields.component.html",
|
||||||
})
|
})
|
||||||
export class ViewCustomFieldsComponent extends BaseViewCustomFieldsComponent {
|
export class ViewCustomFieldsComponent extends BaseViewCustomFieldsComponent {
|
||||||
constructor(eventService: EventService) {
|
constructor(eventCollectionService: EventCollectionService) {
|
||||||
super(eventService);
|
super(eventCollectionService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,17 +88,17 @@
|
|||||||
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
appA11yTitle="{{ 'checkPassword' | i18n }}"
|
||||||
(click)="checkPassword()"
|
(click)="checkPassword()"
|
||||||
[appApiAction]="checkPasswordPromise"
|
[appApiAction]="checkPasswordPromise"
|
||||||
[disabled]="checkPasswordBtn.loading"
|
[disabled]="$any(checkPasswordBtn).loading"
|
||||||
*ngIf="cipher.viewPassword"
|
*ngIf="cipher.viewPassword"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg bwi-check-circle"
|
class="bwi bwi-lg bwi-check-circle"
|
||||||
[hidden]="checkPasswordBtn.loading"
|
[hidden]="$any(checkPasswordBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg bwi-spinner bwi-spin"
|
class="bwi bwi-lg bwi-spinner bwi-spin"
|
||||||
[hidden]="!checkPasswordBtn.loading"
|
[hidden]="!$any(checkPasswordBtn).loading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -537,12 +537,12 @@
|
|||||||
<small class="row-sub-label">{{ attachment.sizeName }}</small>
|
<small class="row-sub-label">{{ attachment.sizeName }}</small>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-download bwi-fw row-sub-icon"
|
class="bwi bwi-download bwi-fw row-sub-icon"
|
||||||
*ngIf="!attachment.downloading"
|
*ngIf="!$any(attachment).downloading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-spinner bwi-fw bwi-spin row-sub-icon"
|
class="bwi bwi-spinner bwi-fw bwi-spin row-sub-icon"
|
||||||
*ngIf="attachment.downloading"
|
*ngIf="$any(attachment).downloading"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|||||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
||||||
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
@@ -58,7 +58,7 @@ export class ViewComponent extends BaseViewComponent {
|
|||||||
ngZone: NgZone,
|
ngZone: NgZone,
|
||||||
changeDetectorRef: ChangeDetectorRef,
|
changeDetectorRef: ChangeDetectorRef,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
eventService: EventService,
|
eventCollectionService: EventCollectionService,
|
||||||
private autofillService: AutofillService,
|
private autofillService: AutofillService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private popupUtilsService: PopupUtilsService,
|
private popupUtilsService: PopupUtilsService,
|
||||||
@@ -80,7 +80,7 @@ export class ViewComponent extends BaseViewComponent {
|
|||||||
broadcasterService,
|
broadcasterService,
|
||||||
ngZone,
|
ngZone,
|
||||||
changeDetectorRef,
|
changeDetectorRef,
|
||||||
eventService,
|
eventCollectionService,
|
||||||
apiService,
|
apiService,
|
||||||
passwordRepromptService,
|
passwordRepromptService,
|
||||||
logService,
|
logService,
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import { BrowserComponentState } from "../../models/browserComponentState";
|
|||||||
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
||||||
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
||||||
|
|
||||||
export abstract class StateService extends BaseStateServiceAbstraction<Account> {
|
export abstract class BrowserStateService extends BaseStateServiceAbstraction<Account> {
|
||||||
|
abstract hasInSessionMemory(key: string): Promise<boolean>;
|
||||||
abstract getFromSessionMemory<T>(key: string, deserializer?: (obj: Jsonify<T>) => T): Promise<T>;
|
abstract getFromSessionMemory<T>(key: string, deserializer?: (obj: Jsonify<T>) => T): Promise<T>;
|
||||||
abstract setInSessionMemory(key: string, value: any): Promise<void>;
|
abstract setInSessionMemory(key: string, value: any): Promise<void>;
|
||||||
getBrowserGroupingComponentState: (
|
getBrowserGroupingComponentState: (
|
||||||
@@ -18,8 +19,8 @@ export abstract class StateService extends BaseStateServiceAbstraction<Account>
|
|||||||
value: BrowserGroupingsComponentState,
|
value: BrowserGroupingsComponentState,
|
||||||
options?: StorageOptions
|
options?: StorageOptions
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getBrowserCipherComponentState: (options?: StorageOptions) => Promise<BrowserComponentState>;
|
getBrowserVaultItemsComponentState: (options?: StorageOptions) => Promise<BrowserComponentState>;
|
||||||
setBrowserCipherComponentState: (
|
setBrowserVaultItemsComponentState: (
|
||||||
value: BrowserComponentState,
|
value: BrowserComponentState,
|
||||||
options?: StorageOptions
|
options?: StorageOptions
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||||
import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType";
|
import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType";
|
||||||
@@ -14,7 +14,6 @@ import { BrowserApi } from "../browser/browserApi";
|
|||||||
import AutofillField from "../models/autofillField";
|
import AutofillField from "../models/autofillField";
|
||||||
import AutofillPageDetails from "../models/autofillPageDetails";
|
import AutofillPageDetails from "../models/autofillPageDetails";
|
||||||
import AutofillScript from "../models/autofillScript";
|
import AutofillScript from "../models/autofillScript";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AutoFillOptions,
|
AutoFillOptions,
|
||||||
@@ -22,6 +21,7 @@ import {
|
|||||||
PageDetail,
|
PageDetail,
|
||||||
FormData,
|
FormData,
|
||||||
} from "./abstractions/autofill.service";
|
} from "./abstractions/autofill.service";
|
||||||
|
import { BrowserStateService } from "./abstractions/browser-state.service";
|
||||||
import {
|
import {
|
||||||
AutoFillConstants,
|
AutoFillConstants,
|
||||||
CreditCardAutoFillConstants,
|
CreditCardAutoFillConstants,
|
||||||
@@ -39,9 +39,9 @@ export interface GenerateFillScriptOptions {
|
|||||||
export default class AutofillService implements AutofillServiceInterface {
|
export default class AutofillService implements AutofillServiceInterface {
|
||||||
constructor(
|
constructor(
|
||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private stateService: StateService,
|
private stateService: BrowserStateService,
|
||||||
private totpService: TotpService,
|
private totpService: TotpService,
|
||||||
private eventService: EventService,
|
private eventCollectionService: EventCollectionService,
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (didAutofill) {
|
if (didAutofill) {
|
||||||
this.eventService.collect(EventType.Cipher_ClientAutofilled, options.cipher.id);
|
this.eventCollectionService.collect(EventType.Cipher_ClientAutofilled, options.cipher.id);
|
||||||
if (totpPromise != null) {
|
if (totpPromise != null) {
|
||||||
return await totpPromise;
|
return await totpPromise;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import { Folder } from "@bitwarden/common/models/domain/folder";
|
|||||||
import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/models/view/folder.view";
|
||||||
import { FolderService as BaseFolderService } from "@bitwarden/common/services/folder/folder.service";
|
import { FolderService as BaseFolderService } from "@bitwarden/common/services/folder/folder.service";
|
||||||
|
|
||||||
import { browserSession, sessionSync } from "../../decorators/session-sync-observable";
|
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||||
|
|
||||||
@browserSession
|
@browserSession
|
||||||
export class FolderService extends BaseFolderService {
|
export class BrowserFolderService extends BaseFolderService {
|
||||||
@sessionSync({ initializer: Folder.fromJSON, initializeAsArray: true })
|
@sessionSync({ initializer: Folder.fromJSON, initializeAs: "array" })
|
||||||
protected _folders: BehaviorSubject<Folder[]>;
|
protected _folders: BehaviorSubject<Folder[]>;
|
||||||
@sessionSync({ initializer: FolderView.fromJSON, initializeAsArray: true })
|
@sessionSync({ initializer: FolderView.fromJSON, initializeAs: "array" })
|
||||||
protected _folderViews: BehaviorSubject<FolderView[]>;
|
protected _folderViews: BehaviorSubject<FolderView[]>;
|
||||||
}
|
}
|
||||||
12
apps/browser/src/services/browser-organization.service.ts
Normal file
12
apps/browser/src/services/browser-organization.service.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
|
import { Organization } from "@bitwarden/common/models/domain/organization";
|
||||||
|
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
|
||||||
|
|
||||||
|
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||||
|
|
||||||
|
@browserSession
|
||||||
|
export class BrowserOrganizationService extends OrganizationService {
|
||||||
|
@sessionSync({ initializer: Organization.fromJSON, initializeAs: "array" })
|
||||||
|
protected _organizations: BehaviorSubject<Organization[]>;
|
||||||
|
}
|
||||||
12
apps/browser/src/services/browser-policy.service.ts
Normal file
12
apps/browser/src/services/browser-policy.service.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
|
import { Policy } from "@bitwarden/common/models/domain/policy";
|
||||||
|
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
|
||||||
|
|
||||||
|
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||||
|
|
||||||
|
@browserSession
|
||||||
|
export class BrowserPolicyService extends PolicyService {
|
||||||
|
@sessionSync({ ctor: Policy, initializeAs: "array" })
|
||||||
|
protected _policies: BehaviorSubject<Policy[]>;
|
||||||
|
}
|
||||||
11
apps/browser/src/services/browser-settings.service.ts
Normal file
11
apps/browser/src/services/browser-settings.service.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
|
import { AccountSettingsSettings } from "@bitwarden/common/models/domain/account";
|
||||||
|
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
||||||
|
|
||||||
|
import { sessionSync } from "../decorators/session-sync-observable";
|
||||||
|
|
||||||
|
export class BrowserSettingsService extends SettingsService {
|
||||||
|
@sessionSync({ initializer: (obj: string[][]) => obj })
|
||||||
|
protected _settings: BehaviorSubject<AccountSettingsSettings>;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user