Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sargon OS Boot fixes #212

Merged
merged 32 commits into from
Sep 30, 2024
Merged

Sargon OS Boot fixes #212

merged 32 commits into from
Sep 30, 2024

Conversation

micbakos-rdx
Copy link
Contributor

@micbakos-rdx micbakos-rdx commented Sep 10, 2024

Sargon Rust changes

  • A new function called derive_wallet in sargon os. This method can be used when restoring a profile from only a seed phrase and some accounts retrieved from GW.
  • A new error is introduced SecureStorageAccessError. This is used specifically in Android were the secure storage driver may fail to read from or write to secure storage key which is secured under biometrics. Currently mnemonics fall under this category. This error can be caused by several states of the system. Since I didn't want to make this Android specific, I introduced SecureStorageAccessErrorKind which will mostly be used for Android. Most of these kinds are system related and two are related to the user cancelling the authorisation. Although, a suggestion, would be for iOS to return SecureStorageAccessError(errorKind: .userCancelled), maybe when authorisation is cancelled since this seems to be the only possible error on iOS. Whatever the decision is, it will not make any difference.

Sargon Android changes

  • SargonOsManager: Holds a reference to sargon os. Boots sargon when initialised. Implemented as a singleton.
  • AndroidProfileStateChangeDriver: Holds the state of the current ProfileState no need for the host to do that.
  • Fixed encrypt method to first encrypt and then encode to base64 and not the other way around. This was a bug.
  • Fixed biometric requests when the system opens the pattern or pin screens and not the biometrics screen. These screens are usually full screen, causing the app to pause and stop. Before this was buggy because it did not account for that case.
  • Inreoduced KeySpec. reset. Please take a look at its doc to understand what it does and what problems it fixes especially on Android API <= 30

@micbakos-rdx micbakos-rdx added Rust 🦀 Changes in Rust Sargon Kotlin 🤖 Changes in Kotlin Sargon UniFFI 🦄 Changes in UniFFI exported APIs labels Sep 10, 2024
@micbakos-rdx micbakos-rdx self-assigned this Sep 10, 2024
Copy link

codecov bot commented Sep 10, 2024

Codecov Report

Attention: Patch coverage is 93.71429% with 11 lines in your changes missing coverage. Please review.

Project coverage is 96.6%. Comparing base (424a98f) to head (f903fe3).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...argon/src/system/sargon_os/profile_state_holder.rs 83.3% 2 Missing ⚠️
crates/sargon/src/system/sargon_os/sargon_os.rs 94.5% 2 Missing ⚠️
...ain/java/com/radixdlt/sargon/os/SargonOsManager.kt 87.5% 0 Missing and 2 partials ⚠️
...on/src/profile/v100/header/profile_id_uniffi_fn.rs 80.0% 1 Missing ⚠️
...ent/secure_storage_client/secure_storage_client.rs 90.0% 1 Missing ⚠️
...ecure_storage_driver/support/secure_storage_key.rs 95.4% 1 Missing ⚠️
...s/sargon/src/system/sargon_os/sargon_os_profile.rs 92.8% 1 Missing ⚠️
...com/radixdlt/sargon/os/storage/EncryptionHelper.kt 92.3% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##            main    #212     +/-   ##
=======================================
- Coverage   97.0%   96.6%   -0.4%     
=======================================
  Files        941     684    -257     
  Lines      14863   12611   -2252     
  Branches      66      70      +4     
=======================================
- Hits       14426   12193   -2233     
+ Misses       430     408     -22     
- Partials       7      10      +3     
Flag Coverage Δ
rust 96.5% <94.3%> (+<0.1%) ⬆️
swift ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
crates/sargon/src/core/error/common_error.rs 100.0% <ø> (ø)
...sargon/src/profile/logic/account/create_account.rs 87.8% <ø> (ø)
...sargon/src/profile/logic/account/query_accounts.rs 100.0% <100.0%> (ø)
...argon/src/profile/logic/gateway/current_gateway.rs 100.0% <100.0%> (ø)
...rates/sargon/src/profile/v100/header/profile_id.rs 100.0% <ø> (+11.1%) ⬆️
...c/profile/v100/networks/network/profile_network.rs 100.0% <100.0%> (ø)
...rgon/src/profile/v100/networks/profile_networks.rs 100.0% <100.0%> (ø)
crates/sargon/src/profile/v100/profile.rs 99.1% <100.0%> (+<0.1%) ⬆️
...rates/sargon/src/profile/v100/profile_uniffi_fn.rs 100.0% <100.0%> (ø)
crates/sargon/src/system/drivers/drivers.rs 100.0% <ø> (ø)
... and 14 more

... and 261 files with indirect coverage changes

@@ -151,6 +151,38 @@ impl SargonOS {
Ok(())
}

