1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00

Compare commits

..

37 Commits

Author SHA1 Message Date
André Bispo
2dd6a3f294 [PM-3340] Change settings screen vault timeout action cell UI. 2023-09-13 17:28:03 +01:00
André Bispo
3e2005e5ed [PM-3606] TDE user with 2FA isn't able to autofill on iOS (#2723)
* [PM-3606] Fix 2FA for autofill

* [PM-3606] Fix autofill when user doesn't have a login method available.

* [PM-3606] PR fixes

* [PM-3606] Add logout logic to other extension projects

* [PM-3606] Move code to base class.

* Transform into property instead of field

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

* Remove double ";"

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

* [PM-3606] Fix iOS extension by changing base class of LockPasswordViewController

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-09-09 17:38:14 -04:00
Will Browning
382eee2ed3 [PM-3556] Change anonaddy to addy io (#2711)
* Update AppResources.af.resx

* Update AnonAddy references

* Reverted AnonAddy to AddyIo refactor, keeping text and url changes

---------

Co-authored-by: Andre Rosado <arosado@bitwarden.com>
2023-09-08 15:23:51 +01:00
github-actions[bot]
b0f1dd00ee Autosync the updated translations (#2751)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-08 09:33:37 +00:00
André Bispo
5961a001ab [PM-3551] Expired SSO token cached (#2718) 2023-09-08 07:48:37 +01:00
André Bispo
9026dd10e5 [PM-3593] Fix enable biometric on autofill when there is not MP (#2717) 2023-09-07 16:30:46 +01:00
ifernandezdiaz
355261679d Adding missing IDs for Set Password and Update Password pages (#2748) 2023-09-07 11:24:48 -03:00
ifernandezdiaz
7f14ec9b5d QA-508 - Build app for automation CI (#2705)
* Adding build steps for .app

* Uploading .app artifact

* Fixing ARCHIVE_PATH variable

* Fixing missing OutputPath

* Fixing Bitwarden .app file name

* Fixing wrong .app location

* Adding Fede's suggestion

* Update .github/workflows/build.yml

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>

---------

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>
2023-09-06 14:25:59 -03:00
Opeyemi
0c72626916 UPDATE: all workflows (#2743) 2023-09-06 15:30:47 +01:00
André Bispo
f21fae7fea [PM-3382] User cannot select Email as a secondary 2FA option following SSO (#2719)
* [PM-3382] Update mobile client to receive and use SsoEmail2faSessionToken

* [PM-3382] Fix null 2fa email with local email on MP login.
2023-09-06 10:26:11 +01:00
github-actions[bot]
6d4792bc24 Autosync the updated translations (#2741)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-01 12:46:27 +00:00
mpbw2
dbadf8c56f [PM-3222] Migration of data from LiteDB to shared pref storage (#2724)
* Migration of data from LiteDB to shared pref storage

* tweaks
2023-08-30 10:55:20 -04:00
André Bispo
4d0f9d1c03 [PM-3543] [PM-3607] Fix password re-prompt when editing and on autofill. (#2713)
* [PM-3543] [PM-3507] Fix password re-prompt when editing and on autofill.
2023-08-30 09:38:46 +01:00
André Bispo
68759fc608 [PM-3547] Change logic to set user key for inactive account (#2715) 2023-08-29 10:28:51 +01:00
github-actions[bot]
47be3d6aef Bumped version to 2023.8.1 (#2730)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-08-28 16:34:38 -04:00
github-actions[bot]
7ec5c8ccfd Bumped version to 2023.8.0 (#2725)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-08-25 19:52:35 -04:00
Jake Fink
819aabb330 don't clear key needed for bio/auto migration in pin migration (#2721) 2023-08-25 09:47:37 -04:00
github-actions[bot]
9c7ff853d7 Autosync the updated translations (#2720)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-08-25 09:03:57 +00:00
mpbw2
e30f9903d1 fix for TDE pref naming collision (#2712)
* fix for TDE pref naming collision

* fix case
2023-08-22 15:51:11 -04:00
André Bispo
249406e3a8 [PM-3545] Fix biometric unlock for autofill (#2710)
* [PM-3545] Fix biometric unlock for autofill

* [PM-3545] Reuse existing method
2023-08-21 20:30:22 +01:00
github-actions[bot]
8cae840c68 Autosync the updated translations (#2704)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-08-19 14:00:16 +00:00
André Bispo
e274c04107 [PM-3513] Show error SSO policy (#2707)
* [PM-3513] Show API error when SSO policy is enforced.
2023-08-18 23:05:52 +01:00
Robyn MacCallum
7043be67dd Update CODEOWNERS (#2701)
* Update CODEOWNERS

* Update CODEOWNERS
2023-08-18 11:20:26 -04:00
Federico Maccaroni
afb8c515d6 [PM-3071] Remove share on save toggle on Send view (#2659)
* PM-3071 Removed share on save toggle on Send view and now it's done automatically, same for copy after saving from the Share extension

* PM-3071 Fix alignments on Share extension send view
2023-08-17 16:42:08 -03:00
Todd Martin
bfcfd367dd Trusted Device Encryption feature (#2656)
* [PM-1208] Add Device approval options screen. View model waiting for additional logic to be added.

* [PM-1208] Add device related api endpoint. Add AccoundDecryptOptions model and property to user Account.

* [PM-1208] Add continue button and not you option

* [PM-1379] add DeviceTrustCryptoService with establish trust logic (#2535)

* [PM-1379] add DeviceCryptoService with establish trust logic

* PM-1379 update api location and other minor refactors

* pm-1379 fix encoding

* update trusted device keys api call to Put

* [PM-1379] rename DeviceCryptoService to DeviceTrustCryptoService
- refactors to prevent side effects

* [PM-1379] rearrange methods in DeviceTrustCryptoService

* [PM-1379] rearrange methods in abstraction

* [PM-1379] deconstruct tuples

* [PM-1379] remove extra tasks

* [PM-2583] Answer auth request with mp field as null if doesn't have it. (#2609)

* [PM-2287][PM-2289][PM-2293] Approval Options (#2608)

* [PM-2293] Add AuthRequestType to PasswordlessLoginPage.

* [PM-2293] Add Actions to ApproveWithDevicePage

* [PM-2293] Change screen text based on AuthRequestType

* [PM-2293] Refactor AuthRequestType enum. Add label. Remove unnecessary actions.

* [PM-2293] Change boolean variable expression.

* [PM-2293] Trust device after admin request login.

* code format

* [PM-2287] Add trust device to master password unlock. Change trust device method. Remove email from SSO login page.

* [PM-2293] Fix state variable get set.

* [PM-2287][PM-2289][PM-2293] Rename method

* [PM-1201] Change timeout actions available based on hasMasterPassword (#2610)

* [PM-1201] Change timeout actions available based on hasMasterPassword

* [PM-2731] add user key and master key types

* [PM-2713] add new state for new keys and obsolete old ones
- UserKey
- MasterKey
- UserKeyMasterKey (enc UserKey from User Table)

* [PM-271] add UserKey and MasterKey support to crypto service

* [PM-2713] rename key hash to password hash & begin add methods to crypto service

* [PM-2713] continue organizing crypto service

* [PM-2713] more updates to crypto service

* [PM-2713] add new pin methods to state service

* [PM-2713] fix signature of GetUserKeyPin

* [PM-2713] add make user key method to crypto service

* [PM-2713] refresh pin key when setting user key

* [PM-2713] use new MakeMasterKey method

* [PM-2713] add toggle method to crypto service for keys

* [PM-2713] converting calls to new crypto service api

* [PM-2713] add migration for pin on lock screens

* [PM-2713] more conversions to new crypto service api

* [PM-2713] convert cipher service and others to crypto service api

* [PM-2713] More conversions to crypto api

* [PM-2713] use new crypto service api in auth service

* [PM-2713] remove unused cached values in crypto service

* [PM-2713] set decrypt and set user key in login helper

* fix bad merge

* Update crypto service api call to fix build

* [PM-1208] Fix app resource file

* [PM-1208] Fix merge

* [PM-1208] Fix merge

* [PM-2713] optimize async code in crypto service

* [PM-2713] rename password hash to master key hash

* [PM-2713] fix casting issues and pin

* [PM-2713] remove extra comment

* [PM-2713] remove broken casting

* [PM-2297] Login with trusted device (Flow 2) (#2623)

* [PM-2297] Add DecryptUserKeyWithDeviceKey method

* [PM-2297] Add methods to DeviceTrustCryptoService update decryption options model

* [PM-2297] Update account decryption options model

* [PM-2297] Fix TrustedDeviceOption and DeviceResponse model. Change StateService device key get set to have default user id

* [PM-2297] Update navigation to decryption options

* [PM-2297] Add missing action navigations to iOS extensions

* [PM-2297] Fix trust device bug/typo

* [PM-2297] Fix model bug

* [PM-2297] Fix state var crash

* [PM-2297] Add trust device login logic to auth service

* [PM-2297] Refactor auth service key connector code

* [PM-2297] Remove reconciledOptions for deviceKey in state service

* [PM-2297] Remove unnecessary user id params

* [PM-2289] [PM-2293] TDE Login with device Admin Request (#2642)

* [PM-2713] deconstruct new key pair

* [PM-2713] rename PrivateKey methods to UserPrivateKey on crypto service

* [PM-2713] rename PinLockEnum to PinLockType

* [PM-2713] don't pass user key as param when encrypting

* [PM-2713] rename toggle method, don't reset enc user key

* [PM-2713] pr feedback

* [PM-2713] PR feedback

* [PM-2713] rename get pin lock type method

* [PM-2713] revert feedback for build

* [PM-2713] rename state methods

* [PM-2713] combine makeDataEncKey methods

* [PM-2713] consolidate attachment key creation
- also fix ios files missed during symbol rename

* [PM-2713] replace generic with inherited class

* rename account keys to be more descriptive

* [PM-2713] add auto unlock key to mobile

* [PM-1208] Add TDE flows for new users (#2655)

* [PM-1208] Create new user on SSO. Logout if not password is setup or has pending admin auth request.

* [PM-1208] Fix new user UserKey decryption.

* [PM-1208] Add new user continue to vault logic. Auto enrol user on continue.

* [PM-1208] Trust device only if needed

* [PM-1208] Add logic for New User SSO.

* [PM-1208] Add logic for New User SSO (missing file).

* [PM-2713] set user key on set password page

* [PM-2713] set enc user key during kc onboarding

* fix formatting

* [PM-2713] make method async again
- returning null from a task thats not async throws

* [PM-2713] clear service cache when adding new account

* Fix build after merge

* [PM-3313] Fix Android SSO Login (#2663)

* [PM-3313] Catch exception on AuthPendingRequest

* [PM-3313] Fix lock timeout action if user doesn't have a master password.

* code format

* [PM-3313] Null email in Approval Options screen (#2664)

* [PM-3313] Fix null email in approval options screen

* [PM-3320][PM-3321] Fix labels and UI tweaks (#2666)

* [PM-3320] Fix UI copy and remember me default ON.

* [PM-3321] Fix UI on Log in with device screen.

* [PM-3337] Fix admin request deny error (#2669)

* [PM-3342] Not you button logs user out. (#2672)

* [PM-3319] Check for admin request in Lock page (#2668)

* [PM-3319] Ignore admin auth request when choosing mp as decryption option.

* [PM-2289] Change header title based on auth request type (#2670)

* [PM-2289] Change header title based on auth request type

* [PM-3333] Check for purged admin auth requests (#2671)

* [PM-3333] Check for purged admin auth requests

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

---------

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

* [PM-3341] Vault Timeout Action not persisted correctly (#2673)

* [PM-3341] Fix timeout action change when navigating

* [PM-3357] Fix copy for Login Initiated (#2674)

* [PM-3362] Fix auth request approval (#2675)

* [PM-3362] Fix auth request approval

* [PM-3362] Add new exception type

* [PM-3102] Update Master password reprompt to be based on MP instead of Key Connector (#2653)

* PM-3102 Added check to see if a user has master password set replacing previous usage of key connector.

* PM-3102 Fix formatting

* [PM-2713] Final merge from Key Migration branch to TDE Feature branch (#2667)

* [PM-2713] add async to key connector service methods

* [PM-2713] rename ephemeral pin key

* add state for biometric key and accept UserKey instead of string for auto key

* Get UserKey from bio state on unlock

* PM-2713 Fix auto-migrating EncKeyEncrypted into MasterKey encrypted UserKey when requesting DecryptUserKeyWithMasterKeyAsync is called

* renaming bio key and fix build

* PM-3194 Fix biometrics button to be shown on upgrade when no UserKey is present yet

* revert removal of key connector service from auth service

* PM-2713 set user key when using KC

* clear enc user key after migration

* use is true for nullable bool

* PR feedback, refactor kc service

---------

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

* Fix app fresh install user login with master password. (#2676)

* [PM-3303] Fix biometric login after key migration (#2679)

* [PM-3303] Add condition to biometric unlock

* [PM-3381] Fix TDE login 2FA flow (#2678)

* [PM-3381] Check for vault lock on 2FA screen

* [PM-3381] Move logic to ViewModel

* [PM-3381] Fix null vm error

* [PM-3379] Fix key rotation on trusted device. (#2680)

* [PM-3381] Update login flows (#2683)

* [PM-3381] Update login flows

* [PM-3381] Remove _authingWithSso parameter

* PM-3385 Fix MP reprompt item level when no MP hash is stored like logging in with TDE. Also refactor code to be more maintainable (#2687)

* PM-3386 Fix MP reprompt / OTP decision to be also based on the master key hash. (#2688)

* PM-3450 Fix has master password with mp key hash check (#2689)

* [PM-3394] Fix login with device for passwordless approvals (#2686)

* set activeUserId to null when logging in a new account
- Also stop the user key from being set in inactive accounts

* get token for login with device if approving device doesn't have master key

* add comment

* simplify logic

* check for route instead of using isAuthenticated
- we don't clear the user id when logging in new account
- this means we can't trust the state service, so we have to base our logic off the route in login with device

* use authenticated auth request for tde login with device

* [PM-3394] Add authingWithSso parameter to LoginPasswordlessRequestPage.

* pr feedback

* [PM-3394] Refactor condition

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

---------

Co-authored-by: André Bispo <abispo@bitwarden.com>
Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* [PM-3462] Handle force password reset on mobile with TDE (#2694)

* [PM-3462] Handle force password reset on mobile with TDE

* [PM-3462] update references to refactored crypto method
- fix kc bug, we were sending private key instead of user key to server
- rename kc service method to be correct

* [PM-3462] Update TwoFactorPage login logic

* [PM-3462] Added pending admin request check to TwoFactorPage

* [PM-3462] Added new exception types for null keys

---------

Co-authored-by: André Bispo <abispo@bitwarden.com>

* [PM-1029] Fix Async suffix in ApiService. Add UserKeyNullExceptions.

* [PM 3513] Fix passwordless 2fa login with device on mobile (#2700)

* [PM-3513] Fix 2FA for normal login with device with users without mp

* move _userKey

---------

Co-authored-by: André Bispo <abispo@bitwarden.com>

* clear encrypted pin on logout (#2699)

---------

Co-authored-by: André Bispo <abispo@bitwarden.com>
Co-authored-by: Jake Fink <jfink@bitwarden.com>
Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-08-17 15:19:35 -04:00
Federico Maccaroni
a23454bc53 [PM-3508] Fix Release iPhoneSimulator configuration for iOS / Extensions (#2698)
* PM-3508 Fix Release iPhoneSimulator configuration for iOS / Extensions

* PM-3508 Fix --deep space on watch app references
2023-08-16 15:55:34 -03:00
mpbw2
6f7100ae4f lib updates (#2696) 2023-08-16 12:48:54 -04:00
ifernandezdiaz
01ac20e6e4 Adding missing AutomationIDs on LoginPasswordlessRequestListPage (#2693) 2023-08-16 11:09:07 -03:00
github-actions[bot]
8474f536ff Autosync the updated translations (#2677)
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>
2023-08-15 13:48:01 +00:00
Daniel James Smith
f426c0e370 Create section for crowdin sync (#2692) 2023-08-15 15:47:08 +02:00
Daniel James Smith
420dc09fd1 Update codeowners (#2691)
* Set team-leads-eng as owners for translations

This is needed to Crowdin sync PRs can be merged.

* Add team-tools as owner of the email-forwarders

* Fix unescaped whitespace

* Remove team-leads-eng from owning English resources
2023-08-15 15:32:57 +02:00
Federico Maccaroni
6d4793d592 [PM-1768] Set up CODEOWNERS file (#2464)
* PM-1768 Add CODEOWNERS file with some initial setup of folders that don't need to be moved and can have their owners assigned already.

* Update CODEOWNERS

Removed entire projects owners cause I didn't consider auth inside of the extensions.
2023-08-10 13:58:03 -03:00
Bernd Schoolmann
eea7c6b7d7 [PM-2901] Synchronize sends on send creation/update/deletion notification (#2606)
* Add sync on send create/update/delete notification

* Update send notifications to only sync sends

* Fix incorrect notification type in PushNotificationListenerService

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>

* Invert if to improve readability

* Simplify shouldUpdate logic in SyncUpsertSendAsync

* Further simplify SyncService code

* Fix if condition in SyncService

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>

* Fixed whitespace formatting

---------

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>
Co-authored-by: Andre Rosado <arosado@bitwarden.com>
2023-08-08 14:59:42 +01:00
Bernd Schoolmann
ec93a61275 [PM-3092] Clarify argon2 ios autofill warning (#2630)
* Clarify argon2 ios warning

* Update Argon2 insufficient memory warning message
2023-08-07 10:41:40 -04:00
Federico Maccaroni
c34d1da6e6 PM-3298 Updated region selector to be logging in on and also its options (#2657) 2023-08-04 11:44:39 -03:00
github-actions[bot]
c4e64e082b Autosync the updated translations (#2660)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-08-04 10:55:27 +00:00
Federico Maccaroni
5aaff1ea20 PM-3249 Removed back button from block autofill uris to be aligned to other views (#2654) 2023-08-02 10:54:01 -03:00
1294 changed files with 8475 additions and 266516 deletions

29
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,29 @@
# Please sort lines alphabetically, this will ensure we don't accidentally add duplicates.
#
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# The following owners will be the default owners for everything in the repo.
# Unless a later match takes precedence
# @bitwarden/tech-leads
## Auth team files ##
## Platform team files ##
appIcons @bitwarden/team-platform-dev
build.cake @bitwarden/team-platform-dev
## Vault team files ##
src/watchOS @bitwarden/team-vault-dev
## Tools team files ##
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
## Crowdin Sync files ##
src/App/Resources @bitwarden/tech-leads
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/tech-leads
## Locales ##
src/App/Resources/AppResources.Designer.cs
src/App/Resources/AppResources.resx
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj

View File

@@ -525,7 +525,7 @@ jobs:
submodules: 'true'
- name: Login to Azure - CI Subscription
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -667,6 +667,22 @@ jobs:
$configuration = "AppStore";
$platform = "iPhone";
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
Write-Output "########################################"
Write-Output "##### Done"
Write-Output "########################################"
shell: pwsh
- name: Archive Build for Mobile Automation
run: |
$configuration = "Release";
$platform = "iPhoneSimulator";
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
@@ -689,6 +705,15 @@ jobs:
-exportOptionsPlist $EXPORT_OPTIONS_PATH
shell: bash
- name: Export .app for Automation CI
run: |
ARCHIVE_PATH="./src/iOS/bin/iPhoneSimulator/Release/BitwardeniOS.app"
EXPORT_PATH="./bitwarden-export"
zip -r -q BitwardeniOS.app.zip $ARCHIVE_PATH
mv BitwardeniOS.app.zip $EXPORT_PATH
shell: bash
- name: Copy all dSYMs files to upload
run: |
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
@@ -711,6 +736,13 @@ jobs:
./bitwarden-export/dSYMs/*.*
if-no-files-found: error
- name: Upload .app file for Automation CI
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
with:
name: BitwardeniOS.app.zip
path: ./bitwarden-export/BitwardeniOS.app.zip
if-no-files-found: error
- name: Install AppCenter CLI
if: |
(github.ref == 'refs/heads/master'
@@ -779,7 +811,7 @@ jobs:
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- name: Login to Azure - CI Subscription
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -845,7 +877,7 @@ jobs:
fi
- name: Login to Azure - CI Subscription
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
if: failure()
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

View File

@@ -18,13 +18,13 @@ jobs:
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- name: Login to Azure - CI Subscription
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/get-keyvault-secrets@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
keyvault: "bitwarden-ci"
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"

View File

@@ -12,6 +12,6 @@ jobs:
pull-requests: write
runs-on: ubuntu-20.04
steps:
- uses: actions/labeler@ba790c862c380240c6d5e7427be5ace9a05c754b # v4.0.3
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
with:
sync-labels: true

View File

@@ -38,11 +38,11 @@ jobs:
fi
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Check Release Version
id: version
uses: bitwarden/gh-actions/release-version-check@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/release-version-check@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
release-type: ${{ github.event.inputs.release_type }}
project-type: xamarin
@@ -87,7 +87,7 @@ jobs:
- name: Create release
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01 # v1.9.0
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
with:
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
./com.x8bit.bitwarden.apk/com.x8bit.bitwarden.apk,
@@ -126,7 +126,7 @@ jobs:
if: inputs.fdroid_publish
steps:
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
@@ -147,9 +147,9 @@ jobs:
name: com.x8bit.bitwarden-fdroid.apk
- name: Set up Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: '10.x'
node-version: '16.x'
- name: Set up F-Droid server
run: |

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: 'Run stale action'
uses: actions/stale@3cc123766321e9f15a6676375c154ccffb12a358 # v5.0.0
uses: actions/stale@f7176fd3007623b69d27091f9b9d4ab7995f0a06 # v5.2.1
with:
stale-issue-label: 'needs-reply'
stale-pr-label: 'needs-changes'

View File

@@ -14,7 +14,7 @@ jobs:
version_number: ${{ steps.version.outputs.new-version }}
steps:
- name: Checkout Branch
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Calculate bumped version
id: version
@@ -35,7 +35,5 @@ jobs:
name: Bump version to ${{ needs.setup.outputs.version_number }}
needs: setup
uses: ./.github/workflows/version-bump.yml
secrets:
AZURE_PROD_KV_CREDENTIALS: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
with:
version_number: ${{ needs.setup.outputs.version_number }}

View File

@@ -12,9 +12,6 @@ on:
version_number:
required: true
type: string
secrets:
AZURE_PROD_KV_CREDENTIALS:
required: true
jobs:
bump_version:
@@ -22,22 +19,22 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout Branch
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Login to Azure - CI Subscription
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/get-keyvault-secrets@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
keyvault: "bitwarden-ci"
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0
uses: crazy-max/ghaction-import-gpg@d6f3f49f3345e29369fe57596a3ca8f94c4d2ca7 # v5.4.0
with:
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
@@ -48,31 +45,31 @@ jobs:
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
- name: Bump Version - Android XML
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/Android/Properties/AndroidManifest.xml"
- name: Bump Version - iOS.Autofill
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Autofill/Info.plist"
- name: Bump Version - iOS.Extension
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Extension/Info.plist"
- name: Bump Version - iOS.ShareExtension
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.ShareExtension/Info.plist"
- name: Bump Version - iOS
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS/Info.plist"

View File

@@ -8,4 +8,4 @@ on:
jobs:
call-workflow:
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@34ecb67b2a357795dc893549df0795e7383ff50f
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67

View File

@@ -1,5 +0,0 @@
{
"sdk": {
"version": "7.0.306"
}
}

View File

@@ -77,21 +77,21 @@
<PackageReference Include="Portable.BouncyCastle">
<Version>1.9.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.5.1.1" />
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.16" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.19" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.10.0" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.3.1.1" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.6.1.3" />
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.21" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.10.1.2" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.4.0.2" />
<PackageReference Include="Xamarin.Essentials">
<Version>1.7.5</Version>
<Version>1.8.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Firebase.Messaging">
<Version>123.1.1.1</Version>
<Version>123.1.2.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.8.0" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.44.2.1" />
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.46.1.2" />
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
<Version>118.0.1.3</Version>
<Version>118.0.1.5</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -68,9 +68,9 @@ namespace Bit.Droid
ServiceContainer.Register<IDeleteAccountActionFlowExecutioner>("deleteAccountActionFlowExecutioner", deleteAccountActionFlowExecutioner);
var verificationActionsFlowHelper = new VerificationActionsFlowHelper(
ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService"),
ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService"),
ServiceContainer.Resolve<ICryptoService>("cryptoService"));
ServiceContainer.Resolve<ICryptoService>("cryptoService"),
ServiceContainer.Resolve<IUserVerificationService>());
ServiceContainer.Register<IVerificationActionsFlowHelper>("verificationActionsFlowHelper", verificationActionsFlowHelper);
var accountsManager = new AccountsManager(
@@ -156,10 +156,10 @@ namespace Bit.Droid
messagingService, broadcasterService);
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
platformUtilsService, new LazyResolve<IEventService>());
var biometricService = new BiometricService(stateService);
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
var biometricService = new BiometricService(stateService, cryptoService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2023.7.1" 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="2023.8.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Android.OS;
using Android.Security.Keystore;
using Bit.App.Services;
using Bit.Core.Abstractions;
using Bit.Core.Services;
using Java.Security;
@@ -9,10 +10,8 @@ using Javax.Crypto;
namespace Bit.Droid.Services
{
public class BiometricService : IBiometricService
public class BiometricService : BaseBiometricService
{
private readonly IStateService _stateService;
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
private const string KeyStoreName = "AndroidKeyStore";
@@ -24,14 +23,14 @@ namespace Bit.Droid.Services
private readonly KeyStore _keystore;
public BiometricService(IStateService stateService)
public BiometricService(IStateService stateService, ICryptoService cryptoService)
: base(stateService, cryptoService)
{
_stateService = stateService;
_keystore = KeyStore.GetInstance(KeyStoreName);
_keystore.Load(null);
}
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
public override async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
@@ -41,7 +40,7 @@ namespace Bit.Droid.Services
return true;
}
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
public override async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
{
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
{

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Bit.Core.Enums;
namespace Bit.App.Abstractions
{
@@ -6,10 +7,8 @@ namespace Bit.App.Abstractions
{
string[] ProtectedFields { get; }
Task<bool> ShowPasswordPromptAsync();
Task<bool> PromptAndCheckPasswordIfNeededAsync(CipherRepromptType repromptType = CipherRepromptType.Password);
Task<(string password, bool valid)> ShowPasswordPromptAndGetItAsync();
Task<bool> Enabled();
}
}

View File

@@ -1,28 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>Bit.App</RootNamespace>
<AssemblyName>BitwardenApp</AssemblyName>
<Configurations>Debug;Release;FDroid</Configurations>
<TargetFrameworks>net7.0-android;net7.0-ios</TargetFrameworks>
<UseMaui>True</UseMaui>
<OutputType>Library</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<SingleProject>true</SingleProject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.3" />
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.6" />
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2612" />
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
<PackageReference Include="MessagePack" Version="2.4.59" />
<PackageReference Include="SkiaSharp.Views.Maui.Core" Version="2.88.3" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.3" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.3" />
<PackageReference Include="CommunityToolkit.Maui" Version="5.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Pages\Accounts\EnvironmentPage.xaml.cs">
<DependentUpon>EnvironmentPage.xaml</DependentUpon>
@@ -125,6 +130,7 @@
<DependentUpon>LoginPasswordlessRequestPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Behaviors\" />
@@ -142,9 +148,11 @@
<Folder Include="Utilities\Automation\" />
<Folder Include="Utilities\Prompts\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Pages\Accounts\AccountsPopupPage.xaml" />
</ItemGroup>
<ItemGroup>
<Compile Update="Styles\Black.xaml.cs">
<DependentUpon>Black.xaml</DependentUpon>
@@ -168,6 +176,7 @@
<DependentUpon>Android.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\AppResources.cs.Designer.cs">
<DependentUpon>AppResources.cs.resx</DependentUpon>
@@ -305,6 +314,7 @@
<AutoGen>True</AutoGen>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\AppResources.cs.resx">
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
@@ -415,6 +425,7 @@
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Behaviors\" />
<None Remove="Xamarin.CommunityToolkit" />
@@ -434,4 +445,4 @@
<None Remove="Utilities\Automation\" />
<None Remove="Utilities\Prompts\" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.App">
<Application.Resources>

View File

@@ -15,9 +15,8 @@ using Bit.Core.Models.Data;
using Bit.Core.Models.Response;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Bit.App
@@ -94,7 +93,6 @@ namespace Bit.App
}
else if (message.Command == "resumed")
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
ResumedAsync().FireAndForget();
@@ -102,7 +100,6 @@ namespace Bit.App
}
else if (message.Command == "slept")
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
await SleptAsync();
@@ -124,7 +121,7 @@ namespace Bit.App
Options.OtpData = new OtpData((string)message.Data);
}
Device.InvokeOnMainThreadAsync(async () =>
await Device.InvokeOnMainThreadAsync(async () =>
{
if (Current.MainPage is TabsPage tabsPage)
{
@@ -296,7 +293,6 @@ namespace Bit.App
{
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
}
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android)
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
@@ -312,7 +308,6 @@ namespace Bit.App
{
System.Diagnostics.Debug.WriteLine("XF App: OnSleep");
_isResumed = false;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android)
{
var isLocked = await _vaultTimeoutService.IsLockedAsync();
@@ -336,7 +331,6 @@ namespace Bit.App
{
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
}
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android)
{
ResumedAsync().FireAndForget();
@@ -402,7 +396,6 @@ namespace Bit.App
private void ClearAutofillUri()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri))
{
Options.Uri = null;
@@ -411,7 +404,6 @@ namespace Bit.App
private bool SetTabsPageFromAutofill(bool isLocked)
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri) &&
!Options.FromAutofillFramework)
{
@@ -460,7 +452,7 @@ namespace Bit.App
private void SyncIfNeeded()
{
if (Microsoft.Maui.Networking.Connectivity.NetworkAccess == Microsoft.Maui.Networking.NetworkAccess.None)
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
return;
}

View File

@@ -1,5 +1,5 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Bit.App.Behaviors
{

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:effects="clr-namespace:Bit.App.Effects"
xmlns:view="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"

View File

@@ -4,8 +4,7 @@ using System.Windows.Input;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -62,8 +61,7 @@ namespace Bit.App.Controls
public ICommand LongPressAccountCommand { get; }
public int AccountListRowHeight => // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
Device.RuntimePlatform == Device.Android ? 74 : 70;
public int AccountListRowHeight => Device.RuntimePlatform == Device.Android ? 74 : 70;
public bool LongPressAccountEnabled { get; set; } = true;

View File

@@ -7,8 +7,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:Class="Bit.App.Controls.AccountViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"

View File

@@ -1,7 +1,6 @@
using System.Windows.Input;
using Bit.Core.Models.View;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<controls:ExtendedGrid xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.AuthenticatorViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -3,8 +3,7 @@ using Bit.App.Pages;
using Bit.App.Utilities;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -5,8 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using Bit.Core.Utilities;
using SkiaSharp;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -161,7 +160,7 @@ namespace Bit.App.Controls
{
if (str == null)
{
return Color.FromArgb("#33ffffff");
return Color.FromHex("#33ffffff");
}
var hash = 0;
for (var i = 0; i < str.Length; i++)
@@ -175,7 +174,7 @@ namespace Bit.App.Controls
var base16 = "00" + Convert.ToString(value, 16);
color += base16.Substring(base16.Length - 2);
}
return Color.FromArgb(color);
return Color.FromHex(color);
}
}
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<controls:ExtendedGrid xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.CipherViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -3,8 +3,7 @@ using System.Windows.Input;
using Bit.App.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,11 +1,9 @@
using System;
using System.Runtime.CompilerServices;
using SkiaSharp;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using SkiaSharp.Views.Maui.Controls;
using SkiaSharp.Views.Maui;
using SkiaSharp.Views.Forms;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -23,13 +21,13 @@ namespace Bit.App.Controls
nameof(StrokeWidth), typeof(float), typeof(CircularProgressbarView), 3f);
public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create(
nameof(ProgressColor), typeof(Color), typeof(CircularProgressbarView), Color.FromArgb("175DDC"));
nameof(ProgressColor), typeof(Color), typeof(CircularProgressbarView), Color.FromHex("175DDC"));
public static readonly BindableProperty EndingProgressColorProperty = BindableProperty.Create(
nameof(EndingProgressColor), typeof(Color), typeof(CircularProgressbarView), Color.FromArgb("dd4b39"));
nameof(EndingProgressColor), typeof(Color), typeof(CircularProgressbarView), Color.FromHex("dd4b39"));
public static readonly BindableProperty BackgroundProgressColorProperty = BindableProperty.Create(
nameof(BackgroundProgressColor), typeof(Color), typeof(CircularProgressbarView), Colors.White);
nameof(BackgroundProgressColor), typeof(Color), typeof(CircularProgressbarView), Color.White);
public double Progress
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<Grid
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:Class="Bit.App.Controls.DateTimePicker"

View File

@@ -1,12 +1,6 @@
using System.Runtime.CompilerServices;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using CommunityToolkit.Maui.Converters;
using CommunityToolkit.Maui.ImageSources;
using CommunityToolkit.Maui;
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Layouts;
using CommunityToolkit.Maui.Views;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,7 +1,6 @@
using System.Linq;
using CommunityToolkit.Maui.Converters;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,7 +1,5 @@
using Bit.App.Utilities;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -9,7 +7,6 @@ namespace Bit.App.Controls
{
public ExtendedSearchBar()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
if (ThemeManager.UsingLightTheme)

View File

@@ -1,12 +1,11 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedSlider : Slider
{
public static readonly BindableProperty ThumbBorderColorProperty = BindableProperty.Create(
nameof(ThumbBorderColor), typeof(Color), typeof(ExtendedSlider), Color.FromArgb("b5b5b5"));
nameof(ThumbBorderColor), typeof(Color), typeof(ExtendedSlider), Color.FromHex("b5b5b5"));
public Color ThumbBorderColor
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,16 +1,14 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedStepper : Stepper
{
public static readonly BindableProperty StepperBackgroundColorProperty = BindableProperty.Create(
nameof(StepperBackgroundColor), typeof(Color), typeof(ExtendedStepper), Colors.White);
nameof(StepperBackgroundColor), typeof(Color), typeof(ExtendedStepper), Color.White);
public static readonly BindableProperty StepperForegroundColorProperty = BindableProperty.Create(
nameof(StepperForegroundColor), typeof(Color), typeof(ExtendedStepper), Colors.Black);
nameof(StepperForegroundColor), typeof(Color), typeof(ExtendedStepper), Color.Black);
public Color StepperBackgroundColor
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,5 @@
using Bit.App.Effects;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -9,7 +8,6 @@ namespace Bit.App.Controls
public IconButton()
{
Padding = 0;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,6 +1,5 @@
using Bit.App.Effects;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -10,7 +9,6 @@ namespace Bit.App.Controls
public IconLabel()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.IconLabelButton"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -5,10 +5,8 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Bit.Core.Models.Domain;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Bit.App.Controls
{
@@ -24,13 +22,13 @@ namespace Bit.App.Controls
nameof(ButtonCommand), typeof(ICommand), typeof(IconLabelButton));
public static readonly BindableProperty IconLabelColorProperty = BindableProperty.Create(
nameof(IconLabelColor), typeof(Color), typeof(IconLabelButton), Colors.White);
nameof(IconLabelColor), typeof(Color), typeof(IconLabelButton), Color.White);
public static readonly BindableProperty IconLabelBackgroundColorProperty = BindableProperty.Create(
nameof(IconLabelBackgroundColor), typeof(Color), typeof(IconLabelButton), Colors.White);
nameof(IconLabelBackgroundColor), typeof(Color), typeof(IconLabelButton), Color.White);
public static readonly BindableProperty IconLabelBorderColorProperty = BindableProperty.Create(
nameof(IconLabelBorderColor), typeof(Color), typeof(IconLabelButton), Colors.White);
nameof(IconLabelBorderColor), typeof(Color), typeof(IconLabelButton), Color.White);
public IconLabelButton()
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -8,7 +7,6 @@ namespace Bit.App.Controls
public MiButton()
{
Padding = 0;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -7,7 +6,6 @@ namespace Bit.App.Controls
{
public MiLabel()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -7,7 +6,6 @@ namespace Bit.App.Controls
{
public MonoEntry()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -7,7 +6,6 @@ namespace Bit.App.Controls
{
public MonoLabel()
{
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
switch (Device.RuntimePlatform)
{
case Device.iOS:

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<StackLayout
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"

View File

@@ -1,7 +1,5 @@
using System;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -102,7 +100,7 @@ namespace Bit.App.Controls
case Controls.PasswordStrengthLevel.Strong:
return StrongColor;
default:
return Colors.Transparent;
return Color.Transparent;
}
}
}

View File

@@ -1,8 +1,7 @@
using System.Collections.Generic;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,8 +1,7 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<controls:ExtendedGrid xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.SendViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -2,8 +2,7 @@
using Bit.App.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Controls
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Effects
{

View File

@@ -1,6 +1,5 @@
using Bit.App.Lists.ItemViewModels.CustomFields;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.DataTemplateSelectors
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<StackLayout
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Lists.ItemLayouts.CustomFields.BooleanCustomFieldItemLayout"
xmlns:u="clr-namespace:Bit.App.Utilities"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemLayouts.CustomFields
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Lists.ItemLayouts.CustomFields.HiddenCustomFieldItemLayout"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemLayouts.CustomFields
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Lists.ItemLayouts.CustomFields.LinkedCustomFieldItemLayout"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemLayouts.CustomFields
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Lists.ItemLayouts.CustomFields.TextCustomFieldItemLayout"
xmlns:controls="clr-namespace:Bit.App.Controls"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemLayouts.CustomFields
{

View File

@@ -1,8 +1,7 @@
using System.Windows.Input;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemViewModels.CustomFields
{

View File

@@ -5,8 +5,7 @@ using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemViewModels.CustomFields
{

View File

@@ -1,7 +1,6 @@
using System.Windows.Input;
using Bit.Core.Models.View;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Lists.ItemViewModels.CustomFields
{

View File

@@ -6,6 +6,7 @@ using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using Xamarin.Essentials;
namespace Bit.App.Pages
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.Accounts.DeleteAccountPage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -1,6 +1,5 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages.Accounts
{

View File

@@ -27,7 +27,7 @@ namespace Bit.App.Pages
{
try
{
if (Microsoft.Maui.Networking.Connectivity.NetworkAccess == Microsoft.Maui.Networking.NetworkAccess.None)
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle, AppResources.Ok);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.EnvironmentPage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -3,8 +3,7 @@ using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -19,7 +18,6 @@ namespace Bit.App.Pages
InitializeComponent();
_vm = BindingContext as EnvironmentPageViewModel;
_vm.Page = this;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android)
{
ToolbarItems.RemoveAt(0);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.HintPage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -13,7 +12,6 @@ namespace Bit.App.Pages
_vm = BindingContext as HintPageViewModel;
_vm.Page = this;
_vm.Email = email;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android)
{
ToolbarItems.RemoveAt(0);

View File

@@ -44,7 +44,7 @@ namespace Bit.App.Pages
public async Task SubmitAsync()
{
if (Microsoft.Maui.Networking.Connectivity.NetworkAccess == Microsoft.Maui.Networking.NetworkAccess.None)
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.HomePage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -4,8 +4,7 @@ using Bit.App.Models;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{

View File

@@ -7,17 +7,17 @@ using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Response;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class HomeViewModel : BaseViewModel
{
private const string LOGGING_IN_ON_US = "bitwarden.com";
private const string LOGGING_IN_ON_EU = "bitwarden.eu";
private readonly IStateService _stateService;
private readonly IMessagingService _messagingService;
private readonly IPlatformUtilsService _platformUtilsService;
@@ -30,8 +30,6 @@ namespace Bit.App.Pages
private bool _rememberEmail;
private string _email;
private string _selectedEnvironmentName;
private bool _isEmailEnabled;
private bool _canLogin;
private bool _displayEuEnvironment;
public HomeViewModel()
@@ -52,9 +50,9 @@ namespace Bit.App.Pages
};
RememberEmailCommand = new Command(() => RememberEmail = !RememberEmail);
ContinueCommand = new AsyncCommand(ContinueToLoginStepAsync, allowsMultipleExecutions: false);
CreateAccountCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(StartRegisterAction),
CreateAccountCommand = new AsyncCommand(async () => await Device.InvokeOnMainThreadAsync(StartRegisterAction),
onException: _logger.Exception, allowsMultipleExecutions: false);
CloseCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(CloseAction),
CloseCommand = new AsyncCommand(async () => await Device.InvokeOnMainThreadAsync(CloseAction),
onException: _logger.Exception, allowsMultipleExecutions: false);
ShowEnvironmentPickerCommand = new AsyncCommand(ShowEnvironmentPickerAsync,
onException: _logger.Exception, allowsMultipleExecutions: false);
@@ -86,7 +84,7 @@ namespace Bit.App.Pages
set => SetProperty(ref _selectedEnvironmentName, value);
}
public string RegionText => $"{AppResources.Region}:";
public string RegionText => $"{AppResources.LoggingInOn}:";
public bool CanContinue => !string.IsNullOrEmpty(Email);
public FormattedString CreateAccountText
@@ -167,12 +165,12 @@ namespace Bit.App.Pages
{
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag);
var options = _displayEuEnvironment
? new string[] { AppResources.US, AppResources.EU, AppResources.SelfHosted }
: new string[] { AppResources.US, AppResources.SelfHosted };
? new string[] { LOGGING_IN_ON_US, LOGGING_IN_ON_EU, AppResources.SelfHosted }
: new string[] { LOGGING_IN_ON_US, AppResources.SelfHosted };
await Device.InvokeOnMainThreadAsync(async () =>
{
var result = await Page.DisplayActionSheet(AppResources.DataRegion, AppResources.Cancel, null, options);
var result = await Page.DisplayActionSheet(AppResources.LoggingInOn, AppResources.Cancel, null, options);
if (result is null || result == AppResources.Cancel)
{
@@ -185,7 +183,7 @@ namespace Bit.App.Pages
return;
}
await _environmentService.SetUrlsAsync(result == AppResources.EU ? EnvironmentUrlData.DefaultEU : EnvironmentUrlData.DefaultUS);
await _environmentService.SetUrlsAsync(result == LOGGING_IN_ON_EU ? EnvironmentUrlData.DefaultEU : EnvironmentUrlData.DefaultUS);
await _configService.GetAsync(true);
SelectedEnvironmentName = result;
});
@@ -198,17 +196,17 @@ namespace Bit.App.Pages
{
await _environmentService.SetUrlsAsync(EnvironmentUrlData.DefaultUS);
environmentsSaved = EnvironmentUrlData.DefaultUS;
SelectedEnvironmentName = AppResources.US;
SelectedEnvironmentName = LOGGING_IN_ON_US;
return;
}
if (environmentsSaved.Base == EnvironmentUrlData.DefaultUS.Base)
{
SelectedEnvironmentName = AppResources.US;
SelectedEnvironmentName = LOGGING_IN_ON_US;
}
else if (environmentsSaved.Base == EnvironmentUrlData.DefaultEU.Base)
{
SelectedEnvironmentName = AppResources.EU;
SelectedEnvironmentName = LOGGING_IN_ON_EU;
}
else
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.LockPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
@@ -46,7 +46,7 @@
<StackLayout StyleClass="box">
<Grid
StyleClass="box-row"
IsVisible="{Binding PinLock}"
IsVisible="{Binding PinEnabled}"
Padding="0, 10, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@@ -89,7 +89,7 @@
<Grid
x:Name="_passwordGrid"
StyleClass="box-row"
IsVisible="{Binding PinLock, Converter={StaticResource inverseBool}}"
IsVisible="{Binding PinEnabled, Converter={StaticResource inverseBool}}"
Padding="0, 10, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -6,8 +6,7 @@ using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -21,17 +20,17 @@ namespace Bit.App.Pages
private bool _promptedAfterResume;
private bool _appeared;
public LockPage(AppOptions appOptions = null, bool autoPromptBiometric = true)
public LockPage(AppOptions appOptions = null, bool autoPromptBiometric = true, bool checkPendingAuthRequests = true)
{
_appOptions = appOptions;
_autoPromptBiometric = autoPromptBiometric;
InitializeComponent();
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>();
_vm = BindingContext as LockPageViewModel;
_vm.CheckPendingAuthRequests = checkPendingAuthRequests;
_vm.Page = this;
_vm.UnlockedAction = () => Device.BeginInvokeOnMainThread(async () => await UnlockedAsync());
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_moreItem);
@@ -46,7 +45,7 @@ namespace Bit.App.Pages
{
get
{
if (_vm?.PinLock ?? false)
if (_vm?.PinEnabled ?? false)
{
return _pin;
}
@@ -56,7 +55,7 @@ namespace Bit.App.Pages
public async Task PromptBiometricAfterResumeAsync()
{
if (_vm.BiometricLock)
if (_vm.BiometricEnabled)
{
await Task.Delay(500);
if (!_promptedAfterResume)
@@ -93,13 +92,13 @@ namespace Bit.App.Pages
_vm.FocusSecretEntry += PerformFocusSecretEntry;
if (!_vm.BiometricLock)
if (!_vm.BiometricEnabled)
{
RequestFocus(SecretEntry);
}
else
{
if (_vm.UsingKeyConnector && !_vm.PinLock)
if (!_vm.HasMasterPassword && !_vm.PinEnabled)
{
_passwordGrid.IsVisible = false;
_unlockButton.IsVisible = false;

View File

@@ -11,9 +11,8 @@ using Bit.Core.Models.Domain;
using Bit.Core.Models.Request;
using Bit.Core.Services;
using Bit.Core.Utilities;
using CommunityToolkit.Maui.Converters;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.CommunityToolkit.Helpers;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -28,27 +27,27 @@ namespace Bit.App.Pages
private readonly IEnvironmentService _environmentService;
private readonly IStateService _stateService;
private readonly IBiometricService _biometricService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly IUserVerificationService _userVerificationService;
private readonly ILogger _logger;
private readonly IWatchDeviceService _watchDeviceService;
private readonly WeakEventManager<int?> _secretEntryFocusWeakEventManager = new WeakEventManager<int?>();
private readonly IPolicyService _policyService;
private readonly IPasswordGenerationService _passwordGenerationService;
private IDeviceTrustCryptoService _deviceTrustCryptoService;
private readonly ISyncService _syncService;
private string _email;
private string _masterPassword;
private string _pin;
private bool _showPassword;
private bool _pinLock;
private bool _biometricLock;
private PinLockType _pinStatus;
private bool _pinEnabled;
private bool _biometricEnabled;
private bool _biometricIntegrityValid = true;
private bool _biometricButtonVisible;
private bool _usingKeyConnector;
private bool _hasMasterPassword;
private string _biometricButtonText;
private string _loggedInAsText;
private string _lockedVerifyText;
private bool _isPinProtected;
private bool _isPinProtectedWithKey;
public LockPageViewModel()
{
@@ -61,11 +60,13 @@ namespace Bit.App.Pages
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
_logger = ServiceContainer.Resolve<ILogger>("logger");
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
_policyService = ServiceContainer.Resolve<IPolicyService>();
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>();
_deviceTrustCryptoService = ServiceContainer.Resolve<IDeviceTrustCryptoService>();
_syncService = ServiceContainer.Resolve<ISyncService>();
PageTitle = AppResources.VerifyMasterPassword;
TogglePasswordCommand = new Command(TogglePassword);
@@ -101,21 +102,21 @@ namespace Bit.App.Pages
});
}
public bool PinLock
public bool PinEnabled
{
get => _pinLock;
set => SetProperty(ref _pinLock, value);
get => _pinEnabled;
set => SetProperty(ref _pinEnabled, value);
}
public bool UsingKeyConnector
public bool HasMasterPassword
{
get => _usingKeyConnector;
get => _hasMasterPassword;
}
public bool BiometricLock
public bool BiometricEnabled
{
get => _biometricLock;
set => SetProperty(ref _biometricLock, value);
get => _biometricEnabled;
set => SetProperty(ref _biometricEnabled, value);
}
public bool BiometricIntegrityValid
@@ -148,6 +149,8 @@ namespace Bit.App.Pages
set => SetProperty(ref _lockedVerifyText, value);
}
public bool CheckPendingAuthRequests { get; set; }
public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
public Command SubmitCommand { get; }
@@ -163,18 +166,32 @@ namespace Bit.App.Pages
public async Task InitAsync()
{
(_isPinProtected, _isPinProtectedWithKey) = await _vaultTimeoutService.IsPinLockSetAsync();
PinLock = (_isPinProtected && await _stateService.GetPinProtectedKeyAsync() != null) ||
_isPinProtectedWithKey;
BiometricLock = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasKeyAsync();
// Users with key connector and without biometric or pin has no MP to unlock with
_usingKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
if (_usingKeyConnector && !(BiometricLock || PinLock))
var pendingRequest = await _stateService.GetPendingAdminAuthRequestAsync();
if (pendingRequest != null && CheckPendingAuthRequests)
{
await _vaultTimeoutService.LogOutAsync();
return;
}
_pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync();
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
?? await _stateService.GetPinProtectedKeyAsync();
PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
_pinStatus == PinLockType.Persistent;
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _biometricService.CanUseBiometricsUnlockAsync();
// Users without MP and without biometric or pin has no MP to unlock with
_hasMasterPassword = await _userVerificationService.HasMasterPasswordAsync();
if (await _stateService.IsAuthenticatedAsync()
&& !_hasMasterPassword
&& !BiometricEnabled
&& !PinEnabled)
{
await _vaultTimeoutService.LogOutAsync();
return;
}
_email = await _stateService.GetEmailAsync();
if (string.IsNullOrWhiteSpace(_email))
{
@@ -189,26 +206,18 @@ namespace Bit.App.Pages
}
var webVaultHostname = CoreHelpers.GetHostname(webVault);
LoggedInAsText = string.Format(AppResources.LoggedInAsOn, _email, webVaultHostname);
if (PinLock)
if (PinEnabled)
{
PageTitle = AppResources.VerifyPIN;
LockedVerifyText = AppResources.VaultLockedPIN;
}
else
{
if (_usingKeyConnector)
{
PageTitle = AppResources.UnlockVault;
LockedVerifyText = AppResources.VaultLockedIdentity;
}
else
{
PageTitle = AppResources.VerifyMasterPassword;
LockedVerifyText = AppResources.VaultLockedMasterPassword;
}
PageTitle = _hasMasterPassword ? AppResources.VerifyMasterPassword : AppResources.UnlockVault;
LockedVerifyText = _hasMasterPassword ? AppResources.VaultLockedMasterPassword : AppResources.VaultLockedIdentity;
}
if (BiometricLock)
if (BiometricEnabled)
{
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
if (!_biometricIntegrityValid)
@@ -218,7 +227,6 @@ namespace Bit.App.Pages
}
BiometricButtonVisible = true;
BiometricButtonText = AppResources.UseBiometricsToUnlock;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
var supportsFace = await _deviceActionService.SupportsFaceBiometricAsync();
@@ -231,14 +239,14 @@ namespace Bit.App.Pages
public async Task SubmitAsync()
{
if (PinLock && string.IsNullOrWhiteSpace(Pin))
if (PinEnabled && string.IsNullOrWhiteSpace(Pin))
{
await Page.DisplayAlert(AppResources.AnErrorHasOccurred,
string.Format(AppResources.ValidationFieldRequired, AppResources.PIN),
AppResources.Ok);
return;
}
if (!PinLock && string.IsNullOrWhiteSpace(MasterPassword))
if (!PinEnabled && string.IsNullOrWhiteSpace(MasterPassword))
{
await Page.DisplayAlert(AppResources.AnErrorHasOccurred,
string.Format(AppResources.ValidationFieldRequired, AppResources.MasterPassword),
@@ -249,34 +257,54 @@ namespace Bit.App.Pages
ShowPassword = false;
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
if (PinLock)
if (PinEnabled)
{
var failed = true;
try
{
if (_isPinProtected)
EncString userKeyPin = null;
EncString oldPinProtected = null;
if (_pinStatus == PinLockType.Persistent)
{
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email,
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync();
var oldEncryptedKey = await _stateService.GetPinProtectedAsync();
oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null;
}
else if (_pinStatus == PinLockType.Transient)
{
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync();
oldPinProtected = await _stateService.GetPinProtectedKeyAsync();
}
UserKey userKey;
if (oldPinProtected != null)
{
userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync(
_pinStatus == PinLockType.Transient,
Pin,
_email,
kdfConfig,
await _stateService.GetPinProtectedKeyAsync());
var encKey = await _cryptoService.GetEncKeyAsync(key);
var protectedPin = await _stateService.GetProtectedPinAsync();
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
failed = decPin != Pin;
if (!failed)
{
Pin = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
}
oldPinProtected
);
}
else
{
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email, kdfConfig);
failed = false;
userKey = await _cryptoService.DecryptUserKeyWithPinAsync(
Pin,
_email,
kdfConfig,
userKeyPin
);
}
var protectedPin = await _stateService.GetProtectedPinAsync();
var decryptedPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), userKey);
failed = decryptedPin != Pin;
if (!failed)
{
Pin = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
await SetUserKeyAndContinueAsync(userKey);
}
}
catch
@@ -297,19 +325,21 @@ namespace Bit.App.Pages
}
else
{
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig);
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig);
var storedKeyHash = await _cryptoService.GetMasterKeyHashAsync();
var passwordValid = false;
MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null;
if (storedKeyHash != null)
{
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key);
// Offline unlock possible
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, masterKey);
}
else
{
// Online unlock required
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
var keyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization);
var request = new PasswordVerificationRequest();
request.MasterPasswordHash = keyHash;
@@ -318,8 +348,8 @@ namespace Bit.App.Pages
var response = await _apiService.PostAccountVerifyPasswordAsync(request);
enforcedMasterPasswordOptions = response.MasterPasswordPolicy;
passwordValid = true;
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
await _cryptoService.SetKeyHashAsync(localKeyHash);
var localKeyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization);
await _cryptoService.SetMasterKeyHashAsync(localKeyHash);
}
catch (Exception e)
{
@@ -329,15 +359,6 @@ namespace Bit.App.Pages
}
if (passwordValid)
{
if (_isPinProtected)
{
var protectedPin = await _stateService.GetProtectedPinAsync();
var encKey = await _cryptoService.GetEncKeyAsync(key);
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, _email, kdfConfig);
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey));
}
if (await RequirePasswordChangeAsync(enforcedMasterPasswordOptions))
{
// Save the ForcePasswordResetReason to force a password reset after unlock
@@ -347,10 +368,13 @@ namespace Bit.App.Pages
MasterPassword = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
await _cryptoService.SetMasterKeyAsync(masterKey);
await SetUserKeyAndContinueAsync(userKey);
// Re-enable biometrics
if (BiometricLock & !BiometricIntegrityValid)
if (BiometricEnabled & !BiometricIntegrityValid)
{
await _biometricService.SetupBiometricAsync();
}
@@ -427,7 +451,7 @@ namespace Bit.App.Pages
public void TogglePassword()
{
ShowPassword = !ShowPassword;
var secret = PinLock ? Pin : MasterPassword;
var secret = PinEnabled ? Pin : MasterPassword;
_secretEntryFocusWeakEventManager.RaiseEvent(string.IsNullOrEmpty(secret) ? 0 : secret.Length, nameof(FocusSecretEntry));
}
@@ -435,32 +459,35 @@ namespace Bit.App.Pages
{
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
BiometricButtonVisible = BiometricIntegrityValid;
if (!BiometricLock || !BiometricIntegrityValid)
if (!BiometricEnabled || !BiometricIntegrityValid)
{
return;
}
var success = await _platformUtilsService.AuthenticateBiometricAsync(null,
PinLock ? AppResources.PIN : AppResources.MasterPassword,
PinEnabled ? AppResources.PIN : AppResources.MasterPassword,
() => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry)));
await _stateService.SetBiometricLockedAsync(!success);
if (success)
{
await DoContinueAsync();
var userKey = await _cryptoService.GetBiometricUnlockKeyAsync();
await SetUserKeyAndContinueAsync(userKey);
}
}
private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key)
private async Task SetUserKeyAndContinueAsync(UserKey key)
{
var hasKey = await _cryptoService.HasKeyAsync();
var hasKey = await _cryptoService.HasUserKeyAsync();
if (!hasKey)
{
await _cryptoService.SetKeyAsync(key);
await _cryptoService.SetUserKeyAsync(key);
}
await _deviceTrustCryptoService.TrustDeviceIfNeededAsync();
await DoContinueAsync();
}
private async Task DoContinueAsync()
{
_syncService.FullSyncAsync(false).FireAndForget();
await _stateService.SetBiometricLockedAsync(false);
_watchDeviceService.SyncDataToWatchAsync().FireAndForget();
_messagingService.Send("unlocked");

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.LoginApproveDevicePage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:LoginApproveDeviceViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:LoginApproveDeviceViewModel />
</ContentPage.BindingContext>
<StackLayout Padding="10, 10">
<StackLayout Padding="5, 10" Orientation="Horizontal">
<StackLayout HorizontalOptions="FillAndExpand">
<Label
StyleClass="text-md"
Text="{u:I18n RememberThisDevice}"/>
<Label
StyleClass="box-sub-label"
Text="{u:I18n TurnOffUsingPublicDevice}"/>
</StackLayout>
<Switch
Scale="0.8"
IsToggled="{Binding RememberThisDevice}"
VerticalOptions="Center"/>
</StackLayout>
<StackLayout Margin="0, 20, 0, 0">
<Button
x:Name="_continue"
Text="{u:I18n Continue}"
StyleClass="btn-primary"
Command="{Binding ContinueCommand}"
IsVisible="{Binding IsNewUser}"/>
<Button
x:Name="_approveWithMyOtherDevice"
Text="{u:I18n ApproveWithMyOtherDevice}"
StyleClass="btn-primary"
Command="{Binding ApproveWithMyOtherDeviceCommand}"
IsVisible="{Binding ApproveWithMyOtherDeviceEnabled}"/>
<Button
x:Name="_requestAdminApproval"
Text="{u:I18n RequestAdminApproval}"
StyleClass="box-button-row"
Command="{Binding RequestAdminApprovalCommand}"
IsVisible="{Binding RequestAdminApprovalEnabled}"/>
<Button
x:Name="_approveWithMasterPassword"
Text="{u:I18n ApproveWithMasterPassword}"
StyleClass="box-button-row"
Command="{Binding ApproveWithMasterPasswordCommand}"
IsVisible="{Binding ApproveWithMasterPasswordEnabled}"/>
<Label
Text="{Binding LoggingInAsText}"
StyleClass="text-sm"
Margin="0,40,0,0"
AutomationId="LoggingInAsLabel"
/>
<Label
Text="{u:I18n NotYou}"
StyleClass="text-md"
HorizontalOptions="Start"
TextColor="{DynamicResource HyperlinkColor}"
AutomationId="NotYouLabel">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LogoutCommand}" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
</pages:BaseContentPage>

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Utilities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class LoginApproveDevicePage : BaseContentPage
{
private readonly LoginApproveDeviceViewModel _vm;
private readonly AppOptions _appOptions;
public LoginApproveDevicePage(AppOptions appOptions = null)
{
InitializeComponent();
_vm = BindingContext as LoginApproveDeviceViewModel;
_vm.LogInWithMasterPasswordAction = () => StartLogInWithMasterPasswordAsync().FireAndForget();
_vm.LogInWithDeviceAction = () => StartLoginWithDeviceAsync().FireAndForget();
_vm.RequestAdminApprovalAction = () => RequestAdminApprovalAsync().FireAndForget();
_vm.ContinueToVaultAction = () => ContinueToVaultAsync().FireAndForget();
_vm.Page = this;
_appOptions = appOptions;
}
protected override void OnAppearing()
{
_vm.InitAsync();
}
private async Task ContinueToVaultAsync()
{
if (AppHelpers.SetAlternateMainPage(_appOptions))
{
return;
}
var previousPage = await AppHelpers.ClearPreviousPage();
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
}
private async Task StartLogInWithMasterPasswordAsync()
{
var page = new LockPage(_appOptions, checkPendingAuthRequests: false);
await Navigation.PushModalAsync(new NavigationPage(page));
}
private async Task StartLoginWithDeviceAsync()
{
var page = new LoginPasswordlessRequestPage(_vm.Email, AuthRequestType.AuthenticateAndUnlock, _appOptions, true);
await Navigation.PushModalAsync(new NavigationPage(page));
}
private async Task RequestAdminApprovalAsync()
{
var page = new LoginPasswordlessRequestPage(_vm.Email, AuthRequestType.AdminApproval, _appOptions, true);
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
}

View File

@@ -0,0 +1,150 @@
using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Windows.Input;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Utilities.AccountManagement;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
using Bit.Core.Models.Request;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class LoginApproveDeviceViewModel : BaseViewModel
{
private bool _rememberThisDevice;
private bool _approveWithMyOtherDeviceEnabled;
private bool _requestAdminApprovalEnabled;
private bool _approveWithMasterPasswordEnabled;
private string _email;
private readonly IStateService _stateService;
private readonly IApiService _apiService;
private IDeviceTrustCryptoService _deviceTrustCryptoService;
private readonly IAuthService _authService;
private readonly ISyncService _syncService;
private readonly IMessagingService _messagingService;
public ICommand ApproveWithMyOtherDeviceCommand { get; }
public ICommand RequestAdminApprovalCommand { get; }
public ICommand ApproveWithMasterPasswordCommand { get; }
public ICommand ContinueCommand { get; }
public ICommand LogoutCommand { get; }
public Action LogInWithMasterPasswordAction { get; set; }
public Action LogInWithDeviceAction { get; set; }
public Action RequestAdminApprovalAction { get; set; }
public Action ContinueToVaultAction { get; set; }
public LoginApproveDeviceViewModel()
{
_stateService = ServiceContainer.Resolve<IStateService>();
_apiService = ServiceContainer.Resolve<IApiService>();
_deviceTrustCryptoService = ServiceContainer.Resolve<IDeviceTrustCryptoService>();
_authService = ServiceContainer.Resolve<IAuthService>();
_syncService = ServiceContainer.Resolve<ISyncService>();
_messagingService = ServiceContainer.Resolve<IMessagingService>();
PageTitle = AppResources.LogInInitiated;
RememberThisDevice = true;
ApproveWithMyOtherDeviceCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithDeviceAction),
onException: ex => HandleException(ex),
allowsMultipleExecutions: false);
RequestAdminApprovalCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(RequestAdminApprovalAction),
onException: ex => HandleException(ex),
allowsMultipleExecutions: false);
ApproveWithMasterPasswordCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction),
onException: ex => HandleException(ex),
allowsMultipleExecutions: false);
ContinueCommand = new AsyncCommand(CreateNewSsoUserAsync,
onException: ex => HandleException(ex),
allowsMultipleExecutions: false);
LogoutCommand = new Command(() => _messagingService.Send(AccountsManagerMessageCommands.LOGOUT));
}
public string LoggingInAsText => string.Format(AppResources.LoggingInAsX, Email);
public bool RememberThisDevice
{
get => _rememberThisDevice;
set => SetProperty(ref _rememberThisDevice, value);
}
public bool ApproveWithMyOtherDeviceEnabled
{
get => _approveWithMyOtherDeviceEnabled;
set => SetProperty(ref _approveWithMyOtherDeviceEnabled, value);
}
public bool RequestAdminApprovalEnabled
{
get => _requestAdminApprovalEnabled;
set => SetProperty(ref _requestAdminApprovalEnabled, value,
additionalPropertyNames: new[] { nameof(IsNewUser) });
}
public bool ApproveWithMasterPasswordEnabled
{
get => _approveWithMasterPasswordEnabled;
set => SetProperty(ref _approveWithMasterPasswordEnabled, value,
additionalPropertyNames: new[] { nameof(IsNewUser) });
}
public bool IsNewUser => !RequestAdminApprovalEnabled && !ApproveWithMasterPasswordEnabled;
public string Email
{
get => _email;
set => SetProperty(ref _email, value, additionalPropertyNames:
new string[] {
nameof(LoggingInAsText)
});
}
public async Task InitAsync()
{
try
{
Email = await _stateService.GetActiveUserEmailAsync();
var decryptOptions = await _stateService.GetAccountDecryptionOptions();
RequestAdminApprovalEnabled = decryptOptions?.TrustedDeviceOption?.HasAdminApproval ?? false;
ApproveWithMasterPasswordEnabled = decryptOptions?.HasMasterPassword ?? false;
ApproveWithMyOtherDeviceEnabled = decryptOptions?.TrustedDeviceOption?.HasLoginApprovingDevice ?? false;
}
catch (Exception ex)
{
HandleException(ex);
}
}
public async Task CreateNewSsoUserAsync()
{
await _authService.CreateNewSsoUserAsync(await _stateService.GetRememberedOrgIdentifierAsync());
if (RememberThisDevice)
{
await _deviceTrustCryptoService.TrustDeviceAsync();
}
_syncService.FullSyncAsync(true).FireAndForget();
await Device.InvokeOnMainThreadAsync(ContinueToVaultAction);
}
private async Task SetDeviceTrustAndInvokeAsync(Action action)
{
await _deviceTrustCryptoService.SetShouldTrustDeviceAsync(RememberThisDevice);
await Device.InvokeOnMainThreadAsync(action);
}
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.LoginPage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -4,11 +4,11 @@ using Bit.App.Models;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -49,7 +49,6 @@ namespace Bit.App.Pages
_vm.Email = email;
MasterPasswordEntry = _masterPassword;
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_moreItem);
@@ -95,7 +94,6 @@ namespace Bit.App.Pages
RequestFocus(_masterPassword);
_inputFocused = true;
}
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
if (Device.RuntimePlatform == Device.Android && !_vm.CanRemoveAccount)
{
ToolbarItems.Add(_removeAccount);
@@ -138,7 +136,7 @@ namespace Bit.App.Pages
private async Task StartLoginWithDeviceAsync()
{
var page = new LoginPasswordlessRequestPage(_vm.Email, _appOptions);
var page = new LoginPasswordlessRequestPage(_vm.Email, AuthRequestType.AuthenticateAndUnlock, _appOptions);
await Navigation.PushModalAsync(new NavigationPage(page));
}

View File

@@ -16,8 +16,7 @@ using Bit.Core.Models.View;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -182,7 +181,7 @@ namespace Bit.App.Pages
public async Task LogInAsync(bool showLoading = true, bool checkForExistingAccount = false)
{
if (Microsoft.Maui.Networking.Connectivity.NetworkAccess == Microsoft.Maui.Networking.NetworkAccess.None)
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle, AppResources.Ok);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<pages:BaseContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.LoginPasswordlessPage"
xmlns:pages="clr-namespace:Bit.App.Pages"

View File

@@ -1,5 +1,4 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using Xamarin.Forms;
namespace Bit.App.Pages
{

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