mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
50 Commits
vault/pm-7
...
bugfix/hel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7a7080cb5 | ||
|
|
22f0c93b47 | ||
|
|
5aeb3cef0a | ||
|
|
8566f5c00a | ||
|
|
b65f18d8e2 | ||
|
|
7a3816007b | ||
|
|
477b1cca44 | ||
|
|
df2f0231a4 | ||
|
|
dee9524b2c | ||
|
|
329103bd3b | ||
|
|
f5572511c6 | ||
|
|
9a17da009c | ||
|
|
b5443c79d2 | ||
|
|
9dc620b492 | ||
|
|
1f966e6cbe | ||
|
|
a4fa03656e | ||
|
|
12385d9add | ||
|
|
13ca0fd4cb | ||
|
|
0b28b954fe | ||
|
|
e4841bb322 | ||
|
|
98621341a2 | ||
|
|
2023fe6644 | ||
|
|
567a23e29f | ||
|
|
8b65d99442 | ||
|
|
f80ec1b221 | ||
|
|
ba1183234b | ||
|
|
5946af9eec | ||
|
|
b091051633 | ||
|
|
06488539b0 | ||
|
|
8f77822b1b | ||
|
|
3c1105b35d | ||
|
|
c847449db8 | ||
|
|
c2771eb3c7 | ||
|
|
6e41731dcb | ||
|
|
7c90b35592 | ||
|
|
93f9dc4498 | ||
|
|
e033832261 | ||
|
|
fa5d92fbf7 | ||
|
|
e672cb132f | ||
|
|
e7a7eed7e8 | ||
|
|
43a4915323 | ||
|
|
b1ae3cc325 | ||
|
|
b9dada07ea | ||
|
|
58442389df | ||
|
|
a3378d33ae | ||
|
|
2e1982b08e | ||
|
|
e9e9b6f7bc | ||
|
|
9be8fec219 | ||
|
|
f52e5ce5e9 | ||
|
|
f9e9143b51 |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -21,7 +21,6 @@ src/App/Platforms/iOS/Info.plist
|
||||
|
||||
## Platform team files ##
|
||||
appIcons @bitwarden/team-platform-dev
|
||||
build.cake @bitwarden/team-platform-dev
|
||||
|
||||
## Vault team files ##
|
||||
src/watchOS @bitwarden/team-vault-dev
|
||||
|
||||
35
.github/labeler.yml
vendored
35
.github/labeler.yml
vendored
@@ -1,19 +1,26 @@
|
||||
android:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- src/Android/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- src/Android/*
|
||||
- 'src/Xamarin.AndroidX.Credentials/*'
|
||||
|
||||
iOS:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- lib/ios/*
|
||||
- src/iOS/*
|
||||
- 'src/iOS.Autofill/*'
|
||||
- 'src/iOS.Core/*'
|
||||
- 'src/iOS.Extension/*'
|
||||
- 'src/iOS.ShareExtension/*'
|
||||
- 'src/iOS.Widget/*'
|
||||
- src/watchOS/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- lib/ios/*
|
||||
- src/iOS/*
|
||||
- 'src/iOS.Autofill/*'
|
||||
- 'src/iOS.Core/*'
|
||||
- 'src/iOS.Extension/*'
|
||||
- 'src/iOS.ShareExtension/*'
|
||||
- 'src/iOS.Widget/*'
|
||||
- src/watchOS/*
|
||||
|
||||
watchOS:
|
||||
- src/watchOS/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- src/watchOS/*
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
close-issue:
|
||||
name: 'Close issue with automatic response'
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
|
||||
345
.github/workflows/build-beta.yml
vendored
345
.github/workflows/build-beta.yml
vendored
@@ -3,3 +3,348 @@ name: Build Beta
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: 'Branch or tag to build'
|
||||
required: true
|
||||
default: 'main'
|
||||
type: string
|
||||
|
||||
env:
|
||||
main_app_folder_path: src/App
|
||||
main_app_project_path: src/App/App.csproj
|
||||
target-net-version: net8.0
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
rc_branch_exists: ${{ steps.branch-check.outputs.rc_branch_exists }}
|
||||
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: Check if special branches exist
|
||||
id: branch-check
|
||||
run: |
|
||||
if [[ $(git ls-remote --heads origin rc) ]]; then
|
||||
echo "rc_branch_exists=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "rc_branch_exists=0" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ $(git ls-remote --heads origin hotfix-rc) ]]; then
|
||||
echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
ios:
|
||||
name: Apple iOS
|
||||
runs-on: macos-14
|
||||
needs: setup
|
||||
env:
|
||||
ios_folder_path: src/App/Platforms/iOS
|
||||
app_output_name: App
|
||||
app_ci_output_filename: App_x64_Debug
|
||||
steps:
|
||||
- name: Set XCode version
|
||||
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
|
||||
with:
|
||||
xcode-version: 15.1
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@a21f25cd3998bf370fde17e3f1b4c12c175172f9 # v2.0.0
|
||||
with:
|
||||
nuget-version: 6.4.0
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
# This step might be obsolete at some point as .NET MAUI workloads
|
||||
# are starting to come pre-installed on the GH Actions build agents.
|
||||
- name: Install MAUI Workload
|
||||
run: dotnet workload install maui --ignore-failed-sources
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
nuget help | grep Version
|
||||
dotnet --info
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ inputs.ref }}
|
||||
submodules: 'true'
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "appcenter-ios-token"
|
||||
|
||||
- name: Download Provisioning Profiles secrets
|
||||
env:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: profiles
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
profiles=(
|
||||
"dist_beta_autofill.mobileprovision"
|
||||
"dist_beta_bitwarden.mobileprovision"
|
||||
"dist_beta_extension.mobileprovision"
|
||||
"dist_beta_share_extension.mobileprovision"
|
||||
"dist_beta_bitwarden_watch_app.mobileprovision"
|
||||
"dist_beta_bitwarden_watch_app_extension.mobileprovision"
|
||||
)
|
||||
|
||||
for FILE in "${profiles[@]}"
|
||||
do
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||
--file $HOME/secrets/$FILE --output none
|
||||
done
|
||||
|
||||
- name: Download Google Services secret
|
||||
env:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: mobile
|
||||
FILE: GoogleService-Info.plist
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||
--file $HOME/secrets/$FILE --output none
|
||||
|
||||
- name: Increment version
|
||||
run: |
|
||||
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
|
||||
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
|
||||
|
||||
echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
|
||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
|
||||
cd src/watchOS/bitwarden
|
||||
agvtool new-version -all $BUILD_NUMBER
|
||||
|
||||
- name: Update Entitlements
|
||||
run: |
|
||||
echo "##### Updating Entitlements"
|
||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>beta<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/ios-distribution |
|
||||
jq -r .value | base64 -d > $HOME/certificates/ios-distribution.p12
|
||||
|
||||
- name: Set up Keychain
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
|
||||
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }}
|
||||
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import $HOME/certificates/ios-distribution.p12 -k build.keychain -P "" -T /usr/bin/codesign \
|
||||
-T /usr/bin/security
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
|
||||
- name: Set up provisioning profiles
|
||||
run: |
|
||||
AUTOFILL_PROFILE_PATH=$HOME/secrets/dist_beta_autofill.mobileprovision
|
||||
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden.mobileprovision
|
||||
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_extension.mobileprovision
|
||||
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_share_extension.mobileprovision
|
||||
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app.mobileprovision
|
||||
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app_extension.mobileprovision
|
||||
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||
|
||||
mkdir -p "$PROFILES_DIR_PATH"
|
||||
|
||||
AUTOFILL_UUID=$(grep UUID -A1 -a $AUTOFILL_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $AUTOFILL_PROFILE_PATH "$PROFILES_DIR_PATH/$AUTOFILL_UUID.mobileprovision"
|
||||
|
||||
BITWARDEN_UUID=$(grep UUID -A1 -a $BITWARDEN_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $BITWARDEN_PROFILE_PATH "$PROFILES_DIR_PATH/$BITWARDEN_UUID.mobileprovision"
|
||||
|
||||
EXTENSION_UUID=$(grep UUID -A1 -a $EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$EXTENSION_UUID.mobileprovision"
|
||||
|
||||
SHARE_EXTENSION_UUID=$(grep UUID -A1 -a $SHARE_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $SHARE_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$SHARE_EXTENSION_UUID.mobileprovision"
|
||||
|
||||
WATCH_APP_UUID=$(grep UUID -A1 -a $WATCH_APP_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $WATCH_APP_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_UUID.mobileprovision"
|
||||
|
||||
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
||||
|
||||
- name: Restore packages
|
||||
run: |
|
||||
dotnet restore
|
||||
dotnet tool restore
|
||||
|
||||
- name: Setup iOS build CAKE (Testing)
|
||||
run: dotnet cake build.cake --target iOS --variant beta
|
||||
|
||||
- name: Bulid WatchApp
|
||||
run: |
|
||||
echo "##### Build WatchApp with Release Configuration"
|
||||
xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden
|
||||
|
||||
echo "##### Done"
|
||||
|
||||
- name: Archive Build for App Store
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Output "##### Archive for Release ios-arm64"
|
||||
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=ios-arm64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false
|
||||
|
||||
Write-Output "##### Done"
|
||||
|
||||
- name: Archive Build for Mobile Automation
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Output "##### Archive Debug for iossimulator-x64"
|
||||
dotnet build ${{ env.main_app_project_path }} -c Debug -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=iossimulator-x64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false
|
||||
|
||||
Write-Output "##### Done"
|
||||
ls ~/Library/Developer/Xcode/Archives
|
||||
|
||||
- name: Export .ipa for App Store
|
||||
env:
|
||||
EXPORT_OPTIONS_PATH: ./.github/resources/export-options-app-store.plist
|
||||
EXPORT_PATH: ./bitwarden-export
|
||||
run: |
|
||||
ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive"
|
||||
|
||||
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \
|
||||
-exportOptionsPlist $EXPORT_OPTIONS_PATH
|
||||
|
||||
- name: Export .app for Automation CI
|
||||
env:
|
||||
ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64
|
||||
EXPORT_PATH: ./bitwarden-export
|
||||
run: |
|
||||
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
|
||||
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
|
||||
|
||||
- name: Show Bitwarden Export
|
||||
shell: bash
|
||||
run: ls -a -R ./bitwarden-export
|
||||
|
||||
- name: Copy all dSYMs files to upload
|
||||
env:
|
||||
EXPORT_PATH: ./bitwarden-export
|
||||
WATCH_ARCHIVE_DSYMS_PATH: ./src/watchOS/bitwarden.xcarchive/dSYMs/
|
||||
WATCH_DSYMS_EXPORT_PATH: ./bitwarden-export/Watch_dSYMs
|
||||
run: |
|
||||
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
|
||||
|
||||
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH
|
||||
mkdir $WATCH_DSYMS_EXPORT_PATH
|
||||
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
|
||||
|
||||
- name: Upload App Store .ipa & dSYMs artifacts
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: Bitwarden iOS
|
||||
path: |
|
||||
./bitwarden-export/Bitwarden*.ipa
|
||||
./bitwarden-export/dSYMs/*.*
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload .app file for Automation CI
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Install AppCenter CLI
|
||||
run: npm install -g appcenter-cli
|
||||
|
||||
- name: Upload dSYMs to App Center
|
||||
env:
|
||||
APPCENTER_IOS_TOKEN: ${{ steps.retrieve-secrets.outputs.appcenter-ios-token }}
|
||||
run: appcenter crashes upload-symbols -a bitwarden/bitwarden -s "./bitwarden-export/dSYMs" --token $APPCENTER_IOS_TOKEN
|
||||
|
||||
- name: Upload Watch dSYMs to Firebase Crashlytics
|
||||
run: |
|
||||
echo "##### Uploading Watch dSYMs to Firebase"
|
||||
find "$HOME/Library/Developer/XCode/DerivedData" -name "upload-symbols" -exec chmod +x {} \; -exec {} -gsp "./src/watchOS/bitwarden/GoogleService-Info.plist" -p ios "./bitwarden-export/Watch_dSYMs" \;
|
||||
|
||||
- name: Validate app in App Store
|
||||
env:
|
||||
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
run: |
|
||||
xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden Beta.ipa" \
|
||||
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
||||
shell: bash
|
||||
|
||||
- name: Deploy to App Store
|
||||
env:
|
||||
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
run: |
|
||||
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden Beta.ipa" \
|
||||
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
||||
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
if: always()
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
- ios
|
||||
steps:
|
||||
- name: Check if any job failed
|
||||
if: |
|
||||
(github.ref == 'refs/heads/main'
|
||||
|| github.ref == 'refs/heads/rc'
|
||||
|| github.ref == 'refs/heads/hotfix-rc')
|
||||
&& contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
if: failure()
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||
if: failure()
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "devops-alerts-slack-webhook-url"
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||
if: failure()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
|
||||
50
.github/workflows/build.yml
vendored
50
.github/workflows/build.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Set up CLOC
|
||||
run: |
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
android_folder_path_bash: src/App/Platforms/Android
|
||||
steps:
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
uses: nuget/setup-nuget@a21f25cd3998bf370fde17e3f1b4c12c175172f9 # v2.0.0
|
||||
with:
|
||||
nuget-version: 6.4.0
|
||||
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
|
||||
|
||||
# This step might be obsolete at some point as .NET MAUI workloads
|
||||
# are starting to come pre-installed on the GH Actions build agents.
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
|
||||
- name: Upload Prod .aab artifact
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: com.x8bit.bitwarden.aab
|
||||
path: ./com.x8bit.bitwarden.aab
|
||||
@@ -234,7 +234,7 @@ jobs:
|
||||
|
||||
- name: Upload Prod .apk artifact
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: com.x8bit.bitwarden.apk
|
||||
path: ./com.x8bit.bitwarden.apk
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
|
||||
- name: Upload Other .apk artifact
|
||||
if: ${{ matrix.variant != 'prod' }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: com.x8bit.bitwarden.${{ matrix.variant }}.apk
|
||||
path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk
|
||||
@@ -262,7 +262,7 @@ jobs:
|
||||
|
||||
- name: Upload .apk sha file for prod
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bw-android-apk-sha256.txt
|
||||
path: ./bw-android-apk-sha256.txt
|
||||
@@ -270,7 +270,7 @@ jobs:
|
||||
|
||||
- name: Upload .apk sha file for other
|
||||
if: ${{ matrix.variant != 'prod' }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bw-android-${{ matrix.variant }}-apk-sha256.txt
|
||||
path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt
|
||||
@@ -300,17 +300,17 @@ jobs:
|
||||
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
|
||||
steps:
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
uses: nuget/setup-nuget@a21f25cd3998bf370fde17e3f1b4c12c175172f9 # v2.0.0
|
||||
with:
|
||||
nuget-version: 6.4.0
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
|
||||
|
||||
# This step might be obsolete at some point as .NET MAUI workloads
|
||||
# are starting to come pre-installed on the GH Actions build agents.
|
||||
@@ -335,7 +335,7 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@@ -414,7 +414,7 @@ jobs:
|
||||
Copy-Item $signedApkPath $signedApkDestPath
|
||||
|
||||
- name: Upload F-Droid .apk artifact
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: com.x8bit.bitwarden-fdroid.apk
|
||||
path: ./com.x8bit.bitwarden-fdroid.apk
|
||||
@@ -426,7 +426,7 @@ jobs:
|
||||
-t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt
|
||||
|
||||
- name: Upload F-Droid sha file
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bw-fdroid-apk-sha256.txt
|
||||
path: ./bw-fdroid-apk-sha256.txt
|
||||
@@ -435,7 +435,7 @@ jobs:
|
||||
|
||||
ios:
|
||||
name: Apple iOS
|
||||
runs-on: macos-13
|
||||
runs-on: macos-14
|
||||
needs: setup
|
||||
env:
|
||||
ios_folder_path: src/App/Platforms/iOS
|
||||
@@ -448,12 +448,12 @@ jobs:
|
||||
xcode-version: 15.1
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
uses: nuget/setup-nuget@a21f25cd3998bf370fde17e3f1b4c12c175172f9 # v2.0.0
|
||||
with:
|
||||
nuget-version: 6.4.0
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
@@ -470,7 +470,7 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
@@ -631,7 +631,7 @@ jobs:
|
||||
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
|
||||
|
||||
- name: Upload App Store .ipa & dSYMs artifacts
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: Bitwarden iOS
|
||||
path: |
|
||||
@@ -640,7 +640,7 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload .app file for Automation CI
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||
@@ -718,7 +718,7 @@ jobs:
|
||||
_CROWDIN_PROJECT_ID: "269690"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@@ -733,7 +733,7 @@ jobs:
|
||||
secrets: "crowdin-api-token"
|
||||
|
||||
- name: Upload Sources
|
||||
uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0
|
||||
uses: crowdin/github-action@8c663f791efc0498270241e9923a8853c99a3a8e # v1.20.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||
@@ -778,7 +778,7 @@ jobs:
|
||||
secrets: "devops-alerts-slack-webhook-url"
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
||||
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||
if: failure()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||
|
||||
2
.github/workflows/cleanup-rc-branch.yml
vendored
2
.github/workflows/cleanup-rc-branch.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||
|
||||
6
.github/workflows/crowdin-pull.yml
vendored
6
.github/workflows/crowdin-pull.yml
vendored
@@ -10,12 +10,12 @@ on:
|
||||
jobs:
|
||||
crowdin-sync:
|
||||
name: Autosync
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
_CROWDIN_PROJECT_ID: "269690"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||
|
||||
- name: Download translations
|
||||
uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0
|
||||
uses: crowdin/github-action@8c663f791efc0498270241e9923a8853c99a3a8e # v1.20.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||
|
||||
2
.github/workflows/enforce-labels.yml
vendored
2
.github/workflows/enforce-labels.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
enforce-label:
|
||||
name: EnforceLabel
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Enforce Label
|
||||
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
||||
|
||||
4
.github/workflows/pr-labeler.yml
vendored
4
.github/workflows/pr-labeler.yml
vendored
@@ -10,8 +10,8 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
|
||||
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
||||
with:
|
||||
sync-labels: true
|
||||
|
||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -23,7 +23,7 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
branch-name: ${{ steps.branch.outputs.branch-name }}
|
||||
steps:
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Check Release Version
|
||||
id: version
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
- name: Download all artifacts
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
|
||||
- name: Dry Run - Download all artifacts
|
||||
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -121,16 +121,16 @@ jobs:
|
||||
|
||||
f-droid:
|
||||
name: F-Droid Release
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: release
|
||||
if: inputs.fdroid_publish
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
|
||||
- name: Download F-Droid .apk artifact
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
|
||||
- name: Dry Run - Download F-Droid .apk artifact
|
||||
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
|
||||
2
.github/workflows/stale-bot.yml
vendored
2
.github/workflows/stale-bot.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
stale:
|
||||
name: 'Check for stale issues and PRs'
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: 'Run stale action'
|
||||
uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
|
||||
|
||||
4
.github/workflows/version-bump.yml
vendored
4
.github/workflows/version-bump.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
version: ${{ inputs.version_number_override }}
|
||||
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
ref: main
|
||||
|
||||
@@ -264,7 +264,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
ref: main
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ The Bitwarden mobile application is written in C# using .NET MAUI.
|
||||
|
||||
# Build/Run
|
||||
|
||||
Please refer to the [Mobile section](https://contributing.bitwarden.com/getting-started/clients/mobile/) 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 [Mobile section](https://contributing.bitwarden.com/getting-started/mobile/) 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.
|
||||
|
||||
# We're Hiring!
|
||||
|
||||
|
||||
59
build.cake
59
build.cake
@@ -15,16 +15,18 @@ abstract record VariantConfig(
|
||||
string AppName,
|
||||
string AndroidPackageName,
|
||||
string iOSBundleId,
|
||||
string ApsEnvironment
|
||||
string ApsEnvironment,
|
||||
string DistProvisioningProfilePrefix
|
||||
);
|
||||
|
||||
const string BASE_BUNDLE_ID_DROID = "com.x8bit.bitwarden";
|
||||
const string BASE_BUNDLE_ID_IOS = "com.8bit.bitwarden";
|
||||
|
||||
record Dev(): VariantConfig("Bitwarden Dev", $"{BASE_BUNDLE_ID_DROID}.dev", $"{BASE_BUNDLE_ID_IOS}.dev", "development");
|
||||
record QA(): VariantConfig("Bitwarden QA", $"{BASE_BUNDLE_ID_DROID}.qa", $"{BASE_BUNDLE_ID_IOS}.qa", "development");
|
||||
record Beta(): VariantConfig("Bitwarden Beta", $"{BASE_BUNDLE_ID_DROID}.beta", $"{BASE_BUNDLE_ID_IOS}.beta", "production");
|
||||
record Prod(): VariantConfig("Bitwarden", $"{BASE_BUNDLE_ID_DROID}", $"{BASE_BUNDLE_ID_IOS}", "production");
|
||||
//NOTE: Beta iOS variants have a different ITSEncryptionExportComplianceCode
|
||||
record Dev(): VariantConfig("Bitwarden Dev", $"{BASE_BUNDLE_ID_DROID}.dev", $"{BASE_BUNDLE_ID_IOS}.dev", "development", "Dist:");
|
||||
record QA(): VariantConfig("Bitwarden QA", $"{BASE_BUNDLE_ID_DROID}.qa", $"{BASE_BUNDLE_ID_IOS}.qa", "development", "Dist:");
|
||||
record Beta(): VariantConfig("Bitwarden Beta", $"{BASE_BUNDLE_ID_DROID}.beta", $"{BASE_BUNDLE_ID_IOS}.beta", "production", "Dist: Beta");
|
||||
record Prod(): VariantConfig("Bitwarden", $"{BASE_BUNDLE_ID_DROID}", $"{BASE_BUNDLE_ID_IOS}", "production", "Dist:");
|
||||
|
||||
VariantConfig GetVariant() => variant.ToLower() switch{
|
||||
"qa" => new QA(),
|
||||
@@ -197,7 +199,8 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
||||
var prevBundleId = plist["CFBundleIdentifier"];
|
||||
var prevBundleName = plist["CFBundleName"];
|
||||
//var newVersion = CreateBuildNumber(prevVersion).ToString();
|
||||
var newVersionName = GetVersionName(prevVersionName, buildVariant, git);
|
||||
// we need to maintain version formatting here composed of one to three period-separated integers, so we cannot use the GetVersionName method as in Android for non-Prod.
|
||||
var newVersionName = prevVersionName;
|
||||
var newBundleId = GetiOSBundleId(buildVariant, projectType);
|
||||
var newBundleName = GetiOSBundleName(buildVariant, projectType);
|
||||
|
||||
@@ -219,6 +222,11 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
||||
plist["NSExtension"]["NSExtensionAttributes"]["NSExtensionActivationRule"] = keyText.Replace("com.8bit.bitwarden", buildVariant.iOSBundleId);
|
||||
}
|
||||
|
||||
if(buildVariant is Beta)
|
||||
{
|
||||
plist["ITSEncryptionExportComplianceCode"] = "3dd3e32f-efa6-4d99-b410-28aa28b1cb77";
|
||||
}
|
||||
|
||||
SerializePlist(plistFile, plist);
|
||||
|
||||
Information($"Changed app name from {prevBundleName} to {newBundleName}");
|
||||
@@ -228,12 +236,15 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
||||
Information($"{plistPath} updated with success!");
|
||||
}
|
||||
|
||||
private void UpdateiOSEntitlementsPlist(string entitlementsPath, VariantConfig buildVariant)
|
||||
private void UpdateiOSEntitlementsPlist(string entitlementsPath, VariantConfig buildVariant, bool updateApsEnv)
|
||||
{
|
||||
var EntitlementlistFile = File(entitlementsPath);
|
||||
dynamic Entitlements = DeserializePlist(EntitlementlistFile);
|
||||
|
||||
Entitlements["aps-environment"] = buildVariant.ApsEnvironment;
|
||||
if (updateApsEnv)
|
||||
{
|
||||
Entitlements["aps-environment"] = buildVariant.ApsEnvironment;
|
||||
}
|
||||
Entitlements["keychain-access-groups"] = new List<string>() { "$(AppIdentifierPrefix)" + buildVariant.iOSBundleId };
|
||||
Entitlements["com.apple.security.application-groups"] = new List<string>() { $"group.{buildVariant.iOSBundleId}" };;
|
||||
|
||||
@@ -272,9 +283,10 @@ private void UpdateWatchPbxproj(string pbxprojPath, string newVersion)
|
||||
const string pattern = @"MARKETING_VERSION = [^;]*;";
|
||||
|
||||
fileText = Regex.Replace(fileText, pattern, $"MARKETING_VERSION = {newVersion};");
|
||||
|
||||
|
||||
FileWriteText(pbxprojPath, fileText);
|
||||
Information($"{pbxprojPath} modified successfully.");
|
||||
|
||||
Information($"{pbxprojPath} modified Marketing Version successfully.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -327,7 +339,7 @@ Task("UpdateiOSPlist")
|
||||
var infoPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Info.plist");
|
||||
var entitlementsPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Entitlements.plist");
|
||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, true);
|
||||
});
|
||||
|
||||
Task("UpdateiOSAutofillPlist")
|
||||
@@ -338,7 +350,7 @@ Task("UpdateiOSAutofillPlist")
|
||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Info.plist");
|
||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Entitlements.plist");
|
||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Autofill);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||
});
|
||||
|
||||
Task("UpdateiOSExtensionPlist")
|
||||
@@ -349,7 +361,7 @@ Task("UpdateiOSExtensionPlist")
|
||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Info.plist");
|
||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Entitlements.plist");
|
||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Extension);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||
});
|
||||
|
||||
Task("UpdateiOSShareExtensionPlist")
|
||||
@@ -360,7 +372,7 @@ Task("UpdateiOSShareExtensionPlist")
|
||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Info.plist");
|
||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Entitlements.plist");
|
||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.ShareExtension);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||
});
|
||||
|
||||
Task("UpdateiOSCodeFiles")
|
||||
@@ -397,6 +409,22 @@ Task("UpdateWatchKitAppInfoPlist")
|
||||
UpdateWatchKitAppInfoPlist(infoPath, buildVariant);
|
||||
});
|
||||
|
||||
Task("UpdateDistProfiles")
|
||||
.IsDependentOn("UpdateiOSCodeFiles")
|
||||
.Does(()=> {
|
||||
var buildVariant = GetVariant();
|
||||
|
||||
var filesToReplace = new string[] {
|
||||
Path.Combine(".github", "resources", "export-options-app-store.plist"),
|
||||
Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden.xcodeproj", "project.pbxproj")
|
||||
};
|
||||
|
||||
foreach(string path in filesToReplace)
|
||||
{
|
||||
ReplaceInFile(path, "Dist:", buildVariant.DistProvisioningProfilePrefix);
|
||||
}
|
||||
});
|
||||
|
||||
#endregion iOS
|
||||
|
||||
#region Main Tasks
|
||||
@@ -418,6 +446,7 @@ Task("iOS")
|
||||
.IsDependentOn("UpdateiOSCodeFiles")
|
||||
.IsDependentOn("UpdateWatchProject")
|
||||
.IsDependentOn("UpdateWatchKitAppInfoPlist")
|
||||
.IsDependentOn("UpdateDistProfiles")
|
||||
.Does(()=>
|
||||
{
|
||||
Information("iOS app updated");
|
||||
@@ -437,4 +466,4 @@ Options:
|
||||
});
|
||||
#endregion Main Tasks
|
||||
|
||||
RunTarget(target);
|
||||
RunTarget(target);
|
||||
|
||||
@@ -117,6 +117,8 @@
|
||||
<Folder Include="Platforms\Android\Services\" />
|
||||
<Folder Include="Platforms\Android\Tiles\" />
|
||||
<Folder Include="Platforms\Android\Utilities\" />
|
||||
<Folder Include="Platforms\Android\Resources\drawable-xxxhdpi\" />
|
||||
<Folder Include="Resources\Raw\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
|
||||
@@ -257,5 +259,13 @@
|
||||
<None Remove="Platforms\iOS\Resources\more_vert.png" />
|
||||
<None Remove="Platforms\iOS\Resources\logo_white.png" />
|
||||
<None Remove="Platforms\iOS\Resources\logo%402x.png" />
|
||||
<None Remove="Platforms\Android\Resources\drawable-xxxhdpi\" />
|
||||
<None Remove="Resources\Raw\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
|
||||
<BundleResource Include="Platforms\iOS\PrivacyInfo.xcprivacy" LogicalName="PrivacyInfo.xcprivacy" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||
<MauiAsset Include="Resources\Raw\fido2_privileged_allow_list.json" LogicalName="fido2_privileged_allow_list.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2024.3.3" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2024.5.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
@@ -24,7 +24,7 @@
|
||||
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true" />
|
||||
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
|
||||
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true" />
|
||||
<!-- Declare MainActivity manually so we can set LaunchMode using API dependant resource -->
|
||||
<!-- Declare exported activities manually so we can set LaunchMode using API dependant resource -->
|
||||
<activity android:name="com.x8bit.bitwarden.MainActivity" android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|uiMode" android:exported="true" android:icon="@mipmap/ic_launcher" android:label="Bitwarden" android:launchMode="@integer/launchModeAPIlevel" android:theme="@style/LaunchTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -39,6 +39,14 @@
|
||||
<data android:mimeType="text/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.x8bit.bitwarden.WebAuthCallbackActivity" android:launchMode="@integer/webAuthCallbackLaunchMode" android:noHistory="true" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="bitwarden" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<!-- Support for Xamarin.Essentials.Browser.OpenAsync (for Android > 11) -->
|
||||
<!-- Related docs: https://learn.microsoft.com/en-us/xamarin/essentials/open-browser?tabs=android -->
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace Bit.Droid.Autofill
|
||||
{
|
||||
[Activity(
|
||||
NoHistory = true,
|
||||
LaunchMode = LaunchMode.SingleTop)]
|
||||
LaunchMode = LaunchMode.SingleTop,
|
||||
Exported = false)]
|
||||
public class AutofillExternalSelectionActivity : MauiAppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
|
||||
321
src/App/Platforms/Android/Autofill/CredentialHelpers.cs
Normal file
321
src/App/Platforms/Android/Autofill/CredentialHelpers.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Nodes;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using AndroidX.Credentials;
|
||||
using AndroidX.Credentials.Exceptions;
|
||||
using AndroidX.Credentials.Provider;
|
||||
using AndroidX.Credentials.WebAuthn;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
using Bit.Core.Utilities.Fido2.Extensions;
|
||||
using Bit.Droid;
|
||||
using Org.Json;
|
||||
using Activity = Android.App.Activity;
|
||||
using Drawables = Android.Graphics.Drawables;
|
||||
|
||||
namespace Bit.App.Platforms.Android.Autofill
|
||||
{
|
||||
public static class CredentialHelpers
|
||||
{
|
||||
public static async Task<List<CredentialEntry>> PopulatePasskeyDataAsync(CallingAppInfo callingAppInfo,
|
||||
BeginGetPublicKeyCredentialOption option, Context context, bool hasVaultBeenUnlockedInThisTransaction)
|
||||
{
|
||||
var passkeyEntries = new List<CredentialEntry>();
|
||||
var requestOptions = new PublicKeyCredentialRequestOptions(option.RequestJson);
|
||||
|
||||
var authenticator = Bit.Core.Utilities.ServiceContainer.Resolve<IFido2AuthenticatorService>();
|
||||
var credentials = await authenticator.SilentCredentialDiscoveryAsync(requestOptions.RpId);
|
||||
|
||||
// We need to change the request code for every pending intent on mapping the credential so the extras are not overriten by the last
|
||||
// credential entry created.
|
||||
int requestCodeAddition = 0;
|
||||
passkeyEntries = credentials.Select(credential => MapCredential(credential, option, context, hasVaultBeenUnlockedInThisTransaction, Bit.Droid.Autofill.CredentialProviderService.UniqueGetRequestCode + requestCodeAddition++) as CredentialEntry).ToList();
|
||||
|
||||
return passkeyEntries;
|
||||
}
|
||||
|
||||
private static PublicKeyCredentialEntry MapCredential(Fido2AuthenticatorDiscoverableCredentialMetadata credential, BeginGetPublicKeyCredentialOption option, Context context, bool hasVaultBeenUnlockedInThisTransaction, int requestCode)
|
||||
{
|
||||
var credDataBundle = new Bundle();
|
||||
credDataBundle.PutByteArray(Bit.Core.Utilities.Fido2.CredentialProviderConstants.CredentialIdIntentExtra, credential.Id);
|
||||
|
||||
var intent = new Intent(context, typeof(Bit.Droid.Autofill.CredentialProviderSelectionActivity))
|
||||
.SetAction(Bit.Droid.Autofill.CredentialProviderService.GetFido2IntentAction).SetPackage(Constants.PACKAGE_NAME);
|
||||
intent.PutExtra(Bit.Core.Utilities.Fido2.CredentialProviderConstants.CredentialDataIntentExtra, credDataBundle);
|
||||
intent.PutExtra(Bit.Core.Utilities.Fido2.CredentialProviderConstants.CredentialProviderCipherId, credential.CipherId);
|
||||
intent.PutExtra(Bit.Core.Utilities.Fido2.CredentialProviderConstants.CredentialHasVaultBeenUnlockedInThisTransactionExtra, hasVaultBeenUnlockedInThisTransaction);
|
||||
var pendingIntent = PendingIntent.GetActivity(context, requestCode, intent,
|
||||
PendingIntentFlags.Mutable | PendingIntentFlags.UpdateCurrent);
|
||||
|
||||
return new PublicKeyCredentialEntry.Builder(
|
||||
context,
|
||||
credential.UserName ?? "No username",
|
||||
pendingIntent,
|
||||
option)
|
||||
.SetDisplayName(credential.UserName ?? "No username")
|
||||
.SetIcon(Drawables.Icon.CreateWithResource(context, Microsoft.Maui.Resource.Drawable.icon))
|
||||
.Build();
|
||||
}
|
||||
|
||||
private static PublicKeyCredentialCreationOptions GetPublicKeyCredentialCreationOptionsFromJson(string json)
|
||||
{
|
||||
var request = new PublicKeyCredentialCreationOptions(json);
|
||||
var jsonObj = new JSONObject(json);
|
||||
var authenticatorSelection = jsonObj.GetJSONObject("authenticatorSelection");
|
||||
request.AuthenticatorSelection = new AndroidX.Credentials.WebAuthn.AuthenticatorSelectionCriteria(
|
||||
authenticatorSelection.OptString("authenticatorAttachment", "platform"),
|
||||
authenticatorSelection.OptString("residentKey", null),
|
||||
authenticatorSelection.OptBoolean("requireResidentKey", false),
|
||||
authenticatorSelection.OptString("userVerification", "preferred"));
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public static async Task CreateCipherPasskeyAsync(ProviderCreateCredentialRequest getRequest, Activity activity)
|
||||
{
|
||||
var callingRequest = getRequest?.CallingRequest as CreatePublicKeyCredentialRequest;
|
||||
|
||||
if (callingRequest is null)
|
||||
{
|
||||
await DisplayAlertAsync(AppResources.AnErrorHasOccurred, string.Empty);
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
var credentialCreationOptions = GetPublicKeyCredentialCreationOptionsFromJson(callingRequest.RequestJson);
|
||||
string origin;
|
||||
try
|
||||
{
|
||||
origin = await ValidateCallingAppInfoAndGetOriginAsync(getRequest.CallingAppInfo, credentialCreationOptions.Rp.Id);
|
||||
}
|
||||
catch (Core.Exceptions.ValidationException valEx)
|
||||
{
|
||||
await DisplayAlertAsync(AppResources.AnErrorHasOccurred, valEx.Message);
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (origin is null)
|
||||
{
|
||||
await DisplayAlertAsync(AppResources.ErrorCreatingPasskey, AppResources.PasskeysNotSupportedForThisApp);
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
var rp = new Core.Utilities.Fido2.PublicKeyCredentialRpEntity()
|
||||
{
|
||||
Id = credentialCreationOptions.Rp.Id,
|
||||
Name = credentialCreationOptions.Rp.Name
|
||||
};
|
||||
|
||||
var user = new Core.Utilities.Fido2.PublicKeyCredentialUserEntity()
|
||||
{
|
||||
Id = credentialCreationOptions.User.GetId(),
|
||||
Name = credentialCreationOptions.User.Name,
|
||||
DisplayName = credentialCreationOptions.User.DisplayName
|
||||
};
|
||||
|
||||
var pubKeyCredParams = new List<Core.Utilities.Fido2.PublicKeyCredentialParameters>();
|
||||
foreach (var pubKeyCredParam in credentialCreationOptions.PubKeyCredParams)
|
||||
{
|
||||
pubKeyCredParams.Add(new Core.Utilities.Fido2.PublicKeyCredentialParameters() { Alg = Convert.ToInt32(pubKeyCredParam.Alg), Type = pubKeyCredParam.Type });
|
||||
}
|
||||
|
||||
var excludeCredentials = new List<Core.Utilities.Fido2.PublicKeyCredentialDescriptor>();
|
||||
foreach (var excludeCred in credentialCreationOptions.ExcludeCredentials)
|
||||
{
|
||||
excludeCredentials.Add(new Core.Utilities.Fido2.PublicKeyCredentialDescriptor() { Id = excludeCred.GetId(), Type = excludeCred.Type, Transports = excludeCred.Transports.ToArray() });
|
||||
}
|
||||
|
||||
var authenticatorSelection = new Core.Utilities.Fido2.AuthenticatorSelectionCriteria()
|
||||
{
|
||||
UserVerification = credentialCreationOptions.AuthenticatorSelection.UserVerification,
|
||||
ResidentKey = credentialCreationOptions.AuthenticatorSelection.ResidentKey,
|
||||
RequireResidentKey = credentialCreationOptions.AuthenticatorSelection.RequireResidentKey
|
||||
};
|
||||
|
||||
var timeout = Convert.ToInt32(credentialCreationOptions.Timeout);
|
||||
|
||||
var credentialCreateParams = new Fido2ClientCreateCredentialParams()
|
||||
{
|
||||
Challenge = credentialCreationOptions.GetChallenge(),
|
||||
Origin = origin,
|
||||
PubKeyCredParams = pubKeyCredParams.ToArray(),
|
||||
Rp = rp,
|
||||
User = user,
|
||||
Timeout = timeout,
|
||||
Attestation = credentialCreationOptions.Attestation,
|
||||
AuthenticatorSelection = authenticatorSelection,
|
||||
ExcludeCredentials = excludeCredentials.ToArray(),
|
||||
Extensions = MapExtensionsFromJson(credentialCreationOptions),
|
||||
SameOriginWithAncestors = true
|
||||
};
|
||||
|
||||
var credentialExtraCreateParams = new Fido2ExtraCreateCredentialParams
|
||||
(
|
||||
callingRequest.GetClientDataHash(),
|
||||
getRequest.CallingAppInfo?.PackageName
|
||||
);
|
||||
|
||||
var fido2MediatorService = ServiceContainer.Resolve<IFido2MediatorService>();
|
||||
var clientCreateCredentialResult = await fido2MediatorService.CreateCredentialAsync(credentialCreateParams, credentialExtraCreateParams);
|
||||
if (clientCreateCredentialResult == null)
|
||||
{
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
var transportsArray = new JSONArray();
|
||||
if (clientCreateCredentialResult.Transports != null)
|
||||
{
|
||||
foreach (var transport in clientCreateCredentialResult.Transports)
|
||||
{
|
||||
transportsArray.Put(transport);
|
||||
}
|
||||
}
|
||||
|
||||
var responseInnerAndroidJson = new JSONObject();
|
||||
if (clientCreateCredentialResult.ClientDataJSON != null)
|
||||
{
|
||||
responseInnerAndroidJson.Put("clientDataJSON", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.ClientDataJSON));
|
||||
}
|
||||
responseInnerAndroidJson.Put("authenticatorData", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.AuthData));
|
||||
responseInnerAndroidJson.Put("attestationObject", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.AttestationObject));
|
||||
responseInnerAndroidJson.Put("transports", transportsArray);
|
||||
responseInnerAndroidJson.Put("publicKeyAlgorithm", clientCreateCredentialResult.PublicKeyAlgorithm);
|
||||
responseInnerAndroidJson.Put("publicKey", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.PublicKey));
|
||||
|
||||
var rootAndroidJson = new JSONObject();
|
||||
rootAndroidJson.Put("id", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.CredentialId));
|
||||
rootAndroidJson.Put("rawId", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.CredentialId));
|
||||
rootAndroidJson.Put("authenticatorAttachment", "platform");
|
||||
rootAndroidJson.Put("type", "public-key");
|
||||
rootAndroidJson.Put("clientExtensionResults", MapExtensionsToJson(clientCreateCredentialResult.Extensions));
|
||||
rootAndroidJson.Put("response", responseInnerAndroidJson);
|
||||
|
||||
var result = new Intent();
|
||||
var publicKeyResponse = new CreatePublicKeyCredentialResponse(rootAndroidJson.ToString());
|
||||
PendingIntentHandler.SetCreateCredentialResponse(result, publicKeyResponse);
|
||||
|
||||
activity.SetResult(Result.Ok, result);
|
||||
activity.Finish();
|
||||
|
||||
async Task DisplayAlertAsync(string title, string message)
|
||||
{
|
||||
if (ServiceContainer.TryResolve<IDeviceActionService>(out var deviceActionService))
|
||||
{
|
||||
await deviceActionService.DisplayAlertAsync(title, message, AppResources.Ok);
|
||||
}
|
||||
}
|
||||
|
||||
void FailAndFinish()
|
||||
{
|
||||
var result = new Intent();
|
||||
PendingIntentHandler.SetCreateCredentialException(result, new CreateCredentialUnknownException());
|
||||
|
||||
activity.SetResult(Result.Ok, result);
|
||||
activity.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
private static Fido2CreateCredentialExtensionsParams MapExtensionsFromJson(PublicKeyCredentialCreationOptions options)
|
||||
{
|
||||
if (options == null || !options.Json.Has("extensions"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var extensions = options.Json.GetJSONObject("extensions");
|
||||
return new Fido2CreateCredentialExtensionsParams
|
||||
{
|
||||
CredProps = extensions.Has("credProps") && extensions.GetBoolean("credProps")
|
||||
};
|
||||
}
|
||||
|
||||
private static JSONObject MapExtensionsToJson(Fido2CreateCredentialExtensionsResult extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var extensionsJson = new JSONObject();
|
||||
if (extensions.CredProps != null)
|
||||
{
|
||||
var credPropsJson = new JSONObject();
|
||||
credPropsJson.Put("rk", extensions.CredProps.Rk);
|
||||
extensionsJson.Put("credProps", credPropsJson);
|
||||
}
|
||||
|
||||
return extensionsJson;
|
||||
}
|
||||
|
||||
public static async Task<string> LoadFido2PrivilegedAllowedListAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var stream = await FileSystem.OpenAppPackageFileAsync("fido2_privileged_allow_list.json");
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> ValidateCallingAppInfoAndGetOriginAsync(CallingAppInfo callingAppInfo, string rpId)
|
||||
{
|
||||
if (callingAppInfo.Origin is null)
|
||||
{
|
||||
return await ValidateAssetLinksAndGetOriginAsync(callingAppInfo, rpId);
|
||||
}
|
||||
|
||||
var privilegedAllowedList = await LoadFido2PrivilegedAllowedListAsync();
|
||||
if (privilegedAllowedList is null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not load Fido2 privileged allowed list");
|
||||
}
|
||||
|
||||
if (!privilegedAllowedList.Contains($"\"package_name\": \"{callingAppInfo.PackageName}\""))
|
||||
{
|
||||
throw new Core.Exceptions.ValidationException(AppResources.PasskeyOperationFailedBecauseBrowserIsNotPrivileged);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return callingAppInfo.GetOrigin(privilegedAllowedList);
|
||||
}
|
||||
catch (Java.Lang.IllegalStateException)
|
||||
{
|
||||
throw new Core.Exceptions.ValidationException(AppResources.PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch);
|
||||
}
|
||||
catch (Java.Lang.IllegalArgumentException)
|
||||
{
|
||||
return null; // wrong list format
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> ValidateAssetLinksAndGetOriginAsync(CallingAppInfo callingAppInfo, string rpId)
|
||||
{
|
||||
if (!ServiceContainer.TryResolve<IAssetLinksService>(out var assetLinksService))
|
||||
{
|
||||
throw new InvalidOperationException("Can't resolve IAssetLinksService");
|
||||
}
|
||||
|
||||
var normalizedFingerprint = callingAppInfo.GetLatestCertificationFingerprint();
|
||||
|
||||
var isValid = await assetLinksService.ValidateAssetLinksAsync(rpId, callingAppInfo.PackageName, normalizedFingerprint);
|
||||
|
||||
return isValid ? callingAppInfo.GetAndroidOrigin() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class CredentialProviderConstants
|
||||
{
|
||||
public const string CredentialProviderCipherId = "credentialProviderCipherId";
|
||||
public const string CredentialDataIntentExtra = "CREDENTIAL_DATA";
|
||||
public const string CredentialIdIntentExtra = "credId";
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using AndroidX.Credentials;
|
||||
using AndroidX.Credentials.Provider;
|
||||
using AndroidX.Credentials.WebAuthn;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
using Bit.Core.Services;
|
||||
using Bit.App.Platforms.Android.Autofill;
|
||||
using AndroidX.Credentials.Exceptions;
|
||||
using Org.Json;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
@@ -15,6 +23,14 @@ namespace Bit.Droid.Autofill
|
||||
LaunchMode = LaunchMode.SingleTop)]
|
||||
public class CredentialProviderSelectionActivity : MauiAppCompatActivity
|
||||
{
|
||||
private LazyResolve<IFido2MediatorService> _fido2MediatorService = new LazyResolve<IFido2MediatorService>();
|
||||
private LazyResolve<IFido2AndroidGetAssertionUserInterface> _fido2GetAssertionUserInterface = new LazyResolve<IFido2AndroidGetAssertionUserInterface>();
|
||||
private LazyResolve<IVaultTimeoutService> _vaultTimeoutService = new LazyResolve<IVaultTimeoutService>();
|
||||
private LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>();
|
||||
private LazyResolve<ICipherService> _cipherService = new LazyResolve<ICipherService>();
|
||||
private LazyResolve<IUserVerificationMediatorService> _userVerificationMediatorService = new LazyResolve<IUserVerificationMediatorService>();
|
||||
private LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
Intent?.Validate();
|
||||
@@ -23,43 +39,145 @@ namespace Bit.Droid.Autofill
|
||||
var cipherId = Intent?.GetStringExtra(CredentialProviderConstants.CredentialProviderCipherId);
|
||||
if (string.IsNullOrEmpty(cipherId))
|
||||
{
|
||||
SetResult(Result.Canceled);
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
GetCipherAndPerformPasskeyAuthAsync(cipherId).FireAndForget();
|
||||
GetCipherAndPerformFido2AuthAsync(cipherId).FireAndForget();
|
||||
}
|
||||
|
||||
private async Task GetCipherAndPerformPasskeyAuthAsync(string cipherId)
|
||||
//Used to avoid crash on MAUI when doing back
|
||||
public override void OnBackPressed()
|
||||
{
|
||||
// TODO this is a work in progress
|
||||
// https://developer.android.com/training/sign-in/credential-provider#passkeys-implement
|
||||
Finish();
|
||||
}
|
||||
|
||||
var getRequest = PendingIntentHandler.RetrieveProviderGetCredentialRequest(Intent);
|
||||
// var publicKeyRequest = getRequest?.CredentialOptions as PublicKeyCredentialRequestOptions;
|
||||
private async Task GetCipherAndPerformFido2AuthAsync(string cipherId)
|
||||
{
|
||||
string RpId = string.Empty;
|
||||
try
|
||||
{
|
||||
var getRequest = PendingIntentHandler.RetrieveProviderGetCredentialRequest(Intent);
|
||||
|
||||
var requestInfo = Intent.GetBundleExtra(CredentialProviderConstants.CredentialDataIntentExtra);
|
||||
var credIdEnc = requestInfo?.GetString(CredentialProviderConstants.CredentialIdIntentExtra);
|
||||
if (getRequest is null)
|
||||
{
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
var cipherService = ServiceContainer.Resolve<ICipherService>();
|
||||
var cipher = await cipherService.GetAsync(cipherId);
|
||||
var decCipher = await cipher.DecryptAsync();
|
||||
var credentialOption = getRequest.CredentialOptions.FirstOrDefault();
|
||||
var credentialPublic = credentialOption as GetPublicKeyCredentialOption;
|
||||
|
||||
var passkey = decCipher.Login.Fido2Credentials.Find(f => f.CredentialId == credIdEnc);
|
||||
var requestOptions = new PublicKeyCredentialRequestOptions(credentialPublic.RequestJson);
|
||||
RpId = requestOptions.RpId;
|
||||
|
||||
var credId = Convert.FromBase64String(credIdEnc);
|
||||
// var privateKey = Convert.FromBase64String(passkey.PrivateKey);
|
||||
// var uid = Convert.FromBase64String(passkey.uid);
|
||||
var requestInfo = Intent.GetBundleExtra(CredentialProviderConstants.CredentialDataIntentExtra);
|
||||
var credentialId = requestInfo?.GetByteArray(CredentialProviderConstants.CredentialIdIntentExtra);
|
||||
var hasVaultBeenUnlockedInThisTransaction = Intent.GetBooleanExtra(CredentialProviderConstants.CredentialHasVaultBeenUnlockedInThisTransactionExtra, false);
|
||||
|
||||
var origin = getRequest?.CallingAppInfo.Origin;
|
||||
var packageName = getRequest?.CallingAppInfo.PackageName;
|
||||
var packageName = getRequest.CallingAppInfo.PackageName;
|
||||
|
||||
// --- continue WIP here (save TOTP copy as last step) ---
|
||||
string origin;
|
||||
try
|
||||
{
|
||||
origin = await CredentialHelpers.ValidateCallingAppInfoAndGetOriginAsync(getRequest.CallingAppInfo, RpId);
|
||||
}
|
||||
catch (Core.Exceptions.ValidationException valEx)
|
||||
{
|
||||
await _deviceActionService.Value.DisplayAlertAsync(AppResources.AnErrorHasOccurred, valEx.Message, AppResources.Ok);
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy TOTP if needed
|
||||
var autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
|
||||
autofillHandler.Autofill(decCipher);
|
||||
if (origin is null)
|
||||
{
|
||||
await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, AppResources.PasskeysNotSupportedForThisApp, AppResources.Ok);
|
||||
FailAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
_fido2GetAssertionUserInterface.Value.Init(
|
||||
cipherId,
|
||||
false,
|
||||
() => hasVaultBeenUnlockedInThisTransaction,
|
||||
RpId
|
||||
);
|
||||
|
||||
var clientAssertParams = new Fido2ClientAssertCredentialParams
|
||||
{
|
||||
Challenge = requestOptions.GetChallenge(),
|
||||
RpId = RpId,
|
||||
AllowCredentials = new Core.Utilities.Fido2.PublicKeyCredentialDescriptor[] { new Core.Utilities.Fido2.PublicKeyCredentialDescriptor { Id = credentialId } },
|
||||
Origin = origin,
|
||||
SameOriginWithAncestors = true,
|
||||
UserVerification = requestOptions.UserVerification
|
||||
};
|
||||
|
||||
var extraAssertParams = new Fido2ExtraAssertCredentialParams
|
||||
(
|
||||
getRequest.CallingAppInfo.Origin != null ? credentialPublic.GetClientDataHash() : null,
|
||||
packageName
|
||||
);
|
||||
|
||||
var assertResult = await _fido2MediatorService.Value.AssertCredentialAsync(clientAssertParams, extraAssertParams);
|
||||
|
||||
var result = new Intent();
|
||||
|
||||
var responseInnerAndroidJson = new JSONObject();
|
||||
if (assertResult.ClientDataJSON != null)
|
||||
{
|
||||
responseInnerAndroidJson.Put("clientDataJSON", CoreHelpers.Base64UrlEncode(assertResult.ClientDataJSON));
|
||||
}
|
||||
responseInnerAndroidJson.Put("authenticatorData", CoreHelpers.Base64UrlEncode(assertResult.AuthenticatorData));
|
||||
responseInnerAndroidJson.Put("signature", CoreHelpers.Base64UrlEncode(assertResult.Signature));
|
||||
responseInnerAndroidJson.Put("userHandle", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.UserHandle));
|
||||
|
||||
var rootAndroidJson = new JSONObject();
|
||||
rootAndroidJson.Put("id", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.Id));
|
||||
rootAndroidJson.Put("rawId", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.Id));
|
||||
rootAndroidJson.Put("authenticatorAttachment", "platform");
|
||||
rootAndroidJson.Put("type", "public-key");
|
||||
rootAndroidJson.Put("clientExtensionResults", new JSONObject());
|
||||
rootAndroidJson.Put("response", responseInnerAndroidJson);
|
||||
|
||||
var json = rootAndroidJson.ToString();
|
||||
|
||||
var cred = new PublicKeyCredential(json);
|
||||
var credResponse = new GetCredentialResponse(cred);
|
||||
PendingIntentHandler.SetGetCredentialResponse(result, credResponse);
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
SetResult(Result.Ok, result);
|
||||
Finish();
|
||||
});
|
||||
}
|
||||
catch (NotAllowedError)
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, string.Format(AppResources.ThereWasAProblemReadingAPasskeyForXTryAgainLater, RpId), AppResources.Ok);
|
||||
FailAndFinish();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, string.Format(AppResources.ThereWasAProblemReadingAPasskeyForXTryAgainLater, RpId), AppResources.Ok);
|
||||
FailAndFinish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void FailAndFinish()
|
||||
{
|
||||
var result = new Intent();
|
||||
PendingIntentHandler.SetGetCredentialException(result, new GetCredentialUnknownException());
|
||||
|
||||
SetResult(Result.Ok, result);
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using Android;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using AndroidX.Credentials.Provider;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using AndroidX.Credentials.Exceptions;
|
||||
using AndroidX.Credentials.WebAuthn;
|
||||
using Bit.Core.Models.View;
|
||||
using Resource = Microsoft.Maui.Resource;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
@@ -20,62 +19,123 @@ namespace Bit.Droid.Autofill
|
||||
[Register("com.x8bit.bitwarden.Autofill.CredentialProviderService")]
|
||||
public class CredentialProviderService : AndroidX.Credentials.Provider.CredentialProviderService
|
||||
{
|
||||
private const string GetPasskeyIntentAction = "PACKAGE_NAME.GET_PASSKEY";
|
||||
private const int UniqueRequestCode = 94556023;
|
||||
public const string GetFido2IntentAction = "PACKAGE_NAME.GET_PASSKEY";
|
||||
public const string CreateFido2IntentAction = "PACKAGE_NAME.CREATE_PASSKEY";
|
||||
public const int UniqueGetRequestCode = 94556023;
|
||||
public const int UniqueCreateRequestCode = 94556024;
|
||||
|
||||
private ICipherService _cipherService;
|
||||
private IUserVerificationService _userVerificationService;
|
||||
private IVaultTimeoutService _vaultTimeoutService;
|
||||
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
||||
private readonly LazyResolve<IVaultTimeoutService> _vaultTimeoutService = new LazyResolve<IVaultTimeoutService>();
|
||||
private readonly LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>();
|
||||
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
||||
|
||||
public override async void OnBeginCreateCredentialRequest(BeginCreateCredentialRequest request,
|
||||
CancellationSignal cancellationSignal, IOutcomeReceiver callback) => throw new NotImplementedException();
|
||||
CancellationSignal cancellationSignal, IOutcomeReceiver callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await ProcessCreateCredentialsRequestAsync(request);
|
||||
if (response != null)
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(() => callback.OnResult(response));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Value.Exception(ex);
|
||||
}
|
||||
MainThread.BeginInvokeOnMainThread(() => callback.OnError(AppResources.ErrorCreatingPasskey));
|
||||
}
|
||||
|
||||
public override async void OnBeginGetCredentialRequest(BeginGetCredentialRequest request,
|
||||
CancellationSignal cancellationSignal, IOutcomeReceiver callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
_vaultTimeoutService ??= ServiceContainer.Resolve<IVaultTimeoutService>();
|
||||
|
||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
||||
var locked = await _vaultTimeoutService.IsLockedAsync();
|
||||
await _vaultTimeoutService.Value.CheckVaultTimeoutAsync();
|
||||
var locked = await _vaultTimeoutService.Value.IsLockedAsync();
|
||||
if (!locked)
|
||||
{
|
||||
var response = await ProcessGetCredentialsRequestAsync(request);
|
||||
callback.OnResult(response);
|
||||
return;
|
||||
}
|
||||
// TODO handle auth/unlock account flow
|
||||
|
||||
var intent = new Intent(ApplicationContext, typeof(MainActivity));
|
||||
intent.PutExtra(CredentialProviderConstants.Fido2CredentialAction, CredentialProviderConstants.Fido2CredentialGet);
|
||||
var pendingIntent = PendingIntent.GetActivity(ApplicationContext, UniqueGetRequestCode, intent,
|
||||
AndroidHelpers.AddPendingIntentMutabilityFlag(PendingIntentFlags.UpdateCurrent, true));
|
||||
|
||||
var unlockAction = new AuthenticationAction(AppResources.Unlock, pendingIntent);
|
||||
|
||||
var unlockResponse = new BeginGetCredentialResponse.Builder()
|
||||
.SetAuthenticationActions(new List<AuthenticationAction>() { unlockAction } )
|
||||
.Build();
|
||||
callback.OnResult(unlockResponse);
|
||||
}
|
||||
catch (GetCredentialException e)
|
||||
{
|
||||
_logger.Value.Exception(e);
|
||||
callback.OnError(e.ErrorMessage ?? "Error getting credentials");
|
||||
callback.OnError(e.ErrorMessage ?? AppResources.ErrorReadingPasskey);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Value.Exception(e);
|
||||
throw;
|
||||
callback.OnError(AppResources.ErrorReadingPasskey);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<BeginCreateCredentialResponse> ProcessCreateCredentialsRequestAsync(
|
||||
BeginCreateCredentialRequest request)
|
||||
{
|
||||
if (request == null) { return null; }
|
||||
|
||||
if (request is BeginCreatePasswordCredentialRequest beginCreatePasswordCredentialRequest)
|
||||
{
|
||||
//This flow can be used if Password flow needs to be implemented
|
||||
throw new NotImplementedException();
|
||||
//return HandleCreatePasswordQuery(beginCreatePasswordCredentialRequest);
|
||||
}
|
||||
else if (request is BeginCreatePublicKeyCredentialRequest beginCreatePublicKeyCredentialRequest)
|
||||
{
|
||||
return await HandleCreatePasskeyQueryAsync(beginCreatePublicKeyCredentialRequest);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<BeginCreateCredentialResponse> HandleCreatePasskeyQueryAsync(BeginCreatePublicKeyCredentialRequest optionRequest)
|
||||
{
|
||||
var intent = new Intent(ApplicationContext, typeof(MainActivity));
|
||||
intent.PutExtra(CredentialProviderConstants.Fido2CredentialAction, CredentialProviderConstants.Fido2CredentialCreate);
|
||||
var pendingIntent = PendingIntent.GetActivity(ApplicationContext, UniqueCreateRequestCode, intent,
|
||||
AndroidHelpers.AddPendingIntentMutabilityFlag(PendingIntentFlags.UpdateCurrent, true));
|
||||
|
||||
var userEmail = await GetSafeActiveAccountEmailAsync();
|
||||
|
||||
var createEntryBuilder = new CreateEntry.Builder(userEmail ?? AppResources.Bitwarden, pendingIntent)
|
||||
.SetDescription(userEmail != null
|
||||
? string.Format(AppResources.YourPasskeyWillBeSavedToYourBitwardenVaultForX, userEmail)
|
||||
: AppResources.YourPasskeyWillBeSavedToYourBitwardenVault)
|
||||
.Build();
|
||||
|
||||
var createCredentialResponse = new BeginCreateCredentialResponse.Builder()
|
||||
.AddCreateEntry(createEntryBuilder);
|
||||
|
||||
return createCredentialResponse.Build();
|
||||
}
|
||||
|
||||
private async Task<BeginGetCredentialResponse> ProcessGetCredentialsRequestAsync(
|
||||
BeginGetCredentialRequest request)
|
||||
{
|
||||
IList<CredentialEntry> credentialEntries = null;
|
||||
var credentialEntries = new List<CredentialEntry>();
|
||||
|
||||
foreach (var option in request.BeginGetCredentialOptions)
|
||||
foreach (var option in request.BeginGetCredentialOptions.OfType<BeginGetPublicKeyCredentialOption>())
|
||||
{
|
||||
var credentialOption = option as BeginGetPublicKeyCredentialOption;
|
||||
if (credentialOption != null)
|
||||
{
|
||||
credentialEntries ??= new List<CredentialEntry>();
|
||||
((List<CredentialEntry>)credentialEntries).AddRange(
|
||||
await PopulatePasskeyDataAsync(request.CallingAppInfo, credentialOption));
|
||||
}
|
||||
credentialEntries.AddRange(await Bit.App.Platforms.Android.Autofill.CredentialHelpers.PopulatePasskeyDataAsync(request.CallingAppInfo, option, ApplicationContext, false));
|
||||
}
|
||||
|
||||
if (credentialEntries == null)
|
||||
if (!credentialEntries.Any())
|
||||
{
|
||||
return new BeginGetCredentialResponse();
|
||||
}
|
||||
@@ -85,63 +145,24 @@ namespace Bit.Droid.Autofill
|
||||
.Build();
|
||||
}
|
||||
|
||||
private async Task<List<CredentialEntry>> PopulatePasskeyDataAsync(CallingAppInfo callingAppInfo,
|
||||
BeginGetPublicKeyCredentialOption option)
|
||||
{
|
||||
var packageName = callingAppInfo.PackageName;
|
||||
var origin = callingAppInfo.Origin;
|
||||
var signingInfo = callingAppInfo.SigningInfo;
|
||||
|
||||
var request = new PublicKeyCredentialRequestOptions(option.RequestJson);
|
||||
|
||||
var passkeyEntries = new List<CredentialEntry>();
|
||||
|
||||
_cipherService ??= ServiceContainer.Resolve<ICipherService>();
|
||||
var ciphers = await _cipherService.GetAllDecryptedForUrlAsync(origin);
|
||||
if (ciphers == null)
|
||||
{
|
||||
return passkeyEntries;
|
||||
}
|
||||
|
||||
var passkeyCiphers = ciphers.Where(cipher => cipher.HasFido2Credential).ToList();
|
||||
if (!passkeyCiphers.Any())
|
||||
{
|
||||
return passkeyEntries;
|
||||
}
|
||||
|
||||
foreach (var cipher in passkeyCiphers)
|
||||
{
|
||||
var passkeyEntry = GetPasskey(cipher, option);
|
||||
passkeyEntries.Add(passkeyEntry);
|
||||
}
|
||||
|
||||
return passkeyEntries;
|
||||
}
|
||||
|
||||
private PublicKeyCredentialEntry GetPasskey(CipherView cipher, BeginGetPublicKeyCredentialOption option)
|
||||
{
|
||||
var credDataBundle = new Bundle();
|
||||
credDataBundle.PutString(CredentialProviderConstants.CredentialIdIntentExtra,
|
||||
cipher.Login.MainFido2Credential.CredentialId);
|
||||
|
||||
var intent = new Intent(ApplicationContext, typeof(CredentialProviderSelectionActivity))
|
||||
.SetAction(GetPasskeyIntentAction).SetPackage(Constants.PACKAGE_NAME);
|
||||
intent.PutExtra(CredentialProviderConstants.CredentialDataIntentExtra, credDataBundle);
|
||||
intent.PutExtra(CredentialProviderConstants.CredentialProviderCipherId, cipher.Id);
|
||||
var pendingIntent = PendingIntent.GetActivity(ApplicationContext, UniqueRequestCode, intent,
|
||||
PendingIntentFlags.Mutable | PendingIntentFlags.UpdateCurrent);
|
||||
|
||||
return new PublicKeyCredentialEntry.Builder(
|
||||
ApplicationContext,
|
||||
cipher.Login.Username ?? "No username",
|
||||
pendingIntent,
|
||||
option)
|
||||
.SetDisplayName(cipher.Name)
|
||||
.SetIcon(Icon.CreateWithResource(ApplicationContext, Resource.Drawable.icon))
|
||||
.Build();
|
||||
}
|
||||
|
||||
public override void OnClearCredentialStateRequest(ProviderClearCredentialStateRequest request,
|
||||
CancellationSignal cancellationSignal, IOutcomeReceiver callback) => throw new NotImplementedException();
|
||||
CancellationSignal cancellationSignal, IOutcomeReceiver callback)
|
||||
{
|
||||
callback.OnResult(null);
|
||||
}
|
||||
|
||||
private async Task<string> GetSafeActiveAccountEmailAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _stateService.Value.GetEmailAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if it throws to get the user's email then we log and continue showing a more generic message
|
||||
_logger.Value.Exception(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.App.Platforms.Android.Autofill
|
||||
{
|
||||
public interface IFido2AndroidGetAssertionUserInterface : IFido2GetAssertionUserInterface
|
||||
{
|
||||
void Init(string cipherId,
|
||||
bool userVerified,
|
||||
Func<bool> hasVaultBeenUnlockedInThisTransaction,
|
||||
string rpId);
|
||||
}
|
||||
|
||||
public class Fido2GetAssertionUserInterface : Core.Utilities.Fido2.Fido2GetAssertionUserInterface, IFido2AndroidGetAssertionUserInterface
|
||||
{
|
||||
private readonly IStateService _stateService;
|
||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
||||
private readonly ICipherService _cipherService;
|
||||
private readonly IUserVerificationMediatorService _userVerificationMediatorService;
|
||||
|
||||
public Fido2GetAssertionUserInterface(IStateService stateService,
|
||||
IVaultTimeoutService vaultTimeoutService,
|
||||
ICipherService cipherService,
|
||||
IUserVerificationMediatorService userVerificationMediatorService)
|
||||
{
|
||||
_stateService = stateService;
|
||||
_vaultTimeoutService = vaultTimeoutService;
|
||||
_cipherService = cipherService;
|
||||
_userVerificationMediatorService = userVerificationMediatorService;
|
||||
}
|
||||
|
||||
public void Init(string cipherId,
|
||||
bool userVerified,
|
||||
Func<bool> hasVaultBeenUnlockedInThisTransaction,
|
||||
string rpId)
|
||||
{
|
||||
Init(cipherId,
|
||||
userVerified,
|
||||
EnsureAuthenAndVaultUnlockedAsync,
|
||||
hasVaultBeenUnlockedInThisTransaction,
|
||||
(cipherId, userVerificationPreference) => VerifyUserAsync(cipherId, userVerificationPreference, rpId, hasVaultBeenUnlockedInThisTransaction()));
|
||||
}
|
||||
|
||||
public async Task EnsureAuthenAndVaultUnlockedAsync()
|
||||
{
|
||||
if (!await _stateService.IsAuthenticatedAsync() || await _vaultTimeoutService.IsLockedAsync())
|
||||
{
|
||||
// this should never happen but just in case.
|
||||
throw new InvalidOperationException("Not authed or vault locked");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> VerifyUserAsync(string selectedCipherId, Fido2UserVerificationPreference userVerificationPreference, string rpId, bool vaultUnlockedDuringThisTransaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
var encrypted = await _cipherService.GetAsync(selectedCipherId);
|
||||
var cipher = await encrypted.DecryptAsync();
|
||||
|
||||
var userVerification = await _userVerificationMediatorService.VerifyUserForFido2Async(
|
||||
new Fido2UserVerificationOptions(
|
||||
cipher?.Reprompt == Core.Enums.CipherRepromptType.Password,
|
||||
userVerificationPreference,
|
||||
vaultUnlockedDuringThisTransaction,
|
||||
rpId)
|
||||
);
|
||||
return !userVerification.IsCancelled && userVerification.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.App.Platforms.Android.Autofill
|
||||
{
|
||||
public class Fido2MakeCredentialUserInterface : IFido2MakeCredentialConfirmationUserInterface
|
||||
{
|
||||
private readonly IStateService _stateService;
|
||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
||||
private readonly ICipherService _cipherService;
|
||||
private readonly IUserVerificationMediatorService _userVerificationMediatorService;
|
||||
private readonly IDeviceActionService _deviceActionService;
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private LazyResolve<IMessagingService> _messagingService = new LazyResolve<IMessagingService>();
|
||||
|
||||
private TaskCompletionSource<(string cipherId, bool? userVerified)> _confirmCredentialTcs;
|
||||
private TaskCompletionSource<bool> _unlockVaultTcs;
|
||||
private Fido2UserVerificationOptions? _currentDefaultUserVerificationOptions;
|
||||
private Func<bool> _checkHasVaultBeenUnlockedInThisTransaction;
|
||||
|
||||
public Fido2MakeCredentialUserInterface(IStateService stateService,
|
||||
IVaultTimeoutService vaultTimeoutService,
|
||||
ICipherService cipherService,
|
||||
IUserVerificationMediatorService userVerificationMediatorService,
|
||||
IDeviceActionService deviceActionService,
|
||||
IPlatformUtilsService platformUtilsService)
|
||||
{
|
||||
_stateService = stateService;
|
||||
_vaultTimeoutService = vaultTimeoutService;
|
||||
_cipherService = cipherService;
|
||||
_userVerificationMediatorService = userVerificationMediatorService;
|
||||
_deviceActionService = deviceActionService;
|
||||
_platformUtilsService = platformUtilsService;
|
||||
}
|
||||
|
||||
public bool HasVaultBeenUnlockedInThisTransaction => _checkHasVaultBeenUnlockedInThisTransaction?.Invoke() == true;
|
||||
|
||||
public bool IsConfirmingNewCredential => _confirmCredentialTcs?.Task != null && !_confirmCredentialTcs.Task.IsCompleted;
|
||||
public bool IsWaitingUnlockVault => _unlockVaultTcs?.Task != null && !_unlockVaultTcs.Task.IsCompleted;
|
||||
|
||||
public async Task<(string CipherId, bool UserVerified)> ConfirmNewCredentialAsync(Fido2ConfirmNewCredentialParams confirmNewCredentialParams)
|
||||
{
|
||||
_confirmCredentialTcs?.TrySetCanceled();
|
||||
_confirmCredentialTcs = null;
|
||||
_confirmCredentialTcs = new TaskCompletionSource<(string cipherId, bool? userVerified)>();
|
||||
|
||||
_currentDefaultUserVerificationOptions = new Fido2UserVerificationOptions(false, confirmNewCredentialParams.UserVerificationPreference, HasVaultBeenUnlockedInThisTransaction, confirmNewCredentialParams.RpId);
|
||||
|
||||
_messagingService.Value.Send(Bit.Core.Constants.CredentialNavigateToAutofillCipherMessageCommand, confirmNewCredentialParams);
|
||||
|
||||
var (cipherId, isUserVerified) = await _confirmCredentialTcs.Task;
|
||||
|
||||
var verified = isUserVerified;
|
||||
if (verified is null)
|
||||
{
|
||||
var userVerification = await VerifyUserAsync(cipherId, confirmNewCredentialParams.UserVerificationPreference, confirmNewCredentialParams.RpId);
|
||||
// TODO: If cancelled then let the user choose another cipher.
|
||||
// I think this can be done by showing a message to the uesr and recursive calling of this method ConfirmNewCredentialAsync
|
||||
verified = !userVerification.IsCancelled && userVerification.Result;
|
||||
}
|
||||
|
||||
if (cipherId is null)
|
||||
{
|
||||
return await CreateNewLoginForFido2CredentialAsync(confirmNewCredentialParams, verified.Value);
|
||||
}
|
||||
|
||||
return (cipherId, verified.Value);
|
||||
}
|
||||
|
||||
private async Task<(string CipherId, bool UserVerified)> CreateNewLoginForFido2CredentialAsync(Fido2ConfirmNewCredentialParams confirmNewCredentialParams, bool userVerified)
|
||||
{
|
||||
if (!userVerified && await _userVerificationMediatorService.ShouldEnforceFido2RequiredUserVerificationAsync(new Fido2UserVerificationOptions
|
||||
(
|
||||
false,
|
||||
confirmNewCredentialParams.UserVerificationPreference,
|
||||
true,
|
||||
confirmNewCredentialParams.RpId
|
||||
)))
|
||||
{
|
||||
return (null, false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
|
||||
|
||||
var cipherId = await _cipherService.CreateNewLoginForPasskeyAsync(confirmNewCredentialParams);
|
||||
|
||||
await _deviceActionService.HideLoadingAsync();
|
||||
|
||||
return (cipherId, userVerified);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _deviceActionService.HideLoadingAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task EnsureUnlockedVaultAsync()
|
||||
{
|
||||
if (!await _stateService.IsAuthenticatedAsync()
|
||||
||
|
||||
await _vaultTimeoutService.IsLoggedOutByTimeoutAsync()
|
||||
||
|
||||
await _vaultTimeoutService.ShouldLogOutByTimeoutAsync())
|
||||
{
|
||||
await NavigateAndWaitForUnlockAsync(Bit.Core.Enums.NavigationTarget.HomeLogin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await _vaultTimeoutService.IsLockedAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await NavigateAndWaitForUnlockAsync(Bit.Core.Enums.NavigationTarget.Lock);
|
||||
}
|
||||
|
||||
private async Task NavigateAndWaitForUnlockAsync(Bit.Core.Enums.NavigationTarget navTarget)
|
||||
{
|
||||
_unlockVaultTcs?.TrySetCanceled();
|
||||
_unlockVaultTcs = new TaskCompletionSource<bool>();
|
||||
|
||||
_messagingService.Value.Send(Bit.Core.Constants.NavigateToMessageCommand, navTarget);
|
||||
|
||||
await _unlockVaultTcs.Task;
|
||||
}
|
||||
|
||||
public Task InformExcludedCredentialAsync(string[] existingCipherIds)
|
||||
{
|
||||
// TODO: Show excluded credential to the user in some screen.
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public void SetCheckHasVaultBeenUnlockedInThisTransaction(Func<bool> checkHasVaultBeenUnlockedInThisTransaction)
|
||||
{
|
||||
_checkHasVaultBeenUnlockedInThisTransaction = checkHasVaultBeenUnlockedInThisTransaction;
|
||||
}
|
||||
|
||||
public void Confirm(string cipherId, bool? userVerified) => _confirmCredentialTcs?.TrySetResult((cipherId, userVerified));
|
||||
public void ConfirmVaultUnlocked() => _unlockVaultTcs?.TrySetResult(true);
|
||||
|
||||
public async Task ConfirmAsync(string cipherId, bool alreadyHasFido2Credential, bool? userVerified)
|
||||
{
|
||||
if (alreadyHasFido2Credential
|
||||
&&
|
||||
!await _platformUtilsService.ShowDialogAsync(
|
||||
AppResources.ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey,
|
||||
AppResources.OverwritePasskey,
|
||||
AppResources.Yes,
|
||||
AppResources.No))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Confirm(cipherId, userVerified);
|
||||
}
|
||||
|
||||
public void Cancel() => _confirmCredentialTcs?.TrySetCanceled();
|
||||
|
||||
public void OnConfirmationException(Exception ex) => _confirmCredentialTcs?.TrySetException(ex);
|
||||
|
||||
private async Task<CancellableResult<bool>> VerifyUserAsync(string selectedCipherId, Fido2UserVerificationPreference userVerificationPreference, string rpId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (selectedCipherId is null && userVerificationPreference == Fido2UserVerificationPreference.Discouraged)
|
||||
{
|
||||
return new CancellableResult<bool>(false);
|
||||
}
|
||||
|
||||
var shouldCheckMasterPasswordReprompt = false;
|
||||
if (selectedCipherId != null)
|
||||
{
|
||||
var encrypted = await _cipherService.GetAsync(selectedCipherId);
|
||||
var cipher = await encrypted.DecryptAsync();
|
||||
shouldCheckMasterPasswordReprompt = cipher?.Reprompt == Core.Enums.CipherRepromptType.Password;
|
||||
}
|
||||
|
||||
return await _userVerificationMediatorService.VerifyUserForFido2Async(
|
||||
new Fido2UserVerificationOptions(
|
||||
shouldCheckMasterPasswordReprompt,
|
||||
userVerificationPreference,
|
||||
HasVaultBeenUnlockedInThisTransaction,
|
||||
rpId)
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
return new CancellableResult<bool>(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Fido2UserVerificationOptions? GetCurrentUserVerificationOptions() => _currentDefaultUserVerificationOptions;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ using Bit.App.Droid.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using FileProvider = AndroidX.Core.Content.FileProvider;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.Droid
|
||||
{
|
||||
@@ -167,6 +168,13 @@ namespace Bit.Droid
|
||||
base.OnNewIntent(intent);
|
||||
try
|
||||
{
|
||||
if (intent?.GetStringExtra(CredentialProviderConstants.Fido2CredentialAction) == CredentialProviderConstants.Fido2CredentialCreate
|
||||
&&
|
||||
_appOptions != null)
|
||||
{
|
||||
_appOptions.HasUnlockedInThisTransaction = false;
|
||||
}
|
||||
|
||||
if (intent?.GetStringExtra("uri") is string uri)
|
||||
{
|
||||
_messagingService.Send(App.App.POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE);
|
||||
@@ -325,12 +333,15 @@ namespace Bit.Droid
|
||||
|
||||
private AppOptions GetOptions()
|
||||
{
|
||||
var fido2CredentialAction = Intent.GetStringExtra(CredentialProviderConstants.Fido2CredentialAction);
|
||||
var options = new AppOptions
|
||||
{
|
||||
Uri = Intent.GetStringExtra("uri") ?? Intent.GetStringExtra(AutofillConstants.AutofillFrameworkUri),
|
||||
MyVaultTile = Intent.GetBooleanExtra("myVaultTile", false),
|
||||
GeneratorTile = Intent.GetBooleanExtra("generatorTile", false),
|
||||
FromAutofillFramework = Intent.GetBooleanExtra(AutofillConstants.AutofillFramework, false),
|
||||
Fido2CredentialAction = fido2CredentialAction,
|
||||
FromFido2Framework = !string.IsNullOrWhiteSpace(fido2CredentialAction),
|
||||
CreateSend = GetCreateSendRequest(Intent)
|
||||
};
|
||||
var fillType = Intent.GetIntExtra(AutofillConstants.AutofillFrameworkFillType, 0);
|
||||
|
||||
@@ -20,7 +20,10 @@ using Bit.App.Utilities;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Utilities.AccountManagement;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Platforms.Android.Autofill;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Services.UserVerification;
|
||||
|
||||
#if !FDROID
|
||||
using Android.Gms.Security;
|
||||
#endif
|
||||
@@ -91,6 +94,51 @@ namespace Bit.Droid
|
||||
ServiceContainer.Resolve<ICryptoService>(),
|
||||
ServiceContainer.Resolve<IVaultTimeoutService>());
|
||||
ServiceContainer.Register<IUserPinService>(userPinService);
|
||||
|
||||
var userVerificationMediatorService = new UserVerificationMediatorService(
|
||||
ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"),
|
||||
ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService"),
|
||||
userPinService,
|
||||
deviceActionService,
|
||||
ServiceContainer.Resolve<IUserVerificationService>());
|
||||
ServiceContainer.Register<IUserVerificationMediatorService>(userVerificationMediatorService);
|
||||
|
||||
var fido2AuthenticatorService = new Fido2AuthenticatorService(
|
||||
ServiceContainer.Resolve<ICipherService>(),
|
||||
ServiceContainer.Resolve<ISyncService>(),
|
||||
ServiceContainer.Resolve<ICryptoFunctionService>(),
|
||||
userVerificationMediatorService);
|
||||
ServiceContainer.Register<IFido2AuthenticatorService>(fido2AuthenticatorService);
|
||||
|
||||
var fido2GetAssertionUserInterface = new Fido2GetAssertionUserInterface(
|
||||
ServiceContainer.Resolve<IStateService>(),
|
||||
ServiceContainer.Resolve<IVaultTimeoutService>(),
|
||||
ServiceContainer.Resolve<ICipherService>(),
|
||||
ServiceContainer.Resolve<IUserVerificationMediatorService>());
|
||||
ServiceContainer.Register<IFido2AndroidGetAssertionUserInterface>(fido2GetAssertionUserInterface);
|
||||
|
||||
var fido2MakeCredentialUserInterface = new Fido2MakeCredentialUserInterface(
|
||||
ServiceContainer.Resolve<IStateService>(),
|
||||
ServiceContainer.Resolve<IVaultTimeoutService>(),
|
||||
ServiceContainer.Resolve<ICipherService>(),
|
||||
ServiceContainer.Resolve<IUserVerificationMediatorService>(),
|
||||
ServiceContainer.Resolve<IDeviceActionService>(),
|
||||
ServiceContainer.Resolve<IPlatformUtilsService>());
|
||||
ServiceContainer.Register<IFido2MakeCredentialConfirmationUserInterface>(fido2MakeCredentialUserInterface);
|
||||
|
||||
var fido2ClientService = new Fido2ClientService(
|
||||
ServiceContainer.Resolve<IStateService>(),
|
||||
ServiceContainer.Resolve<IEnvironmentService>(),
|
||||
ServiceContainer.Resolve<ICryptoFunctionService>(),
|
||||
ServiceContainer.Resolve<IFido2AuthenticatorService>(),
|
||||
fido2GetAssertionUserInterface,
|
||||
fido2MakeCredentialUserInterface);
|
||||
ServiceContainer.Register<IFido2ClientService>(fido2ClientService);
|
||||
|
||||
ServiceContainer.Register<IFido2MediatorService>(new Fido2MediatorService(
|
||||
fido2AuthenticatorService,
|
||||
fido2ClientService,
|
||||
ServiceContainer.Resolve<ICipherService>()));
|
||||
}
|
||||
#if !FDROID
|
||||
if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#if !FDROID
|
||||
#if !FDROID
|
||||
using System;
|
||||
using Android.App;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Firebase.Messaging;
|
||||
@@ -20,7 +21,7 @@ namespace Bit.Droid.Push
|
||||
try {
|
||||
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
||||
var pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService");
|
||||
|
||||
|
||||
await stateService.SetPushRegisteredTokenAsync(token);
|
||||
await pushNotificationService.RegisterAsync();
|
||||
}
|
||||
@@ -38,13 +39,33 @@ namespace Bit.Droid.Push
|
||||
{
|
||||
return;
|
||||
}
|
||||
var data = message.Data.ContainsKey("data") ? message.Data["data"] : null;
|
||||
if (data == null)
|
||||
|
||||
JObject obj = null;
|
||||
if (message.Data.TryGetValue("data", out var data))
|
||||
{
|
||||
// Legacy GCM format
|
||||
obj = JObject.Parse(data);
|
||||
}
|
||||
else if (message.Data.TryGetValue("type", out var typeData) &&
|
||||
Enum.TryParse(typeData, out NotificationType type))
|
||||
{
|
||||
// New FCMv1 format
|
||||
obj = new JObject
|
||||
{
|
||||
{ "type", (int)type }
|
||||
};
|
||||
|
||||
if (message.Data.TryGetValue("payload", out var payloadData))
|
||||
{
|
||||
obj.Add("payload", payloadData);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = JObject.Parse(data);
|
||||
var listener = ServiceContainer.Resolve<IPushNotificationListenerService>(
|
||||
"pushNotificationListenerService");
|
||||
await listener.OnMessageAsync(obj, Device.Android);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<resources>
|
||||
<integer name="launchModeAPIlevel">0</integer>
|
||||
<integer name="webAuthCallbackLaunchMode">1</integer>
|
||||
</resources>
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<resources>
|
||||
<integer name="launchModeAPIlevel">2</integer>
|
||||
<integer name="webAuthCallbackLaunchMode">3</integer>
|
||||
</resources>
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.App;
|
||||
using Android.App.Assist;
|
||||
using Android.Content;
|
||||
using Android.Credentials;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Views.Autofill;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
@@ -43,9 +43,28 @@ namespace Bit.Droid.Services
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// TODO - find a way to programmatically check if the credential provider service is enabled
|
||||
var activity = (MainActivity)Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var credManager = activity.GetSystemService(Java.Lang.Class.FromType(typeof(CredentialManager))) as CredentialManager;
|
||||
if (credManager == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var credentialProviderServiceComponentName = new ComponentName(activity, Java.Lang.Class.FromType(typeof(CredentialProviderService)));
|
||||
return credManager.IsEnabledCredentialProviderService(credentialProviderServiceComponentName);
|
||||
}
|
||||
catch (Java.Lang.NullPointerException)
|
||||
{
|
||||
// CredentialManager API is not working fully and may return a NullPointerException even if the CredentialProviderService is working and enabled
|
||||
// Info Here: https://developer.android.com/reference/android/credentials/CredentialManager#isEnabledCredentialProviderService(android.content.ComponentName)
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
@@ -184,7 +203,10 @@ namespace Bit.Droid.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO - find a way to programmatically disable the provider service, or take the user to the settings page where they can do it
|
||||
// We should try to find a way to programmatically disable the provider service when the API allows for it.
|
||||
// For now we'll take the user to Credential Settings so they can manually disable it
|
||||
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
||||
deviceActionService.OpenCredentialProviderSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Nfc;
|
||||
@@ -17,11 +15,14 @@ using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.App.Utilities.Prompts;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.App.Models;
|
||||
using Bit.Droid.Autofill;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Resource = Bit.Core.Resource;
|
||||
using Application = Android.App.Application;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.Droid.Services
|
||||
{
|
||||
@@ -204,7 +205,7 @@ namespace Bit.Droid.Services
|
||||
string text = null, string okButtonText = null, string cancelButtonText = null,
|
||||
bool numericKeyboard = false, bool autofocus = true, bool password = false)
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
@@ -261,7 +262,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public Task<ValidatablePromptResponse?> DisplayValidatablePromptAsync(ValidatablePromptConfig config)
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return Task.FromResult<ValidatablePromptResponse?>(null);
|
||||
@@ -338,7 +339,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public void RateApp()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
try
|
||||
{
|
||||
var rateIntent = RateIntentForUrl("market://details", activity);
|
||||
@@ -371,14 +372,14 @@ namespace Bit.Droid.Services
|
||||
|
||||
public bool SupportsNfc()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var manager = activity.GetSystemService(Context.NfcService) as NfcManager;
|
||||
return manager.DefaultAdapter?.IsEnabled ?? false;
|
||||
}
|
||||
|
||||
public bool SupportsCamera()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
return activity.PackageManager.HasSystemFeature(PackageManager.FeatureCamera);
|
||||
}
|
||||
|
||||
@@ -394,7 +395,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public Task<string> DisplayAlertAsync(string title, string message, string cancel, params string[] buttons)
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
@@ -475,7 +476,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public void OpenAccessibilityOverlayPermissionSettings()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
try
|
||||
{
|
||||
var intent = new Intent(Settings.ActionManageOverlayPermission);
|
||||
@@ -504,10 +505,10 @@ namespace Bit.Droid.Services
|
||||
|
||||
public void OpenCredentialProviderSettings()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
try
|
||||
{
|
||||
var pendingIntent = CredentialManager.Create(activity).CreateSettingsPendingIntent();
|
||||
var pendingIntent = ICredentialManager.Create(activity).CreateSettingsPendingIntent();
|
||||
pendingIntent.Send();
|
||||
}
|
||||
catch (ActivityNotFoundException)
|
||||
@@ -527,7 +528,7 @@ namespace Bit.Droid.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var intent = new Intent(Settings.ActionAccessibilitySettings);
|
||||
activity.StartActivity(intent);
|
||||
}
|
||||
@@ -536,7 +537,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public void OpenAutofillSettings()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
try
|
||||
{
|
||||
var intent = new Intent(Settings.ActionRequestSetAutofillService);
|
||||
@@ -564,10 +565,92 @@ namespace Bit.Droid.Services
|
||||
// ref: https://developer.android.com/reference/android/os/SystemClock#elapsedRealtime()
|
||||
return SystemClock.ElapsedRealtime();
|
||||
}
|
||||
|
||||
public async Task ExecuteFido2CredentialActionAsync(AppOptions appOptions)
|
||||
{
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null || string.IsNullOrWhiteSpace(appOptions.Fido2CredentialAction))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (appOptions.Fido2CredentialAction == CredentialProviderConstants.Fido2CredentialGet)
|
||||
{
|
||||
await ExecuteFido2GetCredentialAsync(appOptions);
|
||||
}
|
||||
else if (appOptions.Fido2CredentialAction == CredentialProviderConstants.Fido2CredentialCreate)
|
||||
{
|
||||
await ExecuteFido2CreateCredentialAsync();
|
||||
}
|
||||
|
||||
// Clear CredentialAction and FromFido2Framework values to avoid erratic behaviors in subsequent navigation/flows
|
||||
// For Fido2CredentialGet these are no longer needed as a new Activity will be initiated.
|
||||
// For Fido2CredentialCreate the app will rely on IFido2MakeCredentialConfirmationUserInterface.IsConfirmingNewCredential
|
||||
appOptions.Fido2CredentialAction = null;
|
||||
appOptions.FromFido2Framework = false;
|
||||
}
|
||||
|
||||
private async Task ExecuteFido2GetCredentialAsync(AppOptions appOptions)
|
||||
{
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var request = AndroidX.Credentials.Provider.PendingIntentHandler.RetrieveBeginGetCredentialRequest(activity.Intent);
|
||||
var response = new AndroidX.Credentials.Provider.BeginGetCredentialResponse();;
|
||||
var credentialEntries = new List<AndroidX.Credentials.Provider.CredentialEntry>();
|
||||
foreach (var option in request.BeginGetCredentialOptions.OfType<AndroidX.Credentials.Provider.BeginGetPublicKeyCredentialOption>())
|
||||
{
|
||||
credentialEntries.AddRange(await Bit.App.Platforms.Android.Autofill.CredentialHelpers.PopulatePasskeyDataAsync(request.CallingAppInfo, option, activity, appOptions.HasUnlockedInThisTransaction));
|
||||
}
|
||||
|
||||
if (credentialEntries.Any())
|
||||
{
|
||||
response = new AndroidX.Credentials.Provider.BeginGetCredentialResponse.Builder()
|
||||
.SetCredentialEntries(credentialEntries)
|
||||
.Build();
|
||||
}
|
||||
|
||||
var result = new Android.Content.Intent();
|
||||
AndroidX.Credentials.Provider.PendingIntentHandler.SetBeginGetCredentialResponse(result, response);
|
||||
activity.SetResult(Result.Ok, result);
|
||||
activity.Finish();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Bit.Core.Services.LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
|
||||
activity.SetResult(Result.Canceled);
|
||||
activity.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteFido2CreateCredentialAsync()
|
||||
{
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null) { return; }
|
||||
|
||||
try
|
||||
{
|
||||
var getRequest = AndroidX.Credentials.Provider.PendingIntentHandler.RetrieveProviderCreateCredentialRequest(activity.Intent);
|
||||
await Bit.App.Platforms.Android.Autofill.CredentialHelpers.CreateCipherPasskeyAsync(getRequest, activity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Bit.Core.Services.LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
|
||||
activity.SetResult(Result.Canceled);
|
||||
activity.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseMainApp()
|
||||
{
|
||||
var activity = (MainActivity)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
@@ -608,7 +691,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
public float GetSystemFontSizeScale()
|
||||
{
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity as MainActivity;
|
||||
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
|
||||
return activity?.Resources?.Configuration?.FontScale ?? 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Android.OS;
|
||||
using AndroidX.Credentials.Provider;
|
||||
using Bit.Core.Utilities;
|
||||
using Java.Security;
|
||||
|
||||
namespace Bit.App.Droid.Utilities
|
||||
{
|
||||
public static class CallingAppInfoExtensions
|
||||
{
|
||||
public static string GetAndroidOrigin(this CallingAppInfo callingAppInfo)
|
||||
{
|
||||
if (Build.VERSION.SdkInt < BuildVersionCodes.P || callingAppInfo?.SigningInfo?.GetApkContentsSigners().Any() != true)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cert = callingAppInfo.SigningInfo.GetApkContentsSigners()[0].ToByteArray();
|
||||
var md = MessageDigest.GetInstance("SHA-256");
|
||||
var certHash = md.Digest(cert);
|
||||
return $"android:apk-key-hash:{CoreHelpers.Base64UrlEncode(certHash)}";
|
||||
}
|
||||
|
||||
public static string GetLatestCertificationFingerprint(this CallingAppInfo callingAppInfo)
|
||||
{
|
||||
if (callingAppInfo.SigningInfo.HasMultipleSigners)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var signature = callingAppInfo.SigningInfo.GetSigningCertificateHistory()[0].ToByteArray();
|
||||
var md = MessageDigest.GetInstance("SHA-256");
|
||||
var digestedSignature = md.Digest(signature);
|
||||
var normalizedFingerprint = string.Join(":", digestedSignature.Select(b => b.ToString("X2")));
|
||||
return normalizedFingerprint;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,12 @@
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Bit.App.Droid.Utilities;
|
||||
|
||||
namespace Bit.Droid
|
||||
{
|
||||
[Activity(
|
||||
NoHistory = true,
|
||||
LaunchMode = LaunchMode.SingleTop,
|
||||
Exported = true)]
|
||||
[IntentFilter(new[] { Android.Content.Intent.ActionView },
|
||||
Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable },
|
||||
DataScheme = "bitwarden")]
|
||||
[Register("com.x8bit.bitwarden.WebAuthCallbackActivity")]
|
||||
public class WebAuthCallbackActivity : WebAuthenticatorCallbackActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.8bit.bitwarden</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2024.3.3</string>
|
||||
<string>2024.5.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CFBundleIconName</key>
|
||||
|
||||
41
src/App/Platforms/iOS/PrivacyInfo.xcprivacy
Normal file
41
src/App/Platforms/iOS/PrivacyInfo.xcprivacy
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>35F9.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>E174.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>1C8F.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
481
src/App/Resources/Raw/fido2_privileged_allow_list.json
Normal file
481
src/App/Resources/Raw/fido2_privileged_allow_list.json
Normal file
@@ -0,0 +1,481 @@
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.android.chrome",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
|
||||
},
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.chrome.beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "DA:63:3D:34:B6:9E:63:AE:21:03:B4:9D:53:CE:05:2F:C5:F7:F3:C5:3A:AB:94:FD:C2:A2:08:BD:FD:14:24:9C"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.chrome.dev",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "90:44:EE:5F:EE:4B:BC:5E:21:DD:44:66:54:31:C4:EB:1F:1F:71:A3:27:16:A0:BC:92:7B:CB:B3:92:33:CA:BF"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.chrome.canary",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "20:19:DF:A1:FB:23:EF:BF:70:C5:BC:D1:44:3C:5B:EA:B0:4F:3F:2F:F4:36:6E:9A:C1:E3:45:76:39:A2:4C:FC"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.chromium.chrome",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "C6:AD:B8:B8:3C:6D:4C:17:D2:92:AF:DE:56:FD:48:8A:51:D3:16:FF:8F:2C:11:C5:41:02:23:BF:F8:A7:DB:B3"
|
||||
},
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.google.android.apps.chrome",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.fennec_webauthndebug",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "BD:AE:82:02:80:D2:AF:B7:74:94:EF:22:58:AA:78:A9:AE:A1:36:41:7E:8B:C2:3D:C9:87:75:2E:6F:48:E8:48"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.firefox",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "A7:8B:62:A5:16:5B:44:94:B2:FE:AD:9E:76:A2:80:D2:2D:93:7F:EE:62:51:AE:CE:59:94:46:B2:EA:31:9B:04"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.firefox_beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "A7:8B:62:A5:16:5B:44:94:B2:FE:AD:9E:76:A2:80:D2:2D:93:7F:EE:62:51:AE:CE:59:94:46:B2:EA:31:9B:04"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.focus",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.fennec_aurora",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "BC:04:88:83:8D:06:F4:CA:6B:F3:23:86:DA:AB:0D:D8:EB:CF:3E:77:30:78:74:59:F6:2F:B3:CD:14:A1:BA:AA"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "org.mozilla.rocket",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "86:3A:46:F0:97:39:32:B7:D0:19:9B:54:91:12:74:1C:2D:27:31:AC:72:EA:11:B7:52:3A:A9:0A:11:BF:56:91"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx.canary",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx.dev",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx.beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx.rolling",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "32:A2:FC:74:D7:31:10:58:59:E5:A8:5D:F1:6D:95:F1:02:D8:5B:22:09:9B:80:64:C5:D8:91:5C:61:DA:D1:E0"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.microsoft.emmx.local",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "userdebug",
|
||||
"cert_fingerprint_sha256": "32:A2:FC:74:D7:31:10:58:59:E5:A8:5D:F1:6D:95:F1:02:D8:5B:22:09:9B:80:64:C5:D8:91:5C:61:DA:D1:E0"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.brave.browser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.brave.browser_beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.brave.browser_nightly",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "app.vanadium.browser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "C6:AD:B8:B8:3C:6D:4C:17:D2:92:AF:DE:56:FD:48:8A:51:D3:16:FF:8F:2C:11:C5:41:02:23:BF:F8:A7:DB:B3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.vivaldi.browser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.vivaldi.browser.snapshot",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.vivaldi.browser.sopranos",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.citrix.Receiver",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "3D:D1:12:67:10:69:AB:36:4E:F9:BE:73:9A:B7:B5:EE:15:E1:CD:E9:D8:75:7B:1B:F0:64:F5:0C:55:68:9A:49"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "CE:B2:23:D7:77:09:F2:B6:BC:0B:3A:78:36:F5:A5:AF:4C:E1:D3:55:F4:A7:28:86:F7:9D:F8:0D:C9:D6:12:2E"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "AA:D0:D4:57:E6:33:C3:78:25:77:30:5B:C1:B2:D9:E3:81:41:C7:21:DF:0D:AA:6E:29:07:2F:C4:1D:34:F0:AB"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.android.browser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "C9:00:9D:01:EB:F9:F5:D0:30:2B:C7:1B:2F:E9:AA:9A:47:A4:32:BB:A1:73:08:A3:11:1B:75:D7:B2:14:90:25"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.sec.android.app.sbrowser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "C8:A2:E9:BC:CF:59:7C:2F:B6:DC:66:BE:E2:93:FC:13:F2:FC:47:EC:77:BC:6B:2B:0D:52:C1:1F:51:19:2A:B8"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "34:DF:0E:7A:9F:1C:F1:89:2E:45:C0:56:B4:97:3C:D8:1C:CF:14:8A:40:50:D1:1A:EA:4A:C5:A6:5F:90:0A:42"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.sec.android.app.sbrowser.beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "C8:A2:E9:BC:CF:59:7C:2F:B6:DC:66:BE:E2:93:FC:13:F2:FC:47:EC:77:BC:6B:2B:0D:52:C1:1F:51:19:2A:B8"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "34:DF:0E:7A:9F:1C:F1:89:2E:45:C0:56:B4:97:3C:D8:1C:CF:14:8A:40:50:D1:1A:EA:4A:C5:A6:5F:90:0A:42"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.google.android.gms",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "7C:E8:3C:1B:71:F3:D5:72:FE:D0:4C:8D:40:C5:CB:10:FF:75:E6:D8:7D:9D:F6:FB:D5:3F:04:68:C2:90:50:53"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "D2:2C:C5:00:29:9F:B2:28:73:A0:1A:01:0D:E1:C8:2F:BE:4D:06:11:19:B9:48:14:DD:30:1D:AB:50:CB:76:78"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
|
||||
},
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser.beta",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser.alpha",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser.corp",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser.canary",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "1D:A9:CB:AE:2D:CC:C6:A5:8D:6C:94:7B:E9:4C:DB:B7:33:D6:5D:A4:D1:77:0F:A1:4A:53:64:CB:4A:28:EB:49"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"info": {
|
||||
"package_name": "com.yandex.browser.broteam",
|
||||
"signatures": [
|
||||
{
|
||||
"build": "release",
|
||||
"cert_fingerprint_sha256": "1D:A9:CB:AE:2D:CC:C6:A5:8D:6C:94:7B:E9:4C:DB:B7:33:D6:5D:A4:D1:77:0F:A1:4A:53:64:CB:4A:28:EB:49"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Request;
|
||||
using Bit.Core.Models.Response;
|
||||
@@ -46,6 +41,7 @@ namespace Bit.Core.Abstractions
|
||||
Task<CipherResponse> PutShareCipherAsync(string id, CipherShareRequest request);
|
||||
Task PutDeleteCipherAsync(string id);
|
||||
Task<CipherResponse> PutRestoreCipherAsync(string id);
|
||||
Task<bool> HasUnassignedCiphersAsync();
|
||||
Task RefreshIdentityTokenAsync();
|
||||
Task<SsoPrevalidateResponse> PreValidateSsoAsync(string identifier);
|
||||
Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path,
|
||||
@@ -99,5 +95,6 @@ namespace Bit.Core.Abstractions
|
||||
Task<bool> GetDevicesExistenceByTypes(DeviceType[] deviceTypes);
|
||||
Task<ConfigResponse> GetConfigsAsync();
|
||||
Task<string> GetFastmailAccountIdAsync(string apiKey);
|
||||
Task<List<Utilities.DigitalAssetLinks.Statement>> GetDigitalAssetLinksForRpAsync(string rpId);
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Core/Abstractions/IAssetLinksService.cs
Normal file
7
src/Core/Abstractions/IAssetLinksService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public interface IAssetLinksService
|
||||
{
|
||||
Task<bool> ValidateAssetLinksAsync(string rpId, string packageName, string normalizedFingerprint);
|
||||
}
|
||||
}
|
||||
@@ -36,5 +36,6 @@ namespace Bit.Core.Abstractions
|
||||
Task RestoreWithServerAsync(string id);
|
||||
Task<string> CreateNewLoginForPasskeyAsync(Fido2ConfirmNewCredentialParams newPasskeyParams);
|
||||
Task CopyTotpCodeIfNeededAsync(CipherView cipher);
|
||||
Task<bool> VerifyOrganizationHasUnassignedItemsAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Utilities.Prompts;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
@@ -40,6 +41,7 @@ namespace Bit.App.Abstractions
|
||||
void OpenCredentialProviderSettings();
|
||||
void OpenAutofillSettings();
|
||||
long GetActiveTime();
|
||||
Task ExecuteFido2CredentialActionAsync(AppOptions appOptions);
|
||||
void CloseMainApp();
|
||||
float GetSystemFontSizeScale();
|
||||
Task OnAccountSwitchCompleteAsync();
|
||||
|
||||
@@ -20,8 +20,9 @@ namespace Bit.Core.Abstractions
|
||||
/// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-createCredential
|
||||
/// </summary>
|
||||
/// <param name="createCredentialParams">The parameters for the credential creation operation</param>
|
||||
/// <param name="extraParams">Extra parameters for the credential creation operation</param>
|
||||
/// <returns>The new credential</returns>
|
||||
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams);
|
||||
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams);
|
||||
|
||||
/// <summary>
|
||||
/// Allows WebAuthn Relying Party scripts to discover and use an existing public key credential, with the user’s consent.
|
||||
@@ -29,7 +30,8 @@ namespace Bit.Core.Abstractions
|
||||
/// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-getAssertion
|
||||
/// </summary>
|
||||
/// <param name="assertCredentialParams">The parameters for the credential assertion operation</param>
|
||||
/// <param name="extraParams">Extra parameters for the credential assertion operation</param>
|
||||
/// <returns>The asserted credential</returns>
|
||||
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams);
|
||||
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface IFido2MakeCredentialConfirmationUserInterface : IFido2MakeCredentialUserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Call this method after the user chose where to save the new Fido2 credential.
|
||||
/// </summary>
|
||||
/// <param name="cipherId">
|
||||
/// Cipher ID where to save the new credential.
|
||||
/// If <c>null</c> a new default passkey cipher item will be created
|
||||
/// </param>
|
||||
/// <param name="userVerified">
|
||||
/// Whether the user has been verified or not.
|
||||
/// If <c>null</c> verification has not taken place yet.
|
||||
/// </param>
|
||||
void Confirm(string cipherId, bool? userVerified);
|
||||
|
||||
/// <summary>
|
||||
/// Call this method after the user chose where to save the new Fido2 credential.
|
||||
/// </summary>
|
||||
/// <param name="cipherId">
|
||||
/// Cipher ID where to save the new credential.
|
||||
/// If <c>null</c> a new default passkey cipher item will be created
|
||||
/// </param>
|
||||
/// <param name="alreadyHasFido2Credential">
|
||||
/// If the cipher corresponding to the <paramref name="cipherId"/> already has a Fido2 credential.
|
||||
/// </param>
|
||||
/// <param name="userVerified">
|
||||
/// Whether the user has been verified or not.
|
||||
/// If <c>null</c> verification has not taken place yet.
|
||||
/// </param>
|
||||
Task ConfirmAsync(string cipherId, bool alreadyHasFido2Credential, bool? userVerified);
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the current flow to make a credential
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Call this if an exception needs to happen on the credential making process
|
||||
/// </summary>
|
||||
void OnConfirmationException(Exception ex);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// True if we are already confirming a new credential.
|
||||
/// </summary>
|
||||
bool IsConfirmingNewCredential { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Call this after the vault was unlocked so that Fido2 credential creation can proceed.
|
||||
/// </summary>
|
||||
void ConfirmVaultUnlocked();
|
||||
|
||||
/// <summary>
|
||||
/// True if we are waiting for the vault to be unlocked.
|
||||
/// </summary>
|
||||
bool IsWaitingUnlockVault { get; }
|
||||
|
||||
Fido2UserVerificationOptions? GetCurrentUserVerificationOptions();
|
||||
|
||||
void SetCheckHasVaultBeenUnlockedInThisTransaction(Func<bool> checkHasVaultBeenUnlockedInThisTransaction);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface IFido2MediatorService
|
||||
{
|
||||
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams);
|
||||
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams);
|
||||
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams);
|
||||
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams);
|
||||
|
||||
Task<Fido2AuthenticatorMakeCredentialResult> MakeCredentialAsync(Fido2AuthenticatorMakeCredentialParams makeCredentialParams, IFido2MakeCredentialUserInterface userInterface);
|
||||
Task<Fido2AuthenticatorGetAssertionResult> GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface);
|
||||
|
||||
@@ -187,6 +187,8 @@ namespace Bit.Core.Abstractions
|
||||
Task<BwRegion?> GetPreAuthRegionAsync();
|
||||
Task SetPreAuthRegionAsync(BwRegion value);
|
||||
Task ReloadStateAsync();
|
||||
Task<bool> GetShouldCheckOrganizationUnassignedItemsAsync(string userId = null);
|
||||
Task SetShouldCheckOrganizationUnassignedItemsAsync(bool shouldCheck, string userId = null);
|
||||
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
Task<string> GetPinProtectedAsync(string userId = null);
|
||||
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
|
||||
@@ -14,6 +14,7 @@ using Bit.Core.Models.Response;
|
||||
using Bit.Core.Pages;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
namespace Bit.App
|
||||
@@ -37,6 +38,9 @@ namespace Bit.App
|
||||
private readonly IPushNotificationService _pushNotificationService;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly ILogger _logger;
|
||||
#if ANDROID
|
||||
private LazyResolve<IFido2MakeCredentialConfirmationUserInterface> _fido2MakeCredentialConfirmationUserInterface = new LazyResolve<IFido2MakeCredentialConfirmationUserInterface>();
|
||||
#endif
|
||||
|
||||
private static bool _isResumed;
|
||||
// these variables are static because the app is launching new activities on notification click, creating new instances of App.
|
||||
@@ -104,7 +108,10 @@ namespace Bit.App
|
||||
Options.MyVaultTile = appOptions.MyVaultTile;
|
||||
Options.GeneratorTile = appOptions.GeneratorTile;
|
||||
Options.FromAutofillFramework = appOptions.FromAutofillFramework;
|
||||
Options.FromFido2Framework = appOptions.FromFido2Framework;
|
||||
Options.Fido2CredentialAction = appOptions.Fido2CredentialAction;
|
||||
Options.CreateSend = appOptions.CreateSend;
|
||||
Options.HasUnlockedInThisTransaction = appOptions.HasUnlockedInThisTransaction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +127,15 @@ namespace Bit.App
|
||||
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
|
||||
}
|
||||
|
||||
//When executing from CredentialProviderSelectionActivity we don't have "Options" so we need to filter "manually"
|
||||
//In the CredentialProviderSelectionActivity we don't need to show any Page, so we just create a "dummy" Window with a NavigationPage to avoid crashing.
|
||||
if (activationState != null
|
||||
&& activationState.State.ContainsKey("CREDENTIAL_DATA")
|
||||
&& activationState.State.ContainsKey("credentialProviderCipherId"))
|
||||
{
|
||||
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
|
||||
}
|
||||
|
||||
_isResumed = true;
|
||||
return new ResumeWindow(new NavigationPage(new AndroidNavigationRedirectPage(Options)));
|
||||
}
|
||||
@@ -182,7 +198,6 @@ namespace Bit.App
|
||||
{
|
||||
var details = message.Data as DialogDetails;
|
||||
ArgumentNullException.ThrowIfNull(details);
|
||||
ArgumentNullException.ThrowIfNull(MainPage);
|
||||
|
||||
var confirmed = true;
|
||||
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
|
||||
@@ -192,12 +207,14 @@ namespace Bit.App
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(details.CancelText))
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(MainPage);
|
||||
|
||||
confirmed = await MainPage.DisplayAlert(details.Title, details.Text, confirmText,
|
||||
details.CancelText);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MainPage.DisplayAlert(details.Title, details.Text, confirmText);
|
||||
await _deviceActionService.DisplayAlertAsync(details.Title, details.Text, confirmText);
|
||||
}
|
||||
_messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed));
|
||||
}
|
||||
@@ -218,17 +235,17 @@ namespace Bit.App
|
||||
await _accountsManager.NavigateOnAccountChangeAsync();
|
||||
}
|
||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE ||
|
||||
message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE ||
|
||||
message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE ||
|
||||
message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE ||
|
||||
message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
||||
message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE ||
|
||||
message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE ||
|
||||
message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE ||
|
||||
message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
||||
{
|
||||
if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
||||
{
|
||||
Options.OtpData = new OtpData((string)message.Data);
|
||||
}
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(ExecuteNavigationAction);
|
||||
await MainThread.InvokeOnMainThreadAsync(ExecuteNavigationAction);
|
||||
async Task ExecuteNavigationAction()
|
||||
{
|
||||
if (MainPage is TabsPage tabsPage)
|
||||
@@ -239,6 +256,7 @@ namespace Bit.App
|
||||
{
|
||||
await tabsPage.Navigation.PopModalAsync(false);
|
||||
}
|
||||
|
||||
if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE)
|
||||
{
|
||||
MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
||||
@@ -266,6 +284,19 @@ namespace Bit.App
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (message.Command == Constants.CredentialNavigateToAutofillCipherMessageCommand && message.Data is Fido2ConfirmNewCredentialParams createParams)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(MainPage);
|
||||
ArgumentNullException.ThrowIfNull(Options);
|
||||
await MainThread.InvokeOnMainThreadAsync(NavigateToCipherSelectionPageAction);
|
||||
void NavigateToCipherSelectionPageAction()
|
||||
{
|
||||
Options.Uri = createParams.RpId;
|
||||
Options.SaveUsername = createParams.UserName;
|
||||
Options.SaveName = createParams.CredentialName;
|
||||
MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
||||
}
|
||||
}
|
||||
else if (message.Command == "convertAccountToKeyConnector")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(MainPage);
|
||||
@@ -304,12 +335,26 @@ namespace Bit.App
|
||||
|| message.Command == "unlocked"
|
||||
|| message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED)
|
||||
{
|
||||
#if ANDROID
|
||||
if (message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED && _fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
_fido2MakeCredentialConfirmationUserInterface.Value.OnConfirmationException(new AccountSwitchedException());
|
||||
}
|
||||
#endif
|
||||
|
||||
lock (_processingLoginRequestLock)
|
||||
{
|
||||
// lock doesn't allow for async execution
|
||||
CheckPasswordlessLoginRequestsAsync().Wait();
|
||||
}
|
||||
}
|
||||
else if (message.Command == Constants.NavigateToMessageCommand && message.Data is NavigationTarget navigationTarget)
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
Navigate(navigationTarget, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -680,6 +725,15 @@ namespace Bit.App
|
||||
// If we are in background we add the Navigation Actions to a queue to execute when the app resumes.
|
||||
// Links: https://github.com/dotnet/maui/issues/11501 and https://bitwarden.atlassian.net/wiki/spaces/NMME/pages/664862722/MainPage+Assignments+not+working+on+Android+on+Background+or+App+resume
|
||||
#if ANDROID
|
||||
if (_fido2MakeCredentialConfirmationUserInterface != null && _fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
// if it's creating passkey
|
||||
// and we have an active pending TaskCompletionSource
|
||||
// then we let the Fido2 Authenticator flow manage the navigation to avoid issues
|
||||
// like duplicated navigation to lock page.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isResumed)
|
||||
{
|
||||
_onResumeActions.Enqueue(() => NavigateImpl(navTarget, navParams));
|
||||
|
||||
@@ -46,8 +46,11 @@ namespace Bit.Core
|
||||
public const string PreLoginEmailKey = "preLoginEmailKey";
|
||||
public const string ConfigsKey = "configsKey";
|
||||
public const string DisplayEuEnvironmentFlag = "display-eu-environment";
|
||||
public const string UnassignedItemsBannerFlag = "unassigned-items-banner";
|
||||
public const string RegionEnvironment = "regionEnvironment";
|
||||
public const string DuoCallback = "bitwarden://duo-callback";
|
||||
public const string NavigateToMessageCommand = "navigateTo";
|
||||
public const string CredentialNavigateToAutofillCipherMessageCommand = "credentialNavigateToAutofillCipher";
|
||||
|
||||
/// <summary>
|
||||
/// This key is used to store the value of "ShouldConnectToWatch" of the last user that had logged in
|
||||
@@ -136,6 +139,7 @@ namespace Bit.Core
|
||||
public static string ShouldConnectToWatchKey(string userId) => $"shouldConnectToWatch_{userId}";
|
||||
public static string ScreenCaptureAllowedKey(string userId) => $"screenCaptureAllowed_{userId}";
|
||||
public static string PendingAdminAuthRequest(string userId) => $"pendingAdminAuthRequest_{userId}";
|
||||
public static string ShouldCheckOrganizationUnassignedItemsKey(string userId) => $"shouldCheckOrganizationUnassignedItems_{userId}";
|
||||
[Obsolete]
|
||||
public static string KeyKey(string userId) => $"key_{userId}";
|
||||
[Obsolete]
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
|
||||
Text="{Binding ., Converter={StaticResource iconGlyphConverter}}"
|
||||
ShouldUpdateFontSizeDynamicallyForAccesibility="True"
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="CipherTypeIcon" />
|
||||
|
||||
22
src/Core/Controls/Settings/ExternalLinkSubtitleItemView.xaml
Normal file
22
src/Core/Controls/Settings/ExternalLinkSubtitleItemView.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<controls:BaseSettingItemView
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:core="clr-namespace:Bit.Core"
|
||||
x:Class="Bit.App.Controls.ExternalLinkSubtitleItemView"
|
||||
x:Name="_contentView"
|
||||
ControlTemplate="{StaticResource SettingControlTemplate}">
|
||||
<controls:BaseSettingItemView.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="ContentView_Tapped" />
|
||||
</controls:BaseSettingItemView.GestureRecognizers>
|
||||
|
||||
<controls:IconLabel
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ExternalLink}}"
|
||||
TextColor="{DynamicResource TextColor}"
|
||||
FontSize="25"
|
||||
Margin="6,0,7,0"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="Center"
|
||||
SemanticProperties.Description="{Binding Title, Mode=OneWay, Source={x:Reference _contentView}}" />
|
||||
</controls:BaseSettingItemView>
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public partial class ExternalLinkSubtitleItemView : BaseSettingItemView
|
||||
{
|
||||
public static readonly BindableProperty GoToLinkCommandProperty = BindableProperty.Create(
|
||||
nameof(GoToLinkCommand), typeof(ICommand), typeof(ExternalLinkSubtitleItemView));
|
||||
|
||||
public ExternalLinkSubtitleItemView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ICommand GoToLinkCommand
|
||||
{
|
||||
get => GetValue(GoToLinkCommandProperty) as ICommand;
|
||||
set => SetValue(GoToLinkCommandProperty, value);
|
||||
}
|
||||
|
||||
void ContentView_Tapped(System.Object sender, System.EventArgs e)
|
||||
{
|
||||
GoToLinkCommand?.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,11 +82,9 @@
|
||||
<Folder Include="Controls\Avatar\" />
|
||||
<Folder Include="Services\UserVerification\" />
|
||||
<Folder Include="Utilities\WebAuthenticatorMAUI\" />
|
||||
<Folder Include="Resources\Images\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MauiImage Include="Resources\Images\dotnet_bot.svg">
|
||||
<BaseSize>168,208</BaseSize>
|
||||
</MauiImage>
|
||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<MauiFont Include="Resources\Fonts\*" />
|
||||
</ItemGroup>
|
||||
@@ -95,6 +93,9 @@
|
||||
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Controls\Settings\ExternalLinkSubtitleItemView.xaml.cs">
|
||||
<DependentUpon>ExternalLinkSubtitleItemView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Pages\AndroidNavigationRedirectPage.xaml.cs">
|
||||
<DependentUpon>AndroidNavigationRedirectPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -105,6 +106,9 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MauiXaml Update="Controls\Settings\ExternalLinkSubtitleItemView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="Pages\AndroidNavigationRedirectPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
@@ -115,5 +119,12 @@
|
||||
<None Remove="Controls\Avatar\" />
|
||||
<None Remove="Services\UserVerification\" />
|
||||
<None Remove="Utilities\WebAuthenticatorMAUI\" />
|
||||
<None Remove="Resources\Images\" />
|
||||
<None Remove="Resources\Images\empty_items_state_dark.svg" />
|
||||
<None Remove="Resources\Images\empty_items_state.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||
<MauiImage Include="Resources\Images\empty_items_state.svg" />
|
||||
<MauiImage Include="Resources\Images\empty_items_state_dark.svg" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
10
src/Core/Exceptions/ValidationException.cs
Normal file
10
src/Core/Exceptions/ValidationException.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Bit.Core.Exceptions
|
||||
{
|
||||
public class ValidationException : Exception
|
||||
{
|
||||
public ValidationException(string localizedMessage)
|
||||
: base(localizedMessage)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.App.Models
|
||||
@@ -9,6 +8,8 @@ namespace Bit.App.Models
|
||||
public bool MyVaultTile { get; set; }
|
||||
public bool GeneratorTile { get; set; }
|
||||
public bool FromAutofillFramework { get; set; }
|
||||
public bool FromFido2Framework { get; set; }
|
||||
public string Fido2CredentialAction { get; set; }
|
||||
public CipherType? FillType { get; set; }
|
||||
public string Uri { get; set; }
|
||||
public CipherType? SaveType { get; set; }
|
||||
@@ -25,6 +26,8 @@ namespace Bit.App.Models
|
||||
public bool CopyInsteadOfShareAfterSaving { get; set; }
|
||||
public bool HideAccountSwitcher { get; set; }
|
||||
public OtpData? OtpData { get; set; }
|
||||
public bool HasUnlockedInThisTransaction { get; set; }
|
||||
public bool HasJustLoggedInOrUnlocked { get; set; }
|
||||
|
||||
public void SetAllFrom(AppOptions o)
|
||||
{
|
||||
@@ -35,6 +38,7 @@ namespace Bit.App.Models
|
||||
MyVaultTile = o.MyVaultTile;
|
||||
GeneratorTile = o.GeneratorTile;
|
||||
FromAutofillFramework = o.FromAutofillFramework;
|
||||
Fido2CredentialAction = o.Fido2CredentialAction;
|
||||
FillType = o.FillType;
|
||||
Uri = o.Uri;
|
||||
SaveType = o.SaveType;
|
||||
@@ -51,6 +55,7 @@ namespace Bit.App.Models
|
||||
CopyInsteadOfShareAfterSaving = o.CopyInsteadOfShareAfterSaving;
|
||||
HideAccountSwitcher = o.HideAccountSwitcher;
|
||||
OtpData = o.OtpData;
|
||||
HasUnlockedInThisTransaction = o.HasUnlockedInThisTransaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Models.View
|
||||
{
|
||||
@@ -49,7 +51,7 @@ namespace Bit.Core.Models.View
|
||||
public DateTime? DeletedDate { get; set; }
|
||||
public CipherRepromptType Reprompt { get; set; }
|
||||
public CipherKey Key { get; set; }
|
||||
|
||||
|
||||
public ItemView Item
|
||||
{
|
||||
get
|
||||
@@ -119,5 +121,14 @@ namespace Bit.Core.Models.View
|
||||
public bool IsClonable => OrganizationId is null;
|
||||
|
||||
public bool HasFido2Credential => Type == CipherType.Login && Login?.HasFido2Credentials == true;
|
||||
|
||||
public string GetMainFido2CredentialUsername()
|
||||
{
|
||||
return Login?.MainFido2Credential?.UserName
|
||||
.FallbackOnNullOrWhiteSpace(Login?.MainFido2Credential?.UserDisplayName)
|
||||
.FallbackOnNullOrWhiteSpace(Login?.Username)
|
||||
.FallbackOnNullOrWhiteSpace(Name)
|
||||
.FallbackOnNullOrWhiteSpace(AppResources.UnknownAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Models.View
|
||||
{
|
||||
@@ -39,15 +37,4 @@ namespace Bit.Core.Models.View
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoginViewExtensions
|
||||
{
|
||||
public static string GetMainFido2CredentialUsername(this LoginView loginView)
|
||||
{
|
||||
return loginView.MainFido2Credential.UserName
|
||||
.FallbackOnNullOrWhiteSpace(loginView.MainFido2Credential.UserDisplayName)
|
||||
.FallbackOnNullOrWhiteSpace(loginView.Username)
|
||||
.FallbackOnNullOrWhiteSpace(AppResources.UnknownAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
<ScrollView>
|
||||
<StackLayout Spacing="20">
|
||||
<StackLayout StyleClass="box">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
<Label Text="MAUI APP"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
<Label Text="{u:I18n SelfHostedEnvironment, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace Bit.App.Pages
|
||||
var tasks = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(50);
|
||||
MainThread.BeginInvokeOnMainThread(async () => await _vm.SubmitAsync());
|
||||
_vm.SubmitCommand.Execute(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -233,6 +233,10 @@ namespace Bit.App.Pages
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Resources.Localization;
|
||||
@@ -73,7 +74,10 @@ namespace Bit.App.Pages
|
||||
|
||||
PageTitle = AppResources.VerifyMasterPassword;
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
SubmitCommand = new Command(async () => await SubmitAsync());
|
||||
SubmitCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => MainThread.InvokeOnMainThreadAsync(SubmitAsync),
|
||||
onException: _logger.Exception,
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
AccountSwitchingOverlayViewModel =
|
||||
new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
|
||||
@@ -157,7 +161,7 @@ namespace Bit.App.Pages
|
||||
|
||||
public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
|
||||
|
||||
public Command SubmitCommand { get; }
|
||||
public ICommand SubmitCommand { get; }
|
||||
public Command TogglePasswordCommand { get; }
|
||||
|
||||
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
|
||||
@@ -233,8 +237,8 @@ namespace Bit.App.Pages
|
||||
}
|
||||
BiometricButtonVisible = true;
|
||||
BiometricButtonText = AppResources.UseBiometricsToUnlock;
|
||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
||||
if (Device.RuntimePlatform == Device.iOS)
|
||||
|
||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||
{
|
||||
var supportsFace = await _deviceActionService.SupportsFaceBiometricAsync();
|
||||
BiometricButtonText = supportsFace ? AppResources.UseFaceIDToUnlock :
|
||||
@@ -281,6 +285,8 @@ namespace Bit.App.Pages
|
||||
var failed = true;
|
||||
try
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(() => _deviceActionService.ShowLoadingAsync(AppResources.Loading));
|
||||
|
||||
EncString userKeyPin;
|
||||
EncString oldPinProtected;
|
||||
switch (_pinStatus)
|
||||
@@ -329,20 +335,26 @@ namespace Bit.App.Pages
|
||||
{
|
||||
Pin = string.Empty;
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
await SetUserKeyAndContinueAsync(userKey);
|
||||
await SetUserKeyAndContinueAsync(userKey, shouldHandleHideLoading: true);
|
||||
await Task.Delay(150); //Workaround Delay to avoid "duplicate" execution of SubmitAsync on Android when invoked from the ReturnCommand
|
||||
}
|
||||
}
|
||||
catch (LegacyUserException)
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(_deviceActionService.HideLoadingAsync);
|
||||
throw;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Exception(ex);
|
||||
failed = true;
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
var invalidUnlockAttempts = await AppHelpers.IncrementInvalidUnlockAttemptsAsync();
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(_deviceActionService.HideLoadingAsync);
|
||||
|
||||
if (invalidUnlockAttempts >= 5)
|
||||
{
|
||||
_messagingService.Send("logout");
|
||||
@@ -418,6 +430,7 @@ namespace Bit.App.Pages
|
||||
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
|
||||
await _cryptoService.SetMasterKeyAsync(masterKey);
|
||||
await SetUserKeyAndContinueAsync(userKey);
|
||||
await Task.Delay(150); //Workaround Delay to avoid "duplicate" execution of SubmitAsync on Android when invoked from the ReturnCommand
|
||||
|
||||
// Re-enable biometrics
|
||||
if (BiometricEnabled & !BiometricIntegrityValid)
|
||||
@@ -530,7 +543,7 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetUserKeyAndContinueAsync(UserKey key)
|
||||
private async Task SetUserKeyAndContinueAsync(UserKey key, bool shouldHandleHideLoading = false)
|
||||
{
|
||||
var hasKey = await _cryptoService.HasUserKeyAsync();
|
||||
if (!hasKey)
|
||||
@@ -538,14 +551,18 @@ namespace Bit.App.Pages
|
||||
await _cryptoService.SetUserKeyAsync(key);
|
||||
}
|
||||
await _deviceTrustCryptoService.TrustDeviceIfNeededAsync();
|
||||
await DoContinueAsync();
|
||||
await DoContinueAsync(shouldHandleHideLoading);
|
||||
}
|
||||
|
||||
private async Task DoContinueAsync()
|
||||
private async Task DoContinueAsync(bool shouldHandleHideLoading = false)
|
||||
{
|
||||
_syncService.FullSyncAsync(false).FireAndForget();
|
||||
await _stateService.SetBiometricLockedAsync(false);
|
||||
_watchDeviceService.SyncDataToWatchAsync().FireAndForget();
|
||||
if (shouldHandleHideLoading)
|
||||
{
|
||||
await MainThread.InvokeOnMainThreadAsync(_deviceActionService.HideLoadingAsync);
|
||||
}
|
||||
_messagingService.Send("unlocked");
|
||||
UnlockedAction?.Invoke();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Bit.App.Pages
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>();
|
||||
_vm = BindingContext as LoginPageViewModel;
|
||||
_vm.Page = this;
|
||||
_vm.FromIosExtension = _appOptions?.IosExtension ?? false;
|
||||
_vm.StartTwoFactorAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync());
|
||||
_vm.LogInSuccessAction = () => MainThread.BeginInvokeOnMainThread(async () => await LogInSuccessAsync());
|
||||
_vm.LogInWithDeviceAction = () => StartLoginWithDeviceAsync().FireAndForget();
|
||||
@@ -195,6 +196,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Bit.App.Pages
|
||||
_vm.Email = email;
|
||||
_vm.AuthRequestType = authRequestType;
|
||||
_vm.AuthingWithSso = authingWithSso;
|
||||
_vm.FromIosExtension = _appOptions?.IosExtension ?? false;
|
||||
_vm.StartTwoFactorAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync());
|
||||
_vm.LogInSuccessAction = () => MainThread.BeginInvokeOnMainThread(async () => await LogInSuccessAsync());
|
||||
_vm.UpdateTempPasswordAction = () => MainThread.BeginInvokeOnMainThread(async () => await UpdateTempPasswordAsync());
|
||||
@@ -55,6 +56,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Bit.App.Pages
|
||||
|
||||
private async Task StartDeviceApprovalOptionsAsync()
|
||||
{
|
||||
var page = new LoginApproveDevicePage();
|
||||
var page = new LoginApproveDevicePage(_appOptions);
|
||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Bit.App.Pages
|
||||
using Bit.App.Models;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public partial class RegisterPage : BaseContentPage
|
||||
{
|
||||
@@ -6,11 +8,12 @@
|
||||
|
||||
private bool _inputFocused;
|
||||
|
||||
public RegisterPage(HomePage homePage)
|
||||
public RegisterPage(HomePage homePage, AppOptions appOptions = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
_vm = BindingContext as RegisterPageViewModel;
|
||||
_vm.Page = this;
|
||||
_vm.FromIosExtension = appOptions?.IosExtension ?? false;
|
||||
_vm.RegistrationSuccess = () => MainThread.BeginInvokeOnMainThread(async () => await RegistrationSuccessAsync(homePage));
|
||||
_vm.CloseAction = async () =>
|
||||
{
|
||||
|
||||
@@ -71,6 +71,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Bit.App.Pages
|
||||
_vm = BindingContext as TwoFactorPageViewModel;
|
||||
_vm.Page = this;
|
||||
_vm.AuthingWithSso = authingWithSso ?? false;
|
||||
_vm.FromIosExtension = _appOptions?.IosExtension ?? false;
|
||||
_vm.StartSetPasswordAction = () =>
|
||||
MainThread.BeginInvokeOnMainThread(async () => await StartSetPasswordAsync());
|
||||
_vm.TwoFactorAuthSuccessAction = () =>
|
||||
@@ -191,7 +192,7 @@ namespace Bit.App.Pages
|
||||
|
||||
private async Task StartDeviceApprovalOptionsAsync()
|
||||
{
|
||||
var page = new LoginApproveDevicePage();
|
||||
var page = new LoginApproveDevicePage(_appOptions);
|
||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||
}
|
||||
|
||||
@@ -206,6 +207,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.HasJustLoggedInOrUnlocked = true;
|
||||
}
|
||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,13 @@ using Bit.Core.Models.Request;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Bit.Core.Services;
|
||||
|
||||
#if IOS
|
||||
using WebAuthenticator = Bit.Core.Utilities.MAUI.WebAuthenticator;
|
||||
using WebAuthenticatorResult = Bit.Core.Utilities.MAUI.WebAuthenticatorResult;
|
||||
using WebAuthenticatorOptions = Bit.Core.Utilities.MAUI.WebAuthenticatorOptions;
|
||||
#endif
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
@@ -136,6 +143,7 @@ namespace Bit.App.Pages
|
||||
nameof(ShowTryAgain),
|
||||
});
|
||||
}
|
||||
|
||||
public ICommand SubmitCommand { get; }
|
||||
public ICommand MoreCommand { get; }
|
||||
public ICommand AuthenticateWithDuoFramelessCommand { get; }
|
||||
@@ -261,7 +269,11 @@ namespace Bit.App.Pages
|
||||
authResult = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions
|
||||
{
|
||||
Url = new Uri(url),
|
||||
CallbackUrl = new Uri(Constants.DuoCallback)
|
||||
CallbackUrl = new Uri(Constants.DuoCallback),
|
||||
#if IOS
|
||||
ShouldUseSharedApplicationKeyWindow = FromIosExtension
|
||||
#endif
|
||||
|
||||
});
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
@@ -348,6 +360,9 @@ namespace Bit.App.Pages
|
||||
Url = new Uri(url),
|
||||
CallbackUrl = new Uri(callbackUri),
|
||||
PrefersEphemeralWebBrowserSession = true,
|
||||
#if IOS
|
||||
ShouldUseSharedApplicationKeyWindow = FromIosExtension
|
||||
#endif
|
||||
};
|
||||
authResult = await WebAuthenticator.AuthenticateAsync(options);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Microsoft.Maui.Authentication;
|
||||
|
||||
#if IOS
|
||||
using WebAuthenticator = Bit.Core.Utilities.MAUI.WebAuthenticator;
|
||||
using WebAuthenticatorResult = Bit.Core.Utilities.MAUI.WebAuthenticatorResult;
|
||||
using WebAuthenticatorOptions = Bit.Core.Utilities.MAUI.WebAuthenticatorOptions;
|
||||
#endif
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public abstract class CaptchaProtectedViewModel : BaseViewModel
|
||||
@@ -16,6 +22,8 @@ namespace Bit.App.Pages
|
||||
protected abstract IPlatformUtilsService platformUtilsService { get; }
|
||||
protected string _captchaToken = null;
|
||||
|
||||
public bool FromIosExtension { get; set; }
|
||||
|
||||
protected async Task<bool> HandleCaptchaAsync(string captchaSiteKey, bool needsCaptcha, Func<Task> onSuccess)
|
||||
{
|
||||
if (!needsCaptcha)
|
||||
@@ -61,6 +69,9 @@ namespace Bit.App.Pages
|
||||
Url = new Uri(url),
|
||||
CallbackUrl = new Uri(callbackUri),
|
||||
PrefersEphemeralWebBrowserSession = false,
|
||||
#if IOS
|
||||
ShouldUseSharedApplicationKeyWindow = FromIosExtension
|
||||
#endif
|
||||
};
|
||||
authResult = await WebAuthenticator.AuthenticateAsync(options);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,7 @@ namespace Bit.App.Pages
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: REMOVE WHEN MERGED INTO MAIN BRANCH
|
||||
var appInfo = string.Format("MAUI {0}: {1} ({2})",
|
||||
var appInfo = string.Format("{0}: {1} ({2})",
|
||||
AppResources.Version,
|
||||
_platformUtilsService.GetApplicationVersion(),
|
||||
_deviceActionService.GetBuildNumber());
|
||||
|
||||
@@ -19,15 +19,6 @@
|
||||
Text="{u:I18n Autofill}"
|
||||
StyleClass="settings-header" />
|
||||
|
||||
<controls:SwitchItemView
|
||||
Title="{u:I18n CredentialProviderService}"
|
||||
Subtitle="{u:I18n CredentialProviderServiceExplanationLong}"
|
||||
IsVisible="{Binding SupportsCredentialProviderService}"
|
||||
IsToggled="{Binding UseCredentialProviderService}"
|
||||
AutomationId="CredentialProviderServiceSwitch"
|
||||
StyleClass="settings-item-view"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
|
||||
<controls:SwitchItemView
|
||||
Title="{u:I18n AutofillServices}"
|
||||
Subtitle="{u:I18n AutofillServicesExplanationLong}"
|
||||
@@ -47,6 +38,15 @@
|
||||
StyleClass="settings-item-view"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
|
||||
<controls:ExternalLinkSubtitleItemView
|
||||
Title="{u:I18n PasskeyManagement}"
|
||||
Subtitle="{u:I18n PasskeyManagementExplanationLong}"
|
||||
IsVisible="{Binding SupportsCredentialProviderService}"
|
||||
GoToLinkCommand="{Binding GoToCredentialProviderSettingsCommand}"
|
||||
AutomationId="CredentialProviderServiceSwitch"
|
||||
StyleClass="settings-item-view"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
|
||||
<controls:SwitchItemView
|
||||
Title="{u:I18n Accessibility}"
|
||||
Subtitle="{Binding UseAccessibilityDescription}"
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace Bit.App.Pages
|
||||
{
|
||||
public partial class AutofillSettingsPageViewModel
|
||||
{
|
||||
private bool _useCredentialProviderService;
|
||||
private bool _useAutofillServices;
|
||||
private bool _useInlineAutofill;
|
||||
private bool _useAccessibility;
|
||||
@@ -15,18 +14,6 @@ namespace Bit.App.Pages
|
||||
|
||||
public bool SupportsCredentialProviderService => DeviceInfo.Platform == DevicePlatform.Android && _deviceActionService.SupportsCredentialProviderService();
|
||||
|
||||
public bool UseCredentialProviderService
|
||||
{
|
||||
get => _useCredentialProviderService;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _useCredentialProviderService, value))
|
||||
{
|
||||
((ICommand)ToggleUseCredentialProviderServiceCommand).Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool SupportsAndroidAutofillServices => DeviceInfo.Platform == DevicePlatform.Android && _deviceActionService.SupportsAutofillServices();
|
||||
|
||||
public bool UseAutofillServices
|
||||
@@ -99,23 +86,23 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncRelayCommand ToggleUseCredentialProviderServiceCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseAutofillServicesCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseInlineAutofillCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseAccessibilityCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseDrawOverCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleAskToAddLoginCommand { get; private set; }
|
||||
public ICommand GoToBlockAutofillUrisCommand { get; private set; }
|
||||
public ICommand GoToCredentialProviderSettingsCommand { get; private set; }
|
||||
|
||||
private void InitAndroidCommands()
|
||||
{
|
||||
ToggleUseCredentialProviderServiceCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseCredentialProviderService()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseAutofillServicesCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseAutofillServices()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseInlineAutofillCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseInlineAutofillEnabledAsync()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseAccessibilityCommand = CreateDefaultAsyncRelayCommand(ToggleUseAccessibilityAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseDrawOverCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleDrawOver()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleAskToAddLoginCommand = CreateDefaultAsyncRelayCommand(ToggleAskToAddLoginAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
GoToBlockAutofillUrisCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()), allowsMultipleExecutions: false);
|
||||
GoToCredentialProviderSettingsCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => GoToCredentialProviderSettings()), () => _inited, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
private async Task InitAndroidAutofillSettingsAsync()
|
||||
@@ -132,9 +119,6 @@ namespace Bit.App.Pages
|
||||
|
||||
private async Task UpdateAndroidAutofillSettingsAsync()
|
||||
{
|
||||
// TODO - uncomment once _autofillHandler.CredentialProviderServiceEnabled() returns a real value
|
||||
// _useCredentialProviderService =
|
||||
// SupportsCredentialProviderService && _autofillHandler.CredentialProviderServiceEnabled();
|
||||
_useAutofillServices =
|
||||
_autofillHandler.SupportsAutofillService() && _autofillHandler.AutofillServiceEnabled();
|
||||
_useAccessibility = _autofillHandler.AutofillAccessibilityServiceRunning();
|
||||
@@ -143,7 +127,6 @@ namespace Bit.App.Pages
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
TriggerPropertyChanged(nameof(UseCredentialProviderService));
|
||||
TriggerPropertyChanged(nameof(UseAutofillServices));
|
||||
TriggerPropertyChanged(nameof(UseAccessibility));
|
||||
TriggerPropertyChanged(nameof(UseDrawOver));
|
||||
@@ -151,16 +134,15 @@ namespace Bit.App.Pages
|
||||
});
|
||||
}
|
||||
|
||||
private void ToggleUseCredentialProviderService()
|
||||
private async Task GoToCredentialProviderSettings()
|
||||
{
|
||||
if (UseCredentialProviderService)
|
||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.SetBitwardenAsPasskeyManagerDescription, AppResources.ContinueToDeviceSettings,
|
||||
AppResources.Continue,
|
||||
AppResources.Cancel);
|
||||
if (confirmed)
|
||||
{
|
||||
_deviceActionService.OpenCredentialProviderSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
_autofillHandler.DisableCredentialProviderService();
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleUseAutofillServices()
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Bit.App.Pages
|
||||
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
||||
_stateService = ServiceContainer.Resolve<IStateService>();
|
||||
|
||||
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
|
||||
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage, appOptions: appOptions))
|
||||
{
|
||||
Title = AppResources.MyVault,
|
||||
IconImageSource = "lock.png"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.View;
|
||||
@@ -12,6 +13,8 @@ namespace Bit.App.Pages
|
||||
public class AutofillCiphersPageViewModel : CipherSelectionPageViewModel
|
||||
{
|
||||
private CipherType? _fillType;
|
||||
private AppOptions _appOptions;
|
||||
private readonly LazyResolve<IFido2MakeCredentialConfirmationUserInterface> _fido2MakeCredentialConfirmationUserInterface = new LazyResolve<IFido2MakeCredentialConfirmationUserInterface>();
|
||||
|
||||
public string Uri { get; set; }
|
||||
|
||||
@@ -19,6 +22,7 @@ namespace Bit.App.Pages
|
||||
{
|
||||
Uri = appOptions?.Uri;
|
||||
_fillType = appOptions.FillType;
|
||||
_appOptions = appOptions;
|
||||
|
||||
string name = null;
|
||||
if (Uri?.StartsWith(Constants.AndroidAppProtocol) ?? false)
|
||||
@@ -36,6 +40,7 @@ namespace Bit.App.Pages
|
||||
Name = name;
|
||||
PageTitle = string.Format(AppResources.ItemsForUri, Name ?? "--");
|
||||
NoDataText = string.Format(AppResources.NoItemsForUri, Name ?? "--");
|
||||
AddNewItemText = _fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential ? AppResources.SavePasskeyAsNewLogin : AppResources.AddAnItem;
|
||||
}
|
||||
|
||||
protected override async Task<List<GroupingsPageListGroup>> LoadGroupedItemsAsync()
|
||||
@@ -43,7 +48,11 @@ namespace Bit.App.Pages
|
||||
var groupedItems = new List<GroupingsPageListGroup>();
|
||||
var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(Uri, null);
|
||||
|
||||
var matching = ciphers.Item1?.Select(c => new CipherItemViewModel(c, WebsiteIconsEnabled)).ToList();
|
||||
var matching = ciphers.Item1?.Select(c => new CipherItemViewModel(c, WebsiteIconsEnabled)
|
||||
{
|
||||
UsePasskeyIconAsPlaceholderFallback = _fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential
|
||||
}).ToList();
|
||||
|
||||
var hasMatching = matching?.Any() ?? false;
|
||||
if (matching?.Any() ?? false)
|
||||
{
|
||||
@@ -78,6 +87,12 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
|
||||
if (_fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
await _fido2MakeCredentialConfirmationUserInterface.Value.ConfirmAsync(cipher.Id, cipher.Login.HasFido2Credentials, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await _passwordRepromptService.PromptAndCheckPasswordIfNeededAsync(cipher.Reprompt))
|
||||
{
|
||||
return;
|
||||
@@ -130,8 +145,30 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task AddFabCipherAsync()
|
||||
{
|
||||
//Scenario for creating a new Fido2 credential on Android but showing the Cipher Page
|
||||
if (_fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
var pageForOther = new CipherAddEditPage(null, CipherType.Login, appOptions: _appOptions);
|
||||
await Page.Navigation.PushModalAsync(new NavigationPage(pageForOther));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await AddCipherAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task AddCipherAsync()
|
||||
{
|
||||
//Scenario for creating a new Fido2 credential on Android
|
||||
if (_fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
_fido2MakeCredentialConfirmationUserInterface.Value.Confirm(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_fillType.HasValue && _fillType != CipherType.Login)
|
||||
{
|
||||
var pageForOther = new CipherAddEditPage(type: _fillType, fromAutofill: true);
|
||||
@@ -143,5 +180,13 @@ namespace Bit.App.Pages
|
||||
fromAutofill: true);
|
||||
await Page.Navigation.PushModalAsync(new NavigationPage(pageForLogin));
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (_fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
_fido2MakeCredentialConfirmationUserInterface.Value.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding EditMode, Converter={StaticResource inverseBool}}">
|
||||
IsVisible="{Binding TypeEditMode, Converter={StaticResource inverseBool}}">
|
||||
<Label
|
||||
Text="{u:I18n Type}"
|
||||
StyleClass="box-label" />
|
||||
@@ -649,9 +649,11 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
SemanticProperties.Description="{u:I18n URI}"
|
||||
IsEnabled="{Binding BindingContext.IsFromFido2Framework, Source={x:Reference _page}, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="LoginUriEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
IsVisible="{Binding BindingContext.IsFromFido2Framework, Source={x:Reference _page}, Converter={StaticResource inverseBool}}"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
|
||||
Command="{Binding BindingContext.UriOptionsCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
@@ -665,6 +667,7 @@
|
||||
</BindableLayout.ItemTemplate>
|
||||
</StackLayout>
|
||||
<Button Text="{u:I18n NewUri}" StyleClass="box-button-row"
|
||||
IsVisible="{Binding IsFromFido2Framework, Converter={StaticResource inverseBool}}"
|
||||
Clicked="NewUri_Clicked"
|
||||
AutomationId="LoginAddNewUriButton"></Button>
|
||||
</StackLayout>
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Bit.App.Pages
|
||||
private readonly IAutofillHandler _autofillHandler;
|
||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
||||
private readonly IUserVerificationService _userVerificationService;
|
||||
#if ANDROID
|
||||
private readonly LazyResolve<IFido2MakeCredentialConfirmationUserInterface> _fido2MakeCredentialConfirmationUserInterface = new LazyResolve<IFido2MakeCredentialConfirmationUserInterface>();
|
||||
#endif
|
||||
|
||||
private CipherAddEditPageViewModel _vm;
|
||||
private bool _fromAutofill;
|
||||
@@ -45,6 +48,9 @@ namespace Bit.App.Pages
|
||||
_appOptions = appOptions;
|
||||
_fromAutofill = fromAutofill;
|
||||
FromAutofillFramework = _appOptions?.FromAutofillFramework ?? false;
|
||||
#if ANDROID
|
||||
FromAndroidFido2Framework = _fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential;
|
||||
#endif
|
||||
InitializeComponent();
|
||||
_vm = BindingContext as CipherAddEditPageViewModel;
|
||||
_vm.Page = this;
|
||||
@@ -144,6 +150,7 @@ namespace Bit.App.Pages
|
||||
}
|
||||
|
||||
public bool FromAutofillFramework { get; set; }
|
||||
public bool FromAndroidFido2Framework { get; set; }
|
||||
public CipherAddEditPageViewModel ViewModel => _vm;
|
||||
|
||||
protected override async void OnAppearing()
|
||||
|
||||
@@ -17,6 +17,8 @@ using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
using Bit.Core.Services;
|
||||
|
||||
#nullable enable
|
||||
|
||||
@@ -37,7 +39,9 @@ namespace Bit.App.Pages
|
||||
private readonly IAutofillHandler _autofillHandler;
|
||||
private readonly IWatchDeviceService _watchDeviceService;
|
||||
private readonly IAccountsManager _accountsManager;
|
||||
|
||||
private readonly IFido2MakeCredentialConfirmationUserInterface _fido2MakeCredentialConfirmationUserInterface;
|
||||
private readonly IUserVerificationMediatorService _userVerificationMediatorService;
|
||||
|
||||
private bool _showNotesSeparator;
|
||||
private bool _showPassword;
|
||||
private bool _showCardNumber;
|
||||
@@ -92,6 +96,11 @@ namespace Bit.App.Pages
|
||||
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
|
||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||
_accountsManager = ServiceContainer.Resolve<IAccountsManager>();
|
||||
if (ServiceContainer.TryResolve<IFido2MakeCredentialConfirmationUserInterface>(out var fido2MakeService))
|
||||
{
|
||||
_fido2MakeCredentialConfirmationUserInterface = fido2MakeService;
|
||||
}
|
||||
_userVerificationMediatorService = ServiceContainer.Resolve<IUserVerificationMediatorService>();
|
||||
|
||||
GeneratePasswordCommand = new Command(GeneratePassword);
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
@@ -292,7 +301,9 @@ namespace Bit.App.Pages
|
||||
});
|
||||
}
|
||||
public bool ShowCollections => (!EditMode || CloneMode) && Cipher?.OrganizationId != null;
|
||||
public bool IsFromFido2Framework { get; set; }
|
||||
public bool EditMode => !string.IsNullOrWhiteSpace(CipherId);
|
||||
public bool TypeEditMode => !string.IsNullOrWhiteSpace(CipherId) || IsFromFido2Framework;
|
||||
public bool ShowOwnershipOptions => !EditMode || CloneMode;
|
||||
public bool OwnershipPolicyInEffect => ShowOwnershipOptions && !AllowPersonal;
|
||||
public bool CloneMode { get; set; }
|
||||
@@ -324,6 +335,7 @@ namespace Bit.App.Pages
|
||||
public async Task<bool> LoadAsync(AppOptions appOptions = null)
|
||||
{
|
||||
_fromOtp = appOptions?.OtpData != null;
|
||||
IsFromFido2Framework = _fido2MakeCredentialConfirmationUserInterface?.IsConfirmingNewCredential == true;
|
||||
|
||||
var myEmail = await _stateService.GetEmailAsync();
|
||||
OwnershipOptions.Add(new KeyValuePair<string, string>(myEmail, null));
|
||||
@@ -536,6 +548,26 @@ namespace Bit.App.Pages
|
||||
}
|
||||
try
|
||||
{
|
||||
bool isFido2UserVerified = false;
|
||||
if (IsFromFido2Framework)
|
||||
{
|
||||
// Verify the user and prevent saving cipher if enforcing is needed and it's not verified.
|
||||
var userVerification = await VerifyUserAsync();
|
||||
if (userVerification.IsCancelled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
isFido2UserVerified = userVerification.Result;
|
||||
|
||||
var options = _fido2MakeCredentialConfirmationUserInterface.GetCurrentUserVerificationOptions();
|
||||
|
||||
if (!isFido2UserVerified && await _userVerificationMediatorService.ShouldEnforceFido2RequiredUserVerificationAsync(options.Value))
|
||||
{
|
||||
await _platformUtilsService.ShowDialogAsync(AppResources.ErrorCreatingPasskey, AppResources.SavePasskey);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
|
||||
|
||||
await _cipherService.SaveWithServerAsync(cipher);
|
||||
@@ -554,6 +586,11 @@ namespace Bit.App.Pages
|
||||
// Close and go back to app
|
||||
_autofillHandler.CloseAutofill();
|
||||
}
|
||||
else if (IsFromFido2Framework)
|
||||
{
|
||||
_fido2MakeCredentialConfirmationUserInterface.Confirm(cipher.Id, isFido2UserVerified);
|
||||
return true;
|
||||
}
|
||||
else if (_fromOtp)
|
||||
{
|
||||
await _accountsManager.StartDefaultNavigationFlowAsync(op => op.OtpData = null);
|
||||
@@ -589,6 +626,27 @@ namespace Bit.App.Pages
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<CancellableResult<bool>> VerifyUserAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = _fido2MakeCredentialConfirmationUserInterface.GetCurrentUserVerificationOptions();
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
|
||||
if (options.Value.UserVerificationPreference == Fido2UserVerificationPreference.Discouraged)
|
||||
{
|
||||
return new CancellableResult<bool>(false);
|
||||
}
|
||||
|
||||
return await _userVerificationMediatorService.VerifyUserForFido2Async(options.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
return new CancellableResult<bool>(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync()
|
||||
{
|
||||
if (Microsoft.Maui.Networking.Connectivity.NetworkAccess == Microsoft.Maui.Networking.NetworkAccess.None)
|
||||
|
||||
@@ -44,5 +44,7 @@ namespace Bit.App.Pages
|
||||
/// This is useful to check when the cell is being reused.
|
||||
/// </summary>
|
||||
public bool IconImageSuccesfullyLoaded { get; set; }
|
||||
|
||||
public bool UsePasskeyIconAsPlaceholderFallback { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,12 +78,13 @@
|
||||
Spacing="20"
|
||||
IsVisible="{Binding ShowNoData}">
|
||||
<Image
|
||||
x:Name="_emptyItemsPlaceholder"
|
||||
Source="empty_items_state" />
|
||||
<Label
|
||||
Text="{Binding NoDataText}"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
<Button
|
||||
Text="{u:I18n AddAnItem}"
|
||||
Text="{Binding AddNewItemText}"
|
||||
Command="{Binding AddCipherCommand}" />
|
||||
</StackLayout>
|
||||
|
||||
@@ -133,7 +134,7 @@
|
||||
<Button
|
||||
x:Name="_fab"
|
||||
ImageSource="plus.png"
|
||||
Command="{Binding AddCipherCommand}"
|
||||
Command="{Binding AddFabCipherCommand}"
|
||||
Style="{StaticResource btn-fab}"
|
||||
IsVisible="{OnPlatform iOS=false, Android=true}"
|
||||
AbsoluteLayout.LayoutFlags="PositionProportional"
|
||||
|
||||
@@ -115,6 +115,8 @@ namespace Bit.App.Pages
|
||||
await _vm.LoadAsync();
|
||||
}
|
||||
}, _mainContent);
|
||||
|
||||
UpdatePlaceholder();
|
||||
}
|
||||
|
||||
protected override bool OnBackButtonPressed()
|
||||
@@ -127,6 +129,11 @@ namespace Bit.App.Pages
|
||||
|
||||
#if ANDROID
|
||||
_appOptions.Uri = null;
|
||||
|
||||
if (BindingContext is AutofillCiphersPageViewModel autofillVM)
|
||||
{
|
||||
autofillVM.Cancel();
|
||||
}
|
||||
#endif
|
||||
return base.OnBackButtonPressed();
|
||||
}
|
||||
@@ -175,7 +182,27 @@ namespace Bit.App.Pages
|
||||
if (DoOnce())
|
||||
{
|
||||
_accountsManager.StartDefaultNavigationFlowAsync(op => op.OtpData = null).FireAndForget();
|
||||
|
||||
if (BindingContext is AutofillCiphersPageViewModel autofillVM)
|
||||
{
|
||||
autofillVM.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task UpdateOnThemeChanged()
|
||||
{
|
||||
await base.UpdateOnThemeChanged();
|
||||
|
||||
UpdatePlaceholder();
|
||||
}
|
||||
|
||||
private void UpdatePlaceholder()
|
||||
{
|
||||
#if ANDROID
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
_emptyItemsPlaceholder.Source = ImageSource.FromFile(ThemeManager.UsingLightTheme ? "empty_items_state.png" : "empty_items_state_dark.png"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@@ -22,6 +23,7 @@ namespace Bit.App.Pages
|
||||
protected bool _showNoData;
|
||||
protected bool _showList;
|
||||
protected string _noDataText;
|
||||
protected string _addNewItemText;
|
||||
protected bool _websiteIconsEnabled;
|
||||
|
||||
public CipherSelectionPageViewModel()
|
||||
@@ -42,6 +44,9 @@ namespace Bit.App.Pages
|
||||
SelectCipherCommand = CreateDefaultAsyncRelayCommand<IGroupingsPageListItem>(SelectCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
AddFabCipherCommand = CreateDefaultAsyncRelayCommand(AddFabCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
@@ -50,6 +55,8 @@ namespace Bit.App.Pages
|
||||
{
|
||||
AllowAddAccountRow = false
|
||||
};
|
||||
|
||||
AddNewItemText = AppResources.AddAnItem;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
@@ -60,6 +67,7 @@ namespace Bit.App.Pages
|
||||
public ICommand CipherOptionsCommand { get; set; }
|
||||
public ICommand SelectCipherCommand { get; set; }
|
||||
public ICommand AddCipherCommand { get; set; }
|
||||
public ICommand AddFabCipherCommand { get; set; }
|
||||
|
||||
public bool ShowNoData
|
||||
{
|
||||
@@ -79,6 +87,12 @@ namespace Bit.App.Pages
|
||||
set => SetProperty(ref _noDataText, value);
|
||||
}
|
||||
|
||||
public string AddNewItemText
|
||||
{
|
||||
get => _addNewItemText;
|
||||
set => SetProperty(ref _addNewItemText, value);
|
||||
}
|
||||
|
||||
public bool WebsiteIconsEnabled
|
||||
{
|
||||
get => _websiteIconsEnabled;
|
||||
@@ -153,5 +167,6 @@ namespace Bit.App.Pages
|
||||
protected abstract Task SelectCipherAsync(IGroupingsPageListItem item);
|
||||
|
||||
protected abstract Task AddCipherAsync();
|
||||
protected abstract Task AddFabCipherAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Utilities.Fido2;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
@@ -21,6 +22,10 @@ namespace Bit.App.Pages
|
||||
private readonly IPasswordRepromptService _passwordRepromptService;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IPolicyService _policyService;
|
||||
#if ANDROID
|
||||
private readonly LazyResolve<IFido2MakeCredentialConfirmationUserInterface> _fido2MakeCredentialConfirmationUserInterface = new LazyResolve<IFido2MakeCredentialConfirmationUserInterface>();
|
||||
#endif
|
||||
|
||||
private CancellationTokenSource _searchCancellationTokenSource;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -46,6 +51,9 @@ namespace Bit.App.Pages
|
||||
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
AddFabCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
@@ -53,6 +61,7 @@ namespace Bit.App.Pages
|
||||
|
||||
public ICommand CipherOptionsCommand { get; }
|
||||
public ICommand AddCipherCommand { get; }
|
||||
public ICommand AddFabCipherCommand { get; }
|
||||
public ExtendedObservableCollection<CipherItemViewModel> Ciphers { get; set; }
|
||||
public Func<CipherView, bool> Filter { get; set; }
|
||||
public string AutofillUrl { get; set; }
|
||||
@@ -168,6 +177,14 @@ namespace Bit.App.Pages
|
||||
|
||||
public async Task SelectCipherAsync(CipherView cipher)
|
||||
{
|
||||
#if ANDROID
|
||||
if (_fido2MakeCredentialConfirmationUserInterface.Value.IsConfirmingNewCredential)
|
||||
{
|
||||
await _fido2MakeCredentialConfirmationUserInterface.Value.ConfirmAsync(cipher.Id, cipher.Login.HasFido2Credentials, null);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
string selection = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(AutofillUrl))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
@@ -27,7 +28,7 @@ namespace Bit.App.Pages
|
||||
|
||||
public GroupingsPage(bool mainPage, CipherType? type = null, string folderId = null,
|
||||
string collectionId = null, string pageTitle = null, string vaultFilterSelection = null,
|
||||
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false)
|
||||
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false, AppOptions appOptions = null)
|
||||
{
|
||||
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
|
||||
InitializeComponent();
|
||||
@@ -50,6 +51,7 @@ namespace Bit.App.Pages
|
||||
_vm.CollectionId = collectionId;
|
||||
_vm.Deleted = deleted;
|
||||
_vm.ShowTotp = showTotp;
|
||||
_vm.AppOptions = appOptions;
|
||||
_previousPage = previousPage;
|
||||
if (pageTitle != null)
|
||||
{
|
||||
@@ -160,6 +162,8 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
|
||||
await _vm.CheckOrganizationUnassignedItemsAsync();
|
||||
|
||||
// Push registration
|
||||
var lastPushRegistration = await _stateService.GetPushLastRegistrationDateAsync();
|
||||
lastPushRegistration = lastPushRegistration.GetValueOrDefault(DateTime.MinValue);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
@@ -45,6 +46,8 @@ namespace Bit.App.Pages
|
||||
private readonly IPasswordRepromptService _passwordRepromptService;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IPolicyService _policyService;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IEnvironmentService _environmentService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public GroupingsPageViewModel()
|
||||
@@ -61,6 +64,8 @@ namespace Bit.App.Pages
|
||||
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
||||
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
|
||||
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||
_configService = ServiceContainer.Resolve<IConfigService>();
|
||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||
|
||||
Loading = true;
|
||||
@@ -104,6 +109,7 @@ namespace Bit.App.Pages
|
||||
public List<Core.Models.View.CollectionView> Collections { get; set; }
|
||||
public List<TreeNode<Core.Models.View.CollectionView>> NestedCollections { get; set; }
|
||||
|
||||
public AppOptions AppOptions { get; internal set; }
|
||||
protected override ICipherService cipherService => _cipherService;
|
||||
protected override IPolicyService policyService => _policyService;
|
||||
protected override IOrganizationService organizationService => _organizationService;
|
||||
@@ -699,5 +705,59 @@ namespace Bit.App.Pages
|
||||
var folders = decFolders.Where(f => _allCiphers.Any(c => c.FolderId == f.Id)).ToList();
|
||||
return folders.Any() ? folders : null;
|
||||
}
|
||||
|
||||
internal async Task CheckOrganizationUnassignedItemsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AppOptions?.HasJustLoggedInOrUnlocked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppOptions.HasJustLoggedInOrUnlocked = false;
|
||||
|
||||
if (!await _configService.GetFeatureFlagBoolAsync(Core.Constants.UnassignedItemsBannerFlag)
|
||||
||
|
||||
!await _stateService.GetShouldCheckOrganizationUnassignedItemsAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var waitSyncTask = Task.Run(async () =>
|
||||
{
|
||||
while (_syncService.SyncInProgress)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
});
|
||||
await waitSyncTask.WaitAsync(TimeSpan.FromMinutes(5));
|
||||
|
||||
if (!await _cipherService.VerifyOrganizationHasUnassignedItemsAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = _environmentService.SelectedRegion == Core.Enums.Region.SelfHosted
|
||||
? AppResources.OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong
|
||||
: AppResources.OrganizationUnassignedItemsMessageUSEUDescriptionLong;
|
||||
|
||||
var response = await _deviceActionService.DisplayAlertAsync(AppResources.Notice,
|
||||
message,
|
||||
null,
|
||||
AppResources.RemindMeLater,
|
||||
AppResources.Ok);
|
||||
|
||||
if (response == AppResources.Ok)
|
||||
{
|
||||
await _stateService.SetShouldCheckOrganizationUnassignedItemsAsync(false);
|
||||
}
|
||||
}
|
||||
catch (TimeoutException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Exception(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,5 +70,10 @@ namespace Bit.App.Pages
|
||||
var pageForLogin = new CipherAddEditPage(null, CipherType.Login, name: Name, appOptions: _appOptions);
|
||||
await Page.Navigation.PushModalAsync(new NavigationPage(pageForLogin));
|
||||
}
|
||||
|
||||
protected override async Task AddFabCipherAsync()
|
||||
{
|
||||
await AddCipherAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<svg width="419" height="519" viewBox="0 0 419 519" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M284.432 247.568L284.004 221.881C316.359 221.335 340.356 211.735 355.308 193.336C382.408 159.996 372.893 108.183 372.786 107.659L398.013 102.831C398.505 105.432 409.797 167.017 375.237 209.53C355.276 234.093 324.719 246.894 284.432 247.568Z" fill="#8A6FE8"/>
|
||||
<path d="M331.954 109.36L361.826 134.245C367.145 138.676 375.055 137.959 379.497 132.639C383.928 127.32 383.211 119.41 377.891 114.969L348.019 90.0842C342.7 85.6531 334.79 86.3702 330.348 91.6896C325.917 97.0197 326.634 104.929 331.954 109.36Z" fill="#8A6FE8"/>
|
||||
<path d="M407.175 118.062L417.92 94.2263C420.735 87.858 417.856 80.4087 411.488 77.5831C405.12 74.7682 397.67 77.6473 394.845 84.0156L383.831 108.461L407.175 118.062Z" fill="#8A6FE8"/>
|
||||
<path d="M401.363 105.175L401.234 69.117C401.181 62.1493 395.498 56.541 388.53 56.5945C381.562 56.648 375.954 62.3313 376.007 69.2989L376.018 96.11L401.363 105.175Z" fill="#8A6FE8"/>
|
||||
<path d="M386.453 109.071L378.137 73.9548C376.543 67.169 369.757 62.9628 362.971 64.5575C356.185 66.1523 351.979 72.938 353.574 79.7237L362.04 115.482L386.453 109.071Z" fill="#8A6FE8"/>
|
||||
<path d="M381.776 142.261C396.359 142.261 408.181 130.44 408.181 115.857C408.181 101.274 396.359 89.4527 381.776 89.4527C367.194 89.4527 355.372 101.274 355.372 115.857C355.372 130.44 367.194 142.261 381.776 142.261Z" fill="url(#paint0_radial)"/>
|
||||
<path d="M248.267 406.979C248.513 384.727 245.345 339.561 222.376 301.736L199.922 315.372C220.76 349.675 222.323 389.715 221.841 407.182C221.798 408.627 235.263 409.933 248.267 406.979Z" fill="url(#paint1_linear)"/>
|
||||
<path d="M221.841 406.936L242.637 406.84L262.052 518.065L220.311 518.258C217.132 518.269 214.724 515.711 214.938 512.532L221.841 406.936Z" fill="#522CD5"/>
|
||||
<path d="M306.566 488.814C310.173 491.661 310.109 495.782 309.831 500.127L308.964 513.452C308.803 515.839 306.727 517.798 304.34 517.809L260.832 518.012C258.125 518.023 256.08 515.839 256.262 513.142L256.551 499.335C256.883 494.315 255.192 492.474 251.307 487.744C244.649 479.663 224.967 435.62 226.84 406.925L248.256 406.829C249.691 423.858 272.167 461.682 306.566 488.814Z" fill="url(#paint2_linear)"/>
|
||||
<path d="M309.82 500.127C310.023 497.088 310.077 494.176 308.889 491.715L254.635 491.961C256.134 494.166 256.765 496.092 256.562 499.314L256.273 513.121C256.091 515.828 258.146 518.012 260.843 517.99L304.34 517.798C306.727 517.787 308.803 515.828 308.964 513.442L309.82 500.127Z" fill="url(#paint3_radial)"/>
|
||||
<path d="M133.552 407.471C133.103 385.22 135.864 340.021 158.49 301.993L181.073 315.425C160.545 349.921 159.346 389.972 159.989 407.428C160.042 408.884 146.578 410.318 133.552 407.471Z" fill="url(#paint4_linear)"/>
|
||||
<path d="M110.798 497.152C110.765 494.187 111.204 491.575 112.457 487.23C131.882 434.132 133.52 407.364 133.52 407.364L159.999 407.246C159.999 407.246 161.819 433.512 181.716 486.427C183.289 490.195 183.471 493.641 183.674 496.831L183.792 513.816C183.803 516.374 181.716 518.483 179.158 518.494L177.873 518.504L116.781 518.782L115.496 518.793C112.927 518.804 110.83 516.728 110.819 514.159L110.798 497.152Z" fill="url(#paint5_linear)"/>
|
||||
<path d="M110.798 497.152C110.798 496.67 110.808 496.199 110.83 495.739C110.969 494.262 111.643 492.603 114.875 492.582L180.207 492.282C182.561 492.367 183.343 494.176 183.589 495.311C183.621 495.814 183.664 496.328 183.696 496.82L183.813 513.806C183.824 515.411 183.011 516.824 181.769 517.669C181.031 518.172 180.132 518.472 179.179 518.483L177.895 518.494L116.802 518.772L115.528 518.782C114.244 518.793 113.077 518.269 112.232 517.434C111.386 516.599 110.862 515.432 110.851 514.148L110.798 497.152Z" fill="url(#paint6_radial)"/>
|
||||
<path d="M314.979 246.348C324.162 210.407 318.008 181.777 318.008 181.777L326.452 181.734L326.656 181.574C314.262 115.75 256.326 66.0987 186.949 66.4198C108.796 66.773 45.7233 130.424 46.0765 208.577C46.4297 286.731 110.08 349.803 188.234 349.45C249.905 349.172 302.178 309.474 321.304 254.343C321.872 251.999 321.797 247.804 314.979 246.348Z" fill="url(#paint7_radial)"/>
|
||||
<path d="M310.237 279.035L65.877 280.148C71.3998 289.428 77.95 298.012 85.3672 305.761L290.972 304.829C298.336 297.005 304.8 288.368 310.237 279.035Z" fill="#D8CFF7"/>
|
||||
<path d="M235.062 312.794L280.924 312.585L280.74 272.021L234.877 272.23L235.062 312.794Z" fill="#512BD4"/>
|
||||
<path d="M243.001 297.626C242.691 297.626 242.434 297.53 242.22 297.327C242.006 297.123 241.899 296.866 241.899 296.588C241.899 296.299 242.006 296.042 242.22 295.839C242.434 295.625 242.691 295.528 243.001 295.528C243.312 295.528 243.568 295.635 243.782 295.839C243.996 296.042 244.114 296.299 244.114 296.588C244.114 296.877 244.007 297.123 243.793 297.327C243.568 297.519 243.312 297.626 243.001 297.626Z" fill="white"/>
|
||||
<path d="M255.192 297.434H253.212L247.967 289.203C247.839 289 247.721 288.775 247.636 288.55H247.593C247.636 288.786 247.657 289.299 247.657 290.091L247.668 297.444H245.912L245.891 286.228H247.999L253.062 294.265C253.276 294.597 253.415 294.833 253.479 294.95H253.511C253.458 294.651 253.437 294.148 253.437 293.441L253.426 286.217H255.17L255.192 297.434Z" fill="white"/>
|
||||
<path d="M263.733 297.412L257.589 297.423L257.568 286.206L263.465 286.195V287.779L259.387 287.79L259.398 290.969L263.155 290.958V292.532L259.398 292.542L259.409 295.86L263.733 295.85V297.412Z" fill="white"/>
|
||||
<path d="M272.445 287.758L269.298 287.769L269.32 297.401H267.5L267.479 287.769L264.343 287.779V286.195L272.434 286.174L272.445 287.758Z" fill="white"/>
|
||||
<path d="M315.279 246.337C324.355 210.836 318.457 182.483 318.308 181.798L171.484 182.462C171.484 182.462 162.226 181.563 162.268 190.018C162.311 198.463 162.761 222.341 162.878 248.746C162.9 254.172 167.363 256.773 170.863 256.751C170.874 256.751 311.618 252.213 315.279 246.337Z" fill="url(#paint8_radial)"/>
|
||||
<path d="M227.685 246.798C227.685 246.798 250.183 228.827 254.571 225.499C258.959 222.17 262.812 221.977 266.869 225.445C270.925 228.913 293.616 246.498 293.616 246.498L227.685 246.798Z" fill="#A08BE8"/>
|
||||
<path d="M320.748 256.141C320.748 256.141 324.943 248.414 315.279 246.348C315.289 246.305 170.927 246.894 170.927 246.894C167.566 246.905 163.232 244.925 162.846 241.671C162.857 244.004 162.878 246.369 162.889 248.756C162.91 253.68 166.582 256.27 169.878 256.698C170.21 256.73 170.542 256.773 170.874 256.773L180.742 256.73L320.748 256.141Z" fill="#512BD4"/>
|
||||
<path d="M206.4 233.214C212.511 233.095 217.302 224.667 217.102 214.39C216.901 204.112 211.785 195.878 205.674 195.997C199.563 196.116 194.772 204.544 194.973 214.821C195.173 225.099 200.289 233.333 206.4 233.214Z" fill="#512BD4"/>
|
||||
<path d="M306.249 214.267C306.356 203.989 301.488 195.605 295.377 195.541C289.266 195.478 284.225 203.758 284.118 214.037C284.011 224.315 288.878 232.699 294.99 232.763C301.101 232.826 306.142 224.545 306.249 214.267Z" fill="#512BD4"/>
|
||||
<path d="M205.905 205.291C208.152 203.022 211.192 202.016 214.157 202.262C215.912 205.495 217.014 209.733 217.111 214.389C217.164 217.3 216.811 220.04 216.158 222.513C212.669 223.519 208.752 222.662 205.979 219.922C201.912 215.909 201.88 209.348 205.905 205.291Z" fill="#8065E0"/>
|
||||
<path d="M294.996 204.285C297.255 202.016 300.294 200.999 303.259 201.256C305.164 204.628 306.309 209.209 306.256 214.239C306.224 216.808 305.892 219.259 305.303 221.485C301.793 222.523 297.843 221.678 295.061 218.916C291.004 214.892 290.972 208.342 294.996 204.285Z" fill="#8065E0"/>
|
||||
<path d="M11.6342 357.017C10.9171 354.716 -5.72611 300.141 21.3204 258.903C36.9468 235.078 63.3083 221.035 99.6664 217.15L102.449 243.276C74.3431 246.273 54.4676 256.345 43.3579 273.202C23.0971 303.941 36.5722 348.733 36.7113 349.183L11.6342 357.017Z" fill="url(#paint9_linear)"/>
|
||||
<path d="M95.1498 252.802C109.502 252.802 121.137 241.167 121.137 226.815C121.137 212.463 109.502 200.828 95.1498 200.828C80.7976 200.828 69.1628 212.463 69.1628 226.815C69.1628 241.167 80.7976 252.802 95.1498 252.802Z" fill="url(#paint10_radial)"/>
|
||||
<path d="M72.0098 334.434L33.4683 329.307C26.597 328.397 20.2929 333.214 19.3725 340.085C18.4627 346.956 23.279 353.26 30.1504 354.181L68.6919 359.308C75.5632 360.217 81.8673 355.401 82.7878 348.53C83.6975 341.658 78.8705 335.344 72.0098 334.434Z" fill="#8A6FE8"/>
|
||||
<path d="M3.73535 367.185L7.35297 393.076C8.36975 399.968 14.7702 404.731 21.6629 403.725C28.5556 402.708 33.3185 396.308 32.3124 389.415L28.5984 362.861L3.73535 367.185Z" fill="#8A6FE8"/>
|
||||
<path d="M15.5194 374.988L34.849 405.427C38.6058 411.292 46.4082 413.005 52.2735 409.248C58.1387 405.491 59.8512 397.689 56.0945 391.823L41.7953 369.144L15.5194 374.988Z" fill="#8A6FE8"/>
|
||||
<path d="M26.0511 363.739L51.8026 389.019C56.7688 393.911 64.7532 393.846 69.6445 388.88C74.5358 383.914 74.4715 375.929 69.516 371.038L43.2937 345.297L26.0511 363.739Z" fill="#8A6FE8"/>
|
||||
<path d="M26.4043 381.912C40.987 381.912 52.8086 370.091 52.8086 355.508C52.8086 340.925 40.987 329.104 26.4043 329.104C11.8216 329.104 0 340.925 0 355.508C0 370.091 11.8216 381.912 26.4043 381.912Z" fill="url(#paint11_radial)"/>
|
||||
<path d="M184.73 63.6308L157.819 66.5892L158.561 38.5412L177.888 36.4178L184.73 63.6308Z" fill="#8A6FE8"/>
|
||||
<path d="M170.018 41.647C180.455 39.521 187.193 29.3363 185.067 18.8988C182.941 8.46126 172.757 1.72345 162.319 3.84944C151.882 5.97543 145.144 16.1601 147.27 26.5976C149.396 37.0351 159.58 43.773 170.018 41.647Z" fill="#D8CFF7"/>
|
||||
<path d="M196.885 79.385C198.102 79.2464 198.948 78.091 198.684 76.8997C195.851 64.2818 183.923 55.5375 170.773 56.9926C157.622 58.4371 147.886 69.5735 147.865 82.4995C147.863 83.7232 148.949 84.6597 150.168 84.5316L196.885 79.385Z" fill="url(#paint12_radial)"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(382.004 103.457) scale(26.4058)">
|
||||
<stop stop-color="#8065E0"/>
|
||||
<stop offset="1" stop-color="#512BD4"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint1_linear" x1="214.439" y1="303.482" x2="236.702" y2="409.505" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#522CD5"/>
|
||||
<stop offset="0.4397" stop-color="#8A6FE8"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear" x1="231.673" y1="404.144" x2="297.805" y2="522.048" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#522CD5"/>
|
||||
<stop offset="0.4397" stop-color="#8A6FE8"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(280.957 469.555) rotate(-0.260742) scale(45.8326)">
|
||||
<stop offset="0.034" stop-color="#522CD5"/>
|
||||
<stop offset="0.9955" stop-color="#8A6FE8"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint4_linear" x1="166.061" y1="303.491" x2="144.763" y2="409.709" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#522CD5"/>
|
||||
<stop offset="0.4397" stop-color="#8A6FE8"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear" x1="146.739" y1="407.302" x2="147.246" y2="518.627" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#522CD5"/>
|
||||
<stop offset="0.4397" stop-color="#8A6FE8"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint6_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(148.63 470.023) rotate(179.739) scale(50.2476)">
|
||||
<stop offset="0.034" stop-color="#522CD5"/>
|
||||
<stop offset="0.9955" stop-color="#8A6FE8"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint7_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(219.219 153.929) rotate(179.739) scale(140.935)">
|
||||
<stop offset="0.4744" stop-color="#A08BE8"/>
|
||||
<stop offset="0.8618" stop-color="#8065E0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint8_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(314.861 158.738) rotate(179.739) scale(146.053)">
|
||||
<stop offset="0.0933" stop-color="#E1DFDD"/>
|
||||
<stop offset="0.6573" stop-color="white"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint9_linear" x1="54.1846" y1="217.159" x2="54.1846" y2="357.022" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.3344" stop-color="#9780E6"/>
|
||||
<stop offset="0.8488" stop-color="#8A6FE8"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint10_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(90.3494 218.071) rotate(-0.260742) scale(25.9924)">
|
||||
<stop stop-color="#8065E0"/>
|
||||
<stop offset="1" stop-color="#512BD4"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint11_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.805 345.043) scale(26.4106)">
|
||||
<stop stop-color="#8065E0"/>
|
||||
<stop offset="1" stop-color="#512BD4"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint12_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(169.113 67.3662) rotate(-32.2025) scale(21.0773)">
|
||||
<stop stop-color="#8065E0"/>
|
||||
<stop offset="1" stop-color="#512BD4"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
||||
22
src/Core/Resources/Images/empty_items_state.svg
Normal file
22
src/Core/Resources/Images/empty_items_state.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<svg width="192" height="144" viewBox="0 0 192 144" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M89.5555 141.794H150.997" stroke="#89929F" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M109.305 124.239V141.794" stroke="#89929F" stroke-width="4" stroke-linejoin="round"/>
|
||||
<path d="M129.054 124.239V141.794" stroke="#89929F" stroke-width="4" stroke-linejoin="round"/>
|
||||
<rect x="50.0576" y="34.2716" width="139.34" height="89.9678" rx="4" fill="white" stroke="#89929F" stroke-width="4"/>
|
||||
<rect x="61.0293" y="44.1461" width="118.494" height="70.2188" rx="2" fill="#F0F0F0" stroke="#89929F" stroke-width="2"/>
|
||||
<path d="M172.833 55.7086H141.652" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M172.833 67.4015H151.396" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M141.652 67.4015H127.036" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M172.833 79.0944H159.191" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M148.473 79.0944H118.266" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M172.833 90.7873H141.652" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M130.934 90.7873H114.369" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M172.833 102.48H128.985" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M118.266 102.48H92.9316" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M82.2131 102.48H66.6226" stroke="#89929F" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M31.9404 50.4821C31.9404 76.6557 53.4303 97.8736 79.9395 97.8736C106.449 97.8736 127.939 76.6557 127.939 50.4821C127.939 24.3084 106.449 3.09048 79.9395 3.09048C53.4303 3.09048 31.9404 24.3084 31.9404 50.4821Z" fill="white" stroke="#89929F" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3.89833 125.292L6.0312 127.424C7.98382 129.377 11.1496 129.377 13.1023 127.424L42.0281 98.4987L49.6024 90.9244C50.2672 90.2528 50.119 89.1332 49.3407 88.5972C46.1849 86.4236 43.7021 83.7054 42.2973 81.8764C41.8348 81.2744 40.9352 81.1836 40.3984 81.7204L32.8241 89.2947L3.89833 118.221C1.94571 120.173 1.94571 123.339 3.89833 125.292Z" fill="#F0F0F0" stroke="#89929F" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect width="64.311" height="18.5138" rx="4" transform="matrix(-1 0 0 1 112.42 24.5275)" fill="#F0F0F0" stroke="#89929F" stroke-width="4"/>
|
||||
<path d="M83.4487 67.5038V77.4957C83.4487 79.7048 81.6579 81.4957 79.4487 81.4957H45.5107C44.3737 81.4957 43.2833 81.018 42.5568 80.1434C40.012 77.0798 37.6858 73.4766 35.5783 68.7585C34.4526 66.2387 36.3864 63.5038 39.1463 63.5038H79.4487C81.6579 63.5038 83.4487 65.2947 83.4487 67.5038Z" fill="#F0F0F0" stroke="#89929F" stroke-width="4" stroke-linecap="round"/>
|
||||
<path d="M111.445 78.2186V67.5038C111.445 65.2947 113.236 63.5038 115.445 63.5038H120.999C123.729 63.5038 125.544 66.1405 124.303 68.5721C122.306 72.483 119.526 77.0953 117.273 80.2207C116.684 81.0374 115.729 81.4957 114.722 81.4957C112.913 81.4957 111.445 80.0285 111.445 78.2186Z" fill="#F0F0F0" stroke="#89929F" stroke-width="4" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
22
src/Core/Resources/Images/empty_items_state_dark.svg
Normal file
22
src/Core/Resources/Images/empty_items_state_dark.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<svg width="164" height="124" viewBox="0 0 164 124" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M76.4954 121.109H128.977" stroke="#A3A3A3" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M93.3645 106.062V121.109" stroke="#A3A3A3" stroke-width="4" stroke-linejoin="round"/>
|
||||
<path d="M110.233 106.062V121.109" stroke="#A3A3A3" stroke-width="4" stroke-linejoin="round"/>
|
||||
<rect x="42.7576" y="28.9436" width="119.02" height="77.1181" rx="4" fill="#303030" stroke="#A3A3A3" stroke-width="4"/>
|
||||
<rect x="52.1292" y="37.4078" width="101.214" height="60.1898" rx="2" fill="#303030" stroke="#A3A3A3" stroke-width="2"/>
|
||||
<path d="M147.628 47.3188H120.995" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M147.628 57.3417H129.318" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M120.994 57.3417H108.51" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M147.628 67.3646H135.976" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M126.821 67.3646H101.019" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M147.628 77.3875H120.995" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M111.839 77.3875H97.6899" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M147.628 87.4103H110.175" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M101.019 87.4103H79.379" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M70.2236 87.4103H56.9067" stroke="#A3A3A3" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M27.2824 42.8388C27.2824 65.2743 45.6384 83.4617 68.2817 83.4617C90.9249 83.4617 109.281 65.2743 109.281 42.8389C109.281 20.4035 90.9249 2.216 68.2817 2.216C45.6384 2.216 27.2824 20.4034 27.2824 42.8388Z" fill="#303030" stroke="#A3A3A3" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3.83913 107.475L4.6422 108.281C6.59139 110.237 9.75165 110.237 11.7008 108.281L35.8989 83.9975L42.3686 77.505C42.9365 76.9294 42.8099 75.9697 42.1451 75.5102C39.4495 73.647 37.3288 71.3171 36.1288 69.7493C35.7339 69.2333 34.9654 69.1555 34.5069 69.6156L28.0372 76.1081L3.83913 100.391C1.88994 102.347 1.88994 105.519 3.83913 107.475Z" fill="#303030" stroke="#A3A3A3" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect width="54.9323" height="15.8695" rx="4" transform="matrix(-1 0 0 1 96.0254 20.5912)" fill="#303030" stroke="#A3A3A3" stroke-width="4"/>
|
||||
<path d="M71.2791 58.0008V65.4229C71.2791 67.6321 69.4882 69.4229 67.279 69.4229H39.1385C37.999 69.4229 36.905 68.9442 36.1843 68.0616C34.2078 65.6414 32.387 62.8248 30.722 59.2362C29.5612 56.7344 31.4973 54.0008 34.2552 54.0008H67.2791C69.4882 54.0008 71.2791 55.7917 71.2791 58.0008Z" fill="#303030" stroke="#A3A3A3" stroke-width="4" stroke-linecap="round"/>
|
||||
<path d="M95.193 66.6257V58.0008C95.193 55.7917 96.9839 54.0008 99.193 54.0008H102.55C105.279 54.0008 107.078 56.6299 105.813 59.0474C104.144 62.2377 101.962 65.8368 100.17 68.3309C99.6676 69.0302 98.8513 69.4229 97.9902 69.4229C96.4453 69.4229 95.193 68.1706 95.193 66.6257Z" fill="#303030" stroke="#A3A3A3" stroke-width="4" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
162
src/Core/Resources/Localization/AppResources.Designer.cs
generated
162
src/Core/Resources/Localization/AppResources.Designer.cs
generated
@@ -1723,6 +1723,15 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Continue to device Settings?.
|
||||
/// </summary>
|
||||
public static string ContinueToDeviceSettings {
|
||||
get {
|
||||
return ResourceManager.GetString("ContinueToDeviceSettings", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Continue to Help center?.
|
||||
/// </summary>
|
||||
@@ -1912,24 +1921,6 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Credential Provider service.
|
||||
/// </summary>
|
||||
public static string CredentialProviderService {
|
||||
get {
|
||||
return ResourceManager.GetString("CredentialProviderService", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The Android Credential Provider is used for managing passkeys for use with websites and other apps on your device..
|
||||
/// </summary>
|
||||
public static string CredentialProviderServiceExplanationLong {
|
||||
get {
|
||||
return ResourceManager.GetString("CredentialProviderServiceExplanationLong", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Credits.
|
||||
/// </summary>
|
||||
@@ -4938,6 +4929,15 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Notice.
|
||||
/// </summary>
|
||||
public static string Notice {
|
||||
get {
|
||||
return ResourceManager.GetString("Notice", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This account has two-step login set up, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app)..
|
||||
/// </summary>
|
||||
@@ -5173,6 +5173,24 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
|
||||
/// </summary>
|
||||
public static string OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong {
|
||||
get {
|
||||
return ResourceManager.GetString("OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
|
||||
/// </summary>
|
||||
public static string OrganizationUnassignedItemsMessageUSEUDescriptionLong {
|
||||
get {
|
||||
return ResourceManager.GetString("OrganizationUnassignedItemsMessageUSEUDescriptionLong", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Organization identifier.
|
||||
/// </summary>
|
||||
@@ -5227,6 +5245,69 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey management.
|
||||
/// </summary>
|
||||
public static string PasskeyManagement {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyManagement", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use Bitwarden to save new passkeys and log in with passkeys stored in your vault..
|
||||
/// </summary>
|
||||
public static string PasskeyManagementExplanationLong {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyManagementExplanationLong", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey operation failed because app could not be verified.
|
||||
/// </summary>
|
||||
public static string PasskeyOperationFailedBecauseAppCouldNotBeVerified {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyOperationFailedBecauseAppCouldNotBeVerified", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey operation failed because app not found in asset links.
|
||||
/// </summary>
|
||||
public static string PasskeyOperationFailedBecauseAppNotFoundInAssetLinks {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyOperationFailedBecauseAppNotFoundInAssetLinks", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey operation failed because browser is not privileged.
|
||||
/// </summary>
|
||||
public static string PasskeyOperationFailedBecauseBrowserIsNotPrivileged {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyOperationFailedBecauseBrowserIsNotPrivileged", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey operation failed because browser signature does not match.
|
||||
/// </summary>
|
||||
public static string PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey operation failed because of missing asset links.
|
||||
/// </summary>
|
||||
public static string PasskeyOperationFailedBecauseOfMissingAssetLinks {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeyOperationFailedBecauseOfMissingAssetLinks", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkeys.
|
||||
/// </summary>
|
||||
@@ -5245,6 +5326,15 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkeys not supported for this app.
|
||||
/// </summary>
|
||||
public static string PasskeysNotSupportedForThisApp {
|
||||
get {
|
||||
return ResourceManager.GetString("PasskeysNotSupportedForThisApp", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Passkey will not be copied.
|
||||
/// </summary>
|
||||
@@ -5786,6 +5876,15 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remind me later.
|
||||
/// </summary>
|
||||
public static string RemindMeLater {
|
||||
get {
|
||||
return ResourceManager.GetString("RemindMeLater", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remove.
|
||||
/// </summary>
|
||||
@@ -6353,6 +6452,15 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Set Bitwarden as your passkey provider in device settings..
|
||||
/// </summary>
|
||||
public static string SetBitwardenAsPasskeyManagerDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("SetBitwardenAsPasskeyManagerDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Set master password.
|
||||
/// </summary>
|
||||
@@ -8063,6 +8171,24 @@ namespace Bit.Core.Resources.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your passkey will be saved to your Bitwarden vault.
|
||||
/// </summary>
|
||||
public static string YourPasskeyWillBeSavedToYourBitwardenVault {
|
||||
get {
|
||||
return ResourceManager.GetString("YourPasskeyWillBeSavedToYourBitwardenVault", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your passkey will be saved to your Bitwarden vault for {0}.
|
||||
/// </summary>
|
||||
public static string YourPasskeyWillBeSavedToYourBitwardenVaultForX {
|
||||
get {
|
||||
return ResourceManager.GetString("YourPasskeyWillBeSavedToYourBitwardenVaultForX", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your request has been sent to your admin..
|
||||
/// </summary>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Outovuldiens</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Vermy dubbelsinnige karakters</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Skandering gebeur outomaties.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Ons kon nie die Android-outovulinstellingkieslys outomaties vir u open nie. U kan na die outovulinstellingkieslys navigeer dur te gaan na Android Instellings > Stelsel > Tale en toevoer > Gevorderd > Outovuldiens.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Skandering gebeur outomaties.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden kort aandag - Aktiveer “Bo-op” in “Outovuldienste” in Bitwarden Instellings</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Outovuldienste</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@ Wil u na die rekening omskakel?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@ Wil u na die rekening omskakel?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@ Wil u na die rekening omskakel?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@ Wil u na die rekening omskakel?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>خدمة التعبئة التلقائية</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>تجنب الأحرف الغامضة</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>ويندوز هيلو</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>لم نتمكن من فتح قائمة إعدادات موفر بيانات اعتماد أندرويد تلقائياً لك. يمكنك الانتقال إلى قائمة إعدادات موفر بيانات الاعتماد يدويًا من إعدادات الأندرويد > النظام > كلمات المرور والحسابات > كلمات المرور. مفاتيح المرور وخدمات البيانات.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>لم نتمكن من فتح قائمة إعدادات الملء التلقائي لنظام Android نيابةً عنك. يمكنك الانتقال إلى قائمة إعدادات الملء التلقائي يدويًا من إعدادات Android & GT ؛ نظام & GT. اللغات والمدخلات & GT. متقدم & GT. خدمة الملء التلقائي.</value>
|
||||
</data>
|
||||
@@ -1816,6 +1822,9 @@
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>يحتاج Bitwarden إلى الاهتمام - قم بتمكين "السحب" في "خدمات الملء التلقائي" من إعدادات Bitwarden</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>إدارة مفتاح المرور</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>خدمات التعبئة التلقائية</value>
|
||||
</data>
|
||||
@@ -2799,6 +2808,9 @@
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} ساعات</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>استخدم Bitwarden لحفظ مفاتيح المرور الجديدة وتسجيل الدخول باستخدام مفاتيح المرور المخزنة في المخزن الخاص بك.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>يتم استخدام إطار التعبئة التلقائية لأندرويد للمساعدة في ملء معلومات تسجيل الدخول في تطبيقات أخرى على جهازك.</value>
|
||||
</data>
|
||||
@@ -2827,6 +2839,9 @@
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>هل تريد المتابعة إلى متجر التطبيقات؟</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>هل تريد المتابعة إلى إعدادات الجهاز؟</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>اجعل حسابك أكثر أمنا من خلال إعداد تسجيل الدخول بخطوتين في تطبيق Bitwarden على شبكة الإنترنت.</value>
|
||||
</data>
|
||||
@@ -2877,6 +2892,27 @@
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>اختر تسجيل الدخول لحفظ مفتاح المرور هذا إلى</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>حفظ مفتاح المرور كتسجيل دخول جديد</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>حفظ مفتاح المرور</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>مفاتيح المرور لـ {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>كلمات المرور لـ {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>الكتابة فوق مفتاح المرور؟</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>هذا العنصر يحتوي بالفعل على مفتاح مرور. هل أنت متأكد من أنك تريد الكتابة فوق مفتاح المرور الحالي؟</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>تسجيل الدخول لـ Duo من خطوتين مطلوب لحسابك. </value>
|
||||
</data>
|
||||
@@ -2886,4 +2922,87 @@
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>تشغيل Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>التحقق مطلوب من قِبَل {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>التحقق مطلوب لهذا الإجراء. قم بإعداد طريقة إلغاء القفل في Bitwarden للمتابعة.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>خطأ في إنشاء مفتاح المرور</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>خطأ في قراءة مفتاح المرور</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>حدثت مشكلة في إنشاء مفتاح مرور لـ {0}. حاول مرة أخرى لاحقاً.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>حدثت مشكلة في قراءة مفتاح المرور الخاص بك لـ {0}. حاول مرة أخرى لاحقاً.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>التحقق من الهوية...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>كلمات المرور</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>حساب غير معروف</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>إعداد الملء التلقائي</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>احصل على الوصول الفوري إلى كلمات المرور ومفاتيح المرور الخاصة بك!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>لإعداد ملء كلمة المرور التلقائي وإدارة مفتاح المرور، عيّن Bitwarden كموفر مفضل لك في إعدادات iOS.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. انتقل إلى إعدادات جهازك > كلمات المرور > خيارات كلمة المرور</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. تشغيل التعبئة التلقائية</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. حدد "Bitwarden" لاستخدامه لكلمات المرور ومفاتيح المرور</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>سيتم حفظ مفتاح المرور الخاص بك في مخزن Bitwarden الخاص بك</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>سيتم حفظ مفتاح المرور الخاص بك في مخزن Bitwarden الخاص بك لـ {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>عناصر المؤسسة غير المعينة لم تعد مرئية في عرض جميع المستودعات ويمكن الوصول إليها فقط عن طريق لوحة التحكم. تعيين هذه العناصر لمجموعة من وحدة تحكم المدير لجعلها مرئية.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>في 16 مايو 2024، لن تكون عناصر المؤسسة غير المعينة مرئية في عرض جميع المستودعات ويمكن الوصول إليها فقط عن طريق مدير النظام. تعيين هذه العناصر لمجموعة من وحدة تحكم المدير لجعلها مرئية.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>ذكرني لاحقاً</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>إشعار</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>مفاتيح المرور غير مدعومة لهذا التطبيق</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>فشلت عملية مفتاح المرور لأن المتصفح ليس لديه امتيازات</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>فشلت عملية مفتاح المرور لأن توقيع المتصفح غير مطابق</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>فشلت عملية مفتاح المرور بسبب عدم وجود روابط أصلية</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>فشلت عملية مفتاح المرور لأن التطبيق لم يتم العثور عليه في روابط أصلية</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>فشلت عملية مفتاح المرور لأنه تعذر التحقق من التطبيق</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Avto-doldurma xidməti</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Cihaz ayarlarında "Bitwarden"i keçid açarı provayderiniz olaraq ayarlayın.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Anlaşılmaz simvollardan çəkinin</value>
|
||||
</data>
|
||||
@@ -480,7 +483,7 @@
|
||||
<value>Tətbiq uzantısını aktivləşdir</value>
|
||||
</data>
|
||||
<data name="ExtensionInSafari" xml:space="preserve">
|
||||
<value>Safari-də paylaş nişanını istifadə edərək Bitwarden-i tapın (məsləhət: Menyunun ən alt sətrinin sağ hissəsinə baxın).</value>
|
||||
<value>Safari-də paylaş ikonunu istifadə edərək Bitwarden-i tapın (ipucu: menyunun alt sətrində sağa sürüşdürün).</value>
|
||||
<comment>Safari is the name of apple's web browser</comment>
|
||||
</data>
|
||||
<data name="ExtensionInstantAccess" xml:space="preserve">
|
||||
@@ -493,13 +496,13 @@
|
||||
<value>Giriş məlumatlarınıza artıq Safari, Chrome və digər dəstəklənən tətbiqlərdən asanlıqla müraciət edə bilərsiniz.</value>
|
||||
</data>
|
||||
<data name="ExtensionSetup2" xml:space="preserve">
|
||||
<value>Safari və Chrome-da paylaş nişanını istifadə edərək Bitwarden-i tapın (məsləhət: Paylaş menyusunun ən alt sətrinin sağ hissəsinə baxın).</value>
|
||||
<value>Safari və Chrome-da paylaş ikonunu istifadə edərək Bitwarden-i tapın (ipucu: paylaşma menyusunun alt sətrində sağa sürüşdürün).</value>
|
||||
</data>
|
||||
<data name="ExtensionTapIcon" xml:space="preserve">
|
||||
<value>Uzantını başlatmaq üçün menyudakı Bitwarden nişanına toxunun.</value>
|
||||
<value>Uzantını başlatmaq üçün menyudakı Bitwarden ikonuna toxunun.</value>
|
||||
</data>
|
||||
<data name="ExtensionTurnOn" xml:space="preserve">
|
||||
<value>Safari və digər tətbiqlərdə Bitwarden-i işə salmaq üçün menyunun ən alt sətrindəki "daha çox" nişanına toxunun.</value>
|
||||
<value>Safari və digər tətbiqlərdə Bitwarden-i işə salmaq üçün menyunun alt sətrindəki "daha çox" ikonuna toxunun.</value>
|
||||
</data>
|
||||
<data name="Favorite" xml:space="preserve">
|
||||
<value>Sevimli</value>
|
||||
@@ -731,7 +734,7 @@
|
||||
<value>Uzantı aktivləşdirildi!</value>
|
||||
</data>
|
||||
<data name="Icons" xml:space="preserve">
|
||||
<value>Nişanlar</value>
|
||||
<value>İkonlar</value>
|
||||
</data>
|
||||
<data name="Translations" xml:space="preserve">
|
||||
<value>Tərcümələr</value>
|
||||
@@ -1134,13 +1137,13 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Bitmə vaxtı</value>
|
||||
</data>
|
||||
<data name="ShowWebsiteIcons" xml:space="preserve">
|
||||
<value>Veb sayt nişanlarını göstər</value>
|
||||
<value>Veb sayt ikonlarını göstər</value>
|
||||
</data>
|
||||
<data name="ShowWebsiteIconsDescription" xml:space="preserve">
|
||||
<value>Hər girişin yanında tanına bilən təsvir göstər.</value>
|
||||
</data>
|
||||
<data name="IconsUrl" xml:space="preserve">
|
||||
<value>Nişan server URL-si</value>
|
||||
<value>İkon server URL-si</value>
|
||||
</data>
|
||||
<data name="AutofillWithBitwarden" xml:space="preserve">
|
||||
<value>Bitwarden ilə avto-doldurma</value>
|
||||
@@ -1191,6 +1194,9 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>Android kimlik məlumatı provayder ayarları menyusunu sizin üçün avtomatik aça bilmədik. Bu menyunu tapmaq üçün Android Ayarları > Sistem > Parollar və hesablar > Parollar, keçid açarları və data xidmətləri bölməsində tapa bilərsiniz.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Android avto-doldurma ayarları menyusunu avtomatik aça bilmədik. Bu menyunu tapmaq üçün Android Ayarları > Sistem > Dillər və giriş > Qabaqcıl > "Avto-doldurma xidməti"nə gedin.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden diqqətinizi tələb edir - Bitwarden Ayarlarında "Avto-doldurma xidməti"ndə "Üzərindən göstər"i işə salın</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Keçid açarının idarə edilməsi</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Avto-doldurma xidmətləri</value>
|
||||
</data>
|
||||
@@ -2797,6 +2806,9 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} saat</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Yeni keçid açarlarını saxlamaq və anbarınızda saxlanılan keçid açarları ilə giriş etmək üçün Bitwarden-i istifadə edin.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Android Avto-doldurma Çərçivəsi, giriş məlumatlarını cihazınızdakı digər tətbiqlərə doldurmağa kömək etmək üçün istifadə olunur.</value>
|
||||
</data>
|
||||
@@ -2825,6 +2837,9 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Tətbiq mağazası ilə davam edilsin?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Cihaz Ayarlarına davam edilsin?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Bitwarden veb tətbiqində iki addımlı girişi quraraq hesabınızı daha güvənli edin.</value>
|
||||
</data>
|
||||
@@ -2875,6 +2890,27 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Anbar vaxt bitməsi əməliyyatınızı dəyişdirmək üçün bir kilid açma seçimi qurun.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Bu keçid açarını saxlayacaq bir giriş seçin</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Keçid açarını yeni bir giriş olaraq saxla</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Keçid açarını saxla</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>{0} üçün keçid açarları</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>{0} parolları</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Keçid açarının üzərinə yazılsın?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Bu elementdə artıq bir keçid açarı var. Hazırkı keçid açarının üzərinə yazmaq istədiyinizə əminsiniz?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Hesabınız üçün Duo iki addımlı giriş tələb olunur. </value>
|
||||
</data>
|
||||
@@ -2884,4 +2920,87 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Duo-nu başlat</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>{0} tərəfindən doğrulanma tələb olunur</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Bu əməliyyat üçün doğrulama tələb olunur. Davam etmək üçün "Bitwarden"də bir kilid açma üsulu qurun.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Keçid açarını yaratma xətası</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Keçid açarını oxuma xətası</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>{0} üçün keçid açarı yaradılarkən bir problem baş verdi. Daha sonra yenidən sınayın.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>{0} üçün keçid açarınız oxunarkən bir problem baş verdi. Daha sonra yenidən sınayın.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Kimlik doğrulanır...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Parollar</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Bilinməyən hesab</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Avto-doldurmanı qur</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Parollarınıza və keçid açarlarınıza dərhal müraciət edin!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>Parolların avto-doldurulmasını və keçid açarlarının idarə edilməsini qurmaq üçün iOS Ayarlarında "Bitwarden"i tərcih edilən provayderiniz olaraq ayarlayın.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Cihazda Ayarlar > Parollar > "Parol seçimləri"nə gedin</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Avto-doldurmanı işə salın</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Parollar və keçid açarları üçün istifadə etmək məqsədilə "Bitwarden"i seçin</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Keçid açarınız Bitwarden anbarınızda saxlanılacaq</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Keçid açarınız {0} üçün Bitwarden anbarınızda saxlanılacaq</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Təyin edilməmiş təşkilat elementləri artıq Bütün Anbarlar görünüşündə görünməyəndir və yalnız Admin Konsolu vasitəsilə əlçatandır. Bu elementləri görünən etmək üçün Admin Konsolundan bir kolleksiyaya təyin edin.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>16 May 2024-cü ildən etibarən təyin edilməmiş təşkilat elementləri artıq Bütün Anbarlar görünüşündə görünməyən və yalnız Admin Konsolu vasitəsilə əlçatan olacaq. Bu elementləri görünən etmək üçün Admin Konsolundan bir kolleksiyaya təyin edin.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Daha sonra xatırlat</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Xəbərdarlıq</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Keçid açarları bu tətbiq üçün dəstəklənmir</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Brauzer, imtiyazlı olmadığı üçün keçid açarı əməliyyatı uğursuz oldu</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Brauzer imzası uyuşmadığı üçün keçid açarı əməliyyatı uğursuz oldu</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Əskik varlıq keçidlərinə görə keçid açarı əməliyyatı uğursuz oldu</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Varlıq keçidlərində tətbiq tapılmadığına görə keçid açarı əməliyyatı uğursuz oldu</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Tətbiq doğrulana bilmədiyi üçün keçid açarı əməliyyatı uğursuz oldu</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Служба аўтазапаўнення</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Пазбягаць неадназначных сімвалаў</value>
|
||||
</data>
|
||||
@@ -1190,6 +1193,9 @@
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Немагчыма аўтаматычна адкрыць меню наладаў аўтазапаўнення Android. Вы можаце перайсці ў меню наладаў аўтазапаўнення ўручную з Налады Android > Сістэма > Мова і ўвод > Дадаткова > Служба аўтазапаўнення.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden патрабуе вашай увагі - Уключыце "Па-над усімі праграмамі" у "Службе аўтазапаўнення" наладаў Bitwarden</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Службы аўтазапаўнення</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Услуга за автоматично дописване</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Задайте Битуорден за свой доставчик за секретни ключове в настройките на устройството.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Без нееднозначни знаци</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Идентификация чрез Уиндоус (Windows Hello)</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>Екранът с настройките за доставчик на идентификационни данни не може да се отвори автоматично. Може да го достигнете през: Настройки → Системни (Общо управление) → Пароли, кодове за достъп и автоматично попълване.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Екранът за настройките за автоматично дописване не може да се отвори автоматично. Може да го достигнете през: Настройки (Android Settings) → Системни (System) → Езици и вход (Languages and input) → Допълнителни (Advanced) → Услуга за дописване (Autofill service).</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Битуорден има нужда от внимание. Отворете „Изобразяване отгоре“ в „Услуга за автоматично дописване“ в настройките му.</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Управление на секретни ключове</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Услуга за автоматично дописване</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} часа</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Използване на Битуорден за запазване на новите секретни ключове и вписване с такива запазени в трезора.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Подсистемата за автоматично попълване на Андроид се използва за попълване на данните за вход в други приложения на устройството.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Продължаване към магазина за приложения?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Продължаване към настройките на устройството?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Подобрете защитата на регистрацията си, като настроите двустепенното удостоверяване в уеб приложението на Битуорден.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Задайте начин за отключване, за да може да промените действието при изтичане на времето за достъп до трезора.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Изберете елемент, в който да запазите този секретен ключ</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Запазване на секретния ключ като нов елемент за вписване</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Запазване на секретния ключ</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Секретни ключове за {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Пароли за {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Да се замени ли секретният ключ?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Този елемент вече съдържа секретен ключ. Наистина ли искате да замените текущия секретен ключ?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Вашата регистрация изисква двустепенно удостоверяване чрез Duo. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Стартиране на Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Изисква се потвърждение от {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Това действие изисква потвърждение. Настройте метод за отключване в Битуорден, за да продължите.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Грешка при създаването на секретен ключ</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Грешка при четенето на секретен ключ</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Възникна грешка при създаването на секретен ключ за {0}. Опитайте отново по-късно.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Възникна грешка при прочитането на секретния ключ за {0}. Опитайте отново по-късно.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Потвърждаване на самоличността…</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Пароли</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Неизвестна регистрация</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Настройте автоматичното попълване</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Незабавен достъп до паролите и секретните ключове!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>За да настроите автоматичното попълване на пароли и управлението на секретни ключове, задайте Битуорден като предпочитан доставчик за това в настройките на iOS.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Идете в Настройките на устройството > Пароли > Настройки за паролите</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Включете автоматичното попълване</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Изберете, че искате да използвате „Битуорден“ за пароли и секретни ключове</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Секретният ключ ще бъде запазен в трезора на Битуорден</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Секретният ключ ще бъде запазен в трезора на Битуорден за {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Неразпределените елементи на организацията вече не се виждат в изгледа с „Всички трезори“, а са достъпни само през Административната конзола. Добавете тези елементи към някоя колекция в Административната конзола, за да станат видими.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>От 16 май 2024г. неразпределените елементи на организациите вече няма се виждат в изгледа с „Всички трезори“, а ще бъдат достъпни само през Административната конзола. Добавете тези елементи към някоя колекция в Административната конзола, за да станат видими.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Напомнете ми по-късно</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Известие</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>За това приложение не се поддържат секретни ключове</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Операцията със секретния ключ беше неуспешна, тъй като подписът в браузъра не съвпада</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Операцията със секретния ключ беше неуспешна, поради липсващи връзки към ресурси</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Операцията със секретния ключ беше неуспешна, тъй като приложението не е намерено измежду връзките към ресурси</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Операцията със секретния ключ беше неуспешна, тъй като приложението не може да бъде потвърдено</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Auto-fill service</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>অস্পষ্ট বর্ণগুলি বাদ দিয়ে যান</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android autofill settings menu for you. You can navigate to the autofill settings menu manually from Android Settings > System > Languages and input > Advanced > Autofill service.</value>
|
||||
</data>
|
||||
@@ -1816,6 +1822,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden needs attention - Turn on "Draw-Over" in "Auto-fill Services" from Bitwarden Settings</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Auto-fill services</value>
|
||||
</data>
|
||||
@@ -2799,6 +2808,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2827,6 +2839,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2877,6 +2892,27 @@ Do you want to switch to this account?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2886,4 +2922,87 @@ Do you want to switch to this account?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Usluga auto-ispune</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Izbjegavaj dvosmislene znakove</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Zdravo</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Nismo mogli automatski da otvorimo meni za podešavanja Android automatskog popunjavanja. Možete ručno da odete do menija podešavanja automatskog popunjavanja iz Android podešavanja > Sistem > Jezici i unos > Napredno > Usluga automatskog popunjavanja.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden zahtijeva radnju - Bitwarden Postavke -> Usluge auto-ispune -> uključi opciju „Koristi preklapanje”</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Usluga automatskog popunjavanja</value>
|
||||
</data>
|
||||
@@ -2797,6 +2806,9 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2825,6 +2837,9 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2875,6 +2890,27 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2884,4 +2920,87 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Servei d'emplenament automàtic</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Estableix Bitwarden com a proveïdor de claus de pas a la configuració del dispositiu.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Eviteu caràcters ambigus</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ L'escaneig es farà automàticament.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>No hem pogut obrir automàticament el menú de configuració del proveïdor de credencials d'Android. Podeu navegar fins al menú de configuració del proveïdor de credencials manualment des de Configuració d'Android > Sistema > Contrasenyes i comptes > Contrasenyes, claus de pas i serveis de dades.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>No hem pogut obrir automàticament el menú de configuració de l'emplenament automàtic d'Android. Podeu anar manualment des de la configuració d'Android > Sistema > Idiomes i entrada > Avançat > Servei d'emplenament automàtic.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ L'escaneig es farà automàticament.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden necessita atenció: activeu l'opció "Dibuixa-sobre" a "Serveis d'emplenament automàtic" a Configuració de Bitwarden</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Gestió de claus de pas</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Serveis d'emplenament automàtic</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hores</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Utilitzeu Bitwarden per guardar claus de pas noves i iniciar sessió amb les claus emmagatzemades a la vostra caixa forta.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>El marc d'emplenament automàtic d'Android s'utilitza per ajudar a omplir la informació d'inici de sessió a altres aplicacions del vostre dispositiu.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Voleu continuar cap a l'app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Voleu continuar a la configuració del dispositiu?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Fes que el vostre compte siga més segur configurant l'inici de sessió en dos passos a l'aplicació web de Bitwarden.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Configura una opció de desbloqueig per canviar l'acció de temps d'espera de la caixa forta.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Trieu un inici de sessió per guardar aquesta clau de pas</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Guarda la clau de pas com a nou inici de sessió</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Guarda la clau de pas</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Claus de pas per a {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Contrasenyes per a {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Sobreescriure la clau de pas?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Aquest element ja conté una clau de pas. Esteu segur que voleu sobreescriure la actual?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Es requereix l'inici de sessió en dos passos de DUO al vostre compte. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Inicia DUO</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verificació requerida per {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verificació necessària per a aquesta acció. Configura un mètode de desbloqueig a Bitwarden per continuar.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>S'ha produït un error en crear la clau de pas</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>S'ha produït un error en llegir la clau de pas</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>S'ha produït un problema en crear una contrasenya per a {0}. Torneu-ho a provar més tard.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>S'ha produït un problema en llegir la clau de pas per a {0}. Torneu-ho a provar més tard.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>S'està verificant la identitat...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Contrasenyes</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Compte desconegut</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Configura l'emplenament automàtic</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Obteniu accés instantani a les vostres contrasenyes i claus de pas!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>Per configurar l'emplenament automàtic de contrasenyes i la gestió de claus de pas, configureu Bitwarden com a proveïdor preferit a la configuració d'iOS.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Aneu a la configuració del dispositiu > Contrasenyes > Opcions de contrasenya</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Activeu l'emplenament automàtic</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Seleccioneu "Bitwarden" per utilitzar-lo per a les contrasenyes i les claus de pas</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>La clau d'accés es guardarà a la caixa forta de Bitwarden</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>La clau d'accés es guardarà a la caixa forta de Bitwarden per a {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Els elements de l'organització no assignats ja no són visibles a la visualització Totes les caixes fortes i només s'hi poden accedir des de la Consola d'administració. Assigna aquests elements a una col·lecció des de la Consola d'administració per fer-los visibles.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>El 16 de maig de 2024, els elements de l'organització no assignats deixaran de ser visibles a la visualització Totes les caixes fortes i només es podran accedir des de la Consola d'administració. Assigna aquests elements a una col·lecció des de la Consola d'administració per fer-los visibles.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Recorda-m'ho més tard</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Avís</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Les claus de pas no són compatibles amb aquesta aplicació</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>L'operació de la clau de pas ha fallat perquè el navegador no té privilegis</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>L'operació de la clau de pas ha fallat perquè la signatura del navegador no coincideix</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>L'operació de la clau de pas ha fallat perquè falten enllaços de recursos</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>L'operació de la clau de pas ha fallat perquè l'aplicació no s'ha trobat als enllaços de recursos</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>L'operació de la clau de pas ha fallat perquè l'aplicació no s'ha pogut verificar</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Služba automatického vyplňování</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Nastaví Bitwarden jako poskytovatele přístupového hesla v nastavení zařízení.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Nepoužívat zaměnitelné znaky</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Načtení proběhne automaticky.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>Obrazovku nastavení automatického vyplňování Android se nepodařilo otevřít. Nastavení můžete otevřít ručně z Nastavení systému Android > Systém > Hesla a účty > Hesla, přístupové klíče a datové služby.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Obrazovku nastavení automatického vyplňování Android se nepodařilo otevřít. Nastavení můžete otevřít ručně z Nastavení systému Android > Systém > Jazyky a zadávání > Rozšířená nastavení > Služba automatického vyplňování.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Načtení proběhne automaticky.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden vyžaduje pozornost – Povolte volbu "Zobrazit přes ostatní aplikace" ve "Službách automatického vyplňování“ v nastavení aplikace Bitwarden</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Správa přístupových klíčů</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Služby automatického vyplňování</value>
|
||||
</data>
|
||||
@@ -2797,6 +2806,9 @@ Chcete se přepnout na tento účet?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hodin</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Použijte Bitwarden pro ukládání nových přístupových klíčů a přihlašování se pomocí přístupových klíčů uložených ve Vašem trezoru.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Android Autofill Framework se používá k vyplnění přihlašovacích údajů do jiných aplikací na Vašem zařízení.</value>
|
||||
</data>
|
||||
@@ -2825,6 +2837,9 @@ Chcete se přepnout na tento účet?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Pokračovat do obchodu s aplikacemi?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Pokračovat do nastavení zařízení?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Vytvořte svůj účet bezpečnějším nastavením dvoufázového přihlášení ve webové aplikaci Bitwarden.</value>
|
||||
</data>
|
||||
@@ -2875,6 +2890,27 @@ Chcete se přepnout na tento účet?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Nastavte volbu odemknutí, abyste změnili časový limit Vašeho trezoru.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Vyberte přihlášení pro uložení tohoto přístupového klíče</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Uložit přístupový klíč jako nové přihlášení</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Uložit přístupový klíč</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Přístupové klíče pro {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Hesla pro {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Přepsat přístupový klíč?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Tato položka již obsahuje přístupový klíč. Jste si jisti, že chcete přepsat aktuální přístupový klíč?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Pro Váš účet je vyžadováno dvoufázové přihlášení DUO. </value>
|
||||
</data>
|
||||
@@ -2884,4 +2920,87 @@ Chcete se přepnout na tento účet?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Spustit DUO</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Je vyžadováno ověření od {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Pro tuto akci je vyžadováno ověření. Pro pokračování nastavte metodu odemknutí v Bitwardenu.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Chyba při vytváření přístupového klíče</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Chyba při čtení přístupového klíče</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Při vytváření přístupového klíče pro {0} došlo k chybě. Zkuste to znovu později.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Při čtení přístupového klíče pro {0} došlo k chybě. Zkuste to znovu později.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Ověřování identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Hesla</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Neznámý účet</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Nastavit automatické vyplňování</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Získejte okamžitý přístup ke svým heslům a přístupovým klíčům!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>Pro nastavení automatického vyplňování hesla a správy přístupových klíčů nastavte Bitwarden jako preferovaného poskytovatele v nastavení iOS.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Přejděte do nastavení > Hesla > Volby hesla</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Zapněte volbu "Automatické vyplňování hesel a přístupových klíčů"</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. V sekci "Používat hesla a přístupové klíče z:" zvolte "Bitwarden"</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Váš přístupový klíč bude uložen do Vašeho trezoru na Bitwardenu</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Váš přístupový klíč bude pro {0} uložen do Vašeho trezoru na Bitwardenu</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Nepřiřazené položky organizace již nejsou viditelné ve Vašem zobrazení všech trezorů a jsou nyní přístupné jen v konzoli správce. Přiřaďte tyto položky do kolekce z konzole pro správce, aby byly viditelné.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>Dne 16. května 2024 již nebudou nepřiřazené položky organizace viditelné v zobrazení Všechny trezory a budou přístupné jen prostřednictvím konzoly správce. Přiřaďte tyto položky do kolekce z konzoly pro správce, aby byly viditelné.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Připomenout později</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Upozornění</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Přístupové klíče nejsou pro tuto aplikaci podporovány</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Operace přístupového klíče se nezdařila, protože prohlížeč nemá oprávnění</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Operace přístupového klíče se nezdařila, protože se neshoduje s podpisem prohlížeče</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Operace přístupového klíče selhala z důvodu chybějících odkazů na aktiva</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Operace přístupového klíče se nezdařila, protože v odkazech na aktivum nebyla nalezena aplikace</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Operace přístupového klíče se nezdařila, protože aplikaci nelze ověřit</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Gwasanaeth llenwi awtomatig</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Osgoi nodau amwys</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android autofill settings menu for you. You can navigate to the autofill settings menu manually from Android Settings > System > Languages and input > Advanced > Autofill service.</value>
|
||||
</data>
|
||||
@@ -1816,6 +1822,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden needs attention - Turn on "Draw-Over" in "Auto-fill Services" from Bitwarden Settings</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Gwasanaethau llenwi awtomatig</value>
|
||||
</data>
|
||||
@@ -2799,6 +2808,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2827,6 +2839,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Gallwch wneud eich cyfrif yn fwy diogel drwy alluogi mewngofnodi dau gam yn ap gwe Bitwarden.</value>
|
||||
</data>
|
||||
@@ -2877,6 +2892,27 @@ Do you want to switch to this account?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2886,4 +2922,87 @@ Do you want to switch to this account?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Lansio Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Autoudfyldningstjeneste</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Angiv Bitwarden som aktuel adgangsnøgleudbyder i enhedsindstillingerne.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Undgå tvetydige tegn</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Skanning vil ske automatisk.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>Androids legitimationsudbyderindstillingsmenu kunne ikke åbnes automatisk. Legitimationsudbyderindstillingsmenuen kan tilgås manuelt via Androids Indstillinger > System > Adgangskoder og konti > Adgangskoder, adgangsnøgler og datatjenester.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Vi var ude af stand til automatisk at åbne Android indstillingsmenuen AutoFyld-tjenesten for dig. Du kan manuelt navigere til AutoFyld indstillingsmenuen fra Android Indstillinger > System > Sprog og indtastning > Avanceret > AutoFyld-tjenesten.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Skanning vil ske automatisk.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden behøver tilladelse - Aktivér "Tegn over" i "Autoudfyldtjeneste" i Bitwarden-indstillingerne</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Adgangsnøglehåndtering</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Autoudfyldtjeneste</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} timer</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Brug Bitwarden til at gemme nye adgangsnøgler og logge ind med adgangsnøgler gemt i boksen.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Android Autofill Framework bruges til at hjælpe med at udfylde loginoplysninger i andre apps på enheden.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Fortsæt til app-butik?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Fortsæt til Enhedsindstillinger?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Øg kontosikkerheden ved at oprette totrins-indlogning i Bitwarden web-appen.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Opsæt en oplåsningsmetode for at ændre Bokstimeouthandlingen.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Vælg et login at gemme denne adgangsnøgle til</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Gem adgangsnøgle som nyt login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Gem adgangsnøgle</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Adgangsnøgler til {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Adgangskoder til {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overskriv adgangsnøgle?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Dette emne indeholder allerede en adgangsnøgle. Sikker på, at den aktuelle adgangsnøgle skal overskrives?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo-totrinsindlogning kræves for kontoen. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Start Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Bekræftelse kræves af {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Bekræftelse kræves for denne handling. Opsæt en oplåsningsmetode i Bitwarden for at fortsætte.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Fejl under oprettelse af adgangsnøgle</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Fejl under læsning af adgangsnøgle</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Problem med at oprette en adgangsnøgle til {0}. Forsøg igen senere.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Problem med at læse adgangsnøglen til {0}. Forsøg igen senere.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Bekræfter identitet...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Adgangskoder</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Ukendt konto</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Opsæt autoudfyldning</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Få øjeblikkelig adgang til de gemte adgangskoder og -nøgler!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>For at opsætte autoudfyldning af adgangskode og adgangsnøglehåndtering, opsæt Bitwarden som den foretrukne udbyder i iOS-indstillingerne.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Gå til enhedens Indstillinger > Adgangskoder > Adgangskodeindstillinger</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>4. Slå Autoudfyldning til</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Vælg "Bitwarden" til brug for adgangskoder og adgangsnøgler</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Adgangsnøglen gemmes i Bitwarden-boksen</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Adgangsnøglen gemmes i Bitwarden-boksen til {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Utildelte organisationsemner er ikke længere synlige i Alle Bokse-visningen og er kun tilgængelige via Admin-konsollen. Føj disse emner til en samling fra Admin-konsollen for at gøre dem synlige.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>Pr. 16. maj 2024 vil utildelte organisationsemner ikke længere være synlige i Alle Bokse-visningen og vil kun være tilgængelige via Admin-konsollen. Tildel disse emner til en samling via Admin-konsollen for at gøre dem synlige.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Påmind senere</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Varsling</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Adgangsnøgler ikke understøttet til denne app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Adgangsnøglehandling mislykkedes, da webbrowseren ikke er priviligeret</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Adgangsnøglehandling mislykkedes, da webbrowsersignaturen ikke matcher</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Adgangsnøglehandling mislykkedes grundet manglende aktivlinks</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Adgangsnøglehandling mislykkedes, da appen ikke fandtes i aktivlinks</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Adgangsnøglehandling mislykkedes, da appen ikke kunne bekræftes</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Auto-Ausfüllen-Dienst</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Lege Bitwarden in den Geräteeinstellungen als deinen Passkey-Anbieter fest.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Mehrdeutige Zeichen vermeiden</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Das Scannen erfolgt automatisch.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Die Android Auto-Fill Einstellungen konnten nicht automatisch geöffnet werden. Über Android Einstellungen > Sprachen & Eingabe > AutoFill-Dienst kannst du manuell zu den Auto-Fill Einstellungen navigieren.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Das Scannen erfolgt automatisch.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden braucht Aufmerksamkeit - Aktiviere "Überschreiben" im "Auto-Ausfüllen-Dienst" in den Bitwarden-Einstellungen</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey-Verwaltung</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Auto-Ausfüllen-Dienst</value>
|
||||
</data>
|
||||
@@ -2797,6 +2806,9 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} Stunden</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Verwende Bitwarden, um neue Passkeys zu speichern und dich mit Passkeys aus deinem Tresor anzumelden.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Das Android Autofill Framework wird verwendet, um Zugangsdaten in andere Apps auf deinem Gerät auszufüllen.</value>
|
||||
</data>
|
||||
@@ -2825,6 +2837,9 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Weiter zum App Store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Weiter zu den Geräteeinstellungen?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Mache dein Konto sicherer, indem du eine Zwei-Faktor-Authentifizierung in der Bitwarden Web-App einrichtest.</value>
|
||||
</data>
|
||||
@@ -2875,6 +2890,27 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Richte eine Entsperroption ein, um deine Aktion bei Tresor-Timeout zu ändern.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Wähle die Zugangsdaten aus, in die dieser Passkey gespeichert werden soll</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Passkey als neue Zugangsdaten speichern</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Passkey speichern</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys für {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwörter für {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Passkey überschreiben?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>Dieser Eintrag enthält bereits einen Passkey. Bist du sicher, dass du den aktuellen Passkey überschreiben möchtest?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Für dein Konto ist die Duo Zwei-Faktor-Authentifizierung erforderlich. </value>
|
||||
</data>
|
||||
@@ -2884,4 +2920,87 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Duo starten</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verifizierung erforderlich durch {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Diese Aktion erfordert eine Verifizierung. Richte eine Entsperrmethode in Bitwarden ein, um fortzufahren.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Fehler beim Erstellen des Passkeys</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Fehler beim Lesen des Passkeys</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Es gab ein Problem beim Erstellen eines Passkeys für {0}. Versuche es später erneut.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>Es gab ein Problem beim Lesen deines Passkeys für {0}. Versuche es später erneut.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Identität wird verifiziert...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwörter</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unbekanntes Konto</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Auto-Ausfüllen einrichten</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Erhalte sofortigen Zugriff auf deine Passwörter und Passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>Um das automatische Ausfüllen von Passwörtern und die Passkey-Verwaltung einzurichten, lege Bitwarden in den iOS-Einstellungen als deinen bevorzugten Anbieter fest.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Geh in deine Geräteeinstellungen > Passwörter > Passwortoptionen</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Schalte "Automatisch ausfüllen" ein</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Wähle "Bitwarden" bei "Passwörter und Passkeys verwenden von"</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Dein Passkey wird in deinem Bitwarden-Tresor gespeichert</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Dein Passkey wird in deinem Bitwarden-Tresor für {0} gespeichert</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Hinweis: Nicht zugeordnete Organisationseinträge sind nicht mehr in der Ansicht aller Tresore sichtbar und nur über die Administrator-Konsole zugänglich. Weise diese Einträge einer Sammlung aus der Administrator-Konsole zu, um sie sichtbar zu machen.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>Ab dem 16. Mai 2024 werden nicht zugeordnete Organisationseinträge nicht mehr in der Ansicht aller Tresore sichtbar und nur über die Administrator-Konsole zugänglich sein. Weise diese Einträge einer Sammlung aus der Administrator-Konsole zu, um sie sichtbar zu machen.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Später erinnern</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Hinweis</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys werden für diese App nicht unterstützt</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Der Passkey-Vorgang ist fehlgeschlagen, da der Browser nicht autorisiert ist</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Der Passkey-Vorgang ist fehlgeschlagen, da die Browser-Signatur nicht übereinstimmt</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Der Passkey-Vorgang ist wegen fehlender Asset-Links fehlgeschlagen</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Der Passkey-Vorgang ist fehlgeschlagen, da die App nicht in den Asset-Links gefunden wurde</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Der Passwort-Vorgang ist fehlgeschlagen, da die App nicht verifiziert werden konnte</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Υπηρεσία αυτόματης συμπλήρωσης</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Αποφυγή αμφιλεγόμενων χαρακτήρων</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>Δεν ήταν δυνατό να ανοίξουμε αυτόματα το μενού ρυθμίσεων αυτόματης συμπλήρωσης Android για εσάς. Μπορείτε να πλοηγηθείτε στο μενού ρυθμίσεων αυτόματης συμπλήρωσης με μη αυτόματο τρόπο από τις Ρυθμίσεις Android > Σύστημα > Γλώσσες και εισαγωγή > Σύνθετες > Υπηρεσία αυτόματης συμπλήρωσης.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Το Bitwarden χρειάζεται προσοχή - Ενεργοποιήστε το "Draw-Over" στις "Υπηρεσίες αυτόματης συμπλήρωσης" από το Bitwarden Settings</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Υπηρεσία Αυτόματης Συμπλήρωσης</value>
|
||||
</data>
|
||||
@@ -2798,6 +2807,9 @@
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} ώρες</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>Το Android Autofill Framework χρησιμοποιείται για να προσφέρει αυτόματη συμπλήρωση στοιχείων σύνδεσης σε άλλες εφαρμογές στη συσκευή σας.</value>
|
||||
</data>
|
||||
@@ -2826,6 +2838,9 @@
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Συνέχεια στο κατάστημα εφαρμογών;</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Κάντε τον λογαριασμό σας πιο ασφαλή με τη ρύθμιση δύο βημάτων σύνδεσης στην εφαρμογή διαδικτύου Bitwarden.</value>
|
||||
</data>
|
||||
@@ -2876,6 +2891,27 @@
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Ρυθμίστε μια επιλογή κλειδώματος για να αλλάξετε την ενέργεια στη λήξη χρόνου του vault σας.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo σύνδεση δύο βημάτων απαιτείται για το λογαριασμό σας. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Εκκίνηση Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Auto-fill service</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Avoid ambiguous characters</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android auto-fill settings menu for you. You can navigate to the auto-fill settings menu manually from Android Settings > System > Languages and input > Advanced > Autofill service.</value>
|
||||
</data>
|
||||
@@ -1815,6 +1821,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="AccessibilityDrawOverPermissionAlert" xml:space="preserve">
|
||||
<value>Bitwarden needs attention - Turn on "Draw-Over" in "Auto-fill Services" from Bitwarden Settings</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Auto-fill services</value>
|
||||
</data>
|
||||
@@ -2131,10 +2140,10 @@ Scanning will happen automatically.</value>
|
||||
<value>Your organisation policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s)</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
<value>Your organisation policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies have set your vault timeout action to {0}.</value>
|
||||
<value>Your organisation policies have set your vault timeout action to {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Your vault timeout exceeds the restrictions set by your organisation.</value>
|
||||
@@ -2617,7 +2626,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
<value>Your master password does not meet one or more of your organisation policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Current master password</value>
|
||||
@@ -2759,7 +2768,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Account security</value>
|
||||
</data>
|
||||
<data name="BitwardenHelpCenter" xml:space="preserve">
|
||||
<value>Bitwarden Help Center</value>
|
||||
<value>Bitwarden Help Centre</value>
|
||||
</data>
|
||||
<data name="ContactBitwardenSupport" xml:space="preserve">
|
||||
<value>Contact Bitwarden support</value>
|
||||
@@ -2798,6 +2807,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2815,7 +2827,7 @@ Do you want to switch to this account?</value>
|
||||
<comment>The parameter is an URL, like bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="ContinueToHelpCenter" xml:space="preserve">
|
||||
<value>Continue to Help center?</value>
|
||||
<value>Continue to Help centre?</value>
|
||||
</data>
|
||||
<data name="ContinueToContactSupport" xml:space="preserve">
|
||||
<value>Continue to contact support?</value>
|
||||
@@ -2826,6 +2838,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2837,7 +2852,7 @@ Do you want to switch to this account?</value>
|
||||
<comment>The parameter is an URL, like vault.bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="LearnMoreAboutHowToUseBitwardenOnTheHelpCenter" xml:space="preserve">
|
||||
<value>Learn more about how to use Bitwarden on the Help center.</value>
|
||||
<value>Learn more about how to use Bitwarden on the Help centre.</value>
|
||||
</data>
|
||||
<data name="ContactSupportDescriptionLong" xml:space="preserve">
|
||||
<value>Can’t find what you are looking for? Reach out to Bitwarden support on bitwarden.com.</value>
|
||||
@@ -2849,7 +2864,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Explore more features of your Bitwarden account on the web app.</value>
|
||||
</data>
|
||||
<data name="LearnAboutOrganizationsDescriptionLong" xml:space="preserve">
|
||||
<value>Bitwarden allows you to share your vault items with others by using an organization. Learn more on the bitwarden.com website.</value>
|
||||
<value>Bitwarden allows you to share your vault items with others by using an organisation. Learn more on the bitwarden.com website.</value>
|
||||
</data>
|
||||
<data name="RateAppDescriptionLong" xml:space="preserve">
|
||||
<value>Help others find out if Bitwarden is right for them. Visit the app store and leave a rating now.</value>
|
||||
@@ -2868,14 +2883,35 @@ Do you want to switch to this account?</value>
|
||||
<value>Account logged out.</value>
|
||||
</data>
|
||||
<data name="YourOrganizationPermissionsWereUpdatedRequeringYouToSetAMasterPassword" xml:space="preserve">
|
||||
<value>Your organization permissions were updated, requiring you to set a master password.</value>
|
||||
<value>Your organisation permissions were updated, requiring you to set a master password.</value>
|
||||
</data>
|
||||
<data name="YourOrganizationRequiresYouToSetAMasterPassword" xml:space="preserve">
|
||||
<value>Your organization requires you to set a master password.</value>
|
||||
<value>Your organisation requires you to set a master password.</value>
|
||||
</data>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2885,4 +2921,87 @@ Do you want to switch to this account?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organisation items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organisation items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -421,6 +421,9 @@
|
||||
<data name="AutofillService" xml:space="preserve">
|
||||
<value>Auto-fill service</value>
|
||||
</data>
|
||||
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
|
||||
<value>Set Bitwarden as your passkey provider in device settings.</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Avoid ambiguous characters</value>
|
||||
</data>
|
||||
@@ -1191,6 +1194,9 @@ Scanning will happen automatically.</value>
|
||||
<data name="WindowsHello" xml:space="preserve">
|
||||
<value>Windows Hello</value>
|
||||
</data>
|
||||
<data name="BitwardenCredentialProviderGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android credential provider settings menu for you. You can navigate to the credential provider settings menu manually from Android Settings > System > Passwords & accounts > Passwords, passkeys and data services.</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillGoToSettings" xml:space="preserve">
|
||||
<value>We were unable to automatically open the Android auto-fill settings menu for you. You can navigate to the auto-fill settings menu manually from Android Settings > System > Languages and input > Advanced > Autofill service.</value>
|
||||
</data>
|
||||
@@ -1817,6 +1823,9 @@ Scanning will happen automatically.</value>
|
||||
<value>Bitwarden needs attention - Enable "Draw-Over" in "Auto-fill Services" from Bitwarden Settings
|
||||
</value>
|
||||
</data>
|
||||
<data name="PasskeyManagement" xml:space="preserve">
|
||||
<value>Passkey management</value>
|
||||
</data>
|
||||
<data name="AutofillServices" xml:space="preserve">
|
||||
<value>Auto-fill Services
|
||||
</value>
|
||||
@@ -2145,10 +2154,10 @@ Scanning will happen automatically.</value>
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s)</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
<value>Your organisation policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies have set your vault timeout action to {0}.</value>
|
||||
<value>Your organisation policies have set your vault timeout action to {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Your vault timeout exceeds the restrictions set by your organization.</value>
|
||||
@@ -2601,7 +2610,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?</value>
|
||||
</data>
|
||||
<data name="OrganizationSsoIdentifierRequired" xml:space="preserve">
|
||||
<value>Organization SSO identifier required.</value>
|
||||
<value>Organisation SSO identifier required.</value>
|
||||
</data>
|
||||
<data name="AddTheKeyToAnExistingOrNewItem" xml:space="preserve">
|
||||
<value>Add the key to an existing or new item</value>
|
||||
@@ -2631,7 +2640,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
<value>Your master password does not meet one or more of your organisation policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Current master password</value>
|
||||
@@ -2773,7 +2782,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Account security</value>
|
||||
</data>
|
||||
<data name="BitwardenHelpCenter" xml:space="preserve">
|
||||
<value>Bitwarden Help Center</value>
|
||||
<value>Bitwarden Help Centre</value>
|
||||
</data>
|
||||
<data name="ContactBitwardenSupport" xml:space="preserve">
|
||||
<value>Contact Bitwarden support</value>
|
||||
@@ -2812,6 +2821,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="XHours" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
</data>
|
||||
<data name="PasskeyManagementExplanationLong" xml:space="preserve">
|
||||
<value>Use Bitwarden to save new passkeys and log in with passkeys stored in your vault.</value>
|
||||
</data>
|
||||
<data name="AutofillServicesExplanationLong" xml:space="preserve">
|
||||
<value>The Android Autofill Framework is used to assist in filling login information into other apps on your device.</value>
|
||||
</data>
|
||||
@@ -2829,7 +2841,7 @@ Do you want to switch to this account?</value>
|
||||
<comment>The parameter is an URL, like bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="ContinueToHelpCenter" xml:space="preserve">
|
||||
<value>Continue to Help center?</value>
|
||||
<value>Continue to Help centre?</value>
|
||||
</data>
|
||||
<data name="ContinueToContactSupport" xml:space="preserve">
|
||||
<value>Continue to contact support?</value>
|
||||
@@ -2840,6 +2852,9 @@ Do you want to switch to this account?</value>
|
||||
<data name="ContinueToAppStore" xml:space="preserve">
|
||||
<value>Continue to app store?</value>
|
||||
</data>
|
||||
<data name="ContinueToDeviceSettings" xml:space="preserve">
|
||||
<value>Continue to device Settings?</value>
|
||||
</data>
|
||||
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
|
||||
<value>Make your account more secure by setting up two-step login in the Bitwarden web app.</value>
|
||||
</data>
|
||||
@@ -2851,7 +2866,7 @@ Do you want to switch to this account?</value>
|
||||
<comment>The parameter is an URL, like vault.bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="LearnMoreAboutHowToUseBitwardenOnTheHelpCenter" xml:space="preserve">
|
||||
<value>Learn more about how to use Bitwarden on the Help center.</value>
|
||||
<value>Learn more about how to use Bitwarden on the Help centre.</value>
|
||||
</data>
|
||||
<data name="ContactSupportDescriptionLong" xml:space="preserve">
|
||||
<value>Can’t find what you are looking for? Reach out to Bitwarden support on bitwarden.com.</value>
|
||||
@@ -2863,7 +2878,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Explore more features of your Bitwarden account on the web app.</value>
|
||||
</data>
|
||||
<data name="LearnAboutOrganizationsDescriptionLong" xml:space="preserve">
|
||||
<value>Bitwarden allows you to share your vault items with others by using an organization. Learn more on the bitwarden.com website.</value>
|
||||
<value>Bitwarden allows you to share your vault items with others by using an organisation. Learn more on the bitwarden.com website.</value>
|
||||
</data>
|
||||
<data name="RateAppDescriptionLong" xml:space="preserve">
|
||||
<value>Help others find out if Bitwarden is right for them. Visit the app store and leave a rating now.</value>
|
||||
@@ -2882,14 +2897,35 @@ Do you want to switch to this account?</value>
|
||||
<value>Account logged out.</value>
|
||||
</data>
|
||||
<data name="YourOrganizationPermissionsWereUpdatedRequeringYouToSetAMasterPassword" xml:space="preserve">
|
||||
<value>Your organization permissions were updated, requiring you to set a master password.</value>
|
||||
<value>Your organisation permissions were updated, requiring you to set a master password.</value>
|
||||
</data>
|
||||
<data name="YourOrganizationRequiresYouToSetAMasterPassword" xml:space="preserve">
|
||||
<value>Your organization requires you to set a master password.</value>
|
||||
<value>Your organisation requires you to set a master password.</value>
|
||||
</data>
|
||||
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||
</data>
|
||||
<data name="ChooseALoginToSaveThisPasskeyTo" xml:space="preserve">
|
||||
<value>Choose a login to save this passkey to</value>
|
||||
</data>
|
||||
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
|
||||
<value>Save passkey as new login</value>
|
||||
</data>
|
||||
<data name="SavePasskey" xml:space="preserve">
|
||||
<value>Save passkey</value>
|
||||
</data>
|
||||
<data name="PasskeysForX" xml:space="preserve">
|
||||
<value>Passkeys for {0}</value>
|
||||
</data>
|
||||
<data name="PasswordsForX" xml:space="preserve">
|
||||
<value>Passwords for {0}</value>
|
||||
</data>
|
||||
<data name="OverwritePasskey" xml:space="preserve">
|
||||
<value>Overwrite passkey?</value>
|
||||
</data>
|
||||
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
|
||||
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
|
||||
</data>
|
||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||
<value>Duo two-step login is required for your account. </value>
|
||||
</data>
|
||||
@@ -2899,4 +2935,87 @@ Do you want to switch to this account?</value>
|
||||
<data name="LaunchDuo" xml:space="preserve">
|
||||
<value>Launch Duo</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredByX" xml:space="preserve">
|
||||
<value>Verification required by {0}</value>
|
||||
</data>
|
||||
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
|
||||
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
|
||||
</data>
|
||||
<data name="ErrorCreatingPasskey" xml:space="preserve">
|
||||
<value>Error creating passkey</value>
|
||||
</data>
|
||||
<data name="ErrorReadingPasskey" xml:space="preserve">
|
||||
<value>Error reading passkey</value>
|
||||
</data>
|
||||
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem creating a passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
|
||||
<value>There was a problem reading your passkey for {0}. Try again later.</value>
|
||||
<comment>The parameter is the RpId</comment>
|
||||
</data>
|
||||
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
|
||||
<value>Verifying identity...</value>
|
||||
</data>
|
||||
<data name="Passwords" xml:space="preserve">
|
||||
<value>Passwords</value>
|
||||
</data>
|
||||
<data name="UnknownAccount" xml:space="preserve">
|
||||
<value>Unknown account</value>
|
||||
</data>
|
||||
<data name="SetUpAutofill" xml:space="preserve">
|
||||
<value>Set up auto-fill</value>
|
||||
</data>
|
||||
<data name="GetInstantAccessToYourPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>Get instant access to your passwords and passkeys!</value>
|
||||
</data>
|
||||
<data name="SetUpAutoFillDescriptionLong" xml:space="preserve">
|
||||
<value>To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings.</value>
|
||||
</data>
|
||||
<data name="FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions" xml:space="preserve">
|
||||
<value>1. Go to your device's Settings > Passwords > Password Options</value>
|
||||
</data>
|
||||
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
|
||||
<value>2. Turn on AutoFill</value>
|
||||
</data>
|
||||
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
|
||||
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault</value>
|
||||
</data>
|
||||
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
|
||||
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
|
||||
<value>Unassigned organisation items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
|
||||
<value>On May 16, 2024, unassigned organisation items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
|
||||
</data>
|
||||
<data name="RemindMeLater" xml:space="preserve">
|
||||
<value>Remind me later</value>
|
||||
</data>
|
||||
<data name="Notice" xml:space="preserve">
|
||||
<value>Notice</value>
|
||||
</data>
|
||||
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
|
||||
<value>Passkeys not supported for this app</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser is not privileged</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
|
||||
<value>Passkey operation failed because browser signature does not match</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because of missing asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
|
||||
<value>Passkey operation failed because app not found in asset links</value>
|
||||
</data>
|
||||
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
|
||||
<value>Passkey operation failed because app could not be verified</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user