1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-10 05:13:31 +00:00

Compare commits

...

88 Commits

Author SHA1 Message Date
Federico Maccaroni
f312e8c4d2 PM-7052 WIP fix theme change on iOS Autofill extension (with ClipLogger activated) 2024-03-26 10:58:09 -03:00
Federico Maccaroni
1b3d5e5eb2 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-25 15:37:46 -03:00
Federico Maccaroni
81fbb91c76 PM-6475 Fix dark theme on iOS Autofill extension (#3114) 2024-03-25 12:18:00 -03:00
Federico Maccaroni
45641aadfe [PM-6798] Fix account switch on autofill (#3106)
* PM-6798 Force state update when opening the Autofill extension

* PM-6798 Fix InitAppIfNeededAsync to be awaited and also ignored Fido2AuthenticatorException from logging them to AppCenter since they don't add much information and we're logging in other places what we need
2024-03-25 12:17:40 -03:00
Federico Maccaroni
27380abd89 PM-6844 Fix passkey creation cipher list empty label on small devices (#3104) 2024-03-25 12:17:27 -03:00
Bitwarden DevOps
9db32ca019 Bumped version to 2024.3.3 (#3113) 2024-03-25 14:20:35 +00:00
Federico Maccaroni
1fd7dd462e Merge branch 'main' into feature/maui-migration-passkeys 2024-03-22 15:42:51 -03:00
Dinis Vieira
f04ff7777a Added specific try catch in Android launchApp to avoid the app crashing when trying to launch app package name that are not installed on the device. (#3092) 2024-03-22 16:31:15 +00:00
github-actions[bot]
64775694e0 Autosync the updated translations (#3105)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-03-22 16:07:23 +00:00
Dinis Vieira
3c0007a21a [PM-7009] Improved exception messages for the Broadcast Service message callback function (#3091)
* Improved exception messages for the Broadcast Service message callback function

* Update src/Core/App.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Additional Null Check

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Additional Null Check

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Additional Null Check

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Additional Null Check

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Update src/Core/App.xaml.cs

Additional Null Check

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-03-22 12:29:12 -03:00
Federico Maccaroni
ff49d041be [PM-6655] Add username empty fallback on passkey (#3101)
* PM-6655 Added fallback "Unknown account" to passkey username and moved it so it can be shared with Android

* PM-6655 Improved code lines formatting
2024-03-21 13:56:37 -03:00
Federico Maccaroni
b931263662 PM-6793 Updated autofill settings copy (#3102) 2024-03-21 13:28:54 -03:00
Federico Maccaroni
3a10e09469 PM-6706 Fixed UV attempts to be maximum 5 attempts and not 6 (#3103) 2024-03-21 13:28:38 -03:00
Federico Maccaroni
ebc068d820 [PM-6848] Improved User verification on passkeys creation (#3099)
* PM-6848 Updated cancellation flow on passkey user verification and improved UV enforcement on creation

* PM-6848 Added null checks to help diagnosing if NRE is presented
2024-03-21 13:28:14 -03:00
Federico Maccaroni
6bec0ede05 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-20 09:02:57 -03:00
Bitwarden DevOps
35ff235010 Bumped version to 2024.3.2 (#3096) 2024-03-19 15:15:29 +00:00
Bitwarden DevOps
01bd5a7b8d Bumped version to 2024.3.1 (#3095) 2024-03-19 14:43:30 +00:00
Vince Grassia
3fce8c76bc Add Cleanup RC Branch workflow (#3093) 2024-03-18 11:36:21 -06:00
github-actions[bot]
3b64d7b979 Autosync the updated translations (#3083)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-03-15 23:31:54 +00:00
Federico Maccaroni
f343a2cdbb [PM-6852 ] Fix F-Droid build constant (#3085)
* Fix FDROID trackers removal by changing publish to build to see if doing this it adds the corresponding CustomConstants

* Changed parameters in new line delimiter to the one used in bash to see if that fixes passing the corresponding parameters to the build

* Revert "Changed parameters in new line delimiter to the one used in bash to see if that fixes passing the corresponding parameters to the build"

This reverts commit 608b23d115.

* Enable FDROID constant by replacing the content of Directory.Build.props in the clean stage of F-Droid
2024-03-15 17:01:15 -03:00
Federico Maccaroni
39da2a82c6 PM-6706 Add maximum attempts to UV with MP and with PIN (#3079) 2024-03-14 18:22:38 -03:00
Federico Maccaroni
970d3c2621 PM-6468 Implemented copy TOTP if needed after using a Fido2 credential. Also added the Fido2MediatorService to have one point to interact with the authentication and also to add any new logic we need. (#3082) 2024-03-14 18:12:50 -03:00
Federico Maccaroni
faa515b415 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-14 18:08:42 -03:00
Federico Maccaroni
74085689d3 PM-6685 Fix race condition issue where the biometrics check is being done before the iOS extension is being shown. So when we need the UI, we wait until ViewDidAppear happens. (#3078) 2024-03-14 18:07:52 -03:00
Vince Grassia
9a9fb85ad8 Add version codes to GitHub step summary (#3081) 2024-03-14 10:06:51 -06:00
Bitwarden DevOps
e7f9d64edb Bumped version to 2024.3.0 (#3080) 2024-03-14 11:10:21 -04:00
Federico Maccaroni
144fc7c727 [PM-5154] Implement combined view for passwords and passkeys on iOS Autofill extension (#3075)
* PM-5154 Implemented combined view of passwords and passkeys and improved search and items UI

* PM-5154 Code improvement from PR feedback

* PM-5154 Code improvement to log unknown exceptions
2024-03-13 12:06:08 -03:00
Federico Maccaroni
53aedea93a Merge branch 'main' into feature/maui-migration-passkeys 2024-03-12 18:13:08 -03:00
Vince Grassia
459d20c019 DEVOPS-1840 - Update for automatic version bump calculation (#3043) 2024-03-12 14:10:11 -06:00
Federico Maccaroni
dd997aaa47 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-12 12:38:52 -03:00
github-actions[bot]
a8529fa4b7 Autosync the updated translations (#3064)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-03-12 08:41:52 +00:00
Dinis Vieira
d1e82c9f1d [PM-6751]Added missing query intent for CustomTabs that might be responsible for the Exception in WebAuthenticator (#3071)
* Added missing query intent for CustomTabs that might be responsible for the crashes in WebAuthenticator

* minor formatting issue on AndroidManifest.xml

* Fix formatting in AndroidManifest
2024-03-11 19:36:07 -03:00
Federico Maccaroni
46c1d72b3c Merge branch 'main' into feature/maui-migration-passkeys 2024-03-11 18:12:27 -03:00
Dinis Vieira
9bc2901255 [PM-6726] Fix for Android 14 devices crashing when using the Tiles (#3069)
* Fix for Android 14 devices crashing when using the TileService.
Also added fix for an "hidden" crash in accessibility autofill

* Shared StartActivityAndCollapseFromTileService in AndroidHelpers

* Update src/App/Platforms/Android/Utilities/AndroidHelpers.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* Updated name of StartActivityAndCollapseWithIntent method name used by TileService

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-03-11 18:06:37 -03:00
Federico Maccaroni
01fe329f3b Merge branch 'main' into feature/maui-migration-passkeys 2024-03-08 14:03:05 -03:00
Federico Maccaroni
67f7b3156e [PM-6496] Improved iOS extensions cipher cell UI (#3058)
* PM-6496 Improved iOS extensions cipher list to have an updated UI for each cell

* PM-6496 Improved UI on iOS extensions list cells
2024-03-08 13:59:15 -03:00
Vince Grassia
e3441845cd DEVOPS-1866 - Fix F-Droid Signing (#3063) 2024-03-07 23:45:15 +00:00
Vince Grassia
3f463647a0 Add login step to be able to download secrets (#3061) 2024-03-07 07:18:32 -08:00
Bitwarden DevOps
4f169a6fe3 Bumped version to 2024.2.2 (#3060) 2024-03-07 15:07:46 +00:00
Vince Grassia
82c2e91446 Update release workflow with proper paths (#3059) 2024-03-07 15:53:27 +01:00
Federico Maccaroni
39187732c0 [PM-6474] Remove header on Save passkey as new login (#3054)
* PM-6474 Removed header on empty list view on iOS Autofill create passkey flow

* PM-6474 Fix TableView being hidden on Logins scene
2024-03-07 11:04:00 -03:00
renovate[bot]
7482808857 [deps]: Update chrnorm/deployment-status action to v2.0.3 (#3050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-06 13:52:31 -05:00
Federico Maccaroni
4292542155 [PM-6466] Implement passkeys User Verification (#3044)
* PM-6441 Implement passkeys User Verification

* PM-6441 Reorganized UserVerificationMediatorService so everything is not in the same file

* PM-6441 Fix Unit tests

* PM-6441 Refactor UserVerification on Fido2Authenticator and Client services to be of an enum type so we can see which specific preference the RP sent and to be passed into the user verification mediator service to perform the correct flow depending on that. Also updated Unit tests.

* PM-6441 Changed user verification logic a bit so if preference is Preferred and the app has the ability to verify the user then enforce required UV and fix issue on on Discouraged to take into account MP reprompt
2024-03-06 12:32:39 -03:00
Federico Maccaroni
e41abf5003 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-06 11:19:18 -03:00
Opeyemi
fd233fa27f Update Failure Job (#3055) 2024-03-06 13:58:41 +01:00
Andreas Coroiu
4c2932f4d0 Fix FIDO2 client bugs (#3056)
* fix: blockedUris null issue

* fix: trailing slash in origin breaking check
2024-03-06 10:58:48 +00:00
Federico Maccaroni
a10481603d Merge branch 'main' into feature/maui-migration-passkeys
# Conflicts:
#	src/iOS.Core/Controllers/LoginAddViewController.cs
2024-03-05 18:23:23 -03:00
Federico Maccaroni
19f238d9bb [PM-6539] Fix Autofill Extension TDE without MP flow (#3049)
* PM-6539 Fix Autofill Extension TDE without MP updating PromptSSO to work in MAUI and also Generator view. WebAuthenticator copied with UIWindow gotten as it was in Xamarin forms to work. Also fix one NRE on state migration.

* PM-6539 Remove unnecessary using
2024-03-05 18:09:20 -03:00
Vince Grassia
6f6487ccc9 Fix GoogleServices file location (#3053) 2024-03-04 08:11:54 -07:00
Federico Maccaroni
b8ff0e0244 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-04 11:03:30 -03:00
Dinis Vieira
dd3dc82595 PM-6552 Added missing using (#3052) 2024-03-04 13:29:22 +00:00
Dinis Vieira
40c80f082d [PM-6552] Fix for Android Window issues when opening Autofill/Accessibility (#3051)
* PM-6552 Removed several of the Window Workarounds for Android. Now always relying on the AndroidNavigationRedirectPage.
AndroidNavigationRedirectPage now more resilient to failure and navigates to HomePage as fallback.

* Update src/Core/Pages/AndroidNavigationRedirectPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-03-04 13:03:09 +00:00
Federico Maccaroni
85755902e1 Merge branch 'main' into feature/maui-migration-passkeys 2024-03-01 17:15:22 -03:00
André Bispo
bca5b95446 [PM-4760] Admin Recovery Permissions prompted to set MP. (#2912)
* [PM-4760] Add force password reset check on sync complete.

* [PM-4760] Log error on exception
2024-03-01 19:43:18 +00:00
Dinis Vieira
602627b5fa PM-6552 Fix for App only showing Home (Login) Page after closed after opening Accessibility Settings (#3047) 2024-03-01 19:17:45 +00:00
github-actions[bot]
6f32afb919 Autosync the updated translations (#3045)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-03-01 12:26:42 +01:00
Daniel James Smith
2ca47a4da4 Update ownership of translations (#3046)
Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2024-03-01 11:10:15 +00:00
Federico Maccaroni
38d3a7ed41 [PM-6513] Omit creating CredentialIdentity if it throws an exception (#3040)
* PM-6513 Omit creating CredentialIdentity if that throws, so it doesn't affect other ciphers. E.g. if a Passkey doesn't have a UserName it will throw here and it shouldn't break replacing all the other identities.

* PM-6513 Added fallback values to passkey username not being set
2024-02-29 11:08:13 -03:00
Dinis Vieira
4ff56ba11e PM-5916 Fix for incorrect fonts in fingerprint phrases (#3042) 2024-02-29 09:57:25 +00:00
Vince Grassia
22d0cc681c Change version to proper value (#3041) 2024-02-28 11:49:30 -07:00
André Bispo
4e0a18cce5 [PM-6506] Fix double execution of command on returnType Go (#3039)
* [PM-6506] Fix double execution of command on returnType Go

* [PM-6506] Hide keyboard on environment page close

* [PM-6506] Task guard

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-02-28 17:49:46 +00:00
Vince Grassia
c9fdfa7a15 DEVOPS-1746 - Update iOS distribution certificate and profiles (#3018) 2024-02-28 09:48:16 -03:00
Vince Grassia
850a7e754a DEVOPS-1834 - Apply fix for signing issue (#3038) 2024-02-27 20:18:24 +00:00
Federico Maccaroni
18fae7ddd8 Merge branch 'main' into feature/maui-migration-passkeys
# Conflicts:
#	Directory.Build.props
2024-02-27 12:46:30 -03:00
Dinis Vieira
67c5f79625 [PM-5917] Fix for send arrow now being touch sensitive to expand collapse (#3036)
* PM-5917 fix for send arrow not being tappable

* Added min width to send icon button so that it has correct spacing like in Android and old Xamarin Forms app.

* Updated min width from previous commit to 25 instead of 20 for more equivalent look to xamarin forms app on iOS
2024-02-26 23:45:59 +00:00
Federico Maccaroni
04e7cfe06d [PM-6428] Implement Legacy Secure Storage (#3027) 2024-02-26 19:25:08 -03:00
Álison Fernandes
d6c2ebe4c2 [PM-6480] Update MAUI to 8.0.7 (#3035)
* Update MAUI to 8.0.7

Updates MAUI to the future SR2 release version.

* Using the released version instead of nightly
2024-02-26 22:24:44 +00:00
Dinis Vieira
2a28294f91 PM-5912 Added default min height and corner radius for iOS buttons. Also removed incorrect style class from one button. (#3031) 2024-02-26 19:23:06 -03:00
Federico Maccaroni
b83473ce3a Merge branch 'main' into feature/maui-migration-passkeys 2024-02-26 15:42:12 -03:00
Dinis Vieira
8584bbaecc PM-6301 Removed IsRefreshing=true in RefreshAsync as it can trigger the RefreshView to trigger the RefreshView command again (#3026) 2024-02-26 17:28:18 +00:00
Dinis Vieira
2f3cded9c5 PM-6309 Fix to ensure the Icon and Icon placeholder visibility states is updated correctly based on website icons visibility choice (#3033) 2024-02-26 17:16:54 +00:00
github-actions[bot]
eff0ea7ce7 Autosync the updated translations (#3025)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-02-26 15:29:26 +00:00
renovate[bot]
6c3a53dd76 [deps]: Update dawidd6/action-download-artifact action to v3.1.2 (#3028)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-26 09:37:03 -05:00
Federico Maccaroni
e34a58e875 [PM-5154] Implement iOS Passkey -> Add login item (#3019)
* PM-5154 Implement iOS passkey add login

* PM-5154 Added Username to Create new login for passkey, for this the param was changed to the Fido2ConfirmNewCredentialParams object so we have access to the proper values. Also added back RpId to the params to have access to it when creating the vault item. Finally added loading to saving the passkey as new login
2024-02-26 09:33:39 -03:00
Federico Maccaroni
9f92fdeb29 Merge branch 'main' into feature/maui-migration-passkeys
# Conflicts:
#	src/Core/Resources/Localization/AppResources.resx
2024-02-23 20:11:27 -03:00
Vince Grassia
cf8d801c55 Add .NET 3.1 to fix Google Publisher project signing (#3024) 2024-02-22 13:45:42 -07:00
Federico Maccaroni
eaa6844742 Update build.yml to go back to net3.1 Publisher (#3023) 2024-02-22 17:01:33 -03:00
Federico Maccaroni
29e2f728e0 Update Publisher.csproj to go back to net 3.1 to see if that fixes the build (#3022) 2024-02-22 16:39:09 -03:00
Andreas Coroiu
c31444dc8b feat: optimize assertion network calls (#3021)
The server only needs to be updated if we have changed the counter. New passkeys that leave their counters at zero can therefore skip this step.
2024-02-22 14:34:10 +01:00
Federico Maccaroni
16e1b60a4d [PM-5154] Implement Passkeys on iOS (#3017)
* [PM-5731] feat: implement get assertion params object

* [PM-5731] feat: add first test

* [PM-5731] feat: add rp mismatch test

* [PM-5731] feat: ask for credentials when found

* [PM-5731] feat: find discoverable credentials

* [PM-5731] feat: add tests for successful UV requests

* [PM-5731] feat: add user does not consent test

* [PM-5731] feat: check for UV when reprompt is active

* [PM-5731] fix: tests a bit, needed some additional "arrange" steps

* [PM-5731] feat: add support for counter

* [PM-5731] feat: implement assertion without signature

* [PM-5732] feat: finish authenticator assertion implementation

note: CryptoFunctionService still needs Sign implemenation

* [PM-5731] chore: minor clean up

* [PM-5731] feat: scaffold make credential

* [PM-5731] feat: start implementing attestation

* [PM-5731] feat: implement credential exclusion

* [PM-5731] feat: add new credential confirmaiton

* [PM-5731] feat: implement credential creation

* [PM-5731] feat: add user verification checks

* [PM-5731] feat: add unknown error handling

* [PM-5731] chore: clean up unusued params

* [PM-5731] feat: partial attestation implementation

* [PM-5731] feat: implement key generation

* [PM-5731] feat: return public key in DER format

* [PM-5731] feat: implement signing

* [PM-5731] feat: remove logging

* [PM-5731] chore: use primary constructor

* [PM-5731] chore: add Async to method names

* [PM-5731] feat: add support for silent discoverability

* [PM-5731] feat: add support for specifying user presence requirement

* [PM-5731] feat: ensure unlocked vault

* [PM-5731] chore: clean up and refactor assertion tests

* [PM-5731] chore: clean up and refactor attestation tests

* [PM-5731] chore: add user presence todo comment

* [PM-5731] feat: scaffold fido2 client

* PM-5731 Fix build updating discoverable flag

* [PM-5731] fix: failing test

* [PM-5731] feat: add sameOriginWithAncestor and user id length checks

* [PM-5731] feat: add incomplete rpId verification

* [PM-5731] chore: document uri helpers

* [PM-5731] feat: implement fido2 client createCredential

* Added iOS passkeys integration, warning this branch has lots of logs to ease "debugging" extensions.

* [PM-5731] feat: implement credential assertion in client

* PM-5154 Fixed select passkey flow and started implementing create passkey on iOS

* fix wrong signature format

* PM-5154 [Passkeys iOS] Fix Credential ID handling on bytes and string formats. Fix Discoverable to be lowercase on set so it doesn't break parsing on clients. Added UserDisplayName on Fido2 entities. Extracted the Guid Standard/Raw format helpers to a extensions class.

* Fix incompatible GUID conversions

* PM-5154 [Passkeys iOS] Added custom UI flow for passkey creation

* PM-5154 [Passkeys iOS] Updated UI for passkey creation

* PM-5154 [Passkeys iOS] Refactored and added cipher selection for passkey creation on autofill search.

* PM-5154 [Passkeys iOS] Fixed empty top space on autofill password list

---------

Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com>
Co-authored-by: mpbw2 <59324545+mpbw2@users.noreply.github.com>
2024-02-21 14:51:44 -03:00
Opeyemi
fe160a570f Add stub for DEVOPS-1822 (#3016) 2024-02-21 15:27:43 +00:00
Andreas Coroiu
71de3bedf4 [PM-5731] Create C# WebAuthn authenticator to support maui apps (#2951)
* [PM-5731] feat: implement get assertion params object

* [PM-5731] feat: add first test

* [PM-5731] feat: add rp mismatch test

* [PM-5731] feat: ask for credentials when found

* [PM-5731] feat: find discoverable credentials

* [PM-5731] feat: add tests for successful UV requests

* [PM-5731] feat: add user does not consent test

* [PM-5731] feat: check for UV when reprompt is active

* [PM-5731] fix: tests a bit, needed some additional "arrange" steps

* [PM-5731] feat: add support for counter

* [PM-5731] feat: implement assertion without signature

* [PM-5732] feat: finish authenticator assertion implementation

note: CryptoFunctionService still needs Sign implemenation

* [PM-5731] chore: minor clean up

* [PM-5731] feat: scaffold make credential

* [PM-5731] feat: start implementing attestation

* [PM-5731] feat: implement credential exclusion

* [PM-5731] feat: add new credential confirmaiton

* [PM-5731] feat: implement credential creation

* [PM-5731] feat: add user verification checks

* [PM-5731] feat: add unknown error handling

* [PM-5731] chore: clean up unusued params

* [PM-5731] feat: partial attestation implementation

* [PM-5731] feat: implement key generation

* [PM-5731] feat: return public key in DER format

* [PM-5731] feat: implement signing

* [PM-5731] feat: remove logging

* [PM-5731] chore: use primary constructor

* [PM-5731] chore: add Async to method names

* [PM-5731] feat: add support for silent discoverability

* [PM-5731] feat: add support for specifying user presence requirement

* [PM-5731] feat: ensure unlocked vault

* [PM-5731] chore: clean up and refactor assertion tests

* [PM-5731] chore: clean up and refactor attestation tests

* [PM-5731] chore: add user presence todo comment

* [PM-5731] feat: scaffold fido2 client

* PM-5731 Fix build updating discoverable flag

* [PM-5731] fix: failing test

* [PM-5731] feat: add sameOriginWithAncestor and user id length checks

* [PM-5731] feat: add incomplete rpId verification

* [PM-5731] chore: document uri helpers

* [PM-5731] feat: implement fido2 client createCredential

* [PM-5731] feat: implement credential assertion in client

* fix wrong signature format

(cherry picked from commit a1c9ebf01f)

* [PM-5731] fix: issues after cherry-pick

* Fix incompatible GUID conversions

(cherry picked from commit c801b2fc3a)

* [PM-5731] chore: remove default constructor

* [PM-5731] feat: refactor user interface to increase flexibility

* [PM-5731] feat: implement generic assertion user interface class

* [PM-5731] feat: remove ability to make user presence optional

* [PM-5731] chore: remove logging comments

* [PM-5731] feat: add native reprompt support to the authenticator

* [PM-5731] feat: allow pre and post UV

* [PM-5731] chore: add `Async` to method name. Remove `I` from struct

* [PM-5731] fix: discoverable string repr lowercase

* [PM-5731] chore: don't use C# 12 features

* [PM-5731] fix: replace magic strings and numbers with contants and enums

* [PM-5731] fix: use UTC creation date

* [PM-5731] fix: formatting

* [PM-5731] chore: use properties for public fields

* [PM-5731] chore: remove TODO

* [PM-5731] fix: IsValidRpId

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
Co-authored-by: mpbw2 <59324545+mpbw2@users.noreply.github.com>
2024-02-21 12:12:52 -03:00
Dinis Vieira
a508bea4b0 [PM-6291] Fix Device Login Pending Requests screen not displaying anything (#3012)
* PM-6291 Changed Passwordless Request Login Page Layout structure so that it can display properly

* PM-6291 Additional changes to allow iOS to show the correct with on the collectionview items
2024-02-21 10:55:26 +00:00
Dinis Vieira
a73923c4f7 [PM-5909] Fix Font MAUI Sizes (#3014)
* PM-5909 Set the default FontSize for Entry, Editor, SearchBar and Picker on Android so that the fonts have a similar size to the one in the Xamarin Forms app.

* PM-5909 Set the default FontSize for Entry, Editor, SearchBar and Picker on iOS so that the fonts have a similar size to the one in the Xamarin Forms app.

* PM-5909 Added spacing in specific scenario for Send Groups (between icon and text)
2024-02-20 22:06:47 +00:00
renovate[bot]
11465e8975 [deps]: Update gh minor (#3011)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-20 16:01:34 -05:00
André Bispo
4c88524f0e [PM-4615] [PM-6217] Add new DUO frameless 2fa flow (#2956)
* [PM-4615] Update DUO 2FA screen to support DUO frameless flow.
2024-02-20 18:46:47 +00:00
Opeyemi
f1c20e03bc Remove individual linter file (#3010) 2024-02-15 11:15:13 -05:00
github-actions[bot]
920a2273c5 Autosync Crowdin Translations (#3009)
* Autosync the updated translations

* Add whitespace to build.yml to trigger workflow linter

* Remove whitespace from build.yml

---------

Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2024-02-15 12:52:13 -03:00
267 changed files with 10324 additions and 1537 deletions

6
.github/CODEOWNERS vendored
View File

@@ -30,14 +30,14 @@ src/watchOS @bitwarden/team-vault-dev
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
## Crowdin Sync files ## ## Crowdin Sync files ##
src/App/Resources @bitwarden/team-tools-dev src/Core/Resources/Localization @bitwarden/team-tools-dev
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev
store/apple @bitwarden/team-tools-dev store/apple @bitwarden/team-tools-dev
store/google @bitwarden/team-tools-dev store/google @bitwarden/team-tools-dev
## Locales ## ## Locales ##
src/App/Resources/AppResources.Designer.cs src/Core/Resources/Localization/AppResources.Designer.cs
src/App/Resources/AppResources.resx src/Core/Resources/Localization/AppResources.resx
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj
store/apple/en store/apple/en
store/google/en store/google/en

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +0,0 @@
<EFBFBD>
 K<>Y#<23>(<28><><EFBFBD><EFBFBD>EI֐߄T?)l<><6C><EFBFBD><18><><10>"=<3D>|<7C>'e<><0E>m<EFBFBD>/~<7E><>' F<><46>><3E><><EFBFBD><EFBFBD>l<EFBFBD>b<EFBFBD>[<5B>+R<><52>iL<69><4C>"<22><><EFBFBD>~V:<3A><>p<EFBFBD>a<17>ڵel%8t<38><74><EFBFBD>y<<3C>n<EFBFBD><6E><EFBFBD>aU<61>w<16>JD<4A><44><1F><>We<57>9<EFBFBD><39><EFBFBD><EFBFBD><x8d<38>O<EFBFBD>j\<14>ד<EFBFBD><D793><EFBFBD>Vq<56><71>֋
Ǻ<EFBFBD>-<2D>#<23><><11><>]$<24>(<28>l,<2C>Br<42><02><>d<><64><EFBFBD>•a-<2D><><EFBFBD>:<3A><>:<3A><04>9b,!Em<02><19><>Qf<>D<EFBFBD>g<EFBFBD><06><0E>x(P<>ȡ~<7E>͹<EFBFBD><CDB9> <09><>[<06><>!:<3A>;f<><66>

Binary file not shown.

Binary file not shown.

Binary file not shown.

5
.github/workflows/build-beta.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
---
name: Build Beta
on:
workflow_dispatch:

View File

@@ -31,6 +31,7 @@ jobs:
- name: Print lines of code - name: Print lines of code
run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML
setup: setup:
name: Setup name: Setup
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
@@ -58,6 +59,7 @@ jobs:
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
fi fi
android: android:
name: Android name: Android
runs-on: windows-2022 runs-on: windows-2022
@@ -67,7 +69,8 @@ jobs:
matrix: matrix:
variant: ["prod", "qa"] variant: ["prod", "qa"]
env: env:
android_folder_path: src/App/Platforms/Android android_folder_path: src\App\Platforms\Android
android_folder_path_bash: src/App/Platforms/Android
steps: steps:
- name: Setup NuGet - name: Setup NuGet
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0 uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
@@ -93,7 +96,8 @@ jobs:
- name: Install Microsoft OpenJDK 11 - name: Install Microsoft OpenJDK 11
run: | run: |
choco install microsoft-openjdk11 --no-progress choco install microsoft-openjdk11 --no-progress
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | `
Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Output "Java Home: $env:JAVA_HOME" Write-Output "Java Home: $env:JAVA_HOME"
- name: Print environment - name: Print environment
@@ -109,39 +113,43 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Decrypt secrets - name: Login to Azure - CI Subscription
env: uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} with:
run: | creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
mkdir -p ~/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ - name: Download secrets
--output ./${{ env.main_app_folder_path }}/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg env:
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ ACCOUNT_NAME: bitwardenci
--output ./${{ env.main_app_folder_path }}/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg CONTAINER_NAME: mobile
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ run: |
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg mkdir -p $HOME/secrets
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
--name app_play-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_play-keystore.jks --output none
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
--name app_upload-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_upload-keystore.jks --output none
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
--name play_creds.json --file $HOME/secrets/play_creds.json --output none
shell: bash shell: bash
- name: Decrypt secrets - Google Services - name: Download secrets - Google Services
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
env: env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} ACCOUNT_NAME: bitwardenci
CONTAINER_NAME: mobile
run: | run: |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
--output ./${{ env.android_folder_path }}/google-services.json ./.github/secrets/google-services.json.gpg --name google-services.json --file ./${{ env.android_folder_path_bash }}/google-services.json --output none
shell: bash shell: bash
- name: Increment version - name: Increment version
run: | run: |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER)) BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
echo "########################################"
echo "##### Setting Version Code $BUILD_NUMBER"
echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./${{ env.android_folder_path }}/AndroidManifest.xml ./${{ env.android_folder_path_bash }}/AndroidManifest.xml
shell: bash shell: bash
- name: Restore packages - name: Restore packages
@@ -150,78 +158,70 @@ jobs:
- name: Restore tools - name: Restore tools
run: dotnet tool restore run: dotnet tool restore
# - name: Verify Format # - name: Run Core tests
# run: dotnet tool run dotnet-format --check # run: |
# dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" `
# /p:CustomConstants=UT
- name: Run Core tests # - name: Report test results
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" /p:CustomConstants=UT # uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0
# if: always()
- name: Report test results # with:
uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0 # name: Test Results
if: always() # path: "**/test-results.trx"
with: # reporter: dotnet-trx
name: Test Results # fail-on-error: true
path: "**/test-results.trx"
reporter: dotnet-trx
fail-on-error: true
- name: Build Play Store publisher - name: Build Play Store publisher
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
run: dotnet build ./store/google/Publisher/Publisher.csproj -p:Configuration=Release run: dotnet build .\store\google\Publisher\Publisher.csproj /p:Configuration=Release
- name: Setup Android build (${{ matrix.variant }}) - name: Setup Android build (${{ matrix.variant }})
run: dotnet cake build.cake --target Android --variant ${{ matrix.variant }} run: dotnet cake build.cake --target Android --variant ${{ matrix.variant }}
- name: Build Android - name: Build & Sign Android
run: |
$configuration = "Release";
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
Write-Output "########################################"
Write-Output "##### Build $configuration Configuration"
Write-Output "########################################"
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android
- name: Sign Android Build
env: env:
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }} PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }}
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }} UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
run: | run: |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); $projToBuild = "$($env:GITHUB_WORKSPACE)/${{ env.main_app_project_path }}";
$packageName = "com.x8bit.bitwarden"; $packageName = "com.x8bit.bitwarden";
if ("${{ matrix.variant }}" -ne "prod") if ("${{ matrix.variant }}" -ne "prod")
{ {
$packageName = "com.x8bit.bitwarden.${{ matrix.variant }}"; $packageName = "com.x8bit.bitwarden.${{ matrix.variant }}";
} }
Write-Output "########################################"
Write-Output "##### Sign Google Play Bundle Release Configuration" Write-Output "##### Sign Google Play Bundle Release Configuration"
Write-Output "########################################"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidPackageFormats=aab /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_upload-keystore.jks") /p:AndroidSigningKeyAlias=upload /p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore $signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_upload-keystore.jks"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
/p:AndroidPackageFormats=aab `
/p:AndroidKeyStore=true `
/p:AndroidSigningKeyStore=$signingUploadKeyStore `
/p:AndroidSigningKeyAlias=upload `
/p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" `
/p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Google Play Bundle to project root" Write-Output "##### Copy Google Play Bundle to project root"
Write-Output "########################################"
$signedAabPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.aab"); $signedAabPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\publish\$($packageName)-Signed.aab";
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab"); $signedAabDestPath = "$($env:GITHUB_WORKSPACE)\$($packageName).aab";
Copy-Item $signedAabPath $signedAabDestPath Copy-Item $signedAabPath $signedAabDestPath
Write-Output "########################################"
Write-Output "##### Sign APK Release Configuration" Write-Output "##### Sign APK Release Configuration"
Write-Output "########################################"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_play-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore $signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_play-keystore.jks"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
/p:AndroidKeyStore=true `
/p:AndroidSigningKeyStore=$signingPlayKeyStore `
/p:AndroidSigningKeyAlias=bitwarden `
/p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" `
/p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Release APK to project root" Write-Output "##### Copy Release APK to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk");
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).apk");
$signedApkPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\publish\$($packageName)-Signed.apk";
$signedApkDestPath = "$($env:GITHUB_WORKSPACE)\$($packageName).apk";
Copy-Item $signedApkPath $signedApkDestPath Copy-Item $signedApkPath $signedApkDestPath
- name: Upload Prod .aab artifact - name: Upload Prod .aab artifact
@@ -283,20 +283,20 @@ jobs:
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) || (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc' ) }} || github.ref == 'refs/heads/hotfix-rc' ) }}
run: | run: |
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/net7.0/Publisher.dll" $publisherPath = "$($env:GITHUB_WORKSPACE)\store\google\Publisher\bin\Release\net8.0\Publisher.dll"
CREDS_PATH="$HOME/secrets/play_creds.json" $credsPath = "$($HOME)\secrets\play_creds.json"
AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab" $aabPath = "$($env:GITHUB_WORKSPACE)\com.x8bit.bitwarden.aab"
TRACK="internal" $track = "internal"
dotnet $PUBLISHER_PATH $CREDS_PATH $AAB_PATH $TRACK dotnet $publisherPath $credsPath $aabPath $track
shell: bash
f-droid: f-droid:
name: F-Droid Build name: F-Droid Build
runs-on: windows-2022 runs-on: windows-2022
env: env:
android_folder_path: src/App/Platforms/Android android_folder_path: src\App\Platforms\Android
android_folder_path_bash: src/App/Platforms/Android
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
steps: steps:
- name: Setup NuGet - name: Setup NuGet
@@ -337,23 +337,25 @@ jobs:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Decrypt secrets - name: Login to Azure - CI Subscription
env: uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} with:
run: | creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
mkdir -p ~/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ - name: Download secrets
--output ./${{ env.main_app_folder_path }}/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg env:
ACCOUNT_NAME: bitwardenci
CONTAINER_NAME: mobile
FILE: app_fdroid-keystore.jks
run: |
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
--file ${{ env.android_folder_path_bash }}/$FILE --output none
shell: bash shell: bash
- name: Increment version - name: Increment version
run: | run: |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER)) BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
echo "########################################"
echo "##### Setting Version Code $BUILD_NUMBER"
echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./${{ env.android_manifest_path }} ./${{ env.android_manifest_path }}
@@ -361,21 +363,16 @@ jobs:
- name: Clean for F-Droid - name: Clean for F-Droid
run: | run: |
$appPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); $directoryBuildProps = $($env:GITHUB_WORKSPACE + "/Directory.Build.props");
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj");
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}"); $androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}");
Write-Output "########################################" Write-Output "##### Back up project files"
Write-Output "##### Backup project files"
Write-Output "########################################"
Copy-Item $androidManifest $($androidManifest + ".original"); Copy-Item $androidManifest $($androidManifest + ".original");
Copy-Item $appPath $($appPath + ".original"); Copy-Item $directoryBuildProps $($directoryBuildProps + ".original");
Write-Output "########################################"
Write-Output "##### Cleanup Android Manifest" Write-Output "##### Cleanup Android Manifest"
Write-Output "########################################"
$xml=New-Object XML; $xml=New-Object XML;
$xml.Load($androidManifest); $xml.Load($androidManifest);
@@ -385,39 +382,34 @@ jobs:
$xml.Save($androidManifest); $xml.Save($androidManifest);
Write-Output "##### Enabling FDROID constant"
(Get-Content $directoryBuildProps).Replace('<!-- <CustomConstants>FDROID</CustomConstants> -->', '<CustomConstants>FDROID</CustomConstants>') | Set-Content $directoryBuildProps
- name: Restore packages - name: Restore packages
run: dotnet restore run: dotnet restore
- name: Build for F-Droid - name: Build & Sign F-Droid
run: |
$configuration = "Release";
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
Write-Output "########################################"
Write-Output "##### Build $configuration FDROID
Write-Output "########################################"
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android /p:CustomConstants="FDROID"
- name: Sign for F-Droid
env: env:
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }} FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
run: | run: |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); $projToBuild = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_project_path }}";
$packageName = "com.x8bit.bitwarden"; $packageName = "com.x8bit.bitwarden";
Write-Output "########################################"
Write-Output "##### Sign FDroid" Write-Output "##### Sign FDroid"
Write-Output "########################################"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:CustomConstants="FDROID" --no-restore $signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_fdroid-keystore.jks"
dotnet build $projToBuild -c Release -f ${{ env.target-net-version }}-android `
/p:AndroidKeyStore=true `
/p:AndroidSigningKeyStore=$signingFdroidKeyStore `
/p:AndroidSigningKeyAlias=bitwarden `
/p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" `
/p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" ` --no-restore
Write-Output "########################################"
Write-Output "##### Copy FDroid apk to project root" Write-Output "##### Copy FDroid apk to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk"); $signedApkPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\$($packageName)-Signed.apk";
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk"); $signedApkDestPath = "$($env:GITHUB_WORKSPACE)\com.x8bit.bitwarden-fdroid.apk";
Copy-Item $signedApkPath $signedApkDestPath Copy-Item $signedApkPath $signedApkDestPath
@@ -440,6 +432,7 @@ jobs:
path: ./bw-fdroid-apk-sha256.txt path: ./bw-fdroid-apk-sha256.txt
if-no-files-found: error if-no-files-found: error
ios: ios:
name: Apple iOS name: Apple iOS
runs-on: macos-13 runs-on: macos-13
@@ -493,43 +486,41 @@ jobs:
keyvault: "bitwarden-ci" keyvault: "bitwarden-ci"
secrets: "appcenter-ios-token" secrets: "appcenter-ios-token"
- name: Decrypt secrets - name: Download Provisioning Profiles secrets
env: env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} ACCOUNT_NAME: bitwardenci
CONTAINER_NAME: profiles
run: | run: |
mkdir -p ~/secrets mkdir -p $HOME/secrets
profiles=(
"dist_autofill.mobileprovision"
"dist_bitwarden.mobileprovision"
"dist_extension.mobileprovision"
"dist_share_extension.mobileprovision"
"dist_bitwarden_watch_app.mobileprovision"
"dist_bitwarden_watch_app_extension.mobileprovision"
)
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ for FILE in "${profiles[@]}"
--output $HOME/secrets/bitwarden-mobile-key.p12 ./.github/secrets/bitwarden-mobile-key.p12.gpg do
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
--output $HOME/secrets/iphone-distribution-cert.p12 ./.github/secrets/iphone-distribution-cert.p12.gpg --file $HOME/secrets/$FILE --output none
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ done
--output $HOME/secrets/dist_autofill.mobileprovision ./.github/secrets/dist_autofill.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ - name: Download Google Services secret
--output $HOME/secrets/dist_bitwarden.mobileprovision ./.github/secrets/dist_bitwarden.mobileprovision.gpg env:
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ ACCOUNT_NAME: bitwardenci
--output $HOME/secrets/dist_extension.mobileprovision ./.github/secrets/dist_extension.mobileprovision.gpg CONTAINER_NAME: mobile
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ FILE: GoogleService-Info.plist
--output $HOME/secrets/dist_share_extension.mobileprovision \ run: |
./.github/secrets/dist_share_extension.mobileprovision.gpg mkdir -p $HOME/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
--output $HOME/secrets/dist_watch_app.mobileprovision \ --file src/watchOS/bitwarden/$FILE --output none
./.github/secrets/dist_watch_app.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/dist_watch_app_extension.mobileprovision \
./.github/secrets/dist_watch_app_extension.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/watchOS/bitwarden/GoogleService-Info.plist ./.github/secrets/GoogleService-Info.plist.gpg
- name: Increment version - name: Increment version
run: | run: |
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER)) BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
echo "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
echo "########################################"
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
echo "########################################"
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>/' ./${{ 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.Extension/Info.plist
@@ -540,26 +531,26 @@ jobs:
- name: Update Entitlements - name: Update Entitlements
run: | run: |
echo "########################################"
echo "##### Updating Entitlements" echo "##### Updating Entitlements"
echo "########################################"
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/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 - name: Set up Keychain
env: env:
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }}
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
run: | run: |
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
security default-keychain -s build.keychain security default-keychain -s build.keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
security set-keychain-settings -lut 1200 build.keychain security set-keychain-settings -lut 1200 build.keychain
security import ~/secrets/bitwarden-mobile-key.p12 -k build.keychain -P $MOBILE_KEY_PASSWORD \
-T /usr/bin/codesign -T /usr/bin/security security import $HOME/certificates/ios-distribution.p12 -k build.keychain -P "" -T /usr/bin/codesign \
security import ~/secrets/iphone-distribution-cert.p12 -k build.keychain -P $DIST_CERT_PASSWORD \ -T /usr/bin/security
-T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
- name: Set up provisioning profiles - name: Set up provisioning profiles
@@ -568,8 +559,8 @@ jobs:
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_watch_app.mobileprovision WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app.mobileprovision
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_watch_app_extension.mobileprovision WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app_extension.mobileprovision
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
mkdir -p "$PROFILES_DIR_PATH" mkdir -p "$PROFILES_DIR_PATH"
@@ -597,68 +588,44 @@ jobs:
- name: Bulid WatchApp - name: Bulid WatchApp
run: | run: |
echo "########################################"
echo "##### Build WatchApp with Release Configuration" echo "##### Build WatchApp with Release Configuration"
echo "########################################"
xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden
echo "########################################"
echo "##### Done"
echo "########################################"
- name: Archive Build for App Store - name: Archive Build for App Store
run: | run: |
Write-Output "########################################" echo "##### Archive for Release ios-arm64"
Write-Output "##### Archive for Release ios-arm64
Write-Output "########################################"
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 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 "########################################"
Write-Output "##### Done"
Write-Output "########################################"
shell: pwsh
- name: Archive Build for Mobile Automation - name: Archive Build for Mobile Automation
run: | run: |
Write-Output "########################################" echo "##### Archive Debug for iossimulator-x64"
Write-Output "##### Archive Debug for iossimulator-x64
Write-Output "########################################"
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 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
ls $HOME/Library/Developer/Xcode/Archives
Write-Output "########################################"
Write-Output "##### Done"
Write-Output "########################################"
ls ~/Library/Developer/Xcode/Archives
shell: pwsh
- name: Export .ipa for App Store - name: Export .ipa for App Store
env:
EXPORT_OPTIONS_PATH: ./.github/resources/export-options-app-store.plist
EXPORT_PATH: ./bitwarden-export
run: | run: |
EXPORT_OPTIONS_PATH="./.github/resources/export-options-app-store.plist"
ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive" ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive"
EXPORT_PATH="./bitwarden-export"
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \ xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \
-exportOptionsPlist $EXPORT_OPTIONS_PATH -exportOptionsPlist $EXPORT_OPTIONS_PATH
- name: Export .app for Automation CI - 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: | run: |
ARCHIVE_PATH="./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64"
EXPORT_PATH="./bitwarden-export"
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
- name: Copy all dSYMs files to upload - 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: | run: |
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs" ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
EXPORT_PATH="./bitwarden-export"
WATCH_ARCHIVE_DSYMS_PATH="./src/watchOS/bitwarden.xcarchive/dSYMs/"
WATCH_DSYMS_EXPORT_PATH="$EXPORT_PATH/Watch_dSYMs"
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH
mkdir $WATCH_DSYMS_EXPORT_PATH mkdir $WATCH_DSYMS_EXPORT_PATH
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
@@ -707,10 +674,7 @@ jobs:
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) || (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc' || github.ref == 'refs/heads/hotfix-rc'
run: | run: |
echo "########################################"
echo "##### Uploading Watch dSYMs to Firebase" echo "##### Uploading Watch dSYMs to Firebase"
echo "########################################"
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" \; 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 - name: Validate app in App Store
@@ -726,7 +690,6 @@ jobs:
run: | run: |
xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \ xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD" --username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
shell: bash
- name: Deploy to App Store - name: Deploy to App Store
if: | if: |
@@ -770,7 +733,7 @@ jobs:
secrets: "crowdin-api-token" secrets: "crowdin-api-token"
- name: Upload Sources - name: Upload Sources
uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
@@ -794,27 +757,11 @@ jobs:
steps: steps:
- name: Check if any job failed - name: Check if any job failed
if: | if: |
(github.ref == 'refs/heads/main') (github.ref == 'refs/heads/main'
|| (github.ref == 'refs/heads/rc') || github.ref == 'refs/heads/rc'
|| (github.ref == 'refs/heads/hotfix-rc') || github.ref == 'refs/heads/hotfix-rc')
env: && contains(needs.*.result, 'failure')
CLOC_STATUS: ${{ needs.cloc.result }} run: exit 1
ANDROID_STATUS: ${{ needs.android.result }}
F_DROID_STATUS: ${{ needs.f-droid.result }}
IOS_STATUS: ${{ needs.ios.result }}
CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }}
run: |
if [ "$CLOC_STATUS" = "failure" ]; then
exit 1
elif [ "$ANDROID_STATUS" = "failure" ]; then
exit 1
elif [ "$F_DROID_STATUS" = "failure" ]; then
exit 1
elif [ "$IOS_STATUS" = "failure" ]; then
exit 1
elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then
exit 1
fi
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0

53
.github/workflows/cleanup-rc-branch.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
---
name: Cleanup RC Branch
on:
push:
tags:
- v**
jobs:
delete-rc:
name: Delete RC Branch
runs-on: ubuntu-22.04
steps:
- name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve bot secrets
id: retrieve-bot-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: bitwarden-ci
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: Checkout main
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: main
token: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
- name: Check if a RC branch exists
id: branch-check
run: |
hotfix_rc_branch_check=$(git ls-remote --heads origin hotfix-rc | wc -l)
rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
if [[ "${hotfix_rc_branch_check}" -gt 0 ]]; then
echo "hotfix-rc branch exists." | tee -a $GITHUB_STEP_SUMMARY
echo "name=hotfix-rc" >> $GITHUB_OUTPUT
elif [[ "${rc_branch_check}" -gt 0 ]]; then
echo "rc branch exists." | tee -a $GITHUB_STEP_SUMMARY
echo "name=rc" >> $GITHUB_OUTPUT
fi
- name: Delete RC branch
env:
BRANCH_NAME: ${{ steps.branch-check.outputs.name }}
run: |
if ! [[ -z "$BRANCH_NAME" ]]; then
git push --quiet origin --delete $BRANCH_NAME
echo "Deleted $BRANCH_NAME branch." | tee -a $GITHUB_STEP_SUMMARY
fi

View File

@@ -30,7 +30,7 @@ jobs:
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase" secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
- name: Download translations - name: Download translations
uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}

View File

@@ -28,7 +28,7 @@ jobs:
branch-name: ${{ steps.branch.outputs.branch-name }} branch-name: ${{ steps.branch.outputs.branch-name }}
steps: steps:
- name: Branch check - name: Branch check
if: github.event.inputs.release_type != 'Dry Run' if: inputs.release_type != 'Dry Run'
run: | run: |
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
echo "===================================" echo "==================================="
@@ -44,9 +44,9 @@ jobs:
id: version id: version
uses: bitwarden/gh-actions/release-version-check@main uses: bitwarden/gh-actions/release-version-check@main
with: with:
release-type: ${{ github.event.inputs.release_type }} release-type: ${{ inputs.release_type }}
project-type: xamarin project-type: xamarin
file: src/Android/Properties/AndroidManifest.xml file: src/App/Platforms/Android/AndroidManifest.xml
- name: Get branch name - name: Get branch name
id: branch id: branch
@@ -55,7 +55,7 @@ jobs:
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
- name: Create GitHub deployment - name: Create GitHub deployment
if: ${{ github.event.inputs.release_type != 'Dry Run' }} if: ${{ inputs.release_type != 'Dry Run' }}
uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7 uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7
id: deployment id: deployment
with: with:
@@ -67,16 +67,16 @@ jobs:
- name: Download all artifacts - name: Download all artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }} if: ${{ inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
branch: ${{ steps.branch.outputs.branch-name }} branch: ${{ steps.branch.outputs.branch-name }}
- name: Dry Run - Download all artifacts - name: Dry Run - Download all artifacts
if: ${{ github.event.inputs.release_type == 'Dry Run' }} if: ${{ inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -86,7 +86,7 @@ jobs:
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release - name: Create release
if: ${{ github.event.inputs.release_type != 'Dry Run' }} if: ${{ inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0 uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
with: with:
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab, artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
@@ -103,16 +103,16 @@ jobs:
draft: true draft: true
- name: Update deployment status to Success - name: Update deployment status to Success
if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }} if: ${{ inputs.release_type != 'Dry Run' && success() }}
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3
with: with:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
state: 'success' state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }} deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure - name: Update deployment status to Failure
if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }} if: ${{ inputs.release_type != 'Dry Run' && failure() }}
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3
with: with:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure' state: 'failure'
@@ -129,8 +129,8 @@ jobs:
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Download F-Droid .apk artifact - name: Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type != 'Dry Run' }} if: ${{ inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -138,8 +138,8 @@ jobs:
name: com.x8bit.bitwarden-fdroid.apk name: com.x8bit.bitwarden-fdroid.apk
- name: Dry Run - Download F-Droid .apk artifact - name: Dry Run - Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type == 'Dry Run' }} if: ${{ inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -176,13 +176,19 @@ jobs:
- name: Install Node dependencies - name: Install Node dependencies
run: npm install run: npm install
- name: Decrypt secrets - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Download secrets
env: env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} ACCOUNT_NAME: bitwardenci
CONTAINER_NAME: mobile
run: | run: |
mkdir -p ~/secrets mkdir -p $HOME/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
--output ./store/fdroid/keystore.jks ./.github/secrets/store_fdroid-keystore.jks.gpg --name store_fdroid-keystore.jks --file ./store/fdroid/keystore.jks --output none
- name: Compile for F-Droid Store - name: Compile for F-Droid Store
env: env:
@@ -211,5 +217,5 @@ jobs:
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE
- name: Deploy to gh-pages - name: Deploy to gh-pages
if: ${{ github.event.inputs.release_type != 'Dry Run' }} if: ${{ inputs.release_type != 'Dry Run' }}
run: npm run deploy run: npm run deploy

View File

@@ -11,24 +11,6 @@ jobs:
name: Bump Mobile Version name: Bump Mobile Version
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Calculate bumped version
id: version
env:
RELEASE_TAG: ${{ github.ref }}
run: |
CURR_MAJOR=$(echo $RELEASE_TAG | sed -r 's/refs\/tags\/v([0-9]{4}\.[0-9]{1,2})\.([0-9]{1,2})/\1/')
CURR_PATCH=$(echo $RELEASE_TAG | sed -r 's/refs\/tags\/v([0-9]{4}\.[0-9]{1,2})\.([0-9]{1,2})/\2/')
echo "Current Major: $CURR_MAJOR"
echo "Current Patch: $CURR_PATCH"
NEW_PATCH=$((CURR_PATCH+1))
NEW_VER=$CURR_MAJOR.$NEW_PATCH
echo "New Version: $NEW_VER"
echo "new_version=$NEW_VER" >> $GITHUB_OUTPUT
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with: with:
@@ -41,9 +23,9 @@ jobs:
keyvault: bitwarden-ci keyvault: bitwarden-ci
secrets: "github-pat-bitwarden-devops-bot-repo-scope" secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: "Bump version to ${{ steps.version.outputs.new_version }}" - name: Trigger Version Bump workflow
env: env:
GH_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }} GH_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
run: | run: |
echo '{"cut_rc_branch": "false", "version_number": "${{ steps.version.outputs.new_version }}"}' | \ echo '{"cut_rc_branch": "false"}' | \
gh workflow run version-bump.yml --json --repo bitwarden/mobile gh workflow run version-bump.yml --json --repo bitwarden/mobile

View File

@@ -1,13 +1,13 @@
--- ---
name: Version Bump name: Version Bump
run-name: Version Bump - v${{ inputs.version_number }}
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
version_number: version_number_override:
description: "New version (example: '2024.1.0')" description: "New version override (leave blank for automatic calculation, example: '2024.1.0')"
required: true required: false
type: string
cut_rc_branch: cut_rc_branch:
description: "Cut RC branch?" description: "Cut RC branch?"
default: true default: true
@@ -15,22 +15,16 @@ on:
jobs: jobs:
bump_version: bump_version:
name: "Bump Version to v${{ inputs.version_number }}" name: Bump Version
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
outputs:
version: ${{ steps.set-final-version-output.outputs.version }}
steps: steps:
- name: Login to Azure - CI Subscription - name: Validate version input
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 if: ${{ inputs.version_number_override != '' }}
uses: bitwarden/gh-actions/version-check@main
with: with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} version: ${{ inputs.version_number_override }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: "bitwarden-ci"
secrets: "github-gpg-private-key,
github-gpg-private-key-passphrase,
github-pat-bitwarden-devops-bot-repo-scope"
- name: Checkout Branch - name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
@@ -47,6 +41,20 @@ jobs:
exit 1 exit 1
fi fi
- 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: "github-gpg-private-key,
github-gpg-private-key-passphrase,
github-pat-bitwarden-devops-bot-repo-scope"
- name: Import GPG key - name: Import GPG key
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
with: with:
@@ -55,25 +63,38 @@ jobs:
git_user_signingkey: true git_user_signingkey: true
git_commit_gpgsign: true git_commit_gpgsign: true
- name: Setup git
run: |
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com"
git config --local user.name "bitwarden-devops-bot"
- name: Create Version Branch - name: Create Version Branch
id: create-branch id: create-branch
run: | run: |
NAME=version_bump_${{ github.ref_name }}_${{ inputs.version_number }} NAME=version_bump_${{ github.ref_name }}_$(date +"%Y-%m-%d")
git switch -c $NAME git switch -c $NAME
echo "name=$NAME" >> $GITHUB_OUTPUT echo "name=$NAME" >> $GITHUB_OUTPUT
- name: Install xmllint - name: Install xmllint
run: sudo apt install -y libxml2-utils run: |
sudo apt-get update
sudo apt-get install -y libxml2-utils
- name: Verify input version - name: Get current version
env: id: current-version
NEW_VERSION: ${{ inputs.version_number }}
run: | run: |
CURRENT_VERSION=$(xmllint --xpath ' CURRENT_VERSION=$(xmllint --xpath '
string(/manifest/@*[local-name()="versionName" string(/manifest/@*[local-name()="versionName"
and namespace-uri()="http://schemas.android.com/apk/res/android"]) and namespace-uri()="http://schemas.android.com/apk/res/android"])
' src/App/Platforms/Android/AndroidManifest.xml) ' src/App/Platforms/Android/AndroidManifest.xml)
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
- name: Verify input version
if: ${{ inputs.version_number_override != '' }}
env:
CURRENT_VERSION: ${{ steps.current-version.outputs.version }}
NEW_VERSION: ${{ inputs.version_number_override }}
run: |
# Error if version has not changed. # Error if version has not changed.
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
echo "Version has not changed." echo "Version has not changed."
@@ -89,40 +110,93 @@ jobs:
exit 1 exit 1
fi fi
- name: Bump Version - Android XML - name: Calculate next release version
if: ${{ inputs.version_number_override == '' }}
id: calculate-next-version
uses: bitwarden/gh-actions/version-next@main
with:
version: ${{ steps.current-version.outputs.version }}
- name: Bump Version - Android XML - Version Override
if: ${{ inputs.version_number_override != '' }}
id: bump-version-override
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }}
file_path: "src/App/Platforms/Android/AndroidManifest.xml" file_path: "src/App/Platforms/Android/AndroidManifest.xml"
version: ${{ inputs.version_number_override }}
- name: Bump Version - iOS.Autofill - name: Bump Version - Android XML - Automatic Calculation
if: ${{ inputs.version_number_override == '' }}
id: bump-version-automatic
uses: bitwarden/gh-actions/version-bump@main
with:
file_path: "src/App/Platforms/Android/AndroidManifest.xml"
version: ${{ steps.calculate-next-version.outputs.version }}
- name: Bump Version - iOS.Autofill - Version Override
if: ${{ inputs.version_number_override != '' }}
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }}
file_path: "src/iOS.Autofill/Info.plist" file_path: "src/iOS.Autofill/Info.plist"
version: ${{ inputs.version_number_override }}
- name: Bump Version - iOS.Extension - name: Bump Version - iOS.Autofill - Automatic Calculation
if: ${{ inputs.version_number_override == '' }}
uses: bitwarden/gh-actions/version-bump@main
with:
file_path: "src/iOS.Autofill/Info.plist"
version: ${{ steps.calculate-next-version.outputs.version }}
- name: Bump Version - iOS.Extension - Version Override
if: ${{ inputs.version_number_override != '' }}
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }}
file_path: "src/iOS.Extension/Info.plist" file_path: "src/iOS.Extension/Info.plist"
version: ${{ inputs.version_number_override }}
- name: Bump Version - iOS.ShareExtension - name: Bump Version - iOS.Extension - Automatic Calculation
if: ${{ inputs.version_number_override == '' }}
uses: bitwarden/gh-actions/version-bump@main
with:
file_path: "src/iOS.Extension/Info.plist"
version: ${{ steps.calculate-next-version.outputs.version }}
- name: Bump Version - iOS.ShareExtension - Version Override
if: ${{ inputs.version_number_override != '' }}
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }}
file_path: "src/iOS.ShareExtension/Info.plist" file_path: "src/iOS.ShareExtension/Info.plist"
version: ${{ inputs.version_number_override }}
- name: Bump Version - iOS - name: Bump Version - iOS.ShareExtension - Automatic Calculation
if: ${{ inputs.version_number_override == '' }}
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }} file_path: "src/iOS.ShareExtension/Info.plist"
file_path: "src/App/Platforms/iOS/Info.plist" version: ${{ steps.calculate-next-version.outputs.version }}
- name: Setup git - name: Bump Version - iOS - Version Override
if: ${{ inputs.version_number_override != '' }}
uses: bitwarden/gh-actions/version-bump@main
with:
file_path: "src/App/Platforms/iOS/Info.plist"
version: ${{ inputs.version_number_override }}
- name: Bump Version - iOS - Automatic Calculation
if: ${{ inputs.version_number_override == '' }}
uses: bitwarden/gh-actions/version-bump@main
with:
file_path: "src/App/Platforms/iOS/Info.plist"
version: ${{ steps.calculate-next-version.outputs.version }}
- name: Set Job output
id: set-final-version-output
run: | run: |
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com" if [[ "${{ steps.bump-version-override.outcome }}" == "success" ]]; then
git config --local user.name "bitwarden-devops-bot" echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-version-automatic.outcome }}" == "success" ]]; then
echo "version=${{ steps.calculate-next-version.outputs.version }}" >> $GITHUB_OUTPUT
fi
- name: Check if version changed - name: Check if version changed
id: version-changed id: version-changed
@@ -136,7 +210,7 @@ jobs:
- name: Commit files - name: Commit files
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
run: git commit -m "Bumped version to ${{ inputs.version_number }}" -a run: git commit -m "Bumped version to ${{ steps.set-final-version-output.outputs.version }}" -a
- name: Push changes - name: Push changes
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
@@ -150,7 +224,7 @@ jobs:
env: env:
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }} GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
PR_BRANCH: ${{ steps.create-branch.outputs.name }} PR_BRANCH: ${{ steps.create-branch.outputs.name }}
TITLE: "Bump version to ${{ inputs.version_number }}" TITLE: "Bump version to ${{ steps.set-final-version-output.outputs.version }}"
run: | run: |
PR_URL=$(gh pr create --title "$TITLE" \ PR_URL=$(gh pr create --title "$TITLE" \
--base "main" \ --base "main" \
@@ -166,16 +240,18 @@ jobs:
- [X] Other - [X] Other
## Objective ## Objective
Automated version bump to ${{ inputs.version_number }}") Automated version bump to ${{ steps.set-final-version-output.outputs.version }}")
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
- name: Approve PR - name: Approve PR
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
run: gh pr review $PR_NUMBER --approve run: gh pr review $PR_NUMBER --approve
- name: Merge PR - name: Merge PR
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
env: env:
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }} GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
@@ -183,8 +259,8 @@ jobs:
cut_rc: cut_rc:
name: Cut RC branch name: Cut RC branch
needs: bump_version
if: ${{ inputs.cut_rc_branch == true }} if: ${{ inputs.cut_rc_branch == true }}
needs: bump_version
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout Branch - name: Checkout Branch
@@ -193,11 +269,13 @@ jobs:
ref: main ref: main
- name: Install xmllint - name: Install xmllint
run: sudo apt install -y libxml2-utils run: |
sudo apt-get update
sudo apt-get install -y libxml2-utils
- name: Verify version has been updated - name: Verify version has been updated
env: env:
NEW_VERSION: ${{ inputs.version_number }} NEW_VERSION: ${{ needs.bump_version.outputs.version }}
run: | run: |
# Wait for version to change. # Wait for version to change.
while : ; do while : ; do

View File

@@ -1,11 +0,0 @@
---
name: Workflow Linter
on:
pull_request:
paths:
- .github/workflows/**
jobs:
call-workflow:
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main

View File

@@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<MauiVersion>8.0.4-nightly.*</MauiVersion> <MauiVersion>8.0.7</MauiVersion>
<ReleaseCodesignProvision>Automatic:AppStore</ReleaseCodesignProvision> <ReleaseCodesignProvision>Automatic:AppStore</ReleaseCodesignProvision>
<ReleaseCodesignKey>iPhone Distribution</ReleaseCodesignKey> <ReleaseCodesignKey>iPhone Distribution</ReleaseCodesignKey>
<IncludeBitwardeniOSExtensions>True</IncludeBitwardeniOSExtensions> <IncludeBitwardeniOSExtensions>True</IncludeBitwardeniOSExtensions>
@@ -9,5 +9,8 @@
<!-- Uncomment this when Unit Testing--> <!-- Uncomment this when Unit Testing-->
<!-- <CustomConstants>UT</CustomConstants> --> <!-- <CustomConstants>UT</CustomConstants> -->
<!-- Uncomment this when building FDROID-->
<!-- <CustomConstants>FDROID</CustomConstants> -->
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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.2.2" 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.3.3" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
@@ -43,6 +43,9 @@
<!-- Support for Xamarin.Essentials.Browser.OpenAsync (for Android > 11) --> <!-- Support for Xamarin.Essentials.Browser.OpenAsync (for Android > 11) -->
<!-- Related docs: https://learn.microsoft.com/en-us/xamarin/essentials/open-browser?tabs=android --> <!-- Related docs: https://learn.microsoft.com/en-us/xamarin/essentials/open-browser?tabs=android -->
<queries> <queries>
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
<intent> <intent>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<data android:scheme="http" /> <data android:scheme="http" />

View File

@@ -347,7 +347,7 @@ namespace Bit.Droid.Autofill
// InlinePresentation requires nonNull pending intent (even though we only utilize one for the // InlinePresentation requires nonNull pending intent (even though we only utilize one for the
// "my vault" presentation) so we're including an empty one here // "my vault" presentation) so we're including an empty one here
pendingIntent = PendingIntent.GetService(context, 0, new Intent(), pendingIntent = PendingIntent.GetService(context, 0, new Intent(),
AndroidHelpers.AddPendingIntentMutabilityFlag(PendingIntentFlags.OneShot | PendingIntentFlags.UpdateCurrent, true)); AndroidHelpers.AddPendingIntentMutabilityFlag(PendingIntentFlags.OneShot | PendingIntentFlags.UpdateCurrent, false));
} }
var slice = CreateInlinePresentationSlice( var slice = CreateInlinePresentationSlice(
inlinePresentationSpec, inlinePresentationSpec,

View File

@@ -85,6 +85,12 @@ namespace Bit.Droid
ServiceContainer.Resolve<IWatchDeviceService>(), ServiceContainer.Resolve<IWatchDeviceService>(),
ServiceContainer.Resolve<IConditionedAwaiterManager>()); ServiceContainer.Resolve<IConditionedAwaiterManager>());
ServiceContainer.Register<IAccountsManager>("accountsManager", accountsManager); ServiceContainer.Register<IAccountsManager>("accountsManager", accountsManager);
var userPinService = new UserPinService(
ServiceContainer.Resolve<IStateService>(),
ServiceContainer.Resolve<ICryptoService>(),
ServiceContainer.Resolve<IVaultTimeoutService>());
ServiceContainer.Register<IUserPinService>(userPinService);
} }
#if !FDROID #if !FDROID
if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat) if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)
@@ -160,7 +166,6 @@ namespace Bit.Droid
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService); var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(stateService, cryptoFunctionService, logger); var cryptoService = new CryptoService(stateService, cryptoFunctionService, logger);
var biometricService = new BiometricService(stateService, cryptoService); var biometricService = new BiometricService(stateService, cryptoService);
var userPinService = new UserPinService(stateService, cryptoService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService); var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage); ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
@@ -184,7 +189,6 @@ namespace Bit.Droid
ServiceContainer.Register<ICryptoService>("cryptoService", cryptoService); ServiceContainer.Register<ICryptoService>("cryptoService", cryptoService);
ServiceContainer.Register<IPasswordRepromptService>("passwordRepromptService", passwordRepromptService); ServiceContainer.Register<IPasswordRepromptService>("passwordRepromptService", passwordRepromptService);
ServiceContainer.Register<IAvatarImageSourcePool>("avatarImageSourcePool", new AvatarImageSourcePool()); ServiceContainer.Register<IAvatarImageSourcePool>("avatarImageSourcePool", new AvatarImageSourcePool());
ServiceContainer.Register<IUserPinService>(userPinService);
// Push // Push
#if FDROID #if FDROID

View File

@@ -72,6 +72,8 @@ namespace Bit.Droid.Services
} }
public bool LaunchApp(string appName) public bool LaunchApp(string appName)
{
try
{ {
if ((int)Build.VERSION.SdkInt < 33) if ((int)Build.VERSION.SdkInt < 33)
{ {
@@ -85,6 +87,15 @@ namespace Bit.Droid.Services
launchIntentSender?.SendIntent(activity, Result.Ok, null, null, null); launchIntentSender?.SendIntent(activity, Result.Ok, null, null, null);
return launchIntentSender != null; return launchIntentSender != null;
} }
catch (IntentSender.SendIntentException)
{
return false;
}
catch (Android.Util.AndroidException)
{
return false;
}
}
public async Task ShowLoadingAsync(string text) public async Task ShowLoadingAsync(string text)
{ {

View File

@@ -8,6 +8,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Droid.Accessibility; using Bit.Droid.Accessibility;
using Java.Lang; using Java.Lang;
using Bit.App.Droid.Utilities;
namespace Bit.Droid.Tile namespace Bit.Droid.Tile
{ {
@@ -76,7 +77,7 @@ namespace Bit.Droid.Tile
var intent = new Intent(this, typeof(AccessibilityActivity)); var intent = new Intent(this, typeof(AccessibilityActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop); intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
intent.PutExtra("autofillTileClicked", true); intent.PutExtra("autofillTileClicked", true);
StartActivityAndCollapse(intent); this.StartActivityAndCollapseWithIntent(intent, isMutable: true);
} }
private void ShowConfigErrorDialog() private void ShowConfigErrorDialog()

View File

@@ -1,15 +1,8 @@
using System; using Android.App;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content; using Android.Content;
using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Service.QuickSettings; using Android.Service.QuickSettings;
using Android.Views; using Bit.App.Droid.Utilities;
using Android.Widget;
using Java.Lang; using Java.Lang;
namespace Bit.Droid.Tile namespace Bit.Droid.Tile
@@ -62,7 +55,7 @@ namespace Bit.Droid.Tile
var intent = new Intent(this, typeof(MainActivity)); var intent = new Intent(this, typeof(MainActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop); intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
intent.PutExtra("generatorTile", true); intent.PutExtra("generatorTile", true);
StartActivityAndCollapse(intent); this.StartActivityAndCollapseWithIntent(intent, isMutable: false);
} }
} }
} }

View File

@@ -1,15 +1,8 @@
using System; using Android.App;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content; using Android.Content;
using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Service.QuickSettings; using Android.Service.QuickSettings;
using Android.Views; using Bit.App.Droid.Utilities;
using Android.Widget;
using Java.Lang; using Java.Lang;
namespace Bit.Droid.Tile namespace Bit.Droid.Tile
@@ -63,7 +56,7 @@ namespace Bit.Droid.Tile
var intent = new Intent(this, typeof(MainActivity)); var intent = new Intent(this, typeof(MainActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop); intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
intent.PutExtra("myVaultTile", true); intent.PutExtra("myVaultTile", true);
StartActivityAndCollapse(intent); this.StartActivityAndCollapseWithIntent(intent, isMutable: false);
} }
} }
} }

View File

@@ -2,6 +2,7 @@
using Android.Content; using Android.Content;
using Android.OS; using Android.OS;
using Android.Provider; using Android.Provider;
using Android.Service.QuickSettings;
using Bit.App.Utilities; using Bit.App.Utilities;
namespace Bit.App.Droid.Utilities namespace Bit.App.Droid.Utilities
@@ -64,5 +65,26 @@ namespace Bit.App.Droid.Utilities
return pendingIntentFlags; return pendingIntentFlags;
} }
public static void StartActivityAndCollapseWithIntent(this TileService service, Intent intent, bool isMutable)
{
//For Android 14+ We need to use PendingIntent instead of Intent directly. Older versions still need to use Intent.
if (Build.VERSION.SdkInt < BuildVersionCodes.UpsideDownCake)
{
service.StartActivityAndCollapse(intent);
return;
}
var pendingIntent = PendingIntent.GetActivity(
service.ApplicationContext,
0,
intent,
AddPendingIntentMutabilityFlag(PendingIntentFlags.UpdateCurrent, isMutable)
);
if (pendingIntent == null)
{
return;
}
service.StartActivityAndCollapse(pendingIntent);
}
} }
} }

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string> <string>com.8bit.bitwarden</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2024.2.2</string> <string>2024.3.3</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>CFBundleIconName</key> <key>CFBundleIconName</key>

View File

@@ -1,7 +1,4 @@
using System; using Bit.Core.Enums;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Models.View; using Bit.Core.Models.View;
@@ -37,5 +34,7 @@ namespace Bit.Core.Abstractions
Task<byte[]> DownloadAndDecryptAttachmentAsync(string cipherId, AttachmentView attachment, string organizationId); Task<byte[]> DownloadAndDecryptAttachmentAsync(string cipherId, AttachmentView attachment, string organizationId);
Task SoftDeleteWithServerAsync(string id); Task SoftDeleteWithServerAsync(string id);
Task RestoreWithServerAsync(string id); Task RestoreWithServerAsync(string id);
Task<string> CreateNewLoginForPasskeyAsync(Fido2ConfirmNewCredentialParams newPasskeyParams);
Task CopyTotpCodeIfNeededAsync(CipherView cipher);
} }
} }

View File

@@ -1,11 +1,10 @@
using System; namespace Bit.Core.Abstractions
using System.Threading.Tasks;
namespace Bit.Core.Abstractions
{ {
public enum AwaiterPrecondition public enum AwaiterPrecondition
{ {
EnvironmentUrlsInited EnvironmentUrlsInited,
AndroidWindowCreated,
AutofillIOSExtensionViewDidAppear
} }
public interface IConditionedAwaiterManager public interface IConditionedAwaiterManager
@@ -13,5 +12,6 @@ namespace Bit.Core.Abstractions
Task GetAwaiterForPrecondition(AwaiterPrecondition awaiterPrecondition); Task GetAwaiterForPrecondition(AwaiterPrecondition awaiterPrecondition);
void SetAsCompleted(AwaiterPrecondition awaiterPrecondition); void SetAsCompleted(AwaiterPrecondition awaiterPrecondition);
void SetException(AwaiterPrecondition awaiterPrecondition, Exception ex); void SetException(AwaiterPrecondition awaiterPrecondition, Exception ex);
void Recreate(AwaiterPrecondition awaiterPrecondition);
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Domain;
namespace Bit.Core.Abstractions namespace Bit.Core.Abstractions
{ {

View File

@@ -1,9 +0,0 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public interface IFido2AuthenticationService
{
Task<Fido2AuthenticatorGetAssertionResult> GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams);
}
}

View File

@@ -0,0 +1,12 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public interface IFido2AuthenticatorService
{
Task<Fido2AuthenticatorMakeCredentialResult> MakeCredentialAsync(Fido2AuthenticatorMakeCredentialParams makeCredentialParams, IFido2MakeCredentialUserInterface userInterface);
Task<Fido2AuthenticatorGetAssertionResult> GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface);
// TODO: Should this return a List? Or maybe IEnumerable?
Task<Fido2AuthenticatorDiscoverableCredentialMetadata[]> SilentCredentialDiscoveryAsync(string rpId);
}
}

View File

@@ -0,0 +1,35 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
/// <summary>
/// This class represents an abstraction of the WebAuthn Client as described by W3C:
/// https://www.w3.org/TR/webauthn-3/#webauthn-client
///
/// The WebAuthn Client is an intermediary entity typically implemented in the user agent
/// (in whole, or in part). Conceptually, it underlies the Web Authentication API and embodies
/// the implementation of the Web Authentication API's operations.
///
/// It is responsible for both marshalling the inputs for the underlying authenticator operations,
/// and for returning the results of the latter operations to the Web Authentication API's callers.
/// </summary>
public interface IFido2ClientService
{
/// <summary>
/// Allows WebAuthn Relying Party scripts to request the creation of a new public key credential source.
/// 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>
/// <returns>The new credential</returns>
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams);
/// <summary>
/// Allows WebAuthn Relying Party scripts to discover and use an existing public key credential, with the users consent.
/// Relying Party script can optionally specify some criteria to indicate what credential sources are acceptable to it.
/// 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>
/// <returns>The asserted credential</returns>
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams);
}
}

View File

@@ -0,0 +1,20 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public struct Fido2GetAssertionUserInterfaceCredential
{
public string CipherId { get; set; }
public Fido2UserVerificationPreference UserVerificationPreference { get; set; }
}
public interface IFido2GetAssertionUserInterface : IFido2UserInterface
{
/// <summary>
/// Ask the user to pick a credential from a list of existing credentials.
/// </summary>
/// <param name="credentials">The credentials that the user can pick from, and if the user must be verified before completing the operation</param>
/// <returns>The ID of the cipher that contains the credentials the user picked, and if the user was verified before completing the operation</returns>
Task<(string CipherId, bool UserVerified)> PickCredentialAsync(Fido2GetAssertionUserInterfaceCredential[] credentials);
}
}

View File

@@ -0,0 +1,44 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public struct Fido2ConfirmNewCredentialParams
{
///<summary>
/// The name of the credential.
///</summary>
public string CredentialName { get; set; }
///<summary>
/// The name of the user.
///</summary>
public string UserName { get; set; }
/// <summary>
/// The preference to whether or not the user must be verified before completing the operation.
/// </summary>
public Fido2UserVerificationPreference UserVerificationPreference { get; set; }
/// <summary>
/// The relying party identifier
/// </summary>
public string RpId { get; set; }
}
public interface IFido2MakeCredentialUserInterface : IFido2UserInterface
{
/// <summary>
/// Inform the user that the operation was cancelled because their vault contains excluded credentials.
/// </summary>
/// <param name="existingCipherIds">The IDs of the excluded credentials.</param>
/// <returns>When user has confirmed the message</returns>
Task InformExcludedCredentialAsync(string[] existingCipherIds);
/// <summary>
/// Ask the user to confirm the creation of a new credential.
/// </summary>
/// <param name="confirmNewCredentialParams">The parameters to use when asking the user to confirm the creation of a new credential.</param>
/// <returns>The ID of the cipher where the new credential should be saved, and if the user was verified before completing the operation</returns>
Task<(string CipherId, bool UserVerified)> ConfirmNewCredentialAsync(Fido2ConfirmNewCredentialParams confirmNewCredentialParams);
}
}

View File

@@ -0,0 +1,14 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public interface IFido2MediatorService
{
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams);
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams);
Task<Fido2AuthenticatorMakeCredentialResult> MakeCredentialAsync(Fido2AuthenticatorMakeCredentialParams makeCredentialParams, IFido2MakeCredentialUserInterface userInterface);
Task<Fido2AuthenticatorGetAssertionResult> GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface);
Task<Fido2AuthenticatorDiscoverableCredentialMetadata[]> SilentCredentialDiscoveryAsync(string rpId);
}
}

View File

@@ -0,0 +1,17 @@
namespace Bit.Core.Abstractions
{
public interface IFido2UserInterface
{
/// <summary>
/// Whether the vault has been unlocked during this transaction
/// </summary>
bool HasVaultBeenUnlockedInThisTransaction { get; }
/// <summary>
/// Make sure that the vault is unlocked.
/// This should open a window and ask the user to login or unlock the vault if necessary.
/// </summary>
/// <returns>When vault has been unlocked.</returns>
Task EnsureUnlockedVaultAsync();
}
}

View File

@@ -1,5 +1,4 @@
using System.Threading.Tasks; using Bit.Core.Enums;
using Bit.Core.Enums;
namespace Bit.App.Abstractions namespace Bit.App.Abstractions
{ {
@@ -10,5 +9,7 @@ namespace Bit.App.Abstractions
Task<bool> PromptAndCheckPasswordIfNeededAsync(CipherRepromptType repromptType = CipherRepromptType.Password); Task<bool> PromptAndCheckPasswordIfNeededAsync(CipherRepromptType repromptType = CipherRepromptType.Password);
Task<(string password, bool valid)> ShowPasswordPromptAndGetItAsync(); Task<(string password, bool valid)> ShowPasswordPromptAndGetItAsync();
Task<bool> ShouldByPassMasterPasswordRepromptAsync();
} }
} }

View File

@@ -1,7 +1,4 @@
using System; using Bit.Core.Enums;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Enums;
namespace Bit.Core.Abstractions namespace Bit.Core.Abstractions
{ {
@@ -29,7 +26,7 @@ namespace Bit.Core.Abstractions
bool SupportsDuo(); bool SupportsDuo();
Task<bool> SupportsBiometricAsync(); Task<bool> SupportsBiometricAsync();
Task<bool> IsBiometricIntegrityValidAsync(string bioIntegritySrcKey = null); Task<bool> IsBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
Task<bool> AuthenticateBiometricAsync(string text = null, string fallbackText = null, Action fallback = null, bool logOutOnTooManyAttempts = false); Task<bool?> AuthenticateBiometricAsync(string text = null, string fallbackText = null, Action fallback = null, bool logOutOnTooManyAttempts = false, bool allowAlternativeAuthentication = false);
long GetActiveTime(); long GetActiveTime();
} }
} }

View File

@@ -186,6 +186,7 @@ namespace Bit.Core.Abstractions
Task<BwRegion?> GetActiveUserRegionAsync(); Task<BwRegion?> GetActiveUserRegionAsync();
Task<BwRegion?> GetPreAuthRegionAsync(); Task<BwRegion?> GetPreAuthRegionAsync();
Task SetPreAuthRegionAsync(BwRegion value); Task SetPreAuthRegionAsync(BwRegion value);
Task ReloadStateAsync();
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")] [Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
Task<string> GetPinProtectedAsync(string userId = null); Task<string> GetPinProtectedAsync(string userId = null);
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")] [Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]

View File

@@ -1,9 +1,12 @@
using System.Threading.Tasks; using Bit.Core.Services;
namespace Bit.Core.Abstractions namespace Bit.Core.Abstractions
{ {
public interface IUserPinService public interface IUserPinService
{ {
Task<bool> IsPinLockEnabledAsync();
Task SetupPinAsync(string pin, bool requireMasterPasswordOnRestart); Task SetupPinAsync(string pin, bool requireMasterPasswordOnRestart);
Task<bool> VerifyPinAsync(string inputPin);
Task<bool> VerifyPinAsync(string inputPin, string email, KdfConfig kdfConfig, PinLockType pinLockType);
} }
} }

View File

@@ -0,0 +1,28 @@
using Bit.Core.Utilities;
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public interface IUserVerificationMediatorService
{
Task<CancellableResult<bool>> VerifyUserForFido2Async(Fido2UserVerificationOptions options);
Task<bool> CanPerformUserVerificationPreferredAsync(Fido2UserVerificationOptions options);
Task<bool> ShouldPerformMasterPasswordRepromptAsync(Fido2UserVerificationOptions options);
Task<bool> ShouldEnforceFido2RequiredUserVerificationAsync(Fido2UserVerificationOptions options);
Task<CancellableResult<UVResult>> PerformOSUnlockAsync();
Task<CancellableResult<UVResult>> VerifyPinCodeAsync();
Task<CancellableResult<UVResult>> VerifyMasterPasswordAsync(bool isMasterPasswordReprompt);
public struct UVResult
{
public UVResult(bool canPerform, bool isVerified)
{
CanPerform = canPerform;
IsVerified = isVerified;
}
public bool CanPerform { get; set; }
public bool IsVerified { get; set; }
}
}
}

View File

@@ -1,11 +1,11 @@
using System.Threading.Tasks; using Bit.Core.Enums;
using Bit.Core.Enums;
namespace Bit.Core.Abstractions namespace Bit.Core.Abstractions
{ {
public interface IUserVerificationService public interface IUserVerificationService
{ {
Task<bool> VerifyUser(string secret, VerificationType verificationType); Task<bool> VerifyUser(string secret, VerificationType verificationType);
Task<bool> VerifyMasterPasswordAsync(string masterPassword);
Task<bool> HasMasterPasswordAsync(bool checkMasterKeyHash = false); Task<bool> HasMasterPasswordAsync(bool checkMasterKeyHash = false);
} }
} }

View File

@@ -9,6 +9,7 @@ using Bit.Core;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Domain;
using Bit.Core.Models.Response; using Bit.Core.Models.Response;
using Bit.Core.Pages; using Bit.Core.Pages;
using Bit.Core.Services; using Bit.Core.Services;
@@ -46,7 +47,6 @@ namespace Bit.App
// This queue keeps those actions so that when the app has resumed they can still be executed. // This queue keeps those actions so that when the app has resumed they can still be executed.
// 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 // 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
private readonly Queue<Action> _onResumeActions = new Queue<Action>(); private readonly Queue<Action> _onResumeActions = new Queue<Action>();
private bool _hasNavigatedToAutofillWindow;
#if ANDROID #if ANDROID
@@ -120,41 +120,8 @@ namespace Bit.App
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally) return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
} }
//"Internal" Autofill and Uri/Otp/CreateSend. This is where we create the autofill specific Window
if (Options != null && (Options.FromAutofillFramework || Options.Uri != null || Options.OtpData != null || Options.CreateSend != null))
{
_isResumed = true; //Specifically for the Autofill scenario we need to manually set the _isResumed here
_hasNavigatedToAutofillWindow = true;
return new AutoFillWindow(new NavigationPage(new AndroidNavigationRedirectPage()));
}
var homePage = new HomePage(Options);
// WORKAROUND: If the user autofills with Accessibility Services enabled and goes back to the application then there is currently an issue
// where this method is called again
// thus it goes through here and the user goes to HomePage as we see here.
// So to solve this, the next flag check has been added which then turns on a flag on the home page
// that will trigger a navigation on the accounts manager when it loads; workarounding this behavior and navigating the user
// to the proper page depending on its state.
// WARNING: this doens't navigate the user to where they were but it acts as if the user had changed their account.
if(_hasNavigatedToAutofillWindow)
{
homePage.PerformNavigationOnAccountChangedOnLoad = true;
// this is needed because when coming back from AutofillWindow OnResume won't be called and we need this flag
// so that void Navigate(NavigationTarget navTarget, INavigationParams navParams) doesn't enqueue the navigation
// and it performs it directly.
_isResumed = true; _isResumed = true;
_hasNavigatedToAutofillWindow = false; return new ResumeWindow(new NavigationPage(new AndroidNavigationRedirectPage(Options)));
}
//If we have an existing MainAppWindow we can use that one
var mainAppWindow = Windows.OfType<MainAppWindow>().FirstOrDefault();
if (mainAppWindow != null)
{
mainAppWindow.PendingPage = new NavigationPage(homePage);
}
//Create new main window
return new MainAppWindow(new NavigationPage(homePage));
} }
#else #else
//iOS doesn't use the CreateWindow override used in Android so we just set the Application.Current.MainPage directly //iOS doesn't use the CreateWindow override used in Android so we just set the Application.Current.MainPage directly
@@ -201,18 +168,27 @@ namespace Bit.App
_accountsManager.Init(() => Options, this); _accountsManager.Init(() => Options, this);
_broadcasterService.Subscribe(nameof(App), BroadcastServiceMessageCallbackAsync);
Bootstrap(); Bootstrap();
_broadcasterService.Subscribe(nameof(App), async (message) => }
private async void BroadcastServiceMessageCallbackAsync(Message message)
{ {
try try
{ {
ArgumentNullException.ThrowIfNull(message);
if (message.Command == "showDialog") if (message.Command == "showDialog")
{ {
var details = message.Data as DialogDetails; var details = message.Data as DialogDetails;
ArgumentNullException.ThrowIfNull(details);
ArgumentNullException.ThrowIfNull(MainPage);
var confirmed = true; var confirmed = true;
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ? var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
AppResources.Ok : details.ConfirmText; AppResources.Ok : details.ConfirmText;
await MainThread.InvokeOnMainThreadAsync(async () => await MainThread.InvokeOnMainThreadAsync(ShowDialogAction);
async Task ShowDialogAction()
{ {
if (!string.IsNullOrWhiteSpace(details.CancelText)) if (!string.IsNullOrWhiteSpace(details.CancelText))
{ {
@@ -224,7 +200,7 @@ namespace Bit.App
await MainPage.DisplayAlert(details.Title, details.Text, confirmText); await MainPage.DisplayAlert(details.Title, details.Text, confirmText);
} }
_messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed)); _messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed));
}); }
} }
#if IOS #if IOS
else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND) else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND)
@@ -252,10 +228,13 @@ namespace Bit.App
Options.OtpData = new OtpData((string)message.Data); Options.OtpData = new OtpData((string)message.Data);
} }
await MainThread.InvokeOnMainThreadAsync(async () => await MainThread.InvokeOnMainThreadAsync(ExecuteNavigationAction);
async Task ExecuteNavigationAction()
{ {
if (MainPage is TabsPage tabsPage) if (MainPage is TabsPage tabsPage)
{ {
ArgumentNullException.ThrowIfNull(tabsPage.Navigation);
ArgumentNullException.ThrowIfNull(tabsPage.Navigation.ModalStack);
while (tabsPage.Navigation.ModalStack.Count > 0) while (tabsPage.Navigation.ModalStack.Count > 0)
{ {
await tabsPage.Navigation.PopModalAsync(false); await tabsPage.Navigation.PopModalAsync(false);
@@ -281,31 +260,41 @@ namespace Bit.App
else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE) else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
{ {
tabsPage.ResetToVaultPage(); tabsPage.ResetToVaultPage();
ArgumentNullException.ThrowIfNull(tabsPage.Navigation);
await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options))); await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options)));
} }
} }
}); }
} }
else if (message.Command == "convertAccountToKeyConnector") else if (message.Command == "convertAccountToKeyConnector")
{ {
await MainThread.InvokeOnMainThreadAsync(async () => ArgumentNullException.ThrowIfNull(MainPage);
await MainThread.InvokeOnMainThreadAsync(NavigateToRemoveMasterPasswordPageAction);
async Task NavigateToRemoveMasterPasswordPageAction()
{ {
await MainPage.Navigation.PushModalAsync( await MainPage.Navigation.PushModalAsync(
new NavigationPage(new RemoveMasterPasswordPage())); new NavigationPage(new RemoveMasterPasswordPage()));
}); }
} }
else if (message.Command == Constants.ForceUpdatePassword) else if (message.Command == Constants.ForceUpdatePassword)
{ {
await MainThread.InvokeOnMainThreadAsync(async () => ArgumentNullException.ThrowIfNull(MainPage);
await MainThread.InvokeOnMainThreadAsync(NavigateToUpdateTempPasswordPageAction);
async Task NavigateToUpdateTempPasswordPageAction()
{ {
await MainPage.Navigation.PushModalAsync( await MainPage.Navigation.PushModalAsync(
new NavigationPage(new UpdateTempPasswordPage())); new NavigationPage(new UpdateTempPasswordPage()));
}); }
} }
else if (message.Command == Constants.ForceSetPassword) else if (message.Command == Constants.ForceSetPassword)
{ {
await MainThread.InvokeOnMainThreadAsync(() => MainPage.Navigation.PushModalAsync( ArgumentNullException.ThrowIfNull(MainPage);
new NavigationPage(new SetPasswordPage(orgIdentifier: (string)message.Data)))); await MainThread.InvokeOnMainThreadAsync(NavigateToSetPasswordPageAction);
void NavigateToSetPasswordPageAction()
{
MainPage.Navigation.PushModalAsync(
new NavigationPage(new SetPasswordPage(orgIdentifier: (string)message.Data)));
}
} }
else if (message.Command == "syncCompleted") else if (message.Command == "syncCompleted")
{ {
@@ -326,7 +315,6 @@ namespace Bit.App
{ {
LoggerHelper.LogEvenIfCantBeResolved(ex); LoggerHelper.LogEvenIfCantBeResolved(ex);
} }
});
} }
private async Task CheckPasswordlessLoginRequestsAsync() private async Task CheckPasswordlessLoginRequestsAsync()
@@ -341,7 +329,6 @@ namespace Bit.App
{ {
return; return;
} }
var notification = await _stateService.GetPasswordlessLoginNotificationAsync(); var notification = await _stateService.GetPasswordlessLoginNotificationAsync();
if (notification == null) if (notification == null)
{ {

View File

@@ -47,6 +47,7 @@ namespace Bit.Core
public const string ConfigsKey = "configsKey"; public const string ConfigsKey = "configsKey";
public const string DisplayEuEnvironmentFlag = "display-eu-environment"; public const string DisplayEuEnvironmentFlag = "display-eu-environment";
public const string RegionEnvironment = "regionEnvironment"; public const string RegionEnvironment = "regionEnvironment";
public const string DuoCallback = "bitwarden://duo-callback";
/// <summary> /// <summary>
/// This key is used to store the value of "ShouldConnectToWatch" of the last user that had logged in /// This key is used to store the value of "ShouldConnectToWatch" of the last user that had logged in

View File

@@ -53,13 +53,14 @@ namespace Bit.App.Controls
if (BindingContext is CipherItemViewModel cipherItemVM) if (BindingContext is CipherItemViewModel cipherItemVM)
{ {
cipherItemVM.IconImageSuccesfullyLoaded = true; cipherItemVM.IconImageSuccesfullyLoaded = true;
}
MainThread.BeginInvokeOnMainThread(() => MainThread.BeginInvokeOnMainThread(() =>
{ {
Icon.IsVisible = true; Icon.IsVisible = cipherItemVM.ShowIconImage;
IconPlaceholder.IsVisible = false; IconPlaceholder.IsVisible = !cipherItemVM.ShowIconImage;
}); });
} }
}
public void Icon_Error(object sender, FFImageLoading.Maui.CachedImageEvents.ErrorEventArgs e) public void Icon_Error(object sender, FFImageLoading.Maui.CachedImageEvents.ErrorEventArgs e)
{ {

View File

@@ -34,6 +34,7 @@
<PackageReference Include="CsvHelper" Version="30.0.1" /> <PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="LiteDB" Version="5.0.17" /> <PackageReference Include="LiteDB" Version="5.0.17" />
<PackageReference Include="PCLCrypto" Version="2.1.40-alpha" /> <PackageReference Include="PCLCrypto" Version="2.1.40-alpha" />
<PackageReference Include="System.Formats.Cbor" Version="8.0.0" />
<PackageReference Include="zxcvbn-core" Version="7.0.92" /> <PackageReference Include="zxcvbn-core" Version="7.0.92" />
<PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.5.124"> <PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.5.124">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -79,6 +80,8 @@
<Folder Include="Utilities\Fido2\" /> <Folder Include="Utilities\Fido2\" />
<Folder Include="Controls\Picker\" /> <Folder Include="Controls\Picker\" />
<Folder Include="Controls\Avatar\" /> <Folder Include="Controls\Avatar\" />
<Folder Include="Services\UserVerification\" />
<Folder Include="Utilities\WebAuthenticatorMAUI\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MauiImage Include="Resources\Images\dotnet_bot.svg"> <MauiImage Include="Resources\Images\dotnet_bot.svg">
@@ -110,5 +113,7 @@
<None Remove="Utilities\Fido2\" /> <None Remove="Utilities\Fido2\" />
<None Remove="Controls\Picker\" /> <None Remove="Controls\Picker\" />
<None Remove="Controls\Avatar\" /> <None Remove="Controls\Avatar\" />
<None Remove="Services\UserVerification\" />
<None Remove="Utilities\WebAuthenticatorMAUI\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,5 +1,4 @@
using System; using Bit.Core.Models.Domain;
using Bit.Core.Models.Domain;
namespace Bit.Core.Models.Api namespace Bit.Core.Models.Api
{ {
@@ -21,6 +20,7 @@ namespace Bit.Core.Models.Api
RpName = fido2Key.RpName?.EncryptedString; RpName = fido2Key.RpName?.EncryptedString;
UserHandle = fido2Key.UserHandle?.EncryptedString; UserHandle = fido2Key.UserHandle?.EncryptedString;
UserName = fido2Key.UserName?.EncryptedString; UserName = fido2Key.UserName?.EncryptedString;
UserDisplayName = fido2Key.UserDisplayName?.EncryptedString;
Counter = fido2Key.Counter?.EncryptedString; Counter = fido2Key.Counter?.EncryptedString;
CreationDate = fido2Key.CreationDate; CreationDate = fido2Key.CreationDate;
} }
@@ -35,6 +35,7 @@ namespace Bit.Core.Models.Api
public string RpName { get; set; } public string RpName { get; set; }
public string UserHandle { get; set; } public string UserHandle { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string UserDisplayName { get; set; }
public string Counter { get; set; } public string Counter { get; set; }
public DateTime CreationDate { get; set; } public DateTime CreationDate { get; set; }
} }

View File

@@ -19,6 +19,7 @@ namespace Bit.Core.Models.Data
RpName = apiData.RpName; RpName = apiData.RpName;
UserHandle = apiData.UserHandle; UserHandle = apiData.UserHandle;
UserName = apiData.UserName; UserName = apiData.UserName;
UserDisplayName = apiData.UserDisplayName;
Counter = apiData.Counter; Counter = apiData.Counter;
CreationDate = apiData.CreationDate; CreationDate = apiData.CreationDate;
} }
@@ -33,6 +34,7 @@ namespace Bit.Core.Models.Data
public string RpName { get; set; } public string RpName { get; set; }
public string UserHandle { get; set; } public string UserHandle { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string UserDisplayName { get; set; }
public string Counter { get; set; } public string Counter { get; set; }
public DateTime CreationDate { get; set; } public DateTime CreationDate { get; set; }
} }

View File

@@ -1,8 +1,4 @@
using System; using Bit.Core.Models.Data;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.View; using Bit.Core.Models.View;
namespace Bit.Core.Models.Domain namespace Bit.Core.Models.Domain
@@ -21,6 +17,7 @@ namespace Bit.Core.Models.Domain
nameof(RpName), nameof(RpName),
nameof(UserHandle), nameof(UserHandle),
nameof(UserName), nameof(UserName),
nameof(UserDisplayName),
nameof(Counter) nameof(Counter)
}; };
@@ -48,6 +45,7 @@ namespace Bit.Core.Models.Domain
public EncString RpName { get; set; } public EncString RpName { get; set; }
public EncString UserHandle { get; set; } public EncString UserHandle { get; set; }
public EncString UserName { get; set; } public EncString UserName { get; set; }
public EncString UserDisplayName { get; set; }
public EncString Counter { get; set; } public EncString Counter { get; set; }
public DateTime CreationDate { get; set; } public DateTime CreationDate { get; set; }

View File

@@ -1,5 +1,4 @@
using System; using Bit.Core.Enums;
using Bit.Core.Enums;
namespace Bit.Core.Models.Domain namespace Bit.Core.Models.Domain
{ {
@@ -9,7 +8,7 @@ namespace Bit.Core.Models.Domain
{ {
if (key == null) if (key == null)
{ {
throw new Exception("Must provide key."); throw new ArgumentKeyNullException(nameof(key));
} }
if (encType == null) if (encType == null)
@@ -24,7 +23,7 @@ namespace Bit.Core.Models.Domain
} }
else else
{ {
throw new Exception("Unable to determine encType."); throw new InvalidKeyOperationException("Unable to determine encType.");
} }
} }
@@ -48,7 +47,7 @@ namespace Bit.Core.Models.Domain
} }
else else
{ {
throw new Exception("Unsupported encType/key length."); throw new InvalidKeyOperationException("Unsupported encType/key length.");
} }
if (Key != null) if (Key != null)
@@ -72,6 +71,32 @@ namespace Bit.Core.Models.Domain
public string KeyB64 { get; set; } public string KeyB64 { get; set; }
public string EncKeyB64 { get; set; } public string EncKeyB64 { get; set; }
public string MacKeyB64 { get; set; } public string MacKeyB64 { get; set; }
public class ArgumentKeyNullException : ArgumentNullException
{
public ArgumentKeyNullException(string paramName) : base(paramName)
{
}
public ArgumentKeyNullException(string message, Exception innerException) : base(message, innerException)
{
}
public ArgumentKeyNullException(string paramName, string message) : base(paramName, message)
{
}
}
public class InvalidKeyOperationException : InvalidOperationException
{
public InvalidKeyOperationException(string message) : base(message)
{
}
public InvalidKeyOperationException(string message, Exception innerException) : base(message, innerException)
{
}
}
} }
public class UserKey : SymmetricCryptoKey public class UserKey : SymmetricCryptoKey

View File

@@ -1,5 +1,7 @@
using Bit.Core.Enums; using System.Text.Json.Serialization;
using Bit.Core.Enums;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
namespace Bit.Core.Models.View namespace Bit.Core.Models.View
{ {
@@ -24,13 +26,42 @@ namespace Bit.Core.Models.View
public string RpName { get; set; } public string RpName { get; set; }
public string UserHandle { get; set; } public string UserHandle { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string UserDisplayName { get; set; }
public string Counter { get; set; } public string Counter { get; set; }
public DateTime CreationDate { get; set; } public DateTime CreationDate { get; set; }
[JsonIgnore]
public int CounterValue {
get => int.TryParse(Counter, out var counter) ? counter : 0;
set => Counter = value.ToString();
}
[JsonIgnore]
public byte[] UserHandleValue {
get => UserHandle == null ? null : CoreHelpers.Base64UrlDecode(UserHandle);
set => UserHandle = value == null ? null : CoreHelpers.Base64UrlEncode(value);
}
[JsonIgnore]
public byte[] KeyBytes {
get => KeyValue == null ? null : CoreHelpers.Base64UrlDecode(KeyValue);
set => KeyValue = value == null ? null : CoreHelpers.Base64UrlEncode(value);
}
[JsonIgnore]
public bool DiscoverableValue {
get => bool.TryParse(Discoverable, out var discoverable) && discoverable;
set => Discoverable = value.ToString().ToLower();
}
[JsonIgnore]
public override string SubTitle => UserName; public override string SubTitle => UserName;
public override List<KeyValuePair<string, LinkedIdType>> LinkedFieldOptions => new List<KeyValuePair<string, LinkedIdType>>(); public override List<KeyValuePair<string, LinkedIdType>> LinkedFieldOptions => new List<KeyValuePair<string, LinkedIdType>>();
public bool IsDiscoverable => !string.IsNullOrWhiteSpace(Discoverable);
[JsonIgnore]
public bool CanLaunch => !string.IsNullOrEmpty(RpId); public bool CanLaunch => !string.IsNullOrEmpty(RpId);
[JsonIgnore]
public string LaunchUri => $"https://{RpId}"; public string LaunchUri => $"https://{RpId}";
public bool IsUniqueAgainst(Fido2CredentialView fido2View) => fido2View?.RpId != RpId || fido2View?.UserName != UserName; public bool IsUniqueAgainst(Fido2CredentialView fido2View) => fido2View?.RpId != RpId || fido2View?.UserName != UserName;

View File

@@ -1,8 +1,7 @@
using System; using Bit.Core.Enums;
using System.Collections.Generic;
using System.Linq;
using Bit.Core.Enums;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Resources.Localization;
using Bit.Core.Utilities;
namespace Bit.Core.Models.View namespace Bit.Core.Models.View
{ {
@@ -40,4 +39,15 @@ 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);
}
}
} }

View File

@@ -1,6 +1,7 @@
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Resources.Localization; using Bit.Core.Resources.Localization;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.Maui.Platform;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
@@ -26,7 +27,7 @@ namespace Bit.App.Pages
_apiEntry.ReturnCommand = new Command(() => _identityEntry.Focus()); _apiEntry.ReturnCommand = new Command(() => _identityEntry.Focus());
_identityEntry.ReturnType = ReturnType.Next; _identityEntry.ReturnType = ReturnType.Next;
_identityEntry.ReturnCommand = new Command(() => _iconsEntry.Focus()); _identityEntry.ReturnCommand = new Command(() => _iconsEntry.Focus());
_vm.SubmitSuccessAction = () => MainThread.BeginInvokeOnMainThread(async () => await SubmitSuccessAsync()); _vm.SubmitSuccessTask = () => MainThread.InvokeOnMainThreadAsync(SubmitSuccessAsync);
_vm.CloseAction = async () => _vm.CloseAction = async () =>
{ {
await Navigation.PopModalAsync(); await Navigation.PopModalAsync();
@@ -37,6 +38,12 @@ namespace Bit.App.Pages
{ {
_platformUtilsService.ShowToast("success", null, AppResources.EnvironmentSaved); _platformUtilsService.ShowToast("success", null, AppResources.EnvironmentSaved);
await Navigation.PopModalAsync(); await Navigation.PopModalAsync();
#if ANDROID
if (Platform.CurrentActivity.CurrentFocus != null)
{
Platform.CurrentActivity.HideKeyboard(Platform.CurrentActivity.CurrentFocus);
}
#endif
} }
private void Close_Clicked(object sender, EventArgs e) private void Close_Clicked(object sender, EventArgs e)

View File

@@ -44,7 +44,7 @@ namespace Bit.App.Pages
public string WebVaultUrl { get; set; } public string WebVaultUrl { get; set; }
public string IconsUrl { get; set; } public string IconsUrl { get; set; }
public string NotificationsUrls { get; set; } public string NotificationsUrls { get; set; }
public Action SubmitSuccessAction { get; set; } public Func<Task> SubmitSuccessTask { get; set; }
public Action CloseAction { get; set; } public Action CloseAction { get; set; }
public async Task SubmitAsync() public async Task SubmitAsync()
@@ -73,7 +73,10 @@ namespace Bit.App.Pages
IconsUrl = resUrls.Icons; IconsUrl = resUrls.Icons;
NotificationsUrls = resUrls.Notifications; NotificationsUrls = resUrls.Notifications;
SubmitSuccessAction?.Invoke(); if (SubmitSuccessTask != null)
{
await SubmitSuccessTask();
}
} }
public bool ValidateUrls() public bool ValidateUrls()

View File

@@ -12,12 +12,14 @@ namespace Bit.App.Pages
private readonly HomeViewModel _vm; private readonly HomeViewModel _vm;
private readonly AppOptions _appOptions; private readonly AppOptions _appOptions;
private IBroadcasterService _broadcasterService; private IBroadcasterService _broadcasterService;
private IConditionedAwaiterManager _conditionedAwaiterManager;
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>(); readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
public HomePage(AppOptions appOptions = null) public HomePage(AppOptions appOptions = null)
{ {
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>(); _broadcasterService = ServiceContainer.Resolve<IBroadcasterService>();
_conditionedAwaiterManager = ServiceContainer.Resolve<IConditionedAwaiterManager>();
_appOptions = appOptions; _appOptions = appOptions;
InitializeComponent(); InitializeComponent();
_vm = BindingContext as HomeViewModel; _vm = BindingContext as HomeViewModel;
@@ -56,6 +58,8 @@ namespace Bit.App.Pages
PerformNavigationOnAccountChangedOnLoad = false; PerformNavigationOnAccountChangedOnLoad = false;
accountsManager.NavigateOnAccountChangeAsync().FireAndForget(); accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
} }
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.AndroidWindowCreated);
#endif #endif
} }

View File

@@ -515,7 +515,7 @@ namespace Bit.App.Pages
var success = await _platformUtilsService.AuthenticateBiometricAsync(null, var success = await _platformUtilsService.AuthenticateBiometricAsync(null,
PinEnabled ? AppResources.PIN : AppResources.MasterPassword, PinEnabled ? AppResources.PIN : AppResources.MasterPassword,
() => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry)), () => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry)),
!PinEnabled && !HasMasterPassword); !PinEnabled && !HasMasterPassword) ?? false;
await _stateService.SetBiometricLockedAsync(!success); await _stateService.SetBiometricLockedAsync(!success);
if (success) if (success)

View File

@@ -39,7 +39,7 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold"/> FontAttributes="Bold"/>
<controls:MonoLabel <controls:MonoLabel
FormattedText="{Binding LoginRequest.FingerprintPhrase}" Text="{Binding LoginRequest.FingerprintPhrase}"
FontSize="Medium" FontSize="Medium"
TextColor="{DynamicResource FingerprintPhrase}" TextColor="{DynamicResource FingerprintPhrase}"
Margin="0,0,0,27" Margin="0,0,0,27"
@@ -85,7 +85,6 @@
<Button <Button
Text="{u:I18n DenyLogIn}" Text="{u:I18n DenyLogIn}"
Command="{Binding RejectRequestCommand}" Command="{Binding RejectRequestCommand}"
StyleClass="btn-secundary"
AutomationId="DenyLoginButton" /> AutomationId="DenyLoginButton" />
</StackLayout> </StackLayout>

View File

@@ -41,7 +41,7 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold" /> FontAttributes="Bold" />
<controls:MonoLabel <controls:MonoLabel
FormattedText="{Binding FingerprintPhrase}" Text="{Binding FingerprintPhrase}"
FontSize="Small" FontSize="Small"
TextColor="{DynamicResource FingerprintPhrase}" TextColor="{DynamicResource FingerprintPhrase}"
AutomationId="FingerprintPhraseValue" /> AutomationId="FingerprintPhraseValue" />

View File

@@ -21,6 +21,7 @@ namespace Bit.App.Pages
InitializeComponent(); InitializeComponent();
_vm = BindingContext as LoginSsoPageViewModel; _vm = BindingContext as LoginSsoPageViewModel;
_vm.Page = this; _vm.Page = this;
_vm.FromIosExtension = _appOptions?.IosExtension ?? false;
_vm.StartTwoFactorAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync()); _vm.StartTwoFactorAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync());
_vm.StartSetPasswordAction = () => _vm.StartSetPasswordAction = () =>
MainThread.BeginInvokeOnMainThread(async () => await StartSetPasswordAsync()); MainThread.BeginInvokeOnMainThread(async () => await StartSetPasswordAsync());

View File

@@ -15,6 +15,16 @@ using Bit.Core.Utilities;
using Microsoft.Maui.Authentication; using Microsoft.Maui.Authentication;
using Microsoft.Maui.Networking; using Microsoft.Maui.Networking;
using NetworkAccess = Microsoft.Maui.Networking.NetworkAccess; using NetworkAccess = Microsoft.Maui.Networking.NetworkAccess;
using Org.BouncyCastle.Asn1.Ocsp;
#if IOS
using AuthenticationServices;
using Foundation;
using UIKit;
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 namespace Bit.App.Pages
{ {
@@ -64,6 +74,8 @@ namespace Bit.App.Pages
set => SetProperty(ref _orgIdentifier, value); set => SetProperty(ref _orgIdentifier, value);
} }
public bool FromIosExtension { get; set; }
public ICommand LogInCommand { get; } public ICommand LogInCommand { get; }
public Action StartTwoFactorAction { get; set; } public Action StartTwoFactorAction { get; set; }
public Action StartSetPasswordAction { get; set; } public Action StartSetPasswordAction { get; set; }
@@ -153,6 +165,9 @@ namespace Bit.App.Pages
CallbackUrl = new Uri(REDIRECT_URI), CallbackUrl = new Uri(REDIRECT_URI),
Url = new Uri(url), Url = new Uri(url),
PrefersEphemeralWebBrowserSession = _useEphemeralWebBrowserSession, PrefersEphemeralWebBrowserSession = _useEphemeralWebBrowserSession,
#if IOS
ShouldUseSharedApplicationKeyWindow = FromIosExtension
#endif
}); });
var code = GetResultCode(authResult, state); var code = GetResultCode(authResult, state);

View File

@@ -132,14 +132,26 @@
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
<StackLayout Spacing="0" Padding="0" IsVisible="{Binding DuoMethod, Mode=OneWay}" <StackLayout
VerticalOptions="StartAndExpand"> Spacing="0"
Padding="0"
IsVisible="{Binding DuoMethod, Mode=OneWay}"
VerticalOptions="FillAndExpand">
<Label
StyleClass="box"
Text="{Binding DuoFramelessLabel}"
HorizontalOptions="StartAndExpand"
Margin="10,21"
IsVisible="{Binding IsDuoFrameless}"/>
<controls:HybridWebView <controls:HybridWebView
x:Name="_duoWebView" x:Name="_duoWebView"
HorizontalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
HeightRequest="{Binding DuoWebViewHeight, Mode=OneWay}" /> HeightRequest="{Binding DuoWebViewHeight, Mode=OneWay}"
<StackLayout StyleClass="box" VerticalOptions="End"> IsVisible="{Binding IsDuoFrameless, Converter={StaticResource inverseBool}}"/>
<StackLayout
StyleClass="box"
VerticalOptions="End">
<StackLayout StyleClass="box-row, box-row-switch"> <StackLayout StyleClass="box-row, box-row-switch">
<Label <Label
Text="{u:I18n RememberMe}" Text="{u:I18n RememberMe}"
@@ -151,6 +163,12 @@
HorizontalOptions="End" /> HorizontalOptions="End" />
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
<Button Text="{u:I18n LaunchDuo}"
Margin="10,21"
StyleClass="btn-primary"
Command="{Binding AuthenticateWithDuoFramelessCommand}"
AutomationId="DuoFramelessButton"
IsVisible="{Binding IsDuoFrameless}"/>
</StackLayout> </StackLayout>
<StackLayout <StackLayout
Spacing="0" Spacing="0"

View File

@@ -2,6 +2,7 @@
using System.Windows.Input; using System.Windows.Input;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Utilities; using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@@ -34,6 +35,7 @@ namespace Bit.App.Pages
private string _webVaultUrl = "https://vault.bitwarden.com"; private string _webVaultUrl = "https://vault.bitwarden.com";
private bool _enableContinue = false; private bool _enableContinue = false;
private bool _showContinue = true; private bool _showContinue = true;
private bool _isDuoFrameless = false;
private double _duoWebViewHeight; private double _duoWebViewHeight;
public TwoFactorPageViewModel() public TwoFactorPageViewModel()
@@ -56,6 +58,7 @@ namespace Bit.App.Pages
PageTitle = AppResources.TwoStepLogin; PageTitle = AppResources.TwoStepLogin;
SubmitCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(async () => await SubmitAsync()), allowsMultipleExecutions: false); SubmitCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(async () => await SubmitAsync()), allowsMultipleExecutions: false);
MoreCommand = CreateDefaultAsyncRelayCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false); MoreCommand = CreateDefaultAsyncRelayCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
AuthenticateWithDuoFramelessCommand = CreateDefaultAsyncRelayCommand(DuoFramelessAuthenticateAsync, allowsMultipleExecutions: false);
} }
public string TotpInstruction public string TotpInstruction
@@ -103,6 +106,16 @@ namespace Bit.App.Pages
set => SetProperty(ref _enableContinue, value); set => SetProperty(ref _enableContinue, value);
} }
public bool IsDuoFrameless
{
get => _isDuoFrameless;
set => SetProperty(ref _isDuoFrameless, value, additionalPropertyNames: new string[] { nameof(DuoFramelessLabel) });
}
public string DuoFramelessLabel => SelectedProviderType == TwoFactorProviderType.OrganizationDuo ?
$"{AppResources.DuoTwoStepLoginIsRequiredForYourAccount} {AppResources.FollowTheStepsFromDuoToFinishLoggingIn}" :
AppResources.FollowTheStepsFromDuoToFinishLoggingIn;
#if IOS #if IOS
public string YubikeyInstruction => AppResources.YubiKeyInstructionIos; public string YubikeyInstruction => AppResources.YubiKeyInstructionIos;
#else #else
@@ -125,6 +138,7 @@ namespace Bit.App.Pages
} }
public ICommand SubmitCommand { get; } public ICommand SubmitCommand { get; }
public ICommand MoreCommand { get; } public ICommand MoreCommand { get; }
public ICommand AuthenticateWithDuoFramelessCommand { get; }
public Action TwoFactorAuthSuccessAction { get; set; } public Action TwoFactorAuthSuccessAction { get; set; }
public Action LockAction { get; set; } public Action LockAction { get; set; }
public Action StartDeviceApprovalOptionsAction { get; set; } public Action StartDeviceApprovalOptionsAction { get; set; }
@@ -179,6 +193,9 @@ namespace Bit.App.Pages
break; break;
case TwoFactorProviderType.Duo: case TwoFactorProviderType.Duo:
case TwoFactorProviderType.OrganizationDuo: case TwoFactorProviderType.OrganizationDuo:
IsDuoFrameless = providerData.ContainsKey("AuthUrl");
if (!IsDuoFrameless)
{
SetDuoWebViewHeight(); SetDuoWebViewHeight();
var host = WebUtility.UrlEncode(providerData["Host"] as string); var host = WebUtility.UrlEncode(providerData["Host"] as string);
var req = WebUtility.UrlEncode(providerData["Signature"] as string); var req = WebUtility.UrlEncode(providerData["Signature"] as string);
@@ -186,8 +203,19 @@ namespace Bit.App.Pages
page.DuoWebView.RegisterAction(sig => page.DuoWebView.RegisterAction(sig =>
{ {
Token = sig; Token = sig;
SubmitCommand.Execute(null); MainThread.BeginInvokeOnMainThread(async () =>
{
try
{
await SubmitAsync();
}
catch (Exception ex)
{
HandleException(ex);
}
}); });
});
}
break; break;
case TwoFactorProviderType.Email: case TwoFactorProviderType.Email:
TotpInstruction = string.Format(AppResources.EnterVerificationCodeEmail, TotpInstruction = string.Format(AppResources.EnterVerificationCodeEmail,
@@ -211,6 +239,77 @@ namespace Bit.App.Pages
ShowContinue = !(SelectedProviderType == null || DuoMethod || Fido2Method); ShowContinue = !(SelectedProviderType == null || DuoMethod || Fido2Method);
} }
private async Task DuoFramelessAuthenticateAsync()
{
await _deviceActionService.ShowLoadingAsync(AppResources.Validating);
if (!_authService.TwoFactorProvidersData.TryGetValue(SelectedProviderType.Value, out var providerData) ||
!providerData.TryGetValue("AuthUrl", out var urlObject))
{
throw new InvalidOperationException("Duo authentication error: Could not get ProviderData or AuthUrl");
}
var url = urlObject as string;
if (string.IsNullOrWhiteSpace(url))
{
throw new ArgumentNullException("Duo authentication error: Could not get valid auth url");
}
WebAuthenticatorResult authResult;
try
{
authResult = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions
{
Url = new Uri(url),
CallbackUrl = new Uri(Constants.DuoCallback)
});
}
catch (TaskCanceledException)
{
// user canceled
await _deviceActionService.HideLoadingAsync();
return;
}
await _deviceActionService.HideLoadingAsync();
if (authResult == null || authResult.Properties == null)
{
throw new InvalidOperationException("Duo authentication error: Could not get result from authentication");
}
if (authResult.Properties.TryGetValue("error", out var resultError))
{
_logger.Error(resultError);
await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred, AppResources.Ok);
return;
}
string code = null;
if (authResult.Properties.TryGetValue("code", out var resultCodeData))
{
code = Uri.UnescapeDataString(resultCodeData);
}
if (string.IsNullOrWhiteSpace(code))
{
throw new ArgumentException("Duo authentication error: response code is null or empty/whitespace");
}
string state = null;
if (authResult.Properties.TryGetValue("state", out var resultStateData))
{
state = Uri.UnescapeDataString(resultStateData);
}
if (string.IsNullOrWhiteSpace(state))
{
throw new ArgumentException("Duo authentication error: response state is null or empty/whitespace");
}
Token = $"{code}|{state}";
await SubmitAsync(true);
}
public void SetDuoWebViewHeight() public void SetDuoWebViewHeight()
{ {
var screenHeight = DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density; var screenHeight = DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density;

View File

@@ -1,20 +1,40 @@
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Pages;
using Bit.Core.Abstractions;
using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
namespace Bit.Core.Pages; namespace Bit.Core.Pages;
public partial class AndroidNavigationRedirectPage : ContentPage public partial class AndroidNavigationRedirectPage : ContentPage
{ {
private readonly IAccountsManager _accountsManager; private AppOptions _options;
public AndroidNavigationRedirectPage(AppOptions options)
public AndroidNavigationRedirectPage()
{ {
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager"); _options = options ?? new AppOptions();
InitializeComponent(); InitializeComponent();
} }
private void AndroidNavigationRedirectPage_OnLoaded(object sender, EventArgs e) private void AndroidNavigationRedirectPage_OnLoaded(object sender, EventArgs e)
{ {
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget(); if (ServiceContainer.TryResolve<IAccountsManager>(out var accountsManager))
{
accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
}
else
{
Bit.App.App.MainPage = new NavigationPage(new HomePage(_options)); //Fallback scenario to load HomePage just in case something goes wrong when resolving IAccountsManager
}
if (ServiceContainer.TryResolve<IConditionedAwaiterManager>(out var conditionedAwaiterManager))
{
conditionedAwaiterManager?.SetAsCompleted(AwaiterPrecondition.AndroidWindowCreated);
}
else
{
LoggerHelper.LogEvenIfCantBeResolved(new InvalidOperationException("ConditionedAwaiterManager can't be resolved on Android Navigation redirection"));
}
} }
} }

View File

@@ -266,6 +266,8 @@
AutomationId="SendShowHideOptionsButton" /> AutomationId="SendShowHideOptionsButton" />
<controls:IconButton <controls:IconButton
x:Name="_btnOptionsUp" x:Name="_btnOptionsUp"
InputTransparent="True"
MinimumWidthRequest="25"
Text="{Binding Source={x:Static core:BitwardenIcons.ChevronUp}}" Text="{Binding Source={x:Static core:BitwardenIcons.ChevronUp}}"
StyleClass="box-row-button" StyleClass="box-row-button"
TextColor="{DynamicResource PrimaryColor}" TextColor="{DynamicResource PrimaryColor}"
@@ -274,6 +276,8 @@
AutomationId="SendOptionsDisplayed" /> AutomationId="SendOptionsDisplayed" />
<controls:IconButton <controls:IconButton
x:Name="_btnOptionsDown" x:Name="_btnOptionsDown"
InputTransparent="True"
MinimumWidthRequest="25"
Text="{Binding Source={x:Static core:BitwardenIcons.AngleDown}}" Text="{Binding Source={x:Static core:BitwardenIcons.AngleDown}}"
StyleClass="box-row-button" StyleClass="box-row-button"
TextColor="{DynamicResource PrimaryColor}" TextColor="{DynamicResource PrimaryColor}"

View File

@@ -50,6 +50,7 @@
x:DataType="pages:SendGroupingsPageListItem"> x:DataType="pages:SendGroupingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal" <controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform" StyleClass="list-row, list-row-platform"
Spacing="6"
AutomationId="{Binding AutomationId}"> AutomationId="{Binding AutomationId}">
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}" <controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start" HorizontalOptions="Start"

View File

@@ -5,7 +5,7 @@
x:Class="Bit.App.Pages.AutofillPage" x:Class="Bit.App.Pages.AutofillPage"
xmlns:pages="clr-namespace:Bit.App.Pages" xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities" xmlns:u="clr-namespace:Bit.App.Utilities"
Title="{u:I18n PasswordAutofill}"> Title="{u:I18n SetUpAutofill}">
<ContentPage.ToolbarItems> <ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" /> <ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
@@ -15,26 +15,22 @@
<StackLayout Spacing="5" <StackLayout Spacing="5"
Padding="20, 20, 20, 30" Padding="20, 20, 20, 30"
VerticalOptions="FillAndExpand"> VerticalOptions="FillAndExpand">
<Label Text="{u:I18n ExtensionInstantAccess}" <Label Text="{u:I18n GetInstantAccessToYourPasswordsAndPasskeys}"
HorizontalOptions="Center" HorizontalOptions="Center"
HorizontalTextAlignment="Center" HorizontalTextAlignment="Center"
LineBreakMode="WordWrap" LineBreakMode="WordWrap"
StyleClass="text-lg" StyleClass="text-lg"
Margin="0, 0, 0, 15" /> Margin="0, 0, 0, 15" />
<Label Text="{u:I18n AutofillTurnOn}" <Label Text="{u:I18n SetUpAutoFillDescriptionLong}"
HorizontalOptions="Center" HorizontalOptions="Center"
HorizontalTextAlignment="Center" HorizontalTextAlignment="Center"
LineBreakMode="WordWrap" LineBreakMode="WordWrap"
Margin="0, 0, 0, 15" /> Margin="0, 0, 0, 15" />
<Label Text="{u:I18n AutofillTurnOn1}" <Label Text="{u:I18n FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions}"
LineBreakMode="WordWrap" /> LineBreakMode="WordWrap" />
<Label Text="{u:I18n AutofillTurnOn2}" <Label Text="{u:I18n SecondDotTurnOnAutoFill}"
LineBreakMode="WordWrap" /> LineBreakMode="WordWrap" />
<Label Text="{u:I18n AutofillTurnOn3}" <Label Text="{u:I18n ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys}"
LineBreakMode="WordWrap" />
<Label Text="{u:I18n AutofillTurnOn4}"
LineBreakMode="WordWrap" />
<Label Text="{u:I18n AutofillTurnOn5}"
LineBreakMode="WordWrap" /> LineBreakMode="WordWrap" />
<Image Source="autofill-kb.png" <Image Source="autofill-kb.png"
VerticalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"

View File

@@ -37,10 +37,9 @@
<Label <Label
Text="{u:I18n FingerprintPhrase}" Text="{u:I18n FingerprintPhrase}"
FontSize="Small" FontSize="Small"
Padding="0, 10, 0 ,0"
FontAttributes="Bold"/> FontAttributes="Bold"/>
<controls:MonoLabel <controls:MonoLabel
FormattedText="{Binding FingerprintPhrase}" Text="{Binding FingerprintPhrase}"
Grid.Row="1" Grid.Row="1"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
FontSize="Small" FontSize="Small"
@@ -70,21 +69,24 @@
Grid.ColumnSpan="2"/> Grid.ColumnSpan="2"/>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout <Grid
x:Key="mainLayout" RowDefinitions="*, Auto"
x:Name="_mainLayout"
Padding="0, 10"> Padding="0, 10">
<RefreshView <RefreshView
Grid.Row="0"
IsRefreshing="{Binding IsRefreshing}" IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}" Command="{Binding RefreshCommand}"
VerticalOptions="FillAndExpand" VerticalOptions="Fill"
BackgroundColor="{DynamicResource BackgroundColor}"> BackgroundColor="{DynamicResource BackgroundColor}">
<StackLayout> <Grid RowDefinitions="Auto, *">
<VerticalStackLayout Grid.Row="0"
HorizontalOptions="Center">
<Image <Image
x:Name="_emptyPlaceholder" x:Name="_emptyPlaceholder"
Source="empty_login_requests" Source="empty_login_requests"
HorizontalOptions="Center"
WidthRequest="160" WidthRequest="160"
HeightRequest="160" HeightRequest="160"
Margin="0,70,0,0" Margin="0,70,0,0"
@@ -96,9 +98,10 @@
IsVisible="{Binding HasLoginRequests, Converter={StaticResource inverseBool}}" IsVisible="{Binding HasLoginRequests, Converter={StaticResource inverseBool}}"
FontAttributes="{OnPlatform iOS=Bold}" FontAttributes="{OnPlatform iOS=Bold}"
FontWeight="500" FontWeight="500"
HorizontalTextAlignment="Center"
Margin="14,10,14,0"/> Margin="14,10,14,0"/>
</VerticalStackLayout>
<controls:ExtendedCollectionView <controls:ExtendedCollectionView
Grid.Row="1"
ItemsSource="{Binding LoginRequests}" ItemsSource="{Binding LoginRequests}"
ItemTemplate="{StaticResource loginRequestTemplate}" ItemTemplate="{StaticResource loginRequestTemplate}"
SelectionMode="Single" SelectionMode="Single"
@@ -111,9 +114,11 @@
EventArgsConverter="{StaticResource SelectionChangedEventArgsConverter}" /> EventArgsConverter="{StaticResource SelectionChangedEventArgsConverter}" />
</controls:ExtendedCollectionView.Behaviors> </controls:ExtendedCollectionView.Behaviors>
</controls:ExtendedCollectionView> </controls:ExtendedCollectionView>
</StackLayout> </Grid>
</RefreshView> </RefreshView>
<controls:IconLabelButton <controls:IconLabelButton
Grid.Row="1"
VerticalOptions="End" VerticalOptions="End"
Margin="10,0" Margin="10,0"
Icon="{Binding Source={x:Static core:BitwardenIcons.Trash}}" Icon="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
@@ -121,13 +126,13 @@
ButtonCommand="{Binding DeclineAllRequestsCommand}" ButtonCommand="{Binding DeclineAllRequestsCommand}"
IsVisible="{Binding HasLoginRequests}" IsVisible="{Binding HasLoginRequests}"
AutomationId="DeleteAllRequestsButton" /> AutomationId="DeleteAllRequestsButton" />
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>
<ContentView <Grid x:Name="_activityIndicatorGrid" Grid.Row="0" Grid.RowSpan="2" BackgroundColor="{DynamicResource BackgroundColor}">
x:Name="_mainContent"> <ActivityIndicator IsRunning="True"
</ContentView> VerticalOptions="Center"
HorizontalOptions="Center" />
</Grid>
</Grid>
</pages:BaseContentPage> </pages:BaseContentPage>

View File

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Bit.App.Utilities; using Bit.App.Utilities;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Models.Response; using Bit.Core.Models.Response;
using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls; using Microsoft.Maui.Controls;
@@ -19,7 +20,6 @@ namespace Bit.App.Pages
public LoginPasswordlessRequestsListPage() public LoginPasswordlessRequestsListPage()
{ {
InitializeComponent(); InitializeComponent();
SetActivityIndicator(_mainContent);
_vm = BindingContext as LoginPasswordlessRequestsListViewModel; _vm = BindingContext as LoginPasswordlessRequestsListViewModel;
_vm.Page = this; _vm.Page = this;
} }
@@ -27,10 +27,22 @@ namespace Bit.App.Pages
protected override async void OnAppearing() protected override async void OnAppearing()
{ {
base.OnAppearing(); base.OnAppearing();
await LoadOnAppearedAsync(_mainLayout, false, _vm.RefreshAsync, _mainContent); try
{
_activityIndicatorGrid.IsVisible = true;
await _vm.RefreshAsync();
UpdatePlaceholder(); UpdatePlaceholder();
} }
catch (Exception ex)
{
LoggerHelper.LogEvenIfCantBeResolved(ex);
}
finally
{
_activityIndicatorGrid.IsVisible = false;
}
}
private async void Close_Clicked(object sender, System.EventArgs e) private async void Close_Clicked(object sender, System.EventArgs e)
{ {

View File

@@ -66,7 +66,6 @@ namespace Bit.App.Pages
{ {
try try
{ {
IsRefreshing = true;
LoginRequests.ReplaceRange(await _authService.GetActivePasswordlessLoginRequestsAsync()); LoginRequests.ReplaceRange(await _authService.GetActivePasswordlessLoginRequestsAsync());
} }
catch (Exception ex) catch (Exception ex)
@@ -108,7 +107,7 @@ namespace Bit.App.Pages
Origin = loginRequestData.Origin Origin = loginRequestData.Origin
}); });
await Device.InvokeOnMainThreadAsync(() => Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page))); await MainThread.InvokeOnMainThreadAsync(() => Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page)));
} }
private async Task DeclineAllRequestsAsync() private async Task DeclineAllRequestsAsync()

View File

@@ -370,7 +370,7 @@ namespace Bit.App.Pages
if (!_supportsBiometric if (!_supportsBiometric
|| ||
!await _platformUtilsService.AuthenticateBiometricAsync(null, DeviceInfo.Platform == DevicePlatform.Android ? "." : null)) await _platformUtilsService.AuthenticateBiometricAsync(null, DeviceInfo.Platform == DevicePlatform.Android ? "." : null) != true)
{ {
_canUnlockWithBiometrics = false; _canUnlockWithBiometrics = false;
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics))); MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));

View File

@@ -96,6 +96,14 @@ namespace Bit.App.Pages
if (message.Command == "syncCompleted") if (message.Command == "syncCompleted")
{ {
MainThread.BeginInvokeOnMainThread(async () => await UpdateVaultButtonTitleAsync()); MainThread.BeginInvokeOnMainThread(async () => await UpdateVaultButtonTitleAsync());
try
{
await ForcePasswordResetIfNeededAsync();
}
catch (Exception ex)
{
_logger.Value.Exception(ex);
}
} }
}); });
await UpdateVaultButtonTitleAsync(); await UpdateVaultButtonTitleAsync();

View File

@@ -166,15 +166,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> /// <summary>
/// Looks up a localized string similar to Bitwarden needs attention - See &quot;Auto-fill Accessibility Service&quot; from Bitwarden settings. /// Looks up a localized string similar to Bitwarden needs attention - See &quot;Auto-fill Accessibility Service&quot; from Bitwarden settings.
/// </summary> /// </summary>
@@ -1327,6 +1318,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to 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 &gt; System &gt; Passwords &amp; accounts &gt; Passwords, passkeys and data services..
/// </summary>
public static string BitwardenCredentialProviderGoToSettings {
get {
return ResourceManager.GetString("BitwardenCredentialProviderGoToSettings", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Bitwarden Help Center. /// Looks up a localized string similar to Bitwarden Help Center.
/// </summary> /// </summary>
@@ -1543,6 +1543,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Choose a login to save this passkey to.
/// </summary>
public static string ChooseALoginToSaveThisPasskeyTo {
get {
return ResourceManager.GetString("ChooseALoginToSaveThisPasskeyTo", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Choose file. /// Looks up a localized string similar to Choose file.
/// </summary> /// </summary>
@@ -1903,6 +1912,24 @@ 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> /// <summary>
/// Looks up a localized string similar to Credits. /// Looks up a localized string similar to Credits.
/// </summary> /// </summary>
@@ -2344,6 +2371,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Duo two-step login is required for your account. .
/// </summary>
public static string DuoTwoStepLoginIsRequiredForYourAccount {
get {
return ResourceManager.GetString("DuoTwoStepLoginIsRequiredForYourAccount", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Edit. /// Looks up a localized string similar to Edit.
/// </summary> /// </summary>
@@ -2596,6 +2632,24 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Error creating passkey.
/// </summary>
public static string ErrorCreatingPasskey {
get {
return ResourceManager.GetString("ErrorCreatingPasskey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error reading passkey.
/// </summary>
public static string ErrorReadingPasskey {
get {
return ResourceManager.GetString("ErrorReadingPasskey", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to EU. /// Looks up a localized string similar to EU.
/// </summary> /// </summary>
@@ -3136,6 +3190,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to 1. Go to your device&apos;s Settings &gt; Passwords &gt; Password Options.
/// </summary>
public static string FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions {
get {
return ResourceManager.GetString("FirstDotGoToYourDeviceSettingsPasswordsPasswordOptions", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to First name. /// Looks up a localized string similar to First name.
/// </summary> /// </summary>
@@ -3208,6 +3271,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Follow the steps from Duo to finish logging in..
/// </summary>
public static string FollowTheStepsFromDuoToFinishLoggingIn {
get {
return ResourceManager.GetString("FollowTheStepsFromDuoToFinishLoggingIn", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to {0} is not correctly formatted.. /// Looks up a localized string similar to {0} is not correctly formatted..
/// </summary> /// </summary>
@@ -3316,6 +3388,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Get instant access to your passwords and passkeys!.
/// </summary>
public static string GetInstantAccessToYourPasswordsAndPasskeys {
get {
return ResourceManager.GetString("GetInstantAccessToYourPasswordsAndPasskeys", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Get master password hint. /// Looks up a localized string similar to Get master password hint.
/// </summary> /// </summary>
@@ -3802,6 +3883,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Launch Duo.
/// </summary>
public static string LaunchDuo {
get {
return ResourceManager.GetString("LaunchDuo", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Bitwarden allows you to share your vault items with others by using an organization. Learn more on the bitwarden.com website.. /// Looks up a localized string similar to Bitwarden allows you to share your vault items with others by using an organization. Learn more on the bitwarden.com website..
/// </summary> /// </summary>
@@ -5110,6 +5200,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Overwrite passkey?.
/// </summary>
public static string OverwritePasskey {
get {
return ResourceManager.GetString("OverwritePasskey", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Ownership. /// Looks up a localized string similar to Ownership.
/// </summary> /// </summary>
@@ -5137,6 +5236,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Passkeys for {0}.
/// </summary>
public static string PasskeysForX {
get {
return ResourceManager.GetString("PasskeysForX", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Passkey will not be copied. /// Looks up a localized string similar to Passkey will not be copied.
/// </summary> /// </summary>
@@ -5317,6 +5425,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Passwords.
/// </summary>
public static string Passwords {
get {
return ResourceManager.GetString("Passwords", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to This password was not found in any known data breaches. It should be safe to use.. /// Looks up a localized string similar to This password was not found in any known data breaches. It should be safe to use..
/// </summary> /// </summary>
@@ -5326,6 +5443,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Passwords for {0}.
/// </summary>
public static string PasswordsForX {
get {
return ResourceManager.GetString("PasswordsForX", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Password type. /// Looks up a localized string similar to Password type.
/// </summary> /// </summary>
@@ -5831,6 +5957,24 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Save passkey.
/// </summary>
public static string SavePasskey {
get {
return ResourceManager.GetString("SavePasskey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save passkey as new login.
/// </summary>
public static string SavePasskeyAsNewLogin {
get {
return ResourceManager.GetString("SavePasskeyAsNewLogin", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Saving.... /// Looks up a localized string similar to Saving....
/// </summary> /// </summary>
@@ -5939,6 +6083,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to 2. Turn on AutoFill.
/// </summary>
public static string SecondDotTurnOnAutoFill {
get {
return ResourceManager.GetString("SecondDotTurnOnAutoFill", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Secure notes. /// Looks up a localized string similar to Secure notes.
/// </summary> /// </summary>
@@ -6263,6 +6416,24 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Set up auto-fill.
/// </summary>
public static string SetUpAutofill {
get {
return ResourceManager.GetString("SetUpAutofill", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to To set up password auto-fill and passkey management, set Bitwarden as your preferred provider in the iOS Settings..
/// </summary>
public static string SetUpAutoFillDescriptionLong {
get {
return ResourceManager.GetString("SetUpAutoFillDescriptionLong", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Set up TOTP. /// Looks up a localized string similar to Set up TOTP.
/// </summary> /// </summary>
@@ -6668,6 +6839,24 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to There was a problem creating a passkey for {0}. Try again later..
/// </summary>
public static string ThereWasAProblemCreatingAPasskeyForXTryAgainLater {
get {
return ResourceManager.GetString("ThereWasAProblemCreatingAPasskeyForXTryAgainLater", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There was a problem reading your passkey for {0}. Try again later..
/// </summary>
public static string ThereWasAProblemReadingAPasskeyForXTryAgainLater {
get {
return ResourceManager.GetString("ThereWasAProblemReadingAPasskeyForXTryAgainLater", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to The URI {0} is already blocked. /// Looks up a localized string similar to The URI {0} is already blocked.
/// </summary> /// </summary>
@@ -6677,6 +6866,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to 3. Select &quot;Bitwarden&quot; to use for passwords and passkeys.
/// </summary>
public static string ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys {
get {
return ResourceManager.GetString("ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to 30 days. /// Looks up a localized string similar to 30 days.
/// </summary> /// </summary>
@@ -6704,6 +6902,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to This item already contains a passkey. Are you sure you want to overwrite the current passkey?.
/// </summary>
public static string ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey {
get {
return ResourceManager.GetString("ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to This request is no longer valid. /// Looks up a localized string similar to This request is no longer valid.
/// </summary> /// </summary>
@@ -7001,6 +7208,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Unknown account.
/// </summary>
public static string UnknownAccount {
get {
return ResourceManager.GetString("UnknownAccount", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Unknown {0} error occurred.. /// Looks up a localized string similar to Unknown {0} error occurred..
/// </summary> /// </summary>
@@ -7487,6 +7703,24 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Verification required by {0}.
/// </summary>
public static string VerificationRequiredByX {
get {
return ResourceManager.GetString("VerificationRequiredByX", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Verification required for this action. Set up an unlock method in Bitwarden to continue..
/// </summary>
public static string VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue {
get {
return ResourceManager.GetString("VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Verify Face ID. /// Looks up a localized string similar to Verify Face ID.
/// </summary> /// </summary>
@@ -7514,6 +7748,15 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to Verifying identity....
/// </summary>
public static string VerifyingIdentityEllipsis {
get {
return ResourceManager.GetString("VerifyingIdentityEllipsis", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Verify master password. /// Looks up a localized string similar to Verify master password.
/// </summary> /// </summary>
@@ -7694,15 +7937,6 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <summary>
/// Looks up a localized string similar to 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 &gt; System &gt; Passwords &amp; accounts &gt; Passwords, passkeys and data services.
/// </summary>
public static string BitwardenCredentialProviderGoToSettings {
get {
return ResourceManager.GetString("BitwardenCredentialProviderGoToSettings", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Word separator. /// Looks up a localized string similar to Word separator.
/// </summary> /// </summary>
@@ -7721,15 +7955,6 @@ namespace Bit.Core.Resources.Localization {
} }
} }
/// <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> /// <summary>
/// Looks up a localized string similar to {0} hours and one minute. /// Looks up a localized string similar to {0} hours and one minute.
/// </summary> /// </summary>

View File

@@ -2876,4 +2876,13 @@ Wil u na die rekening omskakel?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -276,7 +276,7 @@
<value>هل أنت متأكد من أنك تريد تسجيل الخروج؟</value> <value>هل أنت متأكد من أنك تريد تسجيل الخروج؟</value>
</data> </data>
<data name="RemoveAccount" xml:space="preserve"> <data name="RemoveAccount" xml:space="preserve">
<value>إزالة الحساب</value> <value>أزِل الحساب</value>
</data> </data>
<data name="RemoveAccountConfirmation" xml:space="preserve"> <data name="RemoveAccountConfirmation" xml:space="preserve">
<value>هل أنت متأكد من أنك تريد إزالة هذا الحساب؟</value> <value>هل أنت متأكد من أنك تريد إزالة هذا الحساب؟</value>
@@ -2822,7 +2822,7 @@
<value>مواصلة الاتصال بالدعم؟</value> <value>مواصلة الاتصال بالدعم؟</value>
</data> </data>
<data name="ContinueToPrivacyPolicy" xml:space="preserve"> <data name="ContinueToPrivacyPolicy" xml:space="preserve">
<value>Continue to privacy policy?</value> <value>هل تريد المتابعة إلى سياسة الخصوصية؟</value>
</data> </data>
<data name="ContinueToAppStore" xml:space="preserve"> <data name="ContinueToAppStore" xml:space="preserve">
<value>هل تريد المتابعة إلى متجر التطبيقات؟</value> <value>هل تريد المتابعة إلى متجر التطبيقات؟</value>
@@ -2844,7 +2844,7 @@
<value>لا يمكن العثور على ما تبحث عنه؟ قم بالتواصل مع دعم Bitwarden على bitwarden.com.</value> <value>لا يمكن العثور على ما تبحث عنه؟ قم بالتواصل مع دعم Bitwarden على bitwarden.com.</value>
</data> </data>
<data name="PrivacyPolicyDescriptionLong" xml:space="preserve"> <data name="PrivacyPolicyDescriptionLong" xml:space="preserve">
<value>Check out our privacy policy on bitwarden.com.</value> <value>اطلع على سياستنا للخصوصية على bitwarden.com.</value>
</data> </data>
<data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve"> <data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve">
<value>استكشف المزيد من الميزات لحساب Bitwarden الخاص بك على تطبيق الويب.</value> <value>استكشف المزيد من الميزات لحساب Bitwarden الخاص بك على تطبيق الويب.</value>
@@ -2877,4 +2877,13 @@
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك.</value> <value>أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>تسجيل الدخول لـ Duo من خطوتين مطلوب لحسابك. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>اتبع الخطوات من Duo لإنهاء تسجيل الدخول.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>تشغيل Duo</value>
</data>
</root> </root>

View File

@@ -2875,4 +2875,13 @@ Bu hesaba keçmək istəyirsiniz?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <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> <value>Anbar vaxt bitməsi əməliyyatınızı dəyişdirmək üçün bir kilid açma seçimi qurun.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Hesabınız üçün Duo iki addımlı giriş tələb olunur. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Giriş etməni tamamlamaq üçün Duo-dakı addımları izləyin.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Duo-nu başlat</value>
</data>
</root> </root>

View File

@@ -2623,22 +2623,22 @@
<value>Бягучы асноўны пароль</value> <value>Бягучы асноўны пароль</value>
</data> </data>
<data name="LoggedIn" xml:space="preserve"> <data name="LoggedIn" xml:space="preserve">
<value>Logged in!</value> <value>Вы ўвайшлі!</value>
</data> </data>
<data name="ApproveWithMyOtherDevice" xml:space="preserve"> <data name="ApproveWithMyOtherDevice" xml:space="preserve">
<value>Approve with my other device</value> <value>Approve with my other device</value>
</data> </data>
<data name="RequestAdminApproval" xml:space="preserve"> <data name="RequestAdminApproval" xml:space="preserve">
<value>Request admin approval</value> <value>Запытаць ухваленне адміністратара</value>
</data> </data>
<data name="ApproveWithMasterPassword" xml:space="preserve"> <data name="ApproveWithMasterPassword" xml:space="preserve">
<value>Approve with master password</value> <value>Ухваліць з дапамогай асноўнага пароля</value>
</data> </data>
<data name="TurnOffUsingPublicDevice" xml:space="preserve"> <data name="TurnOffUsingPublicDevice" xml:space="preserve">
<value>Turn off using a public device</value> <value>Turn off using a public device</value>
</data> </data>
<data name="RememberThisDevice" xml:space="preserve"> <data name="RememberThisDevice" xml:space="preserve">
<value>Remember this device</value> <value>Запомніць гэту прыладу</value>
</data> </data>
<data name="Passkey" xml:space="preserve"> <data name="Passkey" xml:space="preserve">
<value>Passkey</value> <value>Passkey</value>
@@ -2677,19 +2677,19 @@
<value>Памылковы токен API</value> <value>Памылковы токен API</value>
</data> </data>
<data name="AdminApprovalRequested" xml:space="preserve"> <data name="AdminApprovalRequested" xml:space="preserve">
<value>Admin approval requested</value> <value>Патрабуецца ўхваленне адміністратара</value>
</data> </data>
<data name="YourRequestHasBeenSentToYourAdmin" xml:space="preserve"> <data name="YourRequestHasBeenSentToYourAdmin" xml:space="preserve">
<value>Your request has been sent to your admin.</value> <value>Ваш запыт адпраўлены адміністратару.</value>
</data> </data>
<data name="YouWillBeNotifiedOnceApproved" xml:space="preserve"> <data name="YouWillBeNotifiedOnceApproved" xml:space="preserve">
<value>You will be notified once approved. </value> <value>Вы атрымаеце апавяшчэння пасля яго ўхвалення. </value>
</data> </data>
<data name="TroubleLoggingIn" xml:space="preserve"> <data name="TroubleLoggingIn" xml:space="preserve">
<value>Trouble logging in?</value> <value>Праблемы з уваходам?</value>
</data> </data>
<data name="LoggingInAsX" xml:space="preserve"> <data name="LoggingInAsX" xml:space="preserve">
<value>Logging in as {0}</value> <value>Увайсці як {0}</value>
</data> </data>
<data name="VaultTimeoutActionChangedToLogOut" xml:space="preserve"> <data name="VaultTimeoutActionChangedToLogOut" xml:space="preserve">
<value>Vault timeout action changed to log out</value> <value>Vault timeout action changed to log out</value>
@@ -2738,7 +2738,7 @@
<value>Немагчыма рэдагаваць некалькі URI адначасова</value> <value>Немагчыма рэдагаваць некалькі URI адначасова</value>
</data> </data>
<data name="LoginApproved" xml:space="preserve"> <data name="LoginApproved" xml:space="preserve">
<value>Login approved</value> <value>Уваход ухвалены</value>
</data> </data>
<data name="LogInWithDeviceMustBeSetUpInTheSettingsOfTheBitwardenAppNeedAnotherOption" xml:space="preserve"> <data name="LogInWithDeviceMustBeSetUpInTheSettingsOfTheBitwardenAppNeedAnotherOption" xml:space="preserve">
<value>Log in with device must be set up in the settings of the Bitwarden app. Need another option?</value> <value>Log in with device must be set up in the settings of the Bitwarden app. Need another option?</value>
@@ -2747,28 +2747,28 @@
<value>Log in with device</value> <value>Log in with device</value>
</data> </data>
<data name="LoggingInOn" xml:space="preserve"> <data name="LoggingInOn" xml:space="preserve">
<value>Logging in on</value> <value>Увайсці на</value>
</data> </data>
<data name="Vault" xml:space="preserve"> <data name="Vault" xml:space="preserve">
<value>Vault</value> <value>Сховішча</value>
</data> </data>
<data name="Appearance" xml:space="preserve"> <data name="Appearance" xml:space="preserve">
<value>Appearance</value> <value>Знешні выгляд</value>
</data> </data>
<data name="AccountSecurity" xml:space="preserve"> <data name="AccountSecurity" xml:space="preserve">
<value>Account security</value> <value>Бяспеке акаўнта</value>
</data> </data>
<data name="BitwardenHelpCenter" xml:space="preserve"> <data name="BitwardenHelpCenter" xml:space="preserve">
<value>Bitwarden Help Center</value> <value>Даведачны цэнтр Bitwarden</value>
</data> </data>
<data name="ContactBitwardenSupport" xml:space="preserve"> <data name="ContactBitwardenSupport" xml:space="preserve">
<value>Contact Bitwarden support</value> <value>Звярніцеся ў службу падтрымкі Bitwarden</value>
</data> </data>
<data name="CopyAppInformation" xml:space="preserve"> <data name="CopyAppInformation" xml:space="preserve">
<value>Copy app information</value> <value>Copy app information</value>
</data> </data>
<data name="SyncNow" xml:space="preserve"> <data name="SyncNow" xml:space="preserve">
<value>Sync now</value> <value>Сінхранізаваць зараз</value>
</data> </data>
<data name="UnlockOptions" xml:space="preserve"> <data name="UnlockOptions" xml:space="preserve">
<value>Unlock options</value> <value>Unlock options</value>
@@ -2805,7 +2805,7 @@
<value>Use inline autofill if your selected keyboard supports it. Otherwise, use the default overlay.</value> <value>Use inline autofill if your selected keyboard supports it. Otherwise, use the default overlay.</value>
</data> </data>
<data name="AdditionalOptions" xml:space="preserve"> <data name="AdditionalOptions" xml:space="preserve">
<value>Additional options</value> <value>Дадатковы параметры</value>
</data> </data>
<data name="ContinueToWebApp" xml:space="preserve"> <data name="ContinueToWebApp" xml:space="preserve">
<value>Continue to web app?</value> <value>Continue to web app?</value>
@@ -2876,4 +2876,13 @@
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2876,4 +2876,13 @@
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Задайте начин за отключване, за да може да промените действието при изтичане на времето за достъп до трезора.</value> <value>Задайте начин за отключване, за да може да промените действието при изтичане на времето за достъп до трезора.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Вашата регистрация изисква двустепенно удостоверяване чрез Duo. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Следвайте стъпките от Duo, за да завършите вписването.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Стартиране на Duo</value>
</data>
</root> </root>

View File

@@ -2877,4 +2877,13 @@ Do you want to switch to this account?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2875,4 +2875,13 @@ Skeniranje će biti izvršeno automatski.</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2876,4 +2876,13 @@ Voleu canviar a aquest compte?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <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> <value>Configura una opció de desbloqueig per canviar l'acció de temps d'espera de la caixa forta.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Es requereix l'inici de sessió en dos passos de DUO al vostre compte. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Seguiu els passos de Duo per acabar d'iniciar la sessió.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Inicia DUO</value>
</data>
</root> </root>

View File

@@ -2875,4 +2875,13 @@ Chcete se přepnout na tento účet?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Nastavte volbu odemknutí, abyste změnili časový limit Vašeho trezoru.</value> <value>Nastavte volbu odemknutí, abyste změnili časový limit Vašeho trezoru.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Pro Váš účet je vyžadováno dvoufázové přihlášení DUO. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Postupujte podle kroků od DUO pro dokončení přihlášení.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Spustit DUO</value>
</data>
</root> </root>

View File

@@ -315,7 +315,7 @@
<comment>Label for notes.</comment> <comment>Label for notes.</comment>
</data> </data>
<data name="Ok" xml:space="preserve"> <data name="Ok" xml:space="preserve">
<value>Ok</value> <value>Iawn</value>
<comment>Acknowledgement.</comment> <comment>Acknowledgement.</comment>
</data> </data>
<data name="Password" xml:space="preserve"> <data name="Password" xml:space="preserve">
@@ -346,7 +346,7 @@
<comment>Confirmation message after successfully deleting a login.</comment> <comment>Confirmation message after successfully deleting a login.</comment>
</data> </data>
<data name="Submit" xml:space="preserve"> <data name="Submit" xml:space="preserve">
<value>Submit</value> <value>Cyflwyno</value>
</data> </data>
<data name="Sync" xml:space="preserve"> <data name="Sync" xml:space="preserve">
<value>Cysoni</value> <value>Cysoni</value>
@@ -371,7 +371,7 @@
<comment>Label for a username.</comment> <comment>Label for a username.</comment>
</data> </data>
<data name="ValidationFieldRequired" xml:space="preserve"> <data name="ValidationFieldRequired" xml:space="preserve">
<value>The {0} field is required.</value> <value>Mae'r maes {0} yn ofynnol.</value>
<comment>Validation message for when a form field is left blank and is required to be entered.</comment> <comment>Validation message for when a form field is left blank and is required to be entered.</comment>
</data> </data>
<data name="ValueHasBeenCopied" xml:space="preserve"> <data name="ValueHasBeenCopied" xml:space="preserve">
@@ -382,7 +382,7 @@
<value>Verify fingerprint</value> <value>Verify fingerprint</value>
</data> </data>
<data name="VerifyMasterPassword" xml:space="preserve"> <data name="VerifyMasterPassword" xml:space="preserve">
<value>Verify master password</value> <value>Gwirio'r prif gyfrinair</value>
</data> </data>
<data name="VerifyPIN" xml:space="preserve"> <data name="VerifyPIN" xml:space="preserve">
<value>Verify PIN</value> <value>Verify PIN</value>
@@ -407,7 +407,7 @@
<value>Cyfrif</value> <value>Cyfrif</value>
</data> </data>
<data name="AccountCreated" xml:space="preserve"> <data name="AccountCreated" xml:space="preserve">
<value>Your new account has been created! You may now log in.</value> <value>Mae eich cyfrif newydd wedi cael ei greu! Gallwch bellach fewngofnodi.</value>
</data> </data>
<data name="AddAnItem" xml:space="preserve"> <data name="AddAnItem" xml:space="preserve">
<value>Ychwanegu eitem</value> <value>Ychwanegu eitem</value>
@@ -784,10 +784,10 @@
<value>Do you want to auto-fill or view this item?</value> <value>Do you want to auto-fill or view this item?</value>
</data> </data>
<data name="BitwardenAutofillServiceMatchConfirm" xml:space="preserve"> <data name="BitwardenAutofillServiceMatchConfirm" xml:space="preserve">
<value>Are you sure you want to auto-fill this item? It is not a complete match for "{0}".</value> <value>Ydych chi'n siŵr eich bod am lenwi'r eitem hon? Dyw hi ddim yn cyfateb yn llwyr i "{0}".</value>
</data> </data>
<data name="MatchingItems" xml:space="preserve"> <data name="MatchingItems" xml:space="preserve">
<value>Matching items</value> <value>Eitemau sy'n cyfateb</value>
</data> </data>
<data name="PossibleMatchingItems" xml:space="preserve"> <data name="PossibleMatchingItems" xml:space="preserve">
<value>Possible matching items</value> <value>Possible matching items</value>
@@ -799,22 +799,22 @@
<value>You are searching for an auto-fill item for "{0}".</value> <value>You are searching for an auto-fill item for "{0}".</value>
</data> </data>
<data name="LearnOrg" xml:space="preserve"> <data name="LearnOrg" xml:space="preserve">
<value>Learn about organizations</value> <value>Dysgu am sefydliadau</value>
</data> </data>
<data name="CannotOpenApp" xml:space="preserve"> <data name="CannotOpenApp" xml:space="preserve">
<value>Cannot open the app "{0}".</value> <value>Methu agor yr ap "{0}".</value>
<comment>Message shown when trying to launch an app that does not exist on the user's device.</comment> <comment>Message shown when trying to launch an app that does not exist on the user's device.</comment>
</data> </data>
<data name="AuthenticatorAppTitle" xml:space="preserve"> <data name="AuthenticatorAppTitle" xml:space="preserve">
<value>Authenticator app</value> <value>Ap dilysu</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="EnterVerificationCodeApp" xml:space="preserve"> <data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Enter the 6 digit verification code from your authenticator app.</value> <value>Rhowch y cod dilysu 6 nod o'ch ap dilysu.</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="EnterVerificationCodeEmail" xml:space="preserve"> <data name="EnterVerificationCodeEmail" xml:space="preserve">
<value>Enter the 6 digit verification code that was emailed to {0}.</value> <value>Rhowch y cod dilysu 6 nod anfonwyd i {0}.</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="LoginUnavailable" xml:space="preserve"> <data name="LoginUnavailable" xml:space="preserve">
@@ -895,7 +895,7 @@
Scanning will happen automatically.</value> Scanning will happen automatically.</value>
</data> </data>
<data name="ScanQrTitle" xml:space="preserve"> <data name="ScanQrTitle" xml:space="preserve">
<value>Scan QR Code</value> <value>Sganio cod QR</value>
</data> </data>
<data name="Camera" xml:space="preserve"> <data name="Camera" xml:space="preserve">
<value>Camera</value> <value>Camera</value>
@@ -1143,7 +1143,7 @@ Scanning will happen automatically.</value>
<value>Icons server URL</value> <value>Icons server URL</value>
</data> </data>
<data name="AutofillWithBitwarden" xml:space="preserve"> <data name="AutofillWithBitwarden" xml:space="preserve">
<value>Auto-fill with Bitwarden</value> <value>Llenwi'n awtomatig â Bitwarden</value>
</data> </data>
<data name="VaultIsLocked" xml:space="preserve"> <data name="VaultIsLocked" xml:space="preserve">
<value>Vault is locked</value> <value>Vault is locked</value>
@@ -1173,7 +1173,7 @@ Scanning will happen automatically.</value>
<value>Use the Bitwarden auto-fill service to fill login information into other apps.</value> <value>Use the Bitwarden auto-fill service to fill login information into other apps.</value>
</data> </data>
<data name="BitwardenAutofillServiceOpenAutofillSettings" xml:space="preserve"> <data name="BitwardenAutofillServiceOpenAutofillSettings" xml:space="preserve">
<value>Open Autofill Settings</value> <value>Agor gosodiadau llenwi awtomatig</value>
</data> </data>
<data name="FaceID" xml:space="preserve"> <data name="FaceID" xml:space="preserve">
<value>Face ID</value> <value>Face ID</value>
@@ -1256,7 +1256,7 @@ Scanning will happen automatically.</value>
<value>Yes, and save</value> <value>Yes, and save</value>
</data> </data>
<data name="AutofillAndSave" xml:space="preserve"> <data name="AutofillAndSave" xml:space="preserve">
<value>Auto-fill and save</value> <value>Llenwi'n awtomatig a chadw</value>
</data> </data>
<data name="Organization" xml:space="preserve"> <data name="Organization" xml:space="preserve">
<value>Sefydliad</value> <value>Sefydliad</value>
@@ -1486,7 +1486,7 @@ Scanning will happen automatically.</value>
<value>Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</value> <value>Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</value>
</data> </data>
<data name="LoggedInAsOn" xml:space="preserve"> <data name="LoggedInAsOn" xml:space="preserve">
<value>Logged in as {0} on {1}.</value> <value>Rydych wedi mewngofnodi fel {0} ar {1}.</value>
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment> <comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
</data> </data>
<data name="VaultLockedMasterPassword" xml:space="preserve"> <data name="VaultLockedMasterPassword" xml:space="preserve">
@@ -1541,7 +1541,7 @@ Scanning will happen automatically.</value>
<comment>Color theme</comment> <comment>Color theme</comment>
</data> </data>
<data name="ThemeDescription" xml:space="preserve"> <data name="ThemeDescription" xml:space="preserve">
<value>Newid thema liwiau'r ap.</value> <value>Newid thema liwiau'r ap</value>
</data> </data>
<data name="ThemeDefault" xml:space="preserve"> <data name="ThemeDefault" xml:space="preserve">
<value>Rhagosodiad (system)</value> <value>Rhagosodiad (system)</value>
@@ -1577,7 +1577,7 @@ Scanning will happen automatically.</value>
<value>Auto-fill blocked URIs</value> <value>Auto-fill blocked URIs</value>
</data> </data>
<data name="AskToAddLogin" xml:space="preserve"> <data name="AskToAddLogin" xml:space="preserve">
<value>Ask to add login</value> <value>Gofyn i ychwanegu manylion mewngofnodi</value>
</data> </data>
<data name="AskToAddLoginDescription" xml:space="preserve"> <data name="AskToAddLoginDescription" xml:space="preserve">
<value>Ask to add an item if one isn't found in your vault.</value> <value>Ask to add an item if one isn't found in your vault.</value>
@@ -1669,7 +1669,7 @@ Scanning will happen automatically.</value>
<comment>Title for the alert to confirm vault exports.</comment> <comment>Title for the alert to confirm vault exports.</comment>
</data> </data>
<data name="Warning" xml:space="preserve"> <data name="Warning" xml:space="preserve">
<value>Warning</value> <value>Rhybudd</value>
</data> </data>
<data name="ExportVaultFailure" xml:space="preserve"> <data name="ExportVaultFailure" xml:space="preserve">
<value>There was a problem exporting your vault. If the problem persists, you'll need to export from the web vault.</value> <value>There was a problem exporting your vault. If the problem persists, you'll need to export from the web vault.</value>
@@ -1945,7 +1945,7 @@ Scanning will happen automatically.</value>
<value>Current access count</value> <value>Current access count</value>
</data> </data>
<data name="NewPassword" xml:space="preserve"> <data name="NewPassword" xml:space="preserve">
<value>New password</value> <value>Cyfrinair newydd</value>
</data> </data>
<data name="PasswordInfo" xml:space="preserve"> <data name="PasswordInfo" xml:space="preserve">
<value>Optionally require a password for users to access this Send.</value> <value>Optionally require a password for users to access this Send.</value>
@@ -2310,7 +2310,7 @@ select Add TOTP to store the key safely</value>
<value>Caniatáu sgrinluniau</value> <value>Caniatáu sgrinluniau</value>
</data> </data>
<data name="AreYouSureYouWantToEnableScreenCapture" xml:space="preserve"> <data name="AreYouSureYouWantToEnableScreenCapture" xml:space="preserve">
<value>Are you sure you want to turn on screen capture?</value> <value>Ydych chi'n siŵr eich bod am ganiatáu sgrinluniau?</value>
</data> </data>
<data name="LogInRequested" xml:space="preserve"> <data name="LogInRequested" xml:space="preserve">
<value>Login requested</value> <value>Login requested</value>
@@ -2394,16 +2394,16 @@ select Add TOTP to store the key safely</value>
<value>Gair ar hap</value> <value>Gair ar hap</value>
</data> </data>
<data name="EmailRequiredParenthesis" xml:space="preserve"> <data name="EmailRequiredParenthesis" xml:space="preserve">
<value>Email (required)</value> <value>Ebost (gofynnol)</value>
</data> </data>
<data name="DomainNameRequiredParenthesis" xml:space="preserve"> <data name="DomainNameRequiredParenthesis" xml:space="preserve">
<value>Enw parth (gofynnol)</value> <value>Enw parth (gofynnol)</value>
</data> </data>
<data name="APIKeyRequiredParenthesis" xml:space="preserve"> <data name="APIKeyRequiredParenthesis" xml:space="preserve">
<value>API key (required)</value> <value>Allwedd API (gofynnol)</value>
</data> </data>
<data name="Service" xml:space="preserve"> <data name="Service" xml:space="preserve">
<value>Service</value> <value>Gwasanaeth</value>
</data> </data>
<data name="AddyIo" xml:space="preserve"> <data name="AddyIo" xml:space="preserve">
<value>addy.io</value> <value>addy.io</value>
@@ -2549,7 +2549,7 @@ Do you want to switch to this account?</value>
<value>Bydd angen ailgychwyn yr ap</value> <value>Bydd angen ailgychwyn yr ap</value>
</data> </data>
<data name="DefaultSystem" xml:space="preserve"> <data name="DefaultSystem" xml:space="preserve">
<value>Default (System)</value> <value>Rhagosodiad (system)</value>
</data> </data>
<data name="Important" xml:space="preserve"> <data name="Important" xml:space="preserve">
<value>Pwysig</value> <value>Pwysig</value>
@@ -2624,7 +2624,7 @@ Do you want to switch to this account?</value>
<value>Prif gyfrinair presennol</value> <value>Prif gyfrinair presennol</value>
</data> </data>
<data name="LoggedIn" xml:space="preserve"> <data name="LoggedIn" xml:space="preserve">
<value>Logged in!</value> <value>Wedi mewngofnodi!</value>
</data> </data>
<data name="ApproveWithMyOtherDevice" xml:space="preserve"> <data name="ApproveWithMyOtherDevice" xml:space="preserve">
<value>Approve with my other device</value> <value>Approve with my other device</value>
@@ -2812,17 +2812,17 @@ Do you want to switch to this account?</value>
<value>Parhau i'r ap gwe?</value> <value>Parhau i'r ap gwe?</value>
</data> </data>
<data name="ContinueToX" xml:space="preserve"> <data name="ContinueToX" xml:space="preserve">
<value>Continue to {0}?</value> <value>Parhau i {0}?</value>
<comment>The parameter is an URL, like bitwarden.com.</comment> <comment>The parameter is an URL, like bitwarden.com.</comment>
</data> </data>
<data name="ContinueToHelpCenter" xml:space="preserve"> <data name="ContinueToHelpCenter" xml:space="preserve">
<value>Continue to Help center?</value> <value>Parhau i'r ganolfan gymorth?</value>
</data> </data>
<data name="ContinueToContactSupport" xml:space="preserve"> <data name="ContinueToContactSupport" xml:space="preserve">
<value>Continue to contact support?</value> <value>Continue to contact support?</value>
</data> </data>
<data name="ContinueToPrivacyPolicy" xml:space="preserve"> <data name="ContinueToPrivacyPolicy" xml:space="preserve">
<value>Continue to privacy policy?</value> <value>Parhau i'r polisi preifatrwydd?</value>
</data> </data>
<data name="ContinueToAppStore" xml:space="preserve"> <data name="ContinueToAppStore" xml:space="preserve">
<value>Continue to app store?</value> <value>Continue to app store?</value>
@@ -2859,11 +2859,11 @@ Do you want to switch to this account?</value>
<value>Choose the dark theme to use when your devices dark mode is in use</value> <value>Choose the dark theme to use when your devices dark mode is in use</value>
</data> </data>
<data name="CreatedXY" xml:space="preserve"> <data name="CreatedXY" xml:space="preserve">
<value>Created {0}, {1}</value> <value>Crëwyd ar {0} am {1}</value>
<comment>To state the date/time in which the cipher was created: Created 03/21/2023, 09:25 AM. First parameter is the date and the second parameter is the time.</comment> <comment>To state the date/time in which the cipher was created: Created 03/21/2023, 09:25 AM. First parameter is the date and the second parameter is the time.</comment>
</data> </data>
<data name="TooManyAttempts" xml:space="preserve"> <data name="TooManyAttempts" xml:space="preserve">
<value>Too many attempts</value> <value>Gormod o geisiadau</value>
</data> </data>
<data name="AccountLoggedOutBiometricExceeded" xml:space="preserve"> <data name="AccountLoggedOutBiometricExceeded" xml:space="preserve">
<value>Account logged out.</value> <value>Account logged out.</value>
@@ -2877,4 +2877,13 @@ Do you want to switch to this account?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Lansio Duo</value>
</data>
</root> </root>

View File

@@ -907,7 +907,7 @@ Skanning vil ske automatisk.</value>
<value>Kopiér TOTP</value> <value>Kopiér TOTP</value>
</data> </data>
<data name="CopyTotpAutomaticallyDescription" xml:space="preserve"> <data name="CopyTotpAutomaticallyDescription" xml:space="preserve">
<value>Har et login en godkendelsesnøgle, kopiér TOTP-bekræftelseskoden til udklipsholderen, når login auto-udfyldes.</value> <value>Har et login en godkendelsesnøgle, kopiér da TOTP-bekræftelseskoden til udklipsholderen, når login autoudfyldes.</value>
</data> </data>
<data name="CopyTotpAutomatically" xml:space="preserve"> <data name="CopyTotpAutomatically" xml:space="preserve">
<value>Kopiér TOTP automatisk</value> <value>Kopiér TOTP automatisk</value>
@@ -2128,7 +2128,7 @@ Skanning vil ske automatisk.</value>
<value>Denne organisation har en virksomhedspolitik, der automatisk tilmelder dig til nulstilling af adgangskode. Tilmelding giver organisationsadministratorer mulighed for at skifte din hovedadgangskode.</value> <value>Denne organisation har en virksomhedspolitik, der automatisk tilmelder dig til nulstilling af adgangskode. Tilmelding giver organisationsadministratorer mulighed for at skifte din hovedadgangskode.</value>
</data> </data>
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve"> <data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
<value>Dine organisationspolitikker påvirker din boks-timeout. Maksimum tilladte boks-timeout er {0} time(r) og {1} minut(ter)</value> <value>Organisationspolitikkerne har sat den maksimalt tilladte bokstimeout til {0} tim(er) og {1} minut(ter).</value>
</data> </data>
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve"> <data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
<value>Organisationspolitikkerne påvirker boks-timeout. Maks. tilladt boks-timeout er {0} time(r) og {1} minut(ter). Boks-timeout er pt. sat til {2}.</value> <value>Organisationspolitikkerne påvirker boks-timeout. Maks. tilladt boks-timeout er {0} time(r) og {1} minut(ter). Boks-timeout er pt. sat til {2}.</value>
@@ -2354,7 +2354,7 @@ vælg Tilføj TOTP for at gemme nøglen sikkert</value>
<value>Godkend loginanmodninger</value> <value>Godkend loginanmodninger</value>
</data> </data>
<data name="UseThisDeviceToApproveLoginRequestsMadeFromOtherDevices" xml:space="preserve"> <data name="UseThisDeviceToApproveLoginRequestsMadeFromOtherDevices" xml:space="preserve">
<value>Brug denne enhed til at godkende loginanmodninger fra andre enheder.</value> <value>Brug denne enhed til at godkende loginanmodninger fra andre enheder</value>
</data> </data>
<data name="AllowNotifications" xml:space="preserve"> <data name="AllowNotifications" xml:space="preserve">
<value>Tillad notifikationer</value> <value>Tillad notifikationer</value>
@@ -2668,7 +2668,7 @@ Vil du skifte til denne konto?</value>
<value>Hjælp til genanmodning om hovedadgangskode</value> <value>Hjælp til genanmodning om hovedadgangskode</value>
</data> </data>
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve"> <data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings or set up biometric unlock to resolve.</value> <value>Oplåsning kan fejle grundet utilstrækkelig hukommelse. Reducér KDF-hukommelsesindstillinger eller opsæt biometrisk oplåsning for at afhjælpe.</value>
</data> </data>
<data name="InvalidAPIKey" xml:space="preserve"> <data name="InvalidAPIKey" xml:space="preserve">
<value>Ugyldig API-nøgle</value> <value>Ugyldig API-nøgle</value>
@@ -2876,4 +2876,13 @@ Vil du skifte til denne konto?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Opsæt en oplåsningsmetode for at ændre Bokstimeouthandlingen.</value> <value>Opsæt en oplåsningsmetode for at ændre Bokstimeouthandlingen.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo-totrinsindlogning kræves for kontoen. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Følg trinnene fra Duo for at færdiggøre indlogningen.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Start Duo</value>
</data>
</root> </root>

View File

@@ -2875,4 +2875,13 @@ Möchtest du zu diesem Konto wechseln?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Richte eine Entsperroption ein, um deine Aktion bei Tresor-Timeout zu ändern.</value> <value>Richte eine Entsperroption ein, um deine Aktion bei Tresor-Timeout zu ändern.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Für dein Konto ist die Duo Zwei-Faktor-Authentifizierung erforderlich. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Folge den Schritten von Duo, um die Anmeldung abzuschließen.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Duo starten</value>
</data>
</root> </root>

View File

@@ -152,11 +152,11 @@
<comment>Copy some value to your clipboard.</comment> <comment>Copy some value to your clipboard.</comment>
</data> </data>
<data name="CopyPassword" xml:space="preserve"> <data name="CopyPassword" xml:space="preserve">
<value>Αντιγραφή Κωδικού</value> <value>Αντιγραφή κωδικού</value>
<comment>The button text that allows a user to copy the login's password to their clipboard.</comment> <comment>The button text that allows a user to copy the login's password to their clipboard.</comment>
</data> </data>
<data name="CopyUsername" xml:space="preserve"> <data name="CopyUsername" xml:space="preserve">
<value>Αντιγραφή Ονόματος Χρήστη</value> <value>Αντιγραφή ονόματος χρήστη</value>
<comment>The button text that allows a user to copy the login's username to their clipboard.</comment> <comment>The button text that allows a user to copy the login's username to their clipboard.</comment>
</data> </data>
<data name="Credits" xml:space="preserve"> <data name="Credits" xml:space="preserve">
@@ -179,14 +179,14 @@
<value>Επεξεργασία</value> <value>Επεξεργασία</value>
</data> </data>
<data name="EditFolder" xml:space="preserve"> <data name="EditFolder" xml:space="preserve">
<value>Επεξεργασία Φακέλου</value> <value>Επεξεργασία φακέλου</value>
</data> </data>
<data name="Email" xml:space="preserve"> <data name="Email" xml:space="preserve">
<value>Email</value> <value>Email</value>
<comment>Short label for an email address.</comment> <comment>Short label for an email address.</comment>
</data> </data>
<data name="EmailAddress" xml:space="preserve"> <data name="EmailAddress" xml:space="preserve">
<value>Διεύθυνση Email</value> <value>Διεύθυνση email</value>
<comment>Full label for a email address.</comment> <comment>Full label for a email address.</comment>
</data> </data>
<data name="EmailUs" xml:space="preserve"> <data name="EmailUs" xml:space="preserve">
@@ -203,7 +203,7 @@
<comment>Title for your favorite items in the vault.</comment> <comment>Title for your favorite items in the vault.</comment>
</data> </data>
<data name="FileBugReport" xml:space="preserve"> <data name="FileBugReport" xml:space="preserve">
<value>Υποβολή Αναφοράς Σφάλματος</value> <value>Υποβολή αναφοράς σφάλματος</value>
</data> </data>
<data name="FileBugReportDescription" xml:space="preserve"> <data name="FileBugReportDescription" xml:space="preserve">
<value>Αναφέρετε το προβλήμα στο GitHub.</value> <value>Αναφέρετε το προβλήμα στο GitHub.</value>
@@ -229,14 +229,14 @@
<value>Φάκελοι</value> <value>Φάκελοι</value>
</data> </data>
<data name="FolderUpdated" xml:space="preserve"> <data name="FolderUpdated" xml:space="preserve">
<value>Ο φάκελος ενημερώθηκε.</value> <value>Ο φάκελος ενημερώθηκε</value>
</data> </data>
<data name="GoToWebsite" xml:space="preserve"> <data name="GoToWebsite" xml:space="preserve">
<value>Μετάβαση στην ιστοσελίδα</value> <value>Μετάβαση στην ιστοσελίδα</value>
<comment>The button text that allows user to launch the website to their web browser.</comment> <comment>The button text that allows user to launch the website to their web browser.</comment>
</data> </data>
<data name="HelpAndFeedback" xml:space="preserve"> <data name="HelpAndFeedback" xml:space="preserve">
<value>Βοήθεια και Σχόλια</value> <value>Βοήθεια και σχόλια</value>
</data> </data>
<data name="Hide" xml:space="preserve"> <data name="Hide" xml:space="preserve">
<value>Απόκρυψη</value> <value>Απόκρυψη</value>
@@ -251,7 +251,7 @@
<comment>Title for the alert when internet connection is required to continue.</comment> <comment>Title for the alert when internet connection is required to continue.</comment>
</data> </data>
<data name="InvalidMasterPassword" xml:space="preserve"> <data name="InvalidMasterPassword" xml:space="preserve">
<value>Μη έγκυρος κύριος κωδικός, δοκιμάστε ξανά.</value> <value>Μη έγκυρος κύριος κωδικός. Δοκιμάστε ξανά.</value>
</data> </data>
<data name="InvalidPIN" xml:space="preserve"> <data name="InvalidPIN" xml:space="preserve">
<value>Μη έγκυρο PIN. Προσπάθηστε ξανά.</value> <value>Μη έγκυρο PIN. Προσπάθηστε ξανά.</value>
@@ -282,7 +282,7 @@
<value>Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτόν τον λογαριασμό?</value> <value>Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτόν τον λογαριασμό?</value>
</data> </data>
<data name="AccountAlreadyAdded" xml:space="preserve"> <data name="AccountAlreadyAdded" xml:space="preserve">
<value>Ο Λογαριασμός Προστέθηκε Ήδη</value> <value>Ο λογαριασμός έχει ήδη προστεθεί</value>
</data> </data>
<data name="SwitchToAlreadyAddedAccountConfirmation" xml:space="preserve"> <data name="SwitchToAlreadyAddedAccountConfirmation" xml:space="preserve">
<value>Θα θέλατε να το αλλάξετε τώρα?</value> <value>Θα θέλατε να το αλλάξετε τώρα?</value>
@@ -296,11 +296,11 @@
<comment>Text to define that there are more options things to see.</comment> <comment>Text to define that there are more options things to see.</comment>
</data> </data>
<data name="MyVault" xml:space="preserve"> <data name="MyVault" xml:space="preserve">
<value>Το Vault μου</value> <value>Το vault μου</value>
<comment>The title for the vault page.</comment> <comment>The title for the vault page.</comment>
</data> </data>
<data name="Authenticator" xml:space="preserve"> <data name="Authenticator" xml:space="preserve">
<value>Εφαρμογή Επαλήθευσης</value> <value>Αυθεντικοποιητής</value>
<comment>Authenticator TOTP feature</comment> <comment>Authenticator TOTP feature</comment>
</data> </data>
<data name="Name" xml:space="preserve"> <data name="Name" xml:space="preserve">
@@ -342,7 +342,7 @@
<comment>Reveal a hidden value (password).</comment> <comment>Reveal a hidden value (password).</comment>
</data> </data>
<data name="ItemDeleted" xml:space="preserve"> <data name="ItemDeleted" xml:space="preserve">
<value>Το στοιχείο έχει διαγραφεί.</value> <value>Το στοιχείο διαγράφτηκε</value>
<comment>Confirmation message after successfully deleting a login.</comment> <comment>Confirmation message after successfully deleting a login.</comment>
</data> </data>
<data name="Submit" xml:space="preserve"> <data name="Submit" xml:space="preserve">
@@ -375,14 +375,14 @@
<comment>Validation message for when a form field is left blank and is required to be entered.</comment> <comment>Validation message for when a form field is left blank and is required to be entered.</comment>
</data> </data>
<data name="ValueHasBeenCopied" xml:space="preserve"> <data name="ValueHasBeenCopied" xml:space="preserve">
<value>{0} έχει αντιγραφεί.</value> <value>{0} έχει αντιγραφεί</value>
<comment>Confirmation message after successfully copying a value to the clipboard.</comment> <comment>Confirmation message after successfully copying a value to the clipboard.</comment>
</data> </data>
<data name="VerifyFingerprint" xml:space="preserve"> <data name="VerifyFingerprint" xml:space="preserve">
<value>Επαλήθευση Δακτυλικού Αποτυπώματος</value> <value>Επαλήθευση δακτυλικού αποτυπώματος</value>
</data> </data>
<data name="VerifyMasterPassword" xml:space="preserve"> <data name="VerifyMasterPassword" xml:space="preserve">
<value>Επαλήθευση Κύριου Κωδικού</value> <value>Επαλήθευση κύριου κωδικού</value>
</data> </data>
<data name="VerifyPIN" xml:space="preserve"> <data name="VerifyPIN" xml:space="preserve">
<value>Επαλήθευση PIN</value> <value>Επαλήθευση PIN</value>
@@ -413,22 +413,22 @@
<value>Προσθήκη στοιχείου</value> <value>Προσθήκη στοιχείου</value>
</data> </data>
<data name="AppExtension" xml:space="preserve"> <data name="AppExtension" xml:space="preserve">
<value>Επέκταση Εφαρμογής</value> <value>Επέκταση εφαρμογής</value>
</data> </data>
<data name="AutofillAccessibilityDescription" xml:space="preserve"> <data name="AutofillAccessibilityDescription" xml:space="preserve">
<value>Χρησιμοποιείστε την υπηρεσία προσβασιμότητας Bitwarden, για την αυτόματη συμπλήρωση συνδέσεων σε εφαρμογές και στο διαδίκτυο.</value> <value>Χρησιμοποιείστε την υπηρεσία προσβασιμότητας Bitwarden, για την αυτόματη συμπλήρωση συνδέσεων σε εφαρμογές και στο διαδίκτυο.</value>
</data> </data>
<data name="AutofillService" xml:space="preserve"> <data name="AutofillService" xml:space="preserve">
<value>Υπηρεσία Αυτόματης Συμπλήρωσης</value> <value>Υπηρεσία αυτόματης συμπλήρωσης</value>
</data> </data>
<data name="AvoidAmbiguousCharacters" xml:space="preserve"> <data name="AvoidAmbiguousCharacters" xml:space="preserve">
<value>Αποφυγή Αμφιλεγόμενων Χαρακτήρων</value> <value>Αποφυγή αμφιλεγόμενων χαρακτήρων</value>
</data> </data>
<data name="BitwardenAppExtension" xml:space="preserve"> <data name="BitwardenAppExtension" xml:space="preserve">
<value>Επέκταση Εφαρμογής Bitwarden</value> <value>Επέκταση εφαρμογής Bitwarden</value>
</data> </data>
<data name="BitwardenAppExtensionAlert2" xml:space="preserve"> <data name="BitwardenAppExtensionAlert2" xml:space="preserve">
<value>Ο ευκολότερος τρόπος για να προσθέστε νέες συνδέσεις στο vault σας, είναι μέσω της επέκτασης εφαρμογής Bitwarden. Μάθετε περισσότερα σχετικά με τη χρήση της επέκτασης, μεταβαίνοντας στις "Ρυθμίσεις".</value> <value>Ο ευκολότερος τρόπος για να προσθέστε νέες συνδέσεις στο vault σας, είναι μέσω της επέκτασης εφαρμογής Bitwarden. Μάθετε περισσότερα σχετικά με τη χρήση της επέκτασης εφαρμογής Bitwarden, μεταβαίνοντας στις "Ρυθμίσεις".</value>
</data> </data>
<data name="BitwardenAppExtensionDescription" xml:space="preserve"> <data name="BitwardenAppExtensionDescription" xml:space="preserve">
<value>Χρήση του Bitwarden στο Safari και σε άλλες εφαρμογές για αυτόματη συμπλήρωση των συνδέσεων σας.</value> <value>Χρήση του Bitwarden στο Safari και σε άλλες εφαρμογές για αυτόματη συμπλήρωση των συνδέσεων σας.</value>
@@ -440,13 +440,13 @@
<value>Χρησιμοποιείστε την υπηρεσία προσβασιμότητας Bitwarden, για την αυτόματη συμπλήρωση συνδέσεων.</value> <value>Χρησιμοποιείστε την υπηρεσία προσβασιμότητας Bitwarden, για την αυτόματη συμπλήρωση συνδέσεων.</value>
</data> </data>
<data name="ChangeEmail" xml:space="preserve"> <data name="ChangeEmail" xml:space="preserve">
<value>Αλλαγή Email</value> <value>Αλλαγή email</value>
</data> </data>
<data name="ChangeEmailConfirmation" xml:space="preserve"> <data name="ChangeEmailConfirmation" xml:space="preserve">
<value>Μπορείτε να αλλάξετε τη διεύθυνση του email σας στο bitwarden.com. Θέλετε να επισκεφθείτε την ιστοσελίδα τώρα;</value> <value>Μπορείτε να αλλάξετε τη διεύθυνση του email σας στο bitwarden.com. Θέλετε να επισκεφθείτε την ιστοσελίδα τώρα;</value>
</data> </data>
<data name="ChangeMasterPassword" xml:space="preserve"> <data name="ChangeMasterPassword" xml:space="preserve">
<value>Αλλαγή Κύριου Κωδικού</value> <value>Αλλαγή κύριου κωδικού</value>
</data> </data>
<data name="Close" xml:space="preserve"> <data name="Close" xml:space="preserve">
<value>Κλείσιμο</value> <value>Κλείσιμο</value>
@@ -455,29 +455,29 @@
<value>Συνέχεια</value> <value>Συνέχεια</value>
</data> </data>
<data name="CreateAccount" xml:space="preserve"> <data name="CreateAccount" xml:space="preserve">
<value>Δημιουργία Λογαριασμού</value> <value>Δημιουργία λογαριασμού</value>
</data> </data>
<data name="CreatingAccount" xml:space="preserve"> <data name="CreatingAccount" xml:space="preserve">
<value>Δημιουργία λογαριασμού...</value> <value>Δημιουργία λογαριασμού...</value>
<comment>Message shown when interacting with the server</comment> <comment>Message shown when interacting with the server</comment>
</data> </data>
<data name="EditItem" xml:space="preserve"> <data name="EditItem" xml:space="preserve">
<value>Επεξεργασία Στοιχείου</value> <value>Επεξεργασία στοιχείου</value>
</data> </data>
<data name="EnableAutomaticSyncing" xml:space="preserve"> <data name="EnableAutomaticSyncing" xml:space="preserve">
<value>Ενεργοποίηση Αυτόματου Συγχρονισμού</value> <value>Επιτρέψτε τον αυτόματο συγχρονισμό</value>
</data> </data>
<data name="EnterEmailForHint" xml:space="preserve"> <data name="EnterEmailForHint" xml:space="preserve">
<value>Εισάγετε την διεύθυνση email του λογαριασμού σας, προκειμένου για να λάβετε υπόδειξη του κύριου κωδικού.</value> <value>Εισάγετε την διεύθυνση email του λογαριασμού σας, προκειμένου για να λάβετε υπόδειξη του κύριου κωδικού.</value>
</data> </data>
<data name="ExntesionReenable" xml:space="preserve"> <data name="ExntesionReenable" xml:space="preserve">
<value>Ενεργοποιείστε εκ νέου την Επέκτασης Εφαρμογής</value> <value>Εκ νέου ενεργοποίηση επέκτασης εφαρμογής</value>
</data> </data>
<data name="ExtensionAlmostDone" xml:space="preserve"> <data name="ExtensionAlmostDone" xml:space="preserve">
<value>Σχεδόν ολοκληρώθηκε!</value> <value>Σχεδόν ολοκληρώθηκε!</value>
</data> </data>
<data name="ExtensionEnable" xml:space="preserve"> <data name="ExtensionEnable" xml:space="preserve">
<value>Ενεργοποίηση Επέκτασης Εφαρμογής</value> <value>Ενεργοποίηση επέκτασης εφαρμογής</value>
</data> </data>
<data name="ExtensionInSafari" xml:space="preserve"> <data name="ExtensionInSafari" xml:space="preserve">
<value>Στο Safari, βρείτε το Bitwarden χρησιμοποιώντας το εικονίδιο κοινής χρήσης (μετακινηθείτε προς τα δεξιά στην κάτω σειρά του μενού).</value> <value>Στο Safari, βρείτε το Bitwarden χρησιμοποιώντας το εικονίδιο κοινής χρήσης (μετακινηθείτε προς τα δεξιά στην κάτω σειρά του μενού).</value>
@@ -508,13 +508,13 @@
<value>Δακτυλικό αποτύπωμα</value> <value>Δακτυλικό αποτύπωμα</value>
</data> </data>
<data name="GeneratePassword" xml:space="preserve"> <data name="GeneratePassword" xml:space="preserve">
<value>Δημιουργία Κωδικού</value> <value>Παραγωγή κωδικού</value>
</data> </data>
<data name="GetPasswordHint" xml:space="preserve"> <data name="GetPasswordHint" xml:space="preserve">
<value>Λήψη υπόδειξης κύριου κωδικού</value> <value>Λήψη υπόδειξης κύριου κωδικού</value>
</data> </data>
<data name="ImportItems" xml:space="preserve"> <data name="ImportItems" xml:space="preserve">
<value>Εισαγωγή Στοιχείων</value> <value>Εισαγωγή στοιχείων</value>
</data> </data>
<data name="ImportItemsConfirmation" xml:space="preserve"> <data name="ImportItemsConfirmation" xml:space="preserve">
<value>Μπορείτε να εισαγάγετε μαζικά στοιχεία διαδικτυακά στο bitwarden.com. Θέλετε να επισκεφθείτε την ιστοσελίδα τώρα;</value> <value>Μπορείτε να εισαγάγετε μαζικά στοιχεία διαδικτυακά στο bitwarden.com. Θέλετε να επισκεφθείτε την ιστοσελίδα τώρα;</value>
@@ -523,7 +523,7 @@
<value>Γρήγορη μαζική εισαγωγή των στοιχείων σας από άλλες εφαρμογές διαχείρισης κωδικών.</value> <value>Γρήγορη μαζική εισαγωγή των στοιχείων σας από άλλες εφαρμογές διαχείρισης κωδικών.</value>
</data> </data>
<data name="LastSync" xml:space="preserve"> <data name="LastSync" xml:space="preserve">
<value>Τελευταίος Συγχρονισμός:</value> <value>Τελευταίος συγχρονισμός:</value>
</data> </data>
<data name="Length" xml:space="preserve"> <data name="Length" xml:space="preserve">
<value>Μήκος</value> <value>Μήκος</value>
@@ -547,10 +547,10 @@
<value>Άμεσα</value> <value>Άμεσα</value>
</data> </data>
<data name="VaultTimeout" xml:space="preserve"> <data name="VaultTimeout" xml:space="preserve">
<value>Χρόνος Λήξης Vault</value> <value>Χρόνος λήξης vault</value>
</data> </data>
<data name="VaultTimeoutAction" xml:space="preserve"> <data name="VaultTimeoutAction" xml:space="preserve">
<value>Ενέργεια Χρόνου Λήξης Vault</value> <value>Ενέργεια χρόνου λήξης vault</value>
</data> </data>
<data name="VaultTimeoutLogOutConfirmation" xml:space="preserve"> <data name="VaultTimeoutLogOutConfirmation" xml:space="preserve">
<value>Η αποσύνδεση θα καταργήσει όλη την πρόσβαση στο vault σας και απαιτεί online έλεγχο ταυτότητας μετά το χρονικό όριο λήξης. Είστε βέβαιοι ότι θέλετε να χρησιμοποιήσετε αυτήν τη ρύθμιση;</value> <value>Η αποσύνδεση θα καταργήσει όλη την πρόσβαση στο vault σας και απαιτεί online έλεγχο ταυτότητας μετά το χρονικό όριο λήξης. Είστε βέβαιοι ότι θέλετε να χρησιμοποιήσετε αυτήν τη ρύθμιση;</value>
@@ -572,7 +572,7 @@
<value>Ο κύριος κωδικός χρησιμοποιείται για πρόσβαση στο vault σας. Είναι πολύ σημαντικό να μην τον ξεχάσετε. Δεν υπάρχει τρόπος να τον ανακτήσετε σε αυτή την περίπτωση.</value> <value>Ο κύριος κωδικός χρησιμοποιείται για πρόσβαση στο vault σας. Είναι πολύ σημαντικό να μην τον ξεχάσετε. Δεν υπάρχει τρόπος να τον ανακτήσετε σε αυτή την περίπτωση.</value>
</data> </data>
<data name="MasterPasswordHint" xml:space="preserve"> <data name="MasterPasswordHint" xml:space="preserve">
<value>Υπόδειξη Κύριου Κωδικού (προαιρετικό)</value> <value>Υπόδειξη κύριου κωδικού (προαιρετικό)</value>
</data> </data>
<data name="MasterPasswordHintDescription" xml:space="preserve"> <data name="MasterPasswordHintDescription" xml:space="preserve">
<value>Η υπόδειξη κύριου κωδικού μπορεί να σας βοηθήσει να θυμηθείτε τον κωδικό σας αν τον ξεχάσετε.</value> <value>Η υπόδειξη κύριου κωδικού μπορεί να σας βοηθήσει να θυμηθείτε τον κωδικό σας αν τον ξεχάσετε.</value>
@@ -581,15 +581,15 @@
<value>Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες.</value> <value>Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες.</value>
</data> </data>
<data name="MinNumbers" xml:space="preserve"> <data name="MinNumbers" xml:space="preserve">
<value>Ελάχιστα Αριθμητικά Ψηφία</value> <value>Ελάχιστα αριθμητικά ψηφία</value>
<comment>Minimum numeric characters for password generator settings</comment> <comment>Minimum numeric characters for password generator settings</comment>
</data> </data>
<data name="MinSpecial" xml:space="preserve"> <data name="MinSpecial" xml:space="preserve">
<value>Ελάχιστο Ειδικών Χαρακτήρων</value> <value>Ελάχιστοι ειδικοί χαρακτήρες</value>
<comment>Minimum special characters for password generator settings</comment> <comment>Minimum special characters for password generator settings</comment>
</data> </data>
<data name="MoreSettings" xml:space="preserve"> <data name="MoreSettings" xml:space="preserve">
<value>Περισσότερες Ρυθμίσεις</value> <value>Περισσότερες ρυθμίσεις</value>
</data> </data>
<data name="MustLogInMainApp" xml:space="preserve"> <data name="MustLogInMainApp" xml:space="preserve">
<value>Πρέπει να συνδεθείτε στην κύρια εφαρμογή Bitwarden για να μπορέσετε να χρησιμοποιήσετε την επέκταση.</value> <value>Πρέπει να συνδεθείτε στην κύρια εφαρμογή Bitwarden για να μπορέσετε να χρησιμοποιήσετε την επέκταση.</value>
@@ -598,7 +598,7 @@
<value>Ποτέ</value> <value>Ποτέ</value>
</data> </data>
<data name="NewItemCreated" xml:space="preserve"> <data name="NewItemCreated" xml:space="preserve">
<value>Δημιουργήθηκε νέο στοιχείο.</value> <value>Το στοιχείο προστέθηκε</value>
</data> </data>
<data name="NoFavorites" xml:space="preserve"> <data name="NoFavorites" xml:space="preserve">
<value>Δεν υπάρχουν αγαπημένα στο vault σας.</value> <value>Δεν υπάρχουν αγαπημένα στο vault σας.</value>
@@ -626,13 +626,13 @@
<value>Άλλες</value> <value>Άλλες</value>
</data> </data>
<data name="PasswordGenerated" xml:space="preserve"> <data name="PasswordGenerated" xml:space="preserve">
<value>Ο κωδικός δημιουργήθηκε.</value> <value>Ο κωδικός δημιουργήθηκε</value>
</data> </data>
<data name="PasswordGenerator" xml:space="preserve"> <data name="PasswordGenerator" xml:space="preserve">
<value>Γεννήτρια Κωδικού</value> <value>Γεννήτρια κωδικού</value>
</data> </data>
<data name="PasswordHint" xml:space="preserve"> <data name="PasswordHint" xml:space="preserve">
<value>Υπόδειξη Κωδικού</value> <value>Υπόδειξη κωδικού</value>
</data> </data>
<data name="PasswordHintAlert" xml:space="preserve"> <data name="PasswordHintAlert" xml:space="preserve">
<value>Σας στείλαμε ένα email με υπόδειξη του κύριου κωδικού.</value> <value>Σας στείλαμε ένα email με υπόδειξη του κύριου κωδικού.</value>
@@ -641,20 +641,20 @@
<value>Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε τον τρέχον κωδικό;</value> <value>Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε τον τρέχον κωδικό;</value>
</data> </data>
<data name="PushNotificationAlert" xml:space="preserve"> <data name="PushNotificationAlert" xml:space="preserve">
<value>Το Bitwarden κρατάει αυτόματα το vault σας, με τη χρήση ειδοποιήσεων push. Για την καλύτερη δυνατή εμπειρία, επιλέξτε "Να επιτρέπεται" στην παρακάτω ερώτηση, όταν σας ζητηθεί να ενεργοποιήσετε τις ειδοποιήσεις push.</value> <value>Το Bitwarden κρατάει συγχρονισμένο το vault σας αυτόματα, με τη χρήση ειδοποιήσεων push. Για την καλύτερη δυνατή εμπειρία, επιλέξτε "Να επιτρέπεται" στην παρακάτω προτροπή όταν σας ζητηθεί να ενεργοποιήσετε τις ειδοποιήσεις push.</value>
<comment>Push notifications for apple products</comment> <comment>Push notifications for apple products</comment>
</data> </data>
<data name="RateTheApp" xml:space="preserve"> <data name="RateTheApp" xml:space="preserve">
<value>Αξιολογήστε την Εφαρμογή</value> <value>Αξιολογήστε την εφαρμογή</value>
</data> </data>
<data name="RateTheAppDescription" xml:space="preserve"> <data name="RateTheAppDescription" xml:space="preserve">
<value>Παρακαλούμε σκεφτείτε να μας βοηθήσετε με μια καλή κριτική!</value> <value>Παρακαλούμε σκεφτείτε να μας βοηθήσετε με μια καλή κριτική!</value>
</data> </data>
<data name="RegeneratePassword" xml:space="preserve"> <data name="RegeneratePassword" xml:space="preserve">
<value>Επαναδημιουργία Κωδικού</value> <value>Επαναδημιουργία κωδικού</value>
</data> </data>
<data name="RetypeMasterPassword" xml:space="preserve"> <data name="RetypeMasterPassword" xml:space="preserve">
<value>Εισάγετε Ξανά τον Κύριο Κωδικό</value> <value>Εισάγετε ξανά τον κύριο κωδικό</value>
</data> </data>
<data name="SearchVault" xml:space="preserve"> <data name="SearchVault" xml:space="preserve">
<value>Αναζήτηση στο vault</value> <value>Αναζήτηση στο vault</value>
@@ -672,10 +672,10 @@
<value>Εισαγωγή τετραψήφιου αριθμού PIN για ξεκλείδωμα εφαρμογής.</value> <value>Εισαγωγή τετραψήφιου αριθμού PIN για ξεκλείδωμα εφαρμογής.</value>
</data> </data>
<data name="ItemInformation" xml:space="preserve"> <data name="ItemInformation" xml:space="preserve">
<value>Πληροφορίες Στοιχείου</value> <value>Πληροφορίες στοιχείου</value>
</data> </data>
<data name="ItemUpdated" xml:space="preserve"> <data name="ItemUpdated" xml:space="preserve">
<value>Το στοιχείο ενημερώθηκε.</value> <value>Το στοιχείο αποθηκεύτηκε</value>
</data> </data>
<data name="Submitting" xml:space="preserve"> <data name="Submitting" xml:space="preserve">
<value>Υποβολή...</value> <value>Υποβολή...</value>
@@ -686,39 +686,39 @@
<comment>Message shown when interacting with the server</comment> <comment>Message shown when interacting with the server</comment>
</data> </data>
<data name="SyncingComplete" xml:space="preserve"> <data name="SyncingComplete" xml:space="preserve">
<value>Ο συγχρονισμός ολοκληρώθηκε.</value> <value>Ο συγχρονισμός ολοκληρώθηκε</value>
</data> </data>
<data name="SyncingFailed" xml:space="preserve"> <data name="SyncingFailed" xml:space="preserve">
<value>Ο συγχρονισμός απέτυχε.</value> <value>Ο συγχρονισμός απέτυχε</value>
</data> </data>
<data name="SyncVaultNow" xml:space="preserve"> <data name="SyncVaultNow" xml:space="preserve">
<value>Συγχρονισμός Vault Τώρα</value> <value>Συγχρονισμός του vault τώρα</value>
</data> </data>
<data name="TouchID" xml:space="preserve"> <data name="TouchID" xml:space="preserve">
<value>Touch ID</value> <value>Touch ID</value>
<comment>What Apple calls their fingerprint reader.</comment> <comment>What Apple calls their fingerprint reader.</comment>
</data> </data>
<data name="TwoStepLogin" xml:space="preserve"> <data name="TwoStepLogin" xml:space="preserve">
<value>Σύνδεση σε δύο βήματα</value> <value>Σύνδεση δύο βημάτων</value>
</data> </data>
<data name="UnlockWith" xml:space="preserve"> <data name="UnlockWith" xml:space="preserve">
<value>Ξεκλείδωμα με {0}</value> <value>Ξεκλείδωμα με {0}</value>
</data> </data>
<data name="UnlockWithPIN" xml:space="preserve"> <data name="UnlockWithPIN" xml:space="preserve">
<value>Ξεκλείδωμα με PIN</value> <value>Ξεκλείδωμα με κωδικό PIN</value>
</data> </data>
<data name="Validating" xml:space="preserve"> <data name="Validating" xml:space="preserve">
<value>Επαλήθευση</value> <value>Επαλήθευση</value>
<comment>Message shown when interacting with the server</comment> <comment>Message shown when interacting with the server</comment>
</data> </data>
<data name="VerificationCode" xml:space="preserve"> <data name="VerificationCode" xml:space="preserve">
<value>Κωδικός Επαλήθευσης</value> <value>Κωδικός επαλήθευσης</value>
</data> </data>
<data name="ViewItem" xml:space="preserve"> <data name="ViewItem" xml:space="preserve">
<value>Προβολή Στοιχείου</value> <value>Προβολή στοιχείου</value>
</data> </data>
<data name="WebVault" xml:space="preserve"> <data name="WebVault" xml:space="preserve">
<value>Bitwarden Web Vault</value> <value>Διαδικτυακό vault Bitwarden</value>
</data> </data>
<data name="Lost2FAApp" xml:space="preserve"> <data name="Lost2FAApp" xml:space="preserve">
<value>Χάσατε την εφαρμογή επαλήθευσης;</value> <value>Χάσατε την εφαρμογή επαλήθευσης;</value>
@@ -728,7 +728,7 @@
<comment>Screen title</comment> <comment>Screen title</comment>
</data> </data>
<data name="ExtensionActivated" xml:space="preserve"> <data name="ExtensionActivated" xml:space="preserve">
<value>Η Επέκταση Ενεργοποιήθηκε!</value> <value>Η επέκταση ενεργοποιήθηκε!</value>
</data> </data>
<data name="Icons" xml:space="preserve"> <data name="Icons" xml:space="preserve">
<value>Εικονίδια</value> <value>Εικονίδια</value>
@@ -799,14 +799,14 @@
<value>Αναζήτηση στοιχείου αυτόματης συμπλήρωσης για "{0}".</value> <value>Αναζήτηση στοιχείου αυτόματης συμπλήρωσης για "{0}".</value>
</data> </data>
<data name="LearnOrg" xml:space="preserve"> <data name="LearnOrg" xml:space="preserve">
<value>Μάθετε για τους Οργανισμούς</value> <value>Μάθετε για τους οργανισμούς</value>
</data> </data>
<data name="CannotOpenApp" xml:space="preserve"> <data name="CannotOpenApp" xml:space="preserve">
<value>Δεν είναι δυνατή η πρόσβαση στην εφαρμογή "{0}".</value> <value>Δεν είναι δυνατή η πρόσβαση στην εφαρμογή "{0}".</value>
<comment>Message shown when trying to launch an app that does not exist on the user's device.</comment> <comment>Message shown when trying to launch an app that does not exist on the user's device.</comment>
</data> </data>
<data name="AuthenticatorAppTitle" xml:space="preserve"> <data name="AuthenticatorAppTitle" xml:space="preserve">
<value>Εφαρμογή Επαλήθευσης</value> <value>Εφαρμογή αυθεντικοποίησης</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="EnterVerificationCodeApp" xml:space="preserve"> <data name="EnterVerificationCodeApp" xml:space="preserve">
@@ -818,14 +818,14 @@
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="LoginUnavailable" xml:space="preserve"> <data name="LoginUnavailable" xml:space="preserve">
<value>Μη Διαθέσιμη Σύνδεση</value> <value>Μη διαθέσιμη σύνδεση</value>
<comment>For 2FA whenever there are no available providers on this device.</comment> <comment>For 2FA whenever there are no available providers on this device.</comment>
</data> </data>
<data name="NoTwoStepAvailable" xml:space="preserve"> <data name="NoTwoStepAvailable" xml:space="preserve">
<value>Αυτός ο λογαριασμός έχει ενεργοποιημένη τη σύνδεση σε δύο βήματα, ωστόσο, σε αυτήν τη συσκευή δεν υποστηρίζεται κανένας από τους διαμορφωμένους παροχείς δύο βημάτων. Χρησιμοποιήστε μια υποστηριζόμενη συσκευή και / ή προσθέστε επιπλέον παρόχους που υποστηρίζονται καλύτερα σε όλες τις συσκευές (όπως μια εφαρμογή επαλήθευσης).</value> <value>Αυτός ο λογαριασμός έχει ενεργοποιημένη τη σύνδεση δύο βημάτων, ωστόσο, σε αυτήν τη συσκευή δεν υποστηρίζεται κανένας από τους διαμορφωμένους παρόχους δύο βημάτων. Παρακαλώ χρησιμοποιήστε μια υποστηριζόμενη συσκευή και/ή προσθέστε επιπλέον παρόχους που υποστηρίζονται καλύτερα σε όλες τις συσκευές (όπως μια εφαρμογή αυθεντικοποίησης).</value>
</data> </data>
<data name="RecoveryCodeTitle" xml:space="preserve"> <data name="RecoveryCodeTitle" xml:space="preserve">
<value>Κωδικός Ανάκτησης</value> <value>Κωδικός ανάκτησης</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="RememberMe" xml:space="preserve"> <data name="RememberMe" xml:space="preserve">
@@ -837,7 +837,7 @@
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="TwoStepLoginOptions" xml:space="preserve"> <data name="TwoStepLoginOptions" xml:space="preserve">
<value>Επιλογές σύνδεσης δύο παραγόντων</value> <value>Επιλογές σύνδεσης δύο βημάτων</value>
</data> </data>
<data name="UseAnotherTwoStepMethod" xml:space="preserve"> <data name="UseAnotherTwoStepMethod" xml:space="preserve">
<value>Χρήση άλλης μεθόδου δύο παραγόντων</value> <value>Χρήση άλλης μεθόδου δύο παραγόντων</value>
@@ -847,18 +847,18 @@
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="VerificationEmailSent" xml:space="preserve"> <data name="VerificationEmailSent" xml:space="preserve">
<value>Το email επιβεβαίωσης στάλθηκε.</value> <value>Το email επιβεβαίωσης στάλθηκε</value>
<comment>For 2FA</comment> <comment>For 2FA</comment>
</data> </data>
<data name="YubiKeyInstruction" xml:space="preserve"> <data name="YubiKeyInstruction" xml:space="preserve">
<value>Για να συνεχίσετε, κρατήστε το YubiKey NEO στο πίσω μέρος της συσκευής ή τοποθετήστε το YubiKey στη θύρα USB της συσκευής σας, και στη συνέχεια πατήστε το κουμπί του.</value> <value>Για να συνεχίσετε, κρατήστε το YubiKey NEO στο πίσω μέρος της συσκευής ή τοποθετήστε το YubiKey στη θύρα USB της συσκευής σας, και στη συνέχεια πατήστε το κουμπί του.</value>
</data> </data>
<data name="YubiKeyTitle" xml:space="preserve"> <data name="YubiKeyTitle" xml:space="preserve">
<value>Κλειδί Ασφαλείας YubiKey</value> <value>Κλειδί ασφαλείας YubiKey</value>
<comment>"YubiKey" is the product name and should not be translated.</comment> <comment>"YubiKey" is the product name and should not be translated.</comment>
</data> </data>
<data name="AddNewAttachment" xml:space="preserve"> <data name="AddNewAttachment" xml:space="preserve">
<value>Προσθήκη Νέου Συνημμένου</value> <value>Προσθήκη συνημμένου</value>
</data> </data>
<data name="Attachments" xml:space="preserve"> <data name="Attachments" xml:space="preserve">
<value>Συνημμένα</value> <value>Συνημμένα</value>
@@ -878,10 +878,10 @@
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment> <comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data> </data>
<data name="AuthenticatorKey" xml:space="preserve"> <data name="AuthenticatorKey" xml:space="preserve">
<value>Κλειδί επαλήθευσης (TOTP)</value> <value>Κλειδί αυθεντικοποίησης (TOTP)</value>
</data> </data>
<data name="VerificationCodeTotp" xml:space="preserve"> <data name="VerificationCodeTotp" xml:space="preserve">
<value>Κωδικός Επαλήθευσης (TOTP)</value> <value>Κωδικός επαλήθευσης (TOTP)</value>
<comment>Totp code label</comment> <comment>Totp code label</comment>
</data> </data>
<data name="AuthenticatorKeyAdded" xml:space="preserve"> <data name="AuthenticatorKeyAdded" xml:space="preserve">
@@ -891,7 +891,8 @@
<value>Αδυναμία ανάγνωσης κλειδιού επαλήθευσης.</value> <value>Αδυναμία ανάγνωσης κλειδιού επαλήθευσης.</value>
</data> </data>
<data name="PointYourCameraAtTheQRCode" xml:space="preserve"> <data name="PointYourCameraAtTheQRCode" xml:space="preserve">
<value>Σημαδέψτε τον κωδικό QR με τη κάμερα. Η σάρωση θα γίνει αυτόματα.</value> <value>Σημαδέψτε με την κάμερα σας τον κωδικό QR.
Η σάρωση θα γίνει αυτόματα.</value>
</data> </data>
<data name="ScanQrTitle" xml:space="preserve"> <data name="ScanQrTitle" xml:space="preserve">
<value>Σάρωση κώδικα QR</value> <value>Σάρωση κώδικα QR</value>
@@ -906,7 +907,7 @@
<value>Αντιγραφή TOTP</value> <value>Αντιγραφή TOTP</value>
</data> </data>
<data name="CopyTotpAutomaticallyDescription" xml:space="preserve"> <data name="CopyTotpAutomaticallyDescription" xml:space="preserve">
<value>Εάν η σύνδεση έχει κάποιο κλειδί επαλήθευσης, αντιγράψτε τον κωδικό επαλήθευσης TOTP στο πρόχειρο κάθε φορά που κάνετε αυτόματη συμπλήρωση τα στοιχεία σύνδεσης.</value> <value>Εάν η σύνδεση έχει κάποιο κλειδί αυθεντικοποίησης, αντιγράψτε τον κωδικό επαλήθευσης TOTP στο πρόχειρο σας όταν κάνετε με αυτόματη συμπλήρωση τη συνδεση.</value>
</data> </data>
<data name="CopyTotpAutomatically" xml:space="preserve"> <data name="CopyTotpAutomatically" xml:space="preserve">
<value>Αυτόματη αντιγραφή TOTP</value> <value>Αυτόματη αντιγραφή TOTP</value>
@@ -921,7 +922,7 @@
<value>Το συνημμένο διαγράφηκε</value> <value>Το συνημμένο διαγράφηκε</value>
</data> </data>
<data name="ChooseFile" xml:space="preserve"> <data name="ChooseFile" xml:space="preserve">
<value>Επιλογή Αρχείου</value> <value>Επιλογή αρχείου</value>
</data> </data>
<data name="File" xml:space="preserve"> <data name="File" xml:space="preserve">
<value>Αρχείο</value> <value>Αρχείο</value>
@@ -945,16 +946,16 @@
<value>Δεν μπορείτε να χρησιμοποιήσετε αυτήν τη δυνατότητα μέχρι να ενημερώσετε το κλειδί κρυπτογράφησης.</value> <value>Δεν μπορείτε να χρησιμοποιήσετε αυτήν τη δυνατότητα μέχρι να ενημερώσετε το κλειδί κρυπτογράφησης.</value>
</data> </data>
<data name="EncryptionKeyMigrationRequiredDescriptionLong" xml:space="preserve"> <data name="EncryptionKeyMigrationRequiredDescriptionLong" xml:space="preserve">
<value>Απαιτείται μεταφορά του κλειδιού κρυπτογράφησης. Παρακαλούμε συνδεθείτε μέσω του web vault για να ενημερώσετε το κλειδί κρυπτογράφησης.</value> <value>Απαιτείται μεταφορά του κλειδιού κρυπτογράφησης. Παρακαλούμε συνδεθείτε μέσω του διαδικτυακού vault για να ενημερώσετε το κλειδί κρυπτογράφησης.</value>
</data> </data>
<data name="LearnMore" xml:space="preserve"> <data name="LearnMore" xml:space="preserve">
<value>Μάθετε Περισσότερα</value> <value>Μάθετε περισσότερα</value>
</data> </data>
<data name="ApiUrl" xml:space="preserve"> <data name="ApiUrl" xml:space="preserve">
<value>URL Διακομιστή API</value> <value>URL διακομιστή API</value>
</data> </data>
<data name="CustomEnvironment" xml:space="preserve"> <data name="CustomEnvironment" xml:space="preserve">
<value>Προσαρμοσμένο Περιβάλλον</value> <value>Προσαρμοσμένο περιβάλλον</value>
</data> </data>
<data name="CustomEnvironmentFooter" xml:space="preserve"> <data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Για προχωρημένους χρήστες. Μπορείτε να ορίσετε τo URL κάθε υπηρεσίας ανεξάρτητα.</value> <value>Για προχωρημένους χρήστες. Μπορείτε να ορίσετε τo URL κάθε υπηρεσίας ανεξάρτητα.</value>
@@ -967,7 +968,7 @@
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment> <comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data> </data>
<data name="IdentityUrl" xml:space="preserve"> <data name="IdentityUrl" xml:space="preserve">
<value>URL Ταυτότητας Διακομιστή</value> <value>URL διακομιστή ταυτότητας</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment> <comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data> </data>
<data name="SelfHostedEnvironment" xml:space="preserve"> <data name="SelfHostedEnvironment" xml:space="preserve">
@@ -980,25 +981,25 @@
<value>URL Διακομιστή</value> <value>URL Διακομιστή</value>
</data> </data>
<data name="WebVaultUrl" xml:space="preserve"> <data name="WebVaultUrl" xml:space="preserve">
<value>URL Διακομιστή Web Vault</value> <value>URL διακομιστή διαδικτυακού vault</value>
</data> </data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve"> <data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Πατήστε στην ειδοποίηση για να συμπληρώσετε αυτόματα ένα στοιχείο από τη λίστα σας.</value> <value>Πατήστε στην ειδοποίηση για να συμπληρώσετε αυτόματα ένα στοιχείο από τη λίστα σας.</value>
</data> </data>
<data name="CustomFields" xml:space="preserve"> <data name="CustomFields" xml:space="preserve">
<value>Προσαρμοσμένα Πεδία</value> <value>Προσαρμοσμένα πεδία</value>
</data> </data>
<data name="CopyNumber" xml:space="preserve"> <data name="CopyNumber" xml:space="preserve">
<value>Αντιγραφή Αριθμού</value> <value>Αντιγραφή αριθμού</value>
</data> </data>
<data name="CopySecurityCode" xml:space="preserve"> <data name="CopySecurityCode" xml:space="preserve">
<value>Αντιγραφή Κωδικού Ασφαλείας</value> <value>Αντιγραφή κωδικού ασφαλείας</value>
</data> </data>
<data name="Number" xml:space="preserve"> <data name="Number" xml:space="preserve">
<value>Αριθμός</value> <value>Αριθμός</value>
</data> </data>
<data name="SecurityCode" xml:space="preserve"> <data name="SecurityCode" xml:space="preserve">
<value>Κωδικός Ασφαλείας</value> <value>Κωδικός ασφαλείας</value>
</data> </data>
<data name="TypeCard" xml:space="preserve"> <data name="TypeCard" xml:space="preserve">
<value>Κάρτα</value> <value>Κάρτα</value>
@@ -1010,7 +1011,7 @@
<value>Σύνδεση</value> <value>Σύνδεση</value>
</data> </data>
<data name="TypeSecureNote" xml:space="preserve"> <data name="TypeSecureNote" xml:space="preserve">
<value>Ασφαλής Σημείωση</value> <value>Ασφαλής σημείωση</value>
</data> </data>
<data name="Address1" xml:space="preserve"> <data name="Address1" xml:space="preserve">
<value>Διεύθυνση 1</value> <value>Διεύθυνση 1</value>
@@ -1049,10 +1050,10 @@
<value>Dr</value> <value>Dr</value>
</data> </data>
<data name="ExpirationMonth" xml:space="preserve"> <data name="ExpirationMonth" xml:space="preserve">
<value>Μήνας Λήξης</value> <value>Μήνας λήξης</value>
</data> </data>
<data name="ExpirationYear" xml:space="preserve"> <data name="ExpirationYear" xml:space="preserve">
<value>Έτος Λήξης</value> <value>Έτος λήξης</value>
</data> </data>
<data name="February" xml:space="preserve"> <data name="February" xml:space="preserve">
<value>Φεβρουάριος</value> <value>Φεβρουάριος</value>
@@ -1076,7 +1077,7 @@
<value>Ονοματεπώνυμο</value> <value>Ονοματεπώνυμο</value>
</data> </data>
<data name="LicenseNumber" xml:space="preserve"> <data name="LicenseNumber" xml:space="preserve">
<value>Αριθμός Άδειας</value> <value>Αριθμός άδειας</value>
</data> </data>
<data name="March" xml:space="preserve"> <data name="March" xml:space="preserve">
<value>Μάρτιος</value> <value>Μάρτιος</value>
@@ -1085,7 +1086,7 @@
<value>Μάιος</value> <value>Μάιος</value>
</data> </data>
<data name="MiddleName" xml:space="preserve"> <data name="MiddleName" xml:space="preserve">
<value>Μεσαίο Όνομα</value> <value>Μεσαίο όνομα</value>
</data> </data>
<data name="Mr" xml:space="preserve"> <data name="Mr" xml:space="preserve">
<value>Κος</value> <value>Κος</value>
@@ -1106,7 +1107,7 @@
<value>Οκτώβριος</value> <value>Οκτώβριος</value>
</data> </data>
<data name="PassportNumber" xml:space="preserve"> <data name="PassportNumber" xml:space="preserve">
<value>Αριθμός Διαβατηρίου</value> <value>Αριθμός διαβατηρίου</value>
</data> </data>
<data name="Phone" xml:space="preserve"> <data name="Phone" xml:space="preserve">
<value>Τηλέφωνο</value> <value>Τηλέφωνο</value>
@@ -1124,7 +1125,7 @@
<value>Τίτλος</value> <value>Τίτλος</value>
</data> </data>
<data name="ZipPostalCode" xml:space="preserve"> <data name="ZipPostalCode" xml:space="preserve">
<value>Ταχυδρομικός Κώδικας</value> <value>Ταχυδρομικός κώδικας</value>
</data> </data>
<data name="Address" xml:space="preserve"> <data name="Address" xml:space="preserve">
<value>Διεύθυνση</value> <value>Διεύθυνση</value>
@@ -1139,7 +1140,7 @@
<value>Εμφάνιση μιας αναγνωρίσιμης εικόνας δίπλα σε κάθε σύνδεση.</value> <value>Εμφάνιση μιας αναγνωρίσιμης εικόνας δίπλα σε κάθε σύνδεση.</value>
</data> </data>
<data name="IconsUrl" xml:space="preserve"> <data name="IconsUrl" xml:space="preserve">
<value>Εικονίδια Διακομιστή URL</value> <value>URL διακομιστή εικονιδίων</value>
</data> </data>
<data name="AutofillWithBitwarden" xml:space="preserve"> <data name="AutofillWithBitwarden" xml:space="preserve">
<value>Αυτόματη συμπλήρωση με Bitwarden</value> <value>Αυτόματη συμπλήρωση με Bitwarden</value>
@@ -1194,7 +1195,7 @@
<value>Δεν ήταν δυνατό να ανοίξουμε αυτόματα το μενού ρυθμίσεων αυτόματης συμπλήρωσης Android για εσάς. Μπορείτε να πλοηγηθείτε στο μενού ρυθμίσεων αυτόματης συμπλήρωσης με μη αυτόματο τρόπο από τις Ρυθμίσεις Android &gt; Σύστημα &gt; Γλώσσες και εισαγωγή &gt; Σύνθετες &gt; Υπηρεσία αυτόματης συμπλήρωσης.</value> <value>Δεν ήταν δυνατό να ανοίξουμε αυτόματα το μενού ρυθμίσεων αυτόματης συμπλήρωσης Android για εσάς. Μπορείτε να πλοηγηθείτε στο μενού ρυθμίσεων αυτόματης συμπλήρωσης με μη αυτόματο τρόπο από τις Ρυθμίσεις Android &gt; Σύστημα &gt; Γλώσσες και εισαγωγή &gt; Σύνθετες &gt; Υπηρεσία αυτόματης συμπλήρωσης.</value>
</data> </data>
<data name="CustomFieldName" xml:space="preserve"> <data name="CustomFieldName" xml:space="preserve">
<value>Όνομα Προσαρμοσμένου Πεδίου</value> <value>Όνομα προσαρμοσμένου πεδίου</value>
</data> </data>
<data name="FieldTypeBoolean" xml:space="preserve"> <data name="FieldTypeBoolean" xml:space="preserve">
<value>Δυαδικό</value> <value>Δυαδικό</value>
@@ -1209,7 +1210,7 @@
<value>Κείμενο</value> <value>Κείμενο</value>
</data> </data>
<data name="NewCustomField" xml:space="preserve"> <data name="NewCustomField" xml:space="preserve">
<value>Νέο Προσαρμοσμένο Πεδίο</value> <value>Νέο προσαρμοσμένο πεδίο</value>
</data> </data>
<data name="SelectTypeField" xml:space="preserve"> <data name="SelectTypeField" xml:space="preserve">
<value>Τι τύπος προσαρμοσμένου πεδίου είναι αυτό που θέλετε να προσθέσετε;</value> <value>Τι τύπος προσαρμοσμένου πεδίου είναι αυτό που θέλετε να προσθέσετε;</value>
@@ -1248,11 +1249,11 @@
<value>Εντοπισμός Αντιστοίχισης URI</value> <value>Εντοπισμός Αντιστοίχισης URI</value>
</data> </data>
<data name="MatchDetection" xml:space="preserve"> <data name="MatchDetection" xml:space="preserve">
<value>Εντοπισμός Αντιστοίχισης</value> <value>Εντοπισμός αντιστοίχισης</value>
<comment>URI match detection for auto-fill.</comment> <comment>URI match detection for auto-fill.</comment>
</data> </data>
<data name="YesAndSave" xml:space="preserve"> <data name="YesAndSave" xml:space="preserve">
<value>Αποδοχή και Αποθήκευση</value> <value>Ναι, και αποθήκευση</value>
</data> </data>
<data name="AutofillAndSave" xml:space="preserve"> <data name="AutofillAndSave" xml:space="preserve">
<value>Αυτόματη συμπλήρωση και αποθήκευση</value> <value>Αυτόματη συμπλήρωση και αποθήκευση</value>
@@ -1274,7 +1275,7 @@
<value>Η υπηρεσία προσβασιμότητας μπορεί να είναι χρήσιμη όταν οι εφαρμογές δεν υποστηρίζουν την τυπική υπηρεσία αυτόματης συμπλήρωσης.</value> <value>Η υπηρεσία προσβασιμότητας μπορεί να είναι χρήσιμη όταν οι εφαρμογές δεν υποστηρίζουν την τυπική υπηρεσία αυτόματης συμπλήρωσης.</value>
</data> </data>
<data name="DatePasswordUpdated" xml:space="preserve"> <data name="DatePasswordUpdated" xml:space="preserve">
<value>Ο Κωδικός Ενημερώθηκε</value> <value>Ο κωδικός ενημερώθηκε</value>
<comment>ex. Date this password was updated</comment> <comment>ex. Date this password was updated</comment>
</data> </data>
<data name="DateUpdated" xml:space="preserve"> <data name="DateUpdated" xml:space="preserve">
@@ -1297,7 +1298,7 @@
<value>Αποκτήστε πρόσβαση στη λίστα σας απευθείας από το πληκτρολόγιό σας για γρήγορη αυτόματη συμπλήρωση κωδικών.</value> <value>Αποκτήστε πρόσβαση στη λίστα σας απευθείας από το πληκτρολόγιό σας για γρήγορη αυτόματη συμπλήρωση κωδικών.</value>
</data> </data>
<data name="AutofillTurnOn" xml:space="preserve"> <data name="AutofillTurnOn" xml:space="preserve">
<value>Για να ενεργοποιήσετε την αυτόματη συμπλήρωση του κωδικού στη συσκευή σας, ακολουθήστε αυτές τις οδηγίες:</value> <value>Για να ενεργοποιήσετε την αυτόματη συμπλήρωση κωδικού στη συσκευή σας, ακολουθήστε αυτές τις οδηγίες:</value>
</data> </data>
<data name="AutofillTurnOn1" xml:space="preserve"> <data name="AutofillTurnOn1" xml:space="preserve">
<value>1. Μεταβείτε στις "Ρυθμίσεις" του iOS</value> <value>1. Μεταβείτε στις "Ρυθμίσεις" του iOS</value>
@@ -1315,7 +1316,7 @@
<value>5. Επιλέξτε "Bitwarden"</value> <value>5. Επιλέξτε "Bitwarden"</value>
</data> </data>
<data name="PasswordAutofill" xml:space="preserve"> <data name="PasswordAutofill" xml:space="preserve">
<value>Αυτόματη Συμπλήρωση Κωδικού</value> <value>Αυτόματη συμπλήρωση κωδικού</value>
</data> </data>
<data name="BitwardenAutofillAlert2" xml:space="preserve"> <data name="BitwardenAutofillAlert2" xml:space="preserve">
<value>Ο ευκολότερος τρόπος για να προσθέσετε νέες συνδέσεις στο vault σας, είναι με την επέκταση αυτόματης συμπλήρωσης κωδικών Bitwarden. Μάθετε περισσότερα σχετικά με τη χρήση της επέκτασης αυτής, μεταβαίνοντας στις "Ρυθμίσεις".</value> <value>Ο ευκολότερος τρόπος για να προσθέσετε νέες συνδέσεις στο vault σας, είναι με την επέκταση αυτόματης συμπλήρωσης κωδικών Bitwarden. Μάθετε περισσότερα σχετικά με τη χρήση της επέκτασης αυτής, μεταβαίνοντας στις "Ρυθμίσεις".</value>
@@ -1333,10 +1334,10 @@
<value>Συνδέσεις</value> <value>Συνδέσεις</value>
</data> </data>
<data name="SecureNotes" xml:space="preserve"> <data name="SecureNotes" xml:space="preserve">
<value>Ασφαλείς Σημειώσεις</value> <value>Ασφαλείς σημειώσεις</value>
</data> </data>
<data name="AllItems" xml:space="preserve"> <data name="AllItems" xml:space="preserve">
<value>Όλα τα Στοιχεία</value> <value>Όλα τα στοιχεία</value>
</data> </data>
<data name="URIs" xml:space="preserve"> <data name="URIs" xml:space="preserve">
<value>URIs</value> <value>URIs</value>
@@ -1356,13 +1357,13 @@
<value>Ο κωδικός αυτός δεν βρέθηκε σε γνωστές διαρροές δεδομένων. Είναι ασφαλής για χρήση.</value> <value>Ο κωδικός αυτός δεν βρέθηκε σε γνωστές διαρροές δεδομένων. Είναι ασφαλής για χρήση.</value>
</data> </data>
<data name="IdentityName" xml:space="preserve"> <data name="IdentityName" xml:space="preserve">
<value>Όνομα Ταυτότητας</value> <value>Όνομα ταυτότητας</value>
</data> </data>
<data name="Value" xml:space="preserve"> <data name="Value" xml:space="preserve">
<value>Τιμή</value> <value>Τιμή</value>
</data> </data>
<data name="PasswordHistory" xml:space="preserve"> <data name="PasswordHistory" xml:space="preserve">
<value>Ιστορικό Κωδικού</value> <value>Ιστορικό κωδικού</value>
</data> </data>
<data name="Types" xml:space="preserve"> <data name="Types" xml:space="preserve">
<value>Τύποι</value> <value>Τύποι</value>
@@ -1433,13 +1434,13 @@
<value>Επιλέξτε έναν οργανισμό στον οποίο θέλετε να μετακινήσετε αυτό το στοιχείο. Η μετακίνηση σε έναν οργανισμό μεταβιβάζει την ιδιοκτησία του στοιχείου σε αυτό τον οργανισμό. Δεν θα είστε πλέον ο άμεσος ιδιοκτήτης αυτού του στοιχείου μόλις το μετακινήσετε.</value> <value>Επιλέξτε έναν οργανισμό στον οποίο θέλετε να μετακινήσετε αυτό το στοιχείο. Η μετακίνηση σε έναν οργανισμό μεταβιβάζει την ιδιοκτησία του στοιχείου σε αυτό τον οργανισμό. Δεν θα είστε πλέον ο άμεσος ιδιοκτήτης αυτού του στοιχείου μόλις το μετακινήσετε.</value>
</data> </data>
<data name="NumberOfWords" xml:space="preserve"> <data name="NumberOfWords" xml:space="preserve">
<value>Αριθμός Λέξεων</value> <value>Αριθμός λέξεων</value>
</data> </data>
<data name="Passphrase" xml:space="preserve"> <data name="Passphrase" xml:space="preserve">
<value>Συνθηματικό</value> <value>Συνθηματικό</value>
</data> </data>
<data name="WordSeparator" xml:space="preserve"> <data name="WordSeparator" xml:space="preserve">
<value>Διαχωριστής Λέξεων</value> <value>Διαχωριστής λέξεων</value>
</data> </data>
<data name="Clear" xml:space="preserve"> <data name="Clear" xml:space="preserve">
<value>Εκκαθάριση</value> <value>Εκκαθάριση</value>
@@ -1453,7 +1454,7 @@
<value>Δεν υπάρχουν φάκελοι προς εμφάνιση.</value> <value>Δεν υπάρχουν φάκελοι προς εμφάνιση.</value>
</data> </data>
<data name="FingerprintPhrase" xml:space="preserve"> <data name="FingerprintPhrase" xml:space="preserve">
<value>Φράση Δακτυλικών Αποτυπωμάτων</value> <value>Φράση δακτυλικών αποτυπωμάτων</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment> <comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data> </data>
<data name="YourAccountsFingerprint" xml:space="preserve"> <data name="YourAccountsFingerprint" xml:space="preserve">
@@ -1464,10 +1465,10 @@
<value>Το Bitwarden επιτρέπει να μοιράζεστε τα στοιχεία του vault σας με άλλους χρησιμοποιώντας ένα λογαριασμό οργανισμού. Θέλετε να επισκεφθείτε την ιστοσελίδα bitwarden.com για να μάθετε περισσότερα;</value> <value>Το Bitwarden επιτρέπει να μοιράζεστε τα στοιχεία του vault σας με άλλους χρησιμοποιώντας ένα λογαριασμό οργανισμού. Θέλετε να επισκεφθείτε την ιστοσελίδα bitwarden.com για να μάθετε περισσότερα;</value>
</data> </data>
<data name="ExportVault" xml:space="preserve"> <data name="ExportVault" xml:space="preserve">
<value>Εξαγωγή Vault</value> <value>Εξαγωγή του vault</value>
</data> </data>
<data name="LockNow" xml:space="preserve"> <data name="LockNow" xml:space="preserve">
<value>Κλείδωμα Τώρα</value> <value>Κλείδωμα τώρα</value>
</data> </data>
<data name="PIN" xml:space="preserve"> <data name="PIN" xml:space="preserve">
<value>PIN</value> <value>PIN</value>
@@ -1476,7 +1477,7 @@
<value>Ξεκλείδωμα</value> <value>Ξεκλείδωμα</value>
</data> </data>
<data name="UnlockVault" xml:space="preserve"> <data name="UnlockVault" xml:space="preserve">
<value>Ξεκλείδωμα Vault</value> <value>Ξεκλείδωμα του vault</value>
</data> </data>
<data name="ThirtyMinutes" xml:space="preserve"> <data name="ThirtyMinutes" xml:space="preserve">
<value>30 λεπτά</value> <value>30 λεπτά</value>
@@ -1521,7 +1522,7 @@
<value>2 λεπτά</value> <value>2 λεπτά</value>
</data> </data>
<data name="ClearClipboard" xml:space="preserve"> <data name="ClearClipboard" xml:space="preserve">
<value>Εκκαθάριση Πρόχειρου</value> <value>Εκκαθάριση πρόχειρου</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment> <comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data> </data>
<data name="ClearClipboardDescription" xml:space="preserve"> <data name="ClearClipboardDescription" xml:space="preserve">
@@ -1549,7 +1550,7 @@
<value>Προεπιλεγμένο σκοτεινό θέμα</value> <value>Προεπιλεγμένο σκοτεινό θέμα</value>
</data> </data>
<data name="CopyNotes" xml:space="preserve"> <data name="CopyNotes" xml:space="preserve">
<value>Αντιγραφή Σημειώσεων</value> <value>Αντιγραφή σημείωσης</value>
</data> </data>
<data name="Exit" xml:space="preserve"> <data name="Exit" xml:space="preserve">
<value>Έξοδος</value> <value>Έξοδος</value>
@@ -1573,19 +1574,19 @@
<comment>'Solarized Dark' is the name of a specific color scheme. It should not be translated.</comment> <comment>'Solarized Dark' is the name of a specific color scheme. It should not be translated.</comment>
</data> </data>
<data name="AutofillBlockedUris" xml:space="preserve"> <data name="AutofillBlockedUris" xml:space="preserve">
<value>Αυτόματη συμπλήρωση μπλοκαρισμένων URIs</value> <value>Αυτόματη συμπλήρωση μπλοκαρισμένων URI</value>
</data> </data>
<data name="AskToAddLogin" xml:space="preserve"> <data name="AskToAddLogin" xml:space="preserve">
<value>Ζητήστε να προσθέστε σύνδεση</value> <value>Ρωτήστε για να προσθέστε σύνδεση</value>
</data> </data>
<data name="AskToAddLoginDescription" xml:space="preserve"> <data name="AskToAddLoginDescription" xml:space="preserve">
<value>Ζητήστε να προσθέσετε ένα αντικείμενο αν δε βρεθεί στην κρύπτη σας.</value> <value>Ρωτήστε για να προσθέσετε ένα αντικείμενο αν δε βρεθεί στο vault σας.</value>
</data> </data>
<data name="OnRestart" xml:space="preserve"> <data name="OnRestart" xml:space="preserve">
<value>Κατά την Επανεκκίνηση Εφαρμογής</value> <value>Κατά την επανεκκίνηση της εφαρμογής</value>
</data> </data>
<data name="AutofillServiceNotEnabled" xml:space="preserve"> <data name="AutofillServiceNotEnabled" xml:space="preserve">
<value>Η αυτόματη συμπλήρωση διευκολύνει την ασφαλή πρόσβαση στη λίστα από άλλες ιστοσελίδες και εφαρμογές. Φαίνεται ότι δεν έχετε ενεργοποιήσει την υπηρεσία αυτόματης συμπλήρωσης για το Bitwarden. Ενεργοποιήστε την από τις "Ρυθμίσεις".</value> <value>Η αυτόματη συμπλήρωση διευκολύνει την ασφαλή πρόσβαση στο vault του Bitwarden από άλλες ιστοσελίδες και εφαρμογές. Φαίνεται ότι δεν έχετε ενεργοποιήσει την υπηρεσία αυτόματης συμπλήρωσης για το Bitwarden. Ενεργοποιήστε την αυτόματη συμπλήρωση από τις "Ρυθμίσεις".</value>
</data> </data>
<data name="ThemeAppliedOnRestart" xml:space="preserve"> <data name="ThemeAppliedOnRestart" xml:space="preserve">
<value>Οι αλλαγές θεμάτων θα ισχύουν όταν γίνει επανεκκίνηση της εφαρμογής.</value> <value>Οι αλλαγές θεμάτων θα ισχύουν όταν γίνει επανεκκίνηση της εφαρμογής.</value>
@@ -1595,7 +1596,7 @@
<comment>ex. Uppercase the first character of a word.</comment> <comment>ex. Uppercase the first character of a word.</comment>
</data> </data>
<data name="IncludeNumber" xml:space="preserve"> <data name="IncludeNumber" xml:space="preserve">
<value>Συμπερίληψη Αριθμών</value> <value>Συμπερίληψη αριθμών</value>
</data> </data>
<data name="Download" xml:space="preserve"> <data name="Download" xml:space="preserve">
<value>Λήψη</value> <value>Λήψη</value>
@@ -1610,13 +1611,13 @@
<value>Η περίοδος σύνδεσης σας έχει λήξει.</value> <value>Η περίοδος σύνδεσης σας έχει λήξει.</value>
</data> </data>
<data name="BiometricsDirection" xml:space="preserve"> <data name="BiometricsDirection" xml:space="preserve">
<value>Χρήση βιομετρικής μεθόδου για επαλήθευση.</value> <value>Βιομετρική επαλήθευση</value>
</data> </data>
<data name="Biometrics" xml:space="preserve"> <data name="Biometrics" xml:space="preserve">
<value>Βιομετρική</value> <value>Βιομετρική</value>
</data> </data>
<data name="UseBiometricsToUnlock" xml:space="preserve"> <data name="UseBiometricsToUnlock" xml:space="preserve">
<value>Χρήση βιομετρικής μεθόδου για ξεκλείδωμα</value> <value>Χρήση βιομετρικών για ξεκλείδωμα</value>
</data> </data>
<data name="AccessibilityOverlayPermissionAlert" xml:space="preserve"> <data name="AccessibilityOverlayPermissionAlert" xml:space="preserve">
<value>Το Bitwarden χρειάζεται προσοχή - Ανατρέξτε στην ενότητα "Υπηρεσία προσβασιμότητας αυτόματης συμπλήρωσης" από τις ρυθμίσεις Bitwarden</value> <value>Το Bitwarden χρειάζεται προσοχή - Ανατρέξτε στην ενότητα "Υπηρεσία προσβασιμότητας αυτόματης συμπλήρωσης" από τις ρυθμίσεις Bitwarden</value>
@@ -1640,7 +1641,7 @@
<value>Χορηγήθηκε</value> <value>Χορηγήθηκε</value>
</data> </data>
<data name="FileFormat" xml:space="preserve"> <data name="FileFormat" xml:space="preserve">
<value>Μορφή Αρχείου</value> <value>Μορφή αρχείου</value>
</data> </data>
<data name="ExportVaultMasterPasswordDescription" xml:space="preserve"> <data name="ExportVaultMasterPasswordDescription" xml:space="preserve">
<value>Εισαγάγετε τον κύριο κωδικό για εξαγωγή των δεδομένων vault.</value> <value>Εισαγάγετε τον κύριο κωδικό για εξαγωγή των δεδομένων vault.</value>
@@ -1649,7 +1650,7 @@
<value>Στείλτε έναν κωδικό επαλήθευσης στο email σας</value> <value>Στείλτε έναν κωδικό επαλήθευσης στο email σας</value>
</data> </data>
<data name="CodeSent" xml:space="preserve"> <data name="CodeSent" xml:space="preserve">
<value>Ο Κωδικός Στάλθηκε</value> <value>Ο κωδικός στάλθηκε!</value>
</data> </data>
<data name="ConfirmYourIdentity" xml:space="preserve"> <data name="ConfirmYourIdentity" xml:space="preserve">
<value>Επιβεβαιώστε την ταυτότητα σας για να συνεχίσετε.</value> <value>Επιβεβαιώστε την ταυτότητα σας για να συνεχίσετε.</value>
@@ -1664,7 +1665,7 @@
<value>Τα κλειδιά κρυπτογράφησης λογαριασμού είναι μοναδικά για κάθε λογαριασμό χρήστη Bitwarden, οπότε δεν μπορείτε να εισάγετε μια κρυπτογραφημένη εξαγωγή σε διαφορετικό λογαριασμό.</value> <value>Τα κλειδιά κρυπτογράφησης λογαριασμού είναι μοναδικά για κάθε λογαριασμό χρήστη Bitwarden, οπότε δεν μπορείτε να εισάγετε μια κρυπτογραφημένη εξαγωγή σε διαφορετικό λογαριασμό.</value>
</data> </data>
<data name="ExportVaultConfirmationTitle" xml:space="preserve"> <data name="ExportVaultConfirmationTitle" xml:space="preserve">
<value>Επιβεβαίωση εξαγωγής Vault</value> <value>Επιβεβαίωση εξαγωγής vault</value>
<comment>Title for the alert to confirm vault exports.</comment> <comment>Title for the alert to confirm vault exports.</comment>
</data> </data>
<data name="Warning" xml:space="preserve"> <data name="Warning" xml:space="preserve">
@@ -1907,7 +1908,7 @@
<value>Ημερομηνία διαγραφής</value> <value>Ημερομηνία διαγραφής</value>
</data> </data>
<data name="DeletionTime" xml:space="preserve"> <data name="DeletionTime" xml:space="preserve">
<value>Χρόνος Διαγραφής</value> <value>Χρόνος διαγραφής</value>
</data> </data>
<data name="DeletionDateInfo" xml:space="preserve"> <data name="DeletionDateInfo" xml:space="preserve">
<value>Το Send θα διαγραφεί οριστικά την καθορισμένη ημερομηνία και ώρα.</value> <value>Το Send θα διαγραφεί οριστικά την καθορισμένη ημερομηνία και ώρα.</value>
@@ -1917,7 +1918,7 @@
<value>Εκκρεμεί διαγραφή</value> <value>Εκκρεμεί διαγραφή</value>
</data> </data>
<data name="ExpirationDate" xml:space="preserve"> <data name="ExpirationDate" xml:space="preserve">
<value>Ημερομηνία Λήξης</value> <value>Ημερομηνία λήξης</value>
</data> </data>
<data name="ExpirationTime" xml:space="preserve"> <data name="ExpirationTime" xml:space="preserve">
<value>Χρόνος λήξης</value> <value>Χρόνος λήξης</value>
@@ -1943,14 +1944,14 @@
<value>Τρέχων Αριθμός Πρόσβασης</value> <value>Τρέχων Αριθμός Πρόσβασης</value>
</data> </data>
<data name="NewPassword" xml:space="preserve"> <data name="NewPassword" xml:space="preserve">
<value>Νέος Κωδικός</value> <value>Νέος κωδικός πρόσβασης</value>
</data> </data>
<data name="PasswordInfo" xml:space="preserve"> <data name="PasswordInfo" xml:space="preserve">
<value>Προαιρετικά απαιτείται κωδικός πρόσβασης για τους χρήστες για να έχουν πρόσβαση σε αυτό το Send.</value> <value>Προαιρετικά απαιτείται κωδικός πρόσβασης για τους χρήστες για να έχουν πρόσβαση σε αυτό το Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment> <comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data> </data>
<data name="RemovePassword" xml:space="preserve"> <data name="RemovePassword" xml:space="preserve">
<value>Αφαίρεση κωδικού</value> <value>Αφαίρεση κωδικού πρόσβασης</value>
</data> </data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve"> <data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Είστε βέβαιοι ότι θέλετε να καταργήσετε τον κωδικό πρόσβασης;</value> <value>Είστε βέβαιοι ότι θέλετε να καταργήσετε τον κωδικό πρόσβασης;</value>
@@ -1978,10 +1979,10 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment> <comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data> </data>
<data name="CopyLink" xml:space="preserve"> <data name="CopyLink" xml:space="preserve">
<value>Αντιγραφή Συνδέσμου</value> <value>Αντιγραφή συνδέσμου</value>
</data> </data>
<data name="ShareLink" xml:space="preserve"> <data name="ShareLink" xml:space="preserve">
<value>Κοινοποίηση Συνδέσμου</value> <value>Κοινοποίηση συνδέσμου</value>
</data> </data>
<data name="SendLink" xml:space="preserve"> <data name="SendLink" xml:space="preserve">
<value>Σύνδεσμος Send</value> <value>Σύνδεσμος Send</value>
@@ -2076,7 +2077,7 @@
<value>Το Captcha απέτυχε. Παρακαλώ προσπάθησε ξανα.</value> <value>Το Captcha απέτυχε. Παρακαλώ προσπάθησε ξανα.</value>
</data> </data>
<data name="UpdatedMasterPassword" xml:space="preserve"> <data name="UpdatedMasterPassword" xml:space="preserve">
<value>Ενημερώθηκε ο κύριος κωδικός πρόσβασης</value> <value>Ενημερωμένος κύριος κωδικός πρόσβασης</value>
</data> </data>
<data name="UpdateMasterPassword" xml:space="preserve"> <data name="UpdateMasterPassword" xml:space="preserve">
<value>Ενημερώστε τον κύριο κωδικό πρόσβασης</value> <value>Ενημερώστε τον κύριο κωδικό πρόσβασης</value>
@@ -2091,7 +2092,7 @@
<value>Δεν είναι δυνατή η ενημέρωση του κωδικού πρόσβασης</value> <value>Δεν είναι δυνατή η ενημέρωση του κωδικού πρόσβασης</value>
</data> </data>
<data name="RemoveMasterPassword" xml:space="preserve"> <data name="RemoveMasterPassword" xml:space="preserve">
<value>Αφαίρεση Κύριου Κωδικού Πρόσβασης</value> <value>Αφαίρεση κύριου κωδικού πρόσβασης</value>
</data> </data>
<data name="RemoveMasterPasswordWarning" xml:space="preserve"> <data name="RemoveMasterPasswordWarning" xml:space="preserve">
<value>{0} χρησιμοποιεί SSO με κρυπτογράφηση διαχείρισης πελατών. Συνεχίζοντας θα καταργήσετε τον Κύριο Κωδικό από το λογαριασμό σας και θα απαιτήσετε SSO για να συνδεθείτε.</value> <value>{0} χρησιμοποιεί SSO με κρυπτογράφηση διαχείρισης πελατών. Συνεχίζοντας θα καταργήσετε τον Κύριο Κωδικό από το λογαριασμό σας και θα απαιτήσετε SSO για να συνδεθείτε.</value>
@@ -2820,7 +2821,7 @@
<value>Συνέχεια στην επικοινωνία με την υποστήριξη;</value> <value>Συνέχεια στην επικοινωνία με την υποστήριξη;</value>
</data> </data>
<data name="ContinueToPrivacyPolicy" xml:space="preserve"> <data name="ContinueToPrivacyPolicy" xml:space="preserve">
<value>Continue to privacy policy?</value> <value>Συνέχεια στην πολιτική απορρήτου;</value>
</data> </data>
<data name="ContinueToAppStore" xml:space="preserve"> <data name="ContinueToAppStore" xml:space="preserve">
<value>Συνέχεια στο κατάστημα εφαρμογών;</value> <value>Συνέχεια στο κατάστημα εφαρμογών;</value>
@@ -2842,7 +2843,7 @@
<value>Δεν μπορείτε να βρείτε αυτό που ψάχνετε; Επικοινωνήστε με την υποστήριξη Bitwarden στο bitwarden.com.</value> <value>Δεν μπορείτε να βρείτε αυτό που ψάχνετε; Επικοινωνήστε με την υποστήριξη Bitwarden στο bitwarden.com.</value>
</data> </data>
<data name="PrivacyPolicyDescriptionLong" xml:space="preserve"> <data name="PrivacyPolicyDescriptionLong" xml:space="preserve">
<value>Check out our privacy policy on bitwarden.com.</value> <value>Δείτε την πολιτική απορρήτου μας στο bitwarden.com.</value>
</data> </data>
<data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve"> <data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve">
<value>Εξερευνήστε περισσότερες δυνατότητες του Bitwarden λογαριασμού σας, στην εφαρμογή διαδικτύου.</value> <value>Εξερευνήστε περισσότερες δυνατότητες του Bitwarden λογαριασμού σας, στην εφαρμογή διαδικτύου.</value>
@@ -2875,4 +2876,13 @@
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Ρυθμίστε μια επιλογή κλειδώματος για να αλλάξετε την ενέργεια στη λήξη χρόνου του vault σας.</value> <value>Ρυθμίστε μια επιλογή κλειδώματος για να αλλάξετε την ενέργεια στη λήξη χρόνου του vault σας.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo σύνδεση δύο βημάτων απαιτείται για το λογαριασμό σας. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Ακολουθήστε τα βήματα από το Duo για να ολοκληρώσετε τη σύνδεση.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Εκκίνηση Duo</value>
</data>
</root> </root>

View File

@@ -2876,4 +2876,13 @@ Do you want to switch to this account?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2890,4 +2890,13 @@ Do you want to switch to this account?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2823,7 +2823,7 @@ seleccione Agregar TOTP para almacenar la clave de forma segura</value>
<value>¿Continuar con el servicio de asistencia?</value> <value>¿Continuar con el servicio de asistencia?</value>
</data> </data>
<data name="ContinueToPrivacyPolicy" xml:space="preserve"> <data name="ContinueToPrivacyPolicy" xml:space="preserve">
<value>Continue to privacy policy?</value> <value>¿Continuar a la política de privacidad?</value>
</data> </data>
<data name="ContinueToAppStore" xml:space="preserve"> <data name="ContinueToAppStore" xml:space="preserve">
<value>¿Continuar a la App Store?</value> <value>¿Continuar a la App Store?</value>
@@ -2845,7 +2845,7 @@ seleccione Agregar TOTP para almacenar la clave de forma segura</value>
<value>¿No encuentras lo que estás buscando? Contacta con el soporte de Bitwarden en bitwarden.com.</value> <value>¿No encuentras lo que estás buscando? Contacta con el soporte de Bitwarden en bitwarden.com.</value>
</data> </data>
<data name="PrivacyPolicyDescriptionLong" xml:space="preserve"> <data name="PrivacyPolicyDescriptionLong" xml:space="preserve">
<value>Check out our privacy policy on bitwarden.com.</value> <value>Revise nuestra política de privacidad en bitwarden.com.</value>
</data> </data>
<data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve"> <data name="ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp" xml:space="preserve">
<value>Explora más características de tu cuenta de Bitwarden en la aplicación web.</value> <value>Explora más características de tu cuenta de Bitwarden en la aplicación web.</value>
@@ -2878,4 +2878,13 @@ seleccione Agregar TOTP para almacenar la clave de forma segura</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Configura una opción de desbloqueo para cambiar tu acción de tiempo de espera de tu caja fuerte.</value> <value>Configura una opción de desbloqueo para cambiar tu acción de tiempo de espera de tu caja fuerte.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Se requiere el inicio de sesión en dos pasos Duo para su cuenta. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Siga los pasos de Duo para terminar de iniciar sesión.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Iniciar Duo</value>
</data>
</root> </root>

View File

@@ -2876,4 +2876,13 @@ Soovid selle konto peale lülituda?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2875,4 +2875,13 @@ Kontu honetara aldatu nahi duzu?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2877,4 +2877,13 @@
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Set up an unlock option to change your vault timeout action.</value> <value>Set up an unlock option to change your vault timeout action.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Duo two-step login is required for your account. </value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Follow the steps from Duo to finish logging in.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Launch Duo</value>
</data>
</root> </root>

View File

@@ -2877,4 +2877,13 @@ Haluatko vaihtaa tähän tiliin?</value>
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve"> <data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
<value>Muuta holvisi aikakatkaisutoimintoa määrittämällä lukituksen avaustapa.</value> <value>Muuta holvisi aikakatkaisutoimintoa määrittämällä lukituksen avaustapa.</value>
</data> </data>
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
<value>Tilillesi kirjautuminen vaatii Duo-vahvistuksen.</value>
</data>
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
<value>Viimeistele kirjautuminen seuraamalla Duon ohjeita.</value>
</data>
<data name="LaunchDuo" xml:space="preserve">
<value>Avaa Duo</value>
</data>
</root> </root>

Some files were not shown because too many files have changed in this diff Show More