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

Apply Shield Wallet Interaction Part 2 #355

Merged
merged 28 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1a52f44
[no ci] WIP
Sajjon Jan 23, 2025
fdea748
[no ci] wip
CyonAlexRDX Jan 23, 2025
9015925
[no ci] wip
CyonAlexRDX Jan 23, 2025
e7fd884
first initial impl of manifests for updating securified entities
Sajjon Jan 24, 2025
54e9967
remove unused input type
Sajjon Jan 24, 2025
20cbf2a
remove unused input types
Sajjon Jan 24, 2025
25188e9
Merge branch 'main' into ac/wallet_interaction_applying_shield_abw-40…
Sajjon Jan 24, 2025
4d8fc6d
add modify_manifest_add_lock_fee_against_xrd_vault_of_access_controller
Sajjon Jan 24, 2025
f2babd1
fix typos
Sajjon Jan 24, 2025
12704e2
doc
Sajjon Jan 24, 2025
58fc8cb
split out confirm of time based to be done later.
Sajjon Jan 24, 2025
4007bae
Replace bad wording 'auto_confirm' with 'timed_confirm' to make it cl…
Sajjon Jan 24, 2025
0ce2b35
fix typo
Sajjon Jan 24, 2025
5529715
review comments
Sajjon Jan 24, 2025
15e0558
refactor and assert manifests
Sajjon Jan 25, 2025
252f2bd
refactored fixtures moved incorrectly placed ones from vector folder.
Sajjon Jan 25, 2025
3489880
interaction
Sajjon Jan 26, 2025
3ac37f3
add interaction model
Sajjon Jan 26, 2025
ebde221
change 'number_of_days_until_timed_confirmation_is_callable' into 'ti…
Sajjon Jan 26, 2025
be7fdca
simplify interaction to use Vec<UnvalidatedTransactionManifest> again
Sajjon Jan 27, 2025
f567ae3
doc
Sajjon Jan 27, 2025
79ef5a7
try fix swift tests
Sajjon Jan 27, 2025
c36de91
try fix kotlin
Sajjon Jan 27, 2025
6e8a14a
Merge branch 'main' into ac/wallet_interaction_applying_shield_abw-40…
Sajjon Jan 27, 2025
30ebbdc
polish
CyonAlexRDX Jan 29, 2025
f24f196
dont set ROLA key when using timed completion of recovery.
CyonAlexRDX Jan 29, 2025
383d131
Merge branch 'main' into ac/wallet_interaction_applying_shield_abw-40…
CyonAlexRDX Jan 29, 2025
0de346a
Release 1.1.123
CyonAlexRDX Jan 29, 2025
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
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ FIXTURES_TX = "fixtures/transaction"
FIXTURES_VECTOR = "fixtures/vector"
FIXTURES_MODELS = "fixtures/models"
FIXTURES_MODELS_GW = "fixtures/models/gateway"
FIXTURES_MODELS_INTERACTION = "fixtures/models/interaction"
FIXTURES_MODELS_PROFILES = "fixtures/models/profile"
FIXTURES_MODELS_PROFILE = "fixtures/models/profile_submodels"
2 changes: 2 additions & 0 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 @@ -2,7 +2,7 @@ import Foundation
import SargonUniFFI

// MARK: - FileManager + @unchecked Sendable
extension FileManager: @unchecked Sendable {}
extension FileManager: @unchecked @retroactive Sendable {}

// Makes it possible to type `.shared` on an initalizer/func taking
// `some FileSystemDriver` as parameter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import SargonUniFFI

// MARK: - UserDefaults + @unchecked Sendable
extension UserDefaults: @unchecked Sendable {}
extension UserDefaults: @unchecked @retroactive Sendable {}

// Makes it possible to type `.shared` on an initalizer/func taking
// `some UnsafeStorageDriver` as parameter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ extension SecurityShieldBuilder {
public typealias Factor = FactorSourceID