pub async fn derive_wallet(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why "derive"? This is not deriving anything..?

Why "wallet"?

Can we name it something "profile with accounts" ?

Copy link
Contributor Author

@micbakos-rdx micbakos-rdx Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to keep the wallet name consistent with the other "entry" methods like

  • new_wallet
  • import_wallet
  • delete_wallet

Maybe new_wallet_with_derived_bdfs ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I had forgot we had functions called import_wallet.

Right I think my idea is that we loosely define "wallet = (Profile, (BDFS) Mnemonic).

Maybe new_profile_with_restored_accounts?

Btw! Are we asserting that the SecureStorage does in fact contain the device factor source?

If not, we should right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that is impossible. I wanted to do the same, but in order to do that I need another biometric prompt. The same should apply to import wallet.

Why is that?

  • If we need to ask for biometrics only once, we need to pass the mnemonic to ffi. I am not sure if we want to do that. If we ever did that, then sargon os could check the validity and store it. Thus having total control over it.
  • Otherwise we let the host store the mnemonic, as it used to, but now this method will need to read the mnemonic again, asking for biometrics for a second time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I think we should do any of those too.

We are already passing the mnemonic across FFI in the form of entropy. So I think best pass a PrivateHierarchicalDeterministicFactorSource from Host, that way we know user has intact "wallet"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or well, we know if we also check that the accounts are controlled by that DeviceFactorSource

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favour of passing the mnemonic over FFI, unless there are some specific concerns. Can't see any in particular.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are already passing the mnemonic across FFI in the form of entropy.

You are right @CyonAlexRDX I forgot about that. Will make the changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyonAlexRDX I have implemented the logic to

  1. pass thePrivateHierarchicalDeterministicFactorSource into the function
  2. Validate the accounts public keys
  3. Ensure that secure storage succeeds saving the mnemonic
    84c7af6

Please let me know if the execution is valid


let mainnet_network = match maybe_accounts {
None => ProfileNetwork::new_empty_on(NetworkID::Mainnet),
Some(accounts) => ProfileNetwork::new_with_accounts(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not assert that all accounts are controlled by the BDFS? Maybe not, if accounts passed is a mix of Ledger accounts has software.

Hmmm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to ask about that. We are currently only checking if the accounts are not on mainnet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue is that this probably seems like a very generic purpose API, while it should be used only when recovering with a Seed Phrase which by definition can be only BDFS currently. It is meant to replace this Host logic.

crates/sargon/src/profile/v100/profile.rs Show resolved Hide resolved
biometricsResultsChannel.send(result)
}
biometricRequestsChannel
.receiveAsFlow()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why you define the biometricRequestsChannel and biometricsResultsChannel as Channel and then receive the as Flow?
Why not to define them as Flows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to implement a logic of two cold flows. Sargon os can ask for biometrics at any time. So I wanted to solve 2 problems

  1. No activity is yet STARTED in order to handle biometrics. Remember in order to ask for biometrics, we need a reference to a FragmentActivity. In order for the biometrics dialog to show up, we need the activity to be at least started. So I wanted to have a suspending function waiting for an activity to either register and start or return from background. This is why biometricRequestsChannel exists. It waits for the request to be handled by one activity.
  2. The biometricsResultsChannel is waiting for the USER to respond. The values of the channel will be emitted by another function.

.map(|c| c.transaction_signing.public_key)
.map_err(|_| CommonError::EntitiesNotDerivedByFactorSource)
})
.try_collect()?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, I did not know about try_collect, we should embrace it!

I think I'd prefer let ..: Vec<T> = ....try_collect()? be rewritten as let .. = ....try_collect::<Vec<_>>()?

where try_collect::<Vec<_>>() is verbatim, the _ usage tells rust to fill it in (which it can do based on .map(|c| c.transaction_signing.public_key).

That is the code style I've mostly used elsewhere in Sargon - the advantage is that for long chains of functional calls one can control the return type at the end of the chain, which one typically does by adding yet another map that makes it a bit easier to maintain IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like doing this too, but this does not compile. I cannot find a sane way to make this compile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example of this working is this:

.try_collect::<_, Vec<_>, _>()?;

Does this look more readable?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah it is generic over many things. Right, yeah I prefer that actually


if !hd_factor_source
.mnemonic_with_passphrase
.validate_public_keys(hd_keys)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! so now we assert that all factor instances are indeed controlled by the specified mnemonic

Copy link
Contributor

@CyonAlexRDX CyonAlexRDX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM,I like the change to PrivateHDFS.

Left a minor remark about code style

),
AccountLockerClaimableResource.Fungible(
resourceAddress = ResourceAddress.init("resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd"),
amount = 1500.toDecimal192()
),
AccountLockerClaimableResource.NonFungible(
resourceAddress = ResourceAddress.init("resource_rdx1n2ekdd2m0jsxjt9wasmu3p49twy2yfalpaa6wf08md46sk8dfmldnd"),
ids = listOf(NonFungibleLocalId.stringId("foobar"))
numberOfItems = 1.toULong()
Copy link
Contributor

@sergiupuhalschi-rdx sergiupuhalschi-rdx Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about this, it escaped me while working on the account locker. It's good that we have the kotlin-test workflow fixed now and it shouldn't happen anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sergiupuhalschi-rdx wanted to ask you about this

Copy link
Contributor

@sergiupuhalschi-rdx sergiupuhalschi-rdx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! It's impressive how you found what was the issue with the Keystore secret key generation and fixed it 🏅

Copy link
Contributor

@GhenadieVP GhenadieVP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Amazing work 🔥!

Copy link
Contributor

@giannis-rdx giannis-rdx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦅

@micbakos-rdx
Copy link
Contributor Author

@GhenadieVP Latest commit 8505a88 addresses deleting old ephemeral profile and associated mnemonic when booting again.

* wip

* fix

* fix

* wip

* wip

* wip
@GhenadieVP GhenadieVP merged commit 817779d into main Sep 30, 2024
11 of 12 checks passed
@GhenadieVP GhenadieVP deleted the fixes branch September 30, 2024 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Kotlin 🤖 Changes in Kotlin Sargon Rust 🦀 Changes in Rust Sargon UniFFI 🦄 Changes in UniFFI exported APIs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants