-
Notifications
You must be signed in to change notification settings - Fork 1
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
Entities linked to Factor Source #302
Conversation
crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs
Outdated
Show resolved
Hide resolved
crates/sargon/src/system/drivers/unsafe_storage_driver/support/unsafe_storage_key.rs
Outdated
Show resolved
Hide resolved
...on_os/entities_controlled_by_factor_source/sargon_os_entities_controlled_by_factor_source.rs
Outdated
Show resolved
Hide resolved
...rgon_os/entities_controlled_by_factor_source/support/entities_controlled_by_factor_source.rs
Outdated
Show resolved
Hide resolved
pub factor_source: FactorSource, | ||
|
||
/// Whether the mnemonic of the factor source is present in keychain. | ||
pub is_mnemonic_present_in_keychain: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
many of the fields here are DeviceFactorSource
specific. If the WHOLE query is that, we should name it EntitiesUsingDeviceFactorSource
? Or we should generalize it, probably with enums with associated data, so that is_mnemonic_present_in_keychain: bool
only exists when the factor source is of kind device
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, on iOS it is currently related to DeviceFactorSource
, but the idea of moving it to Sargon is to generalize it so that we can later check which entities are related to, for example, an Arculus Card (ref).
You are right that is_mnemonic_present_in_keychain
& is_mnemonic_marked_as_backed_up
only applies to DeviceFactorSource
, so probabky the enum with associated data is the way to go here.
@@ -19,6 +19,11 @@ pub trait SecureStorageDriver: Send + Sync + std::fmt::Debug { | |||
) -> Result<()>; | |||
|
|||
async fn delete_data_for_key(&self, key: SecureStorageKey) -> Result<()>; | |||
|
|||
async fn contains_data_for_key( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a batch query would make sense? contains_data_for_keys
? Check with @micbakos-rdx but on iOS we can load the entire contents of Keychain in one go without prompting for biometrics and check the list of key-values. So we can actually impl check_existence_of_mnemonics_for_device_factor_sources(ids: IndexSet<FactorSourceIDFromHash>) -> IndexSet<FactorSourceIDFromHash>
where if return value == ids.len() then all was found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the current implementation we will only make the request for a given Factor Source, but I can extend it to take a set of keys instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@micbakos-rdx mentioned that we can check for key existence without any biometrics.
...fi/src/system/sargon_os/entities_controlled_by_factor_source/support/accessibility/device.rs
Outdated
Show resolved
Hide resolved
crates/sargon/src/profile/mfa/secured_entity_control/secured_entity_control.rs
Outdated
Show resolved
Hide resolved
...tem/sargon_os/entities_linked_to_factor_source/sargon_os_entities_linked_to_factor_source.rs
Outdated
Show resolved
Hide resolved
factor_source: FactorSource, | ||
profile_to_check: ProfileToCheck, | ||
) -> Result<EntitiesLinkedToFactorSource> { | ||
let accessibility = self.accessibility(factor_source.clone()).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same review comment as in some PRs ago... :) this should not be on SargonOS
:) SargonOS
ought to only "forward" calls to Profile
(via ProfileHolder
.). since you here support ProfileToCheck::Specific
so maybe something like?:
impl SargonOS {
/// Returns the entities linked to a given `FactorSource`, either on the current `Profile` or a specific one.
pub async fn entities_linked_to_factor_source(
&self,
factor_source: FactorSource,
profile_to_check: ProfileToCheck,
) -> Result<EntitiesLinkedToFactorSource> {
let existence = self.claimed_and_actual_existence_of_factor_source(factor_source.clone()).await?;
match profile_to_check {
ProfileToCheck::Specific(profile) => profile.entities_linked_to_factor_source(factor_source, existence),
ProfileToCheck::Current => self.profile().entities_linked_to_factor_source(factor_source, existence),
}
}
}
|
||
#[derive(Debug)] | ||
pub struct MockSecureStorage { | ||
mock_contains_data_for_key: IndexMap<SecureStorageKey, bool>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm is this needed? We have:
pub struct EphemeralSecureStorage {
pub storage: RwLock<HashMap<SecureStorageKey, BagOfBytes>>,
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deleted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, very nice improvement.
let hidden_accounts = self | ||
.accounts | ||
.hidden() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I guess we should have similar function to accounts_non_hidden
on ProfileNetwork - accounts_hidden
a.security_state | ||
.is_linked_to_factor_source(factor_source.clone()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be in a common function, then passed to filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that what was my original idea: to define the filter
predicate once and then use it on every collection:
let filter = |e: &dyn HasSecurityState| {
e.security_state().is_linked_to_factor_source(factor_source.clone())
};
I wasn't able to make it work with a closure, but using a function that sends the factor_source
each time works, thanks!
29fbf1d
to
b6b39df
Compare
pub struct DeviceFactorSourceIntegrity { | ||
/// The factor source that is linked to the entities. | ||
pub factor_source: DeviceFactorSource, | ||
|
||
/// Whether the mnemonic of the factor source is present in keychain. | ||
pub is_mnemonic_present_in_keychain: bool, | ||
|
||
/// Whether the mnemonic of the factor source is marked as backed up. | ||
pub is_mnemonic_marked_as_backed_up: bool, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit lost here.
first of all is this input for sargon or output that hosts will use?
it's the output
what is the difference between is_mnemonic_present_in_keychain
and is_mnemonic_marked_as_backed_up
?
If is_mnemonic_marked_as_backed_up
is true then doesn't that mean the is_mnemonic_present_in_keychain
is also true?
What android has to do with the is_mnemonic_present_in_keychain
? Or is it a boolean that just used by iOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_mnemonic_marked_as_backed_up
is set to true if the user says "I have written this down".
is_mnemonic_present_in_keychain
is app/sargon checking that SecureStorage at least contains a key-value tuple where the key matches the FactorSourceID of some DeviceFactorSource.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the name has to be related to iOS though?
shouldn't be is_mnemonic_present
or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have similar thing in Android mnemonicExist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should probably be _in_secure_storage
. Not "keychain", good catch @giannis-rdx
And @matiasbzurovski we can have a computed property in Swift Sargon called ...inKeychain, to make it clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated it to replace every reference to _in_keychain
to _in_secure_stroage
.
|
profile_to_check: ProfileToCheck, | ||
) -> Result<EntitiesLinkedToFactorSource> { | ||
let integrity = self.integrity(factor_source.clone()).await?; | ||
match profile_to_check { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer expressions:
let profile_network = match profile_to_check {
ProfileToCheck::Current => self.profile()?.current_network()?,
ProfileToCheck::Specific(specific_profile) => specific_profile.networks
.get_id(NetworkID::Mainnet)
.ok_or(CommonError::Unknown)?
};
profile_network
.entities_linked_to_factor_source(factor_source, integrity),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't compile because of multiple errors about borrowed values not living long enough, and in order to fix it I need to add more variables which I think complicates the code more.
Changelog
Exposes a function on
SargonOS
to allow checking entities related to aFactorSource
.This allow us to determine, for example, which entities were created under a given
DeviceFactorSource
or aLedgerFactorSource
. Also, it will work for Securified Entities to see if the given factor source is in any way involved in the matrix that securifies it.Output
Asides from returning the corresponding entities and their visibility, the output includes also an
integrity
field which will become helpful for host apps to determine the integrity of the mentionedFactorSource
.In the case of
DeviceFactorSource
, its integrity will detail whether its mnemonic is present in keychain, and if it has been backed up by the user.Storage clients
To check if the mnemonic is present in Keychain, I make use of the
SecureStorageClient
using the previously supported keyDeviceFactorSourceMnemonic
.However, in order to check if the mnemonic is backed up I need to make usage of the
UnsafeStorageClient
. In iOS, when booting SargonOS, we implement theUnsafeStorageDriver
directly from nativeUserDefaults
. In other words, every time Sargon needs to read/write some values on unsafe storage, it will directly use theUserDefaults
.Then, the only pending thing I needed to add was a way to map the keys previously defined by iOS Wallet, into the ones expected by Sargon. Right now we only have one
UnsafeStorageKey
which isFactorSourceUserHasWrittenDown
, which I map on iOS into its pre-Sargon-defined-key named"mnemonicsUserClaimsToHaveBackedUp"
.Important
This approach only works for both platforms if someone from Android team can validate that:
FactorSourceIDFromHash
of device factor sources whose mnemonic has been written down.If this is not the case, then we may not be able to have the straightforward solution of interacting directly with
UserDefaults
on iOS, and instead we would need to treat unsafe storage similarly to secure storage: just send the key to the host and let it read/write the value however it decides to.