Skip to content

Commit

Permalink
[ABW-3848] Security problems logic (#287)
Browse files Browse the repository at this point in the history
* define models

* WIP

* added tests

* WIP

* WIP

* add Swift extensions

* feedback

* use InternalConversion

* bump sargon

* missing test

* fix iOS test
  • Loading branch information
matiasbzurovski authored Dec 6, 2024
1 parent 5fdde66 commit 730f216
Show file tree
Hide file tree
Showing 29 changed files with 1,085 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extension FileSystem {
extension FileSystem {
private static func appDirPathNotNecessarilyExisting(fileManager: FileManager) throws -> String {
#if os(iOS)
return try fileManager.urls(
fileManager.urls(
for: .cachesDirectory,
in: .userDomainMask
).first!.path()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation
import SargonUniFFI

extension SecurityProblem {
public var kind: SecurityProblemKind {
securityProblemKind(value: self)
}
}

// MARK: - SecurityProblem + Identifiable
extension SecurityProblem: Identifiable {
public var id: UInt64 {
securityProblemId(value: self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Foundation
import SargonUniFFI

extension SecurityProblemKind: CaseIterable {
public static var allCases: [SecurityProblemKind] {
[.configurationBackup, .securityFactors]
}
}
41 changes: 41 additions & 0 deletions apple/Tests/TestCases/SecurityCenter/SecurityProblemTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Foundation
import SargonUniFFI
import XCTest

final class SecurityProblemTests: TestCase {
typealias SUT = SecurityProblem

func testKind() throws {
var sut = SUT.problem3(addresses: .init(accounts: [], hiddenAccounts: [], personas: [], hiddenPersonas: []))
XCTAssertEqual(sut.kind, .securityFactors)

sut = SUT.problem5
XCTAssertEqual(sut.kind, .configurationBackup)

sut = SUT.problem6
XCTAssertEqual(sut.kind, .configurationBackup)

sut = SUT.problem7
XCTAssertEqual(sut.kind, .configurationBackup)

sut = .problem9(addresses: .init(accounts: [], hiddenAccounts: [], personas: [], hiddenPersonas: []))
XCTAssertEqual(sut.kind, .securityFactors)
}

func testId() throws {
var sut = SUT.problem3(addresses: .init(accounts: [], hiddenAccounts: [], personas: [], hiddenPersonas: []))
XCTAssertEqual(sut.id, 3)

sut = SUT.problem5
XCTAssertEqual(sut.id, 5)

sut = SUT.problem6
XCTAssertEqual(sut.id, 6)

sut = SUT.problem7
XCTAssertEqual(sut.id, 7)

sut = .problem9(addresses: .init(accounts: [], hiddenAccounts: [], personas: [], hiddenPersonas: []))
XCTAssertEqual(sut.id, 9)
}
}
2 changes: 1 addition & 1 deletion crates/sargon-uniffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "sargon-uniffi"
# Don't forget to update version in crates/sargon/Cargo.toml
version = "1.1.74"
version = "1.1.75"
edition = "2021"
build = "build.rs"

Expand Down
2 changes: 2 additions & 0 deletions crates/sargon-uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod home_cards;
mod keys_collector;
mod profile;
mod radix_connect;
mod security_center;
mod signing;
mod system;
mod types;
Expand All @@ -23,6 +24,7 @@ pub mod prelude {
pub use crate::keys_collector::*;
pub use crate::profile::*;
pub use crate::radix_connect::*;
pub use crate::security_center::*;
pub use crate::signing::*;
pub use crate::system::*;
pub use crate::types::*;
Expand Down
7 changes: 7 additions & 0 deletions crates/sargon-uniffi/src/security_center/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod security_problem;
mod security_problem_kind;
mod support;

pub use security_problem::*;
pub use security_problem_kind::*;
pub use support::*;
46 changes: 46 additions & 0 deletions crates/sargon-uniffi/src/security_center/security_problem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::prelude::*;
use sargon::SecurityProblem as InternalSecurityProblem;

#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Enum)]
/// An enum describing each potential Security Problem the Wallet can encounter.
///
/// See [the Confluence doc for details][doc].
///
/// [doc]: https://radixdlt.atlassian.net/wiki/spaces/AT/pages/3392569357/Security-related+Problem+States+in+the+Wallet
pub enum SecurityProblem {
/// The given addresses of `accounts` and `personas` are unrecoverable if the user loses their phone, since their corresponding seed phrase has not been written down.
/// NOTE: This definition differs from the one at Confluence since we don't have shields implemented yet.
Problem3 {
addresses: AddressesOfEntitiesInBadState,
},

/// Wallet backups to the cloud aren’t working (wallet tried to do a backup, and it didn’t work within, say, 5 minutes.)
/// This means that currently all accounts and personas are at risk of being practically unrecoverable if the user loses their phone.
/// Also they would lose all of their other non-security wallet settings and data.
Problem5,

/// Cloud backups are turned off and user has never done a manual file export. This means that currently all accounts and personas are at risk of
/// being practically unrecoverable if the user loses their phone. Also, they would lose all of their other non-security wallet settings and data.
Problem6,

/// Cloud backups are turned off and user previously did a manual file export, but has made a change and haven’t yet re-exported a file backup that
/// includes that change. This means that any changes made will be lost if the user loses their phone - including control of new accounts/personas they’ve
/// created, as well as changed settings or changed/added data.
Problem7,

/// User has gotten a new phone (and restored their wallet from backup) and the wallet sees that there are accounts without shields using a phone key,
/// meaning they can only be recovered with the seed phrase. (See problem 2) This would also be the state if a user disabled their PIN (and reenabled it), clearing phone keys.
Problem9 {
addresses: AddressesOfEntitiesInBadState,
},
}

#[uniffi::export]
pub fn security_problem_kind(value: &SecurityProblem) -> SecurityProblemKind {
value.into_internal().kind().into()
}

#[uniffi::export]
pub fn security_problem_id(value: &SecurityProblem) -> u64 {
value.into_internal().id()
}
10 changes: 10 additions & 0 deletions crates/sargon-uniffi/src/security_center/security_problem_kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::prelude::*;
use sargon::SecurityProblemKind as InternalSecurityProblemKind;

#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Enum)]
/// An enum describing the different types of Security Problems the Wallet can encounter.
pub enum SecurityProblemKind {
SecurityFactors,

ConfigurationBackup,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::prelude::*;
use sargon::AddressesOfEntitiesInBadState as InternalAddressesOfEntitiesInBadState;

/// A struct that represents the addresses of entities in a bad state.
#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Record)]
pub struct AddressesOfEntitiesInBadState {
pub accounts: Vec<AccountAddress>,
pub hidden_accounts: Vec<AccountAddress>,
pub personas: Vec<IdentityAddress>,
pub hidden_personas: Vec<IdentityAddress>,
}
39 changes: 39 additions & 0 deletions crates/sargon-uniffi/src/security_center/support/backup_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::prelude::*;
use sargon::BackupResult as InternalBackupResult;
use sargon::IsBackupResultCurrent;
use sargon::IsBackupResultFailed;

/// A struct that represents the result of a given backup.
///
/// Reference for iOS: it is a combination of `BackupStatus` and `BackupResult` (all in one).
#[derive(Clone, PartialEq, Eq, uniffi::Record)]
pub struct BackupResult {
/// The identifier of the backup.
pub save_identifier: String,

/// Whether this backup matches the one on Profile.
pub is_current: bool,

/// Whether this backup has failed.
pub is_failed: bool,
}

impl From<InternalBackupResult> for BackupResult {
fn from(internal: InternalBackupResult) -> Self {
Self {
save_identifier: internal.save_identifier,
is_current: internal.is_current.0,
is_failed: internal.is_failed.0,
}
}
}

impl From<BackupResult> for InternalBackupResult {
fn from(backup_result: BackupResult) -> Self {
InternalBackupResult {
save_identifier: backup_result.save_identifier,
is_current: IsBackupResultCurrent(backup_result.is_current),
is_failed: IsBackupResultFailed(backup_result.is_failed),
}
}
}
23 changes: 23 additions & 0 deletions crates/sargon-uniffi/src/security_center/support/input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::prelude::*;
use sargon::CheckSecurityProblemsInput as InternalCheckSecurityProblemsInput;
use sargon::IsCloudProfileSyncEnabled;

#[derive(Clone, PartialEq, Eq, uniffi::Record, InternalConversion)]
pub struct CheckSecurityProblemsInput {
/// Whether the cloud profile sync is enabled.
pub is_cloud_profile_sync_enabled: bool,

/// Addresses of entities that are unrecoverable. This is, the Factor Source used to create such entities
/// has not been backed up (e.g. seed phrase was not written down).
pub unrecoverable_entities: AddressesOfEntitiesInBadState,

/// Addresses of entities that we don't have control over them. This is, the Factor Source used to create such entities
/// is missing (e.g. entity was imported but seed phrase never entered).
pub without_control_entities: AddressesOfEntitiesInBadState,

/// Information about the latest backup made on the cloud.
pub last_cloud_backup: Option<BackupResult>,

/// Information about the latest backup made manually.
pub last_manual_backup: Option<BackupResult>,
}
7 changes: 7 additions & 0 deletions crates/sargon-uniffi/src/security_center/support/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod addresses_entities_bad_state;
mod backup_result;
mod input;

pub use addresses_entities_bad_state::*;
pub use backup_result::*;
pub use input::*;
2 changes: 2 additions & 0 deletions crates/sargon-uniffi/src/system/sargon_os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod sargon_os_accounts;
mod sargon_os_factors;
mod sargon_os_gateway;
mod sargon_os_profile;
mod sargon_os_security_center;
mod sargon_os_security_structures;
mod sargon_os_signing;
mod sargon_os_sync_accounts;
Expand All @@ -19,6 +20,7 @@ pub use sargon_os_accounts::*;
pub use sargon_os_factors::*;
pub use sargon_os_gateway::*;
pub use sargon_os_profile::*;
pub use sargon_os_security_center::*;
pub use sargon_os_security_structures::*;
pub use sargon_os_signing::*;
pub use sargon_os_sync_accounts::*;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::prelude::*;

// ==================
// Check Security Problems
// ==================
#[uniffi::export]
impl SargonOS {
/// Returns all the `SecurityProblem`s that are present for the given input.
pub fn check_security_problems(
&self,
input: CheckSecurityProblemsInput,
) -> Result<Vec<SecurityProblem>> {
self.wrapped
.check_security_problems(input.into_internal())
.into_result()
}
}
2 changes: 1 addition & 1 deletion crates/sargon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "sargon"
# Don't forget to update version in crates/sargon-uniffi/Cargo.toml
version = "1.1.74"
version = "1.1.75"
edition = "2021"
build = "build.rs"

Expand Down
21 changes: 21 additions & 0 deletions crates/sargon/src/core/types/bool_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ macro_rules! decl_bool_type {
&self.0
}
}

impl From<bool> for $name {
fn from(value: bool) -> Self {
$name(value)
}
}

impl From<$name> for bool {
fn from(value: $name) -> bool {
value.0
}
}
};
}

Expand Down Expand Up @@ -92,4 +104,13 @@ mod tests {
example_false.0 = true;
assert!(*example_false);
}

#[test]
fn from_into() {
let value = true;
assert!(ExampleTrue::from(value).0);

let value = false;
assert!(!ExampleTrue::from(value).0);
}
}
2 changes: 2 additions & 0 deletions crates/sargon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod home_cards;
mod keys_collector;
mod profile;
mod radix_connect;
mod security_center;
mod signing;
mod system;
mod types;
Expand All @@ -32,6 +33,7 @@ pub mod prelude {
pub use crate::keys_collector::*;
pub use crate::profile::*;
pub use crate::radix_connect::*;
pub use crate::security_center::*;
pub use crate::signing::*;
pub use crate::system::*;
pub use crate::types::*;
Expand Down
Loading

0 comments on commit 730f216

Please sign in to comment.