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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
54e834c
Replace kotlin base64 with android base 64 and mock it in unit tests
micbakos-rdx Sep 3, 2024
1a26596
Make profileStateChanges a shared flow
micbakos-rdx Sep 3, 2024
c74384f
Remove planting of debug tree
micbakos-rdx Sep 3, 2024
4b8a375
Print errors with timber in example app too
micbakos-rdx Sep 4, 2024
0f5eccc
Fix example profile states
micbakos-rdx Sep 4, 2024
a54e521
Remove checks before asking for biometrics
micbakos-rdx Sep 4, 2024
64fe07c
Suspend request for biometrics until activity is at least started
micbakos-rdx Sep 5, 2024
f1c6ebe
Report secure storage access error
micbakos-rdx Sep 5, 2024
e190154
Make read and write methods public
micbakos-rdx Sep 5, 2024
6c07461
Make encrypt and decrypt methods public
micbakos-rdx Sep 5, 2024
0879e59
Implement function to remove a list of keyspecs
micbakos-rdx Sep 5, 2024
48c5dca
Make generateSecretKey public for now
micbakos-rdx Sep 9, 2024
7968a8f
Add error kind for biometrics failure
micbakos-rdx Sep 9, 2024
b16c975
Export method to derive profile based on bdfs and some accounts
micbakos-rdx Sep 9, 2024
68e6c7c
Emit derived profile in profile state change
micbakos-rdx Sep 9, 2024
b4e5352
Store profile state into android state change driver
micbakos-rdx Sep 9, 2024
fba06db
Make reset keyspec method to regenerate a new key when fail
micbakos-rdx Sep 10, 2024
4089ab3
Included SargonOsManager into sargon android
micbakos-rdx Sep 10, 2024
58c5d22
Make drivers explicit
micbakos-rdx Sep 10, 2024
2cfe61d
Replace with new_wallet_with_derived_bdfs
micbakos-rdx Sep 11, 2024
0c0057b
Change doc
micbakos-rdx Sep 11, 2024
f7720c3
Allow set profile to set one profile when none exists
micbakos-rdx Sep 11, 2024
9b554cc
Change iOS test
micbakos-rdx Sep 11, 2024
4e07965
Fix android test
micbakos-rdx Sep 11, 2024
ef45de0
Fix set_profile to notify ProfileStateChange client about the latest …
micbakos-rdx Sep 12, 2024
43eda31
Fix content hint to report correct total amount of personas
micbakos-rdx Sep 13, 2024
bd365aa
Create initial profile with no networks
micbakos-rdx Sep 13, 2024
ca40ae4
Delete ephemeral profile when booting
micbakos-rdx Sep 16, 2024
7d6a571
Return error when network does not yet exist
micbakos-rdx Sep 17, 2024
3d8d347
Profile snapshot id payload (#214)
GhenadieVP Sep 19, 2024
ad4feee
Bump cargo version
micbakos-rdx Sep 30, 2024
f903fe3
Profile safe concurrent access (#225)
GhenadieVP Sep 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apple/Sources/Sargon/SargonOS/SargonOS+Static+Shared.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extension SargonOS {
if !isEmulatingFreshInstall, _shared != nil {
throw SargonOSAlreadyBooted()
}
let shared = try await SargonOS.boot(bios: bios)
let shared = await SargonOS.boot(bios: bios)
Self._shared = shared
return shared
}
Expand Down
6 changes: 3 additions & 3 deletions apple/Sources/Sargon/SargonOS/TestOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ extension TestOS: SargonOSProtocol {}

// MARK: Private
extension TestOS {
private func nextAccountName() throws -> DisplayName {
let index = try accountsForDisplayOnCurrentNetwork.count
return DisplayName(value: "Unnamed \(index)")
private func nextAccountName() -> DisplayName {
let index = (try? accountsForDisplayOnCurrentNetwork.count) ?? 0
return DisplayName(value: "Unnamed \(index)")
}
}

Expand Down
8 changes: 4 additions & 4 deletions apple/Sources/Sargon/Util/EventPublisher.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import AsyncExtensions

public final actor EventPublisher<Element: Sendable> {
public typealias Subject = AsyncPassthroughSubject<Element>
public typealias Stream = AsyncThrowingPassthroughSubject<Element, any Error>
public typealias Subject = AsyncReplaySubject<Element>
public typealias Stream = AsyncThrowingReplaySubject<Element, any Error>

let stream = Stream()
let subject = Subject()
let stream = Stream(bufferSize: 1)
let subject = Subject(bufferSize: 1)

public func eventStream() -> AsyncMulticastSequence<Subject, Stream> {
subject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ final class DriversTests: TestCase {
}

func test_bios_insecure() async throws {
let _ = try await SargonOS.boot(bios: BIOS.insecure())
let _ = await SargonOS.boot(bios: BIOS.insecure())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class EventBusDriverTests: DriverTest<EventBus> {
func test() async throws {
let sut = SUT()

let expectedEvents = Array<EventKind>([.booted, .profileSaved, .factorSourceUpdated, .accountAdded, .profileSaved])
let expectedEvents = Array<EventKind>([.booted, .profileSaved, .profileSaved, .factorSourceUpdated, .accountAdded, .profileSaved])
let task = Task {
var notifications = Set<EventNotification>()
for await notification in await sut.notifications().prefix(expectedEvents.count) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class InsecureStorageDriverTests: DriverTest<Insecure︕!TestOnly︕!Ephemer
func test() async throws {
let sut = SUT.init(keychainService: "test")
let data = Data.sampleAced
let key = SUT.Key.profileSnapshot
let key = SUT.Key.profileSnapshot(profileId: newProfileIdSample())
try await sut.saveData(key: key, data: data)
let loaded = try await sut.loadData(key: key)
XCTAssertEqual(loaded, data)
Expand Down
2 changes: 1 addition & 1 deletion apple/Tests/IntegrationTests/SargonOS/SargonOSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class SargonOSTests: OSTest {
}

func test() async throws {
let _ = try await SUT.boot(
let _ = await SUT.boot(
bios: .init(
drivers: .test()
)
Expand Down
2 changes: 1 addition & 1 deletion crates/sargon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sargon"
version = "1.1.23"
version = "1.1.24"
edition = "2021"
build = "build.rs"

Expand Down
20 changes: 16 additions & 4 deletions crates/sargon/src/core/error/common_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,22 +230,26 @@ pub enum CommonError {
#[error("Invalid DisplayName cannot be empty.")]
InvalidDisplayNameEmpty = 10062,

#[error("FREE")]
FREE = 10063,
#[error("Failed to access secure storage due to \"{error_message}\" for key {} ", key.identifier())]
SecureStorageAccessError {
key: SecureStorageKey,
error_kind: SecureStorageAccessErrorKind,
error_message: String,
} = 10063,

#[error("Invalid ISO8601 Time string: {bad_value}")]
InvalidISO8601String { bad_value: String } = 10064,

#[error("Unknown account.")]
UnknownAccount = 10065,

#[error("Failed to read from secure storage (Keychain).")]
#[error("Failed to read from secure storage.")]
SecureStorageReadError = 10066,

#[error("Failed to load DeviceFactorSource from secure storage")]
UnableToLoadDeviceFactorSourceFromSecureStorage = 10067,

#[error("Failed to write to secure storage (Keychain).")]
#[error("Failed to write to secure storage.")]
SecureStorageWriteError = 10068,

#[error("Failed Serialize value to JSON.")]
Expand Down Expand Up @@ -644,6 +648,14 @@ pub enum CommonError {
global_address_as_hex: String,
network_id: NetworkID,
} = 10181,

#[error(
"The provided entities do not derive from the given factor source"
)]
EntitiesNotDerivedByFactorSource = 10182,

#[error("The network {network_id} does not exist in profile")]
NoNetworkInProfile { network_id: NetworkID } = 10183,
}

#[uniffi::export]
Expand Down
1 change: 1 addition & 0 deletions crates/sargon/src/profile/logic/account/create_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ mod tests {
.factor_source,
HostId::sample(),
HostInfo::sample(),
None::<Accounts>,
);

let (_, accounts) = sut
Expand Down
22 changes: 12 additions & 10 deletions crates/sargon/src/profile/logic/account/query_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ use crate::prelude::*;
impl Profile {
/// Returns the non-hidden accounts on the current network, empty if no accounts
/// on the network
pub fn accounts_on_current_network(&self) -> Accounts {
self.current_network().accounts.non_hidden()
pub fn accounts_on_current_network(&self) -> Result<Accounts> {
self.current_network().map(|n| n.accounts.non_hidden())
}

/// Returns the non-hidden accounts on the current network as `AccountForDisplay`
pub fn accounts_for_display_on_current_network(
&self,
) -> AccountsForDisplay {
self.accounts_on_current_network()
.iter()
.map(AccountForDisplay::from)
.collect::<AccountsForDisplay>()
) -> Result<AccountsForDisplay> {
self.accounts_on_current_network().map(|accounts| {
accounts
.iter()
.map(AccountForDisplay::from)
.collect::<AccountsForDisplay>()
})
}

/// Looks up the account by account address, returns Err if the account is
Expand Down Expand Up @@ -44,7 +46,7 @@ mod tests {
fn test_accounts_on_current_network() {
let sut = SUT::sample();
assert_eq!(
sut.accounts_on_current_network(),
sut.accounts_on_current_network().unwrap(),
Accounts::sample_mainnet()
);
}
Expand All @@ -53,7 +55,7 @@ mod tests {
fn test_accounts_on_current_network_stokenet() {
let sut = SUT::sample_other();
assert_eq!(
sut.accounts_on_current_network(),
sut.accounts_on_current_network().unwrap(),
Accounts::just(Account::sample_stokenet_nadia()) // olivia is hidden
);
}
Expand All @@ -62,7 +64,7 @@ mod tests {
fn test_accounts_for_display_on_current_network() {
let sut = SUT::sample();
assert_eq!(
sut.accounts_for_display_on_current_network(),
sut.accounts_for_display_on_current_network().unwrap(),
Accounts::sample_mainnet()
.iter()
.map(AccountForDisplay::from)
Expand Down
11 changes: 7 additions & 4 deletions crates/sargon/src/profile/logic/gateway/current_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ impl Profile {
/// The ProfileNetwork of the currently used Network dependent on the `current`
/// Gateway set in AppPreferences. This affects which Accounts users see in
/// "Home screen" in wallet apps.
pub fn current_network(&self) -> &ProfileNetwork {
self.networks
.get_id(self.current_network_id())
.expect("Should have current network")
pub fn current_network(&self) -> Result<&ProfileNetwork> {
let current_network_id = self.current_network_id();
self.networks.get_id(current_network_id).ok_or(
CommonError::NoNetworkInProfile {
network_id: current_network_id,
},
)
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/sargon/src/profile/v100/header/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod device_info_uniffi_fn;
mod header;
mod header_uniffi_fn;
mod profile_id;
mod profile_id_uniffi_fn;

pub use content_hint::*;
pub use device_id::*;
Expand All @@ -17,3 +18,4 @@ pub use device_info_uniffi_fn::*;
pub use header::*;
pub use header_uniffi_fn::*;
pub use profile_id::*;
pub use profile_id_uniffi_fn::*;
1 change: 0 additions & 1 deletion crates/sargon/src/profile/v100/header/profile_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use crate::prelude::*;
)]
#[serde(transparent)]
pub struct ProfileID(pub(crate) Uuid);
uniffi::custom_newtype!(ProfileID, Uuid);

impl FromStr for ProfileID {
type Err = CommonError;
Expand Down
37 changes: 37 additions & 0 deletions crates/sargon/src/profile/v100/header/profile_id_uniffi_fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::prelude::*;

uniffi::custom_newtype!(ProfileID, Uuid);

Check warning on line 3 in crates/sargon/src/profile/v100/header/profile_id_uniffi_fn.rs

View check run for this annotation

Codecov / codecov/patch

crates/sargon/src/profile/v100/header/profile_id_uniffi_fn.rs#L3

Added line #L3 was not covered by tests

#[uniffi::export]
pub fn new_profile_id_sample() -> ProfileID {
ProfileID::sample()
}

#[uniffi::export]
pub fn new_profile_id_sample_other() -> ProfileID {
ProfileID::sample_other()
}

#[cfg(test)]
mod uniffi_test {

use super::*;

#[allow(clippy::upper_case_acronyms)]
type SUT = ProfileID;

#[test]
fn hash_of_samples() {
assert_eq!(
HashSet::<SUT>::from_iter([
new_profile_id_sample(),
new_profile_id_sample_other(),
// duplicates should get removed
new_profile_id_sample(),
new_profile_id_sample_other(),
])
.len(),
2
);
}
}
29 changes: 29 additions & 0 deletions crates/sargon/src/profile/v100/networks/network/profile_network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ impl ProfileNetwork {
ResourcePreferences::new(),
)
}

/// Instantiates a new `ProfileNetwork` from `network_id` and `accounts`, with all
/// the rest i.e. Personas, AuthorizedDapps all being empty.
pub fn new_with_accounts(
network_id: impl Into<NetworkID>,
accounts: impl Into<Accounts>,
) -> Self {
Self::new(
network_id,
accounts,
Personas::new(),
AuthorizedDapps::new(),
ResourcePreferences::new(),
)
}
}

impl ProfileNetwork {
Expand Down Expand Up @@ -310,6 +325,20 @@ mod tests {
);
}

#[test]
#[should_panic(
expected = "Discrepancy, found an AuthorizedDapp on other network than mainnet"
)]
fn panic_when_network_id_mismatch_between_accounts_when_new_() {
SUT::new(
NetworkID::Mainnet,
Accounts::sample_mainnet(),
Personas::sample_mainnet(),
AuthorizedDapps::just(AuthorizedDapp::sample_stokenet()),
ResourcePreferences::default(),
);
}

#[test]
fn json_roundtrip_sample_mainnet() {
let sut = SUT::sample_mainnet();
Expand Down
10 changes: 8 additions & 2 deletions crates/sargon/src/profile/v100/networks/profile_networks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ impl ProfileNetworks {
pub fn content_hint(&self) -> ContentHint {
let number_of_accounts =
self.iter().fold(0, |acc, x| acc + x.accounts.len());
ContentHint::with_counters(number_of_accounts, 0, self.len())
let number_of_personas =
self.iter().fold(0, |per, x| per + x.personas.len());
ContentHint::with_counters(
number_of_accounts,
number_of_personas,
self.len(),
)
}
}

Expand Down Expand Up @@ -218,7 +224,7 @@ mod tests {
fn content_hint() {
assert_eq!(
SUT::sample().content_hint(),
ContentHint::with_counters(4, 0, 2)
ContentHint::with_counters(4, 4, 2)
);
}

Expand Down
Loading
Loading