/// Confirmation Role
public var timePeriodUntilAutoConfirm: TimePeriod {
getTimePeriodUntilAutoConfirm()
public var timeUntilTimedConfirmationIsCallable: TimePeriod {
getTimeUntilTimedConfirmationIsCallable()
}

public var threshold: Threshold {
Expand Down
5 changes: 1 addition & 4 deletions apple/Sources/Sargon/Protocols/EntityProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ extension EntityBaseProtocol {
flags.contains(.hiddenByUser)
}

// TODO: MOVE TO SARGON
public var virtualHierarchicalDeterministicFactorInstances:
Set<HierarchicalDeterministicFactorInstance>
{
Expand All @@ -55,15 +54,13 @@ extension EntityBaseProtocol {
}
}

// TODO: MOVE TO SARGON
public var hasAuthenticationSigningKey: Bool {
switch securityState {
case let .unsecured(unsecuredEntityControl):
case .unsecured:
false
}
}

// TODO: MOVE TO SARGON
public var deviceFactorSourceID: FactorSourceIDFromHash? {
switch self.securityState {
case let .unsecured(control):
Expand Down
1 change: 1 addition & 0 deletions apple/Tests/IntegrationTests/SargonOS/TestOSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ final class TestOSTests: OSTest {
XCTAssertEqual(try sut.os.profile().header.creatingDevice, newCreatingDevice) // assert change worked
}

@available(*, deprecated)
func batch_create_many_accounts() async throws {
let sut = await TestOS()
try await sut.os.newWallet(shouldPreDeriveInstances: false)
Expand Down
3 changes: 3 additions & 0 deletions apple/Tests/TestCases/Profile/Collection/AccountsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class AccountsTests: CollectionTest<Account> {
/// We can have this test implemented when swift-testing is stable to be used,
/// and we will use "exit tests" to test it:
/// https://forums.swift.org/t/exit-tests-death-tests-and-you/71186
@available(*, deprecated)
func omit_crash_if_duplicates() { // this test is relevant for Personas, AuthorizedDapps, ProfileNetworks etc etc... they all use the same rust type, which does not allow duplicates
var profile = Profile.sample
let a = Account.sample
Expand All @@ -27,12 +28,14 @@ final class AccountsTests: CollectionTest<Account> {
let _ = profile.jsonData() // should crash
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_accounts_contains_duplicates() throws {
var json = JSON(Profile.sample)
json["profileNetworks.accounts"] = [Account.sample, Account.sample]
XCTAssertThrowsError(try Profile(jsonData: json.rawData()))
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_accounts_contains_duplicated_ids() throws {
var json = JSON(Profile.sample)
let a = Account.sample
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,28 @@ final class FactorSourcesTests: CollectionTest<FactorSource> {
/// We can have this test implemented when swift-testing is stable to be used,
/// and we will use "exit tests" to test it:
/// https://forums.swift.org/t/exit-tests-death-tests-and-you/71186
@available(*, deprecated)
func omit_crash_if_empty() {
var profile = Profile.sample
profile.factorSources = [] // empty FactorSources is not allowed
let _ = profile.jsonData() // should crash
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_factorSources_is_empty() throws {
var json = JSON(Profile.sample)
json["factorSources"] = []
XCTAssertThrowsError(try Profile(jsonData: json.rawData()))
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_factorSources_contains_duplicates() throws {
var json = JSON(Profile.sample)
json["factorSources"] = [FactorSource.sample, FactorSource.sample]
XCTAssertThrowsError(try Profile(jsonData: json.rawData()))
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_factorSources_contains_duplicated_ids() throws {
var json = JSON(Profile.sample)
let a = FactorSource.sample
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ final class DeviceFactorSourceTests: SpecificFactorSourceTest<DeviceFactorSource
)
}

@available(*, deprecated)
func test_json_decoding_of_profile_fails_if_factorSource_supported_curves_is_empty() throws {
var json = JSON(Profile.sample)
json["factorSources"][0]["device.common.cryptoParameters.supportedCurves"] = []
Expand Down
54 changes: 38 additions & 16 deletions apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ struct ShieldTests {
@Test("days")
func days() {
var builder = SecurityShieldBuilder()
#expect(builder.timePeriodUntilAutoConfirm == TimePeriod(days: 14))
builder = builder.setTimePeriodUntilAutoConfirm(timePeriod: TimePeriod(days: 237))
#expect(builder.timePeriodUntilAutoConfirm == TimePeriod(days: 237))
#expect(builder.timeUntilTimedConfirmationIsCallable == TimePeriod(days: 14))
builder = builder.setTimeUntilDelayedConfirmationIsCallable(timePeriod: TimePeriod(days: 237))
#expect(builder.timeUntilTimedConfirmationIsCallable == TimePeriod(days: 237))
}

@Test("empty primary threshold")
Expand Down Expand Up @@ -58,7 +58,13 @@ struct ShieldTests {
@Test("primary override validation status trustedContact")
func primValidationStatusTrustedContact() {
let builder = SecurityShieldBuilder()
#expect(builder.validationForAdditionOfFactorSourceToPrimaryOverrideForEach(factorSources: [TrustedContactFactorSource.sample.asGeneral.id]).compactMap(\.reasonIfInvalid) == [FactorSourceValidationStatusReasonIfInvalid.nonBasic(SecurityShieldBuilderRuleViolation.PrimaryCannotContainTrustedContact)])
#expect(
builder.validationForAdditionOfFactorSourceToPrimaryOverrideForEach(factorSources: [
TrustedContactFactorSource.sample.asGeneral.id,
]).compactMap(\.reasonIfInvalid) == [
FactorSourceValidationStatusReasonIfInvalid.nonBasic(
SecurityShieldBuilderRuleViolation.PrimaryCannotContainTrustedContact),
])
}

@Test("Auto lowering of threshold upon deletion")
Expand All @@ -76,14 +82,18 @@ struct ShieldTests {

#expect(builder.threshold == Threshold.specific(3))

builder = builder.removeFactorFromPrimary(factorSourceId: x, factorListKind: FactorListKind.threshold)
builder = builder.removeFactorFromPrimary(
factorSourceId: x, factorListKind: FactorListKind.threshold
)
#expect(builder.threshold == Threshold.specific(2))

builder = builder.removeFactorFromAllRoles(factorSourceId: y)
#expect(builder.recoveryRoleFactors == []) // assert `y` is removed from Recovery and Primary
#expect(builder.threshold == Threshold.specific(1))

builder = builder.removeFactorFromPrimary(factorSourceId: z, factorListKind: FactorListKind.threshold)
builder = builder.removeFactorFromPrimary(
factorSourceId: z, factorListKind: FactorListKind.threshold
)
#expect(builder.threshold == Threshold.all)
#expect(builder.primaryRoleThresholdFactors == [])
}
Expand Down Expand Up @@ -115,9 +125,11 @@ struct ShieldTests {
#expect(builder.primaryRoleThresholdFactors == [factor])
#expect(builder.primaryRoleOverrideFactors == [other])

builder = builder.removeFactorFromPrimary(factorSourceId: factor, factorListKind: FactorListKind.threshold)
.addFactorSourceToPrimaryOverride(factorSourceId: factor)
.addFactorSourceToPrimaryThreshold(factorSourceId: other)
builder = builder.removeFactorFromPrimary(
factorSourceId: factor, factorListKind: FactorListKind.threshold
)
.addFactorSourceToPrimaryOverride(factorSourceId: factor)
.addFactorSourceToPrimaryThreshold(factorSourceId: other)
#expect(builder.primaryRoleThresholdFactors == [other])
#expect(builder.primaryRoleOverrideFactors == [other, factor])

Expand All @@ -130,7 +142,7 @@ struct ShieldTests {
func build() throws {
var builder = SecurityShieldBuilder()
.setName(name: "S.H.I.E.L.D.")
.setTimePeriodUntilAutoConfirm(timePeriod: TimePeriod(days: 42))
.setTimeUntilDelayedConfirmationIsCallable(timePeriod: TimePeriod(days: 42))
.setAuthenticationSigningFactor(new: .sampleDevice)

// Primary
Expand All @@ -145,7 +157,9 @@ struct ShieldTests {
// Confirmation
.addFactorSourceToConfirmationOverride(factorSourceId: .sampleDevice)
// Remove
.removeFactorFromPrimary(factorSourceId: .sampleArculusOther, factorListKind: FactorListKind.override)
.removeFactorFromPrimary(
factorSourceId: .sampleArculusOther, factorListKind: FactorListKind.override
)
.removeFactorFromRecovery(factorSourceId: .sampleLedgerOther)

builder = builder.setAuthenticationSigningFactor(new: .sampleDevice)
Expand Down Expand Up @@ -175,7 +189,11 @@ struct ShieldTests {
let builder = SecurityShieldBuilder()
.addFactorSourceToPrimaryThreshold(factorSourceId: .samplePassword)

#expect(builder.selectedPrimaryThresholdFactorsStatus() == .invalid(reason: SelectedPrimaryThresholdFactorsStatusInvalidReason.cannotBeUsedAlone(factorSourceKind: FactorSourceKind.password)))
#expect(
builder.selectedPrimaryThresholdFactorsStatus()
== .invalid(
reason: SelectedPrimaryThresholdFactorsStatusInvalidReason.cannotBeUsedAlone(
factorSourceKind: FactorSourceKind.password)))
}

@Test("selected primary threshold factors status")
Expand Down Expand Up @@ -209,12 +227,16 @@ extension FactorSourceID {
public static let samplePasswordOther = PasswordFactorSource.sampleOther.asGeneral.id

public static let sampleOffDeviceMnemonic = OffDeviceMnemonicFactorSource.sample.asGeneral.id
public static let sampleOffDeviceMnemonicOther = OffDeviceMnemonicFactorSource.sampleOther.asGeneral.id
public static let sampleOffDeviceMnemonicOther = OffDeviceMnemonicFactorSource.sampleOther
.asGeneral.id

public static let sampleTrustedContact = TrustedContactFactorSource.sample.asGeneral.id
public static let sampleTrustedContactOther = TrustedContactFactorSource.sampleOther.asGeneral.id
public static let sampleTrustedContactOther = TrustedContactFactorSource.sampleOther.asGeneral
.id

public static let sampleSecurityQuestions = SecurityQuestionsNotProductionReadyFactorSource.sample.asGeneral.id
public static let sampleSecurityQuestionsOther = SecurityQuestionsNotProductionReadyFactorSource.sampleOther.asGeneral.id
public static let sampleSecurityQuestions = SecurityQuestionsNotProductionReadyFactorSource
.sample.asGeneral.id
public static let sampleSecurityQuestionsOther = SecurityQuestionsNotProductionReadyFactorSource
.sampleOther.asGeneral.id
}
#endif
10 changes: 7 additions & 3 deletions apple/Tests/TestCases/Profile/ProfileTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class ProfileTests: Test<Profile> {
XCTAssertNoDifference(SUT.sample.id, SUT.sample.header.id)
}

@available(*, deprecated)
func test_encryption_roundtrip() throws {
let password = "ultra secret"
let sut = SUT.sample
Expand Down Expand Up @@ -102,6 +103,7 @@ final class ProfileTests: Test<Profile> {
XCTAssertTrue(jsonString.contains("version"))
}

@available(*, deprecated)
func test_json_roundtrip() throws {
func doTest(_ sut: SUT, _ json: String) throws {
let encoded = sut.toJSONString(prettyPrinted: false)
Expand Down Expand Up @@ -146,8 +148,9 @@ final class ProfileTests: Test<Profile> {
}
}

@available(*, deprecated)
func test_check_if_profile_json_contains_legacy_p2p_links_when_p2p_links_are_present() throws {
let json = try openFile(subPath: "vector", "only_plaintext_profile_snapshot_version_100", extension: "json")
let json = try jsonData(file: "only_plaintext_profile_snapshot_version_100")
XCTAssert(
SUT.checkIfProfileJsonContainsLegacyP2PLinks(contents: json)
)
Expand All @@ -159,15 +162,16 @@ final class ProfileTests: Test<Profile> {
)
}

@available(*, deprecated)
func test_check_if_encrypted_profile_json_contains_legacy_p2p_links_when_p2p_links_are_present() throws {
let json = try openFile(subPath: "vector", "profile_encrypted_by_password_of_babylon", extension: "json")
let json = try jsonData(file: "profile_encrypted_by_password_of_babylon")
XCTAssert(
SUT.checkIfEncryptedProfileJsonContainsLegacyP2PLinks(contents: json, password: "babylon")
)
}

func test_check_if_encrypted_profile_json_string_contains_legacy_p2p_links_when_p2p_links_are_present() throws {
let json = try openFile(subPath: "vector", "profile_encrypted_by_password_of_babylon", extension: "json")
let json = try jsonData(file: "profile_encrypted_by_password_of_babylon")
let jsonString = try XCTUnwrap(String(data: json, encoding: .utf8))
XCTAssert(
SUT.checkIfEncryptedProfileJsonStringContainsLegacyP2PLinks(jsonString: jsonString, password: "babylon")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import XCTest

final class WalletToDappInteractionResponseTests: Test<WalletToDappInteractionResponse> {
func test_codable() throws {
let json = try openFile(
subPath: "vector",
"wallet_interactions_wallet_to_dapp",
extension: "json"
let json = try jsonData(
file: "wallet_interactions_wallet_to_dapp",
in: "models/interaction"
)
let sut = try JSONDecoder().decode([SUT].self, from: json)
let encoded = try JSONEncoder().encode(sut)
Expand Down
6 changes: 4 additions & 2 deletions apple/Tests/Utils/Extensions/UUID+Literals.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import Foundation

// MARK: - UUID + ExpressibleByStringLiteral
extension UUID: ExpressibleByStringLiteral {
extension UUID: @retroactive ExpressibleByExtendedGraphemeClusterLiteral {}
extension UUID: @retroactive ExpressibleByUnicodeScalarLiteral {}
extension UUID: @retroactive ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self.init(uuidString: value)!
}
}

// MARK: - UUID + ExpressibleByIntegerLiteral
extension UUID: ExpressibleByIntegerLiteral {
extension UUID: @retroactive ExpressibleByIntegerLiteral {
public init(integerLiteral value: UInt8) {
self.init(uuidString: "00000000-0000-0000-0000-0000000000" + String(format: "%02d", value))!
}
Expand Down
24 changes: 17 additions & 7 deletions apple/Tests/Utils/Test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,43 @@ class TestCase: XCTestCase {
func jsonFixture<T: Decodable>(
as: T.Type = T.self,
file fileName: String,
in subPath: String? = nil,
decode: (Data) throws -> T = { try JSONDecoder().decode(T.self, from: $0) }
) throws -> (model: T, json: Data) {
let json = try openFile(subPath: "vector", fileName, extension: "json")
let json = try jsonData(file: fileName, in: subPath)
let model: T = try decode(json)
return (model, json)
}

func jsonFixture<T>(
as: T.Type = T.self,
file fileName: String,
in subPath: String? = nil,
decode: (Data) throws -> T
) throws -> (model: T, json: Data) {
let json = try openFile(subPath: "vector", fileName, extension: "json")
let json = try jsonData(file: fileName, in: subPath)
let model: T = try decode(json)
return (model, json)
}

func jsonData(
file fileName: String,
in subPath: String? = nil
) throws -> Data {
try openFile(
subPath: subPath ?? "models/profile",
fileName,
extension: "json"
)
}

func jsonString<T>(
as: T.Type = T.self,
file fileName: String,
in subPath: String? = nil,
decode: (String) throws -> T
) throws -> (model: T, jsonString: String) {
let jsonData = try openFile(
subPath: "vector",
fileName,
extension: "json"
)
let jsonData = try jsonData(file: fileName, in: subPath)
let jsonString = try XCTUnwrap(String(data: jsonData, encoding: .utf8))
let model: T = try decode(jsonString)
return (model, jsonString)
Expand Down
Loading
Loading