diff --git a/Cargo.lock b/Cargo.lock index eb70a3b43..fb83fe46c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "account-for-display" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "derive_more", @@ -49,10 +49,10 @@ dependencies = [ [[package]] name = "addresses" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", - "bytes 1.1.112", + "bytes 1.1.113", "cap26-models", "core-utils", "derive_more", @@ -246,7 +246,7 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "assert-json" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json-diff", "error", @@ -546,7 +546,7 @@ dependencies = [ [[package]] name = "build-info" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "cargo_toml", @@ -573,7 +573,7 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytes" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "delegate", @@ -607,7 +607,7 @@ dependencies = [ [[package]] name = "cap26-models" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "derive_more", @@ -748,7 +748,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clients" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "async-trait", @@ -808,7 +808,7 @@ checksum = "0d8a42181e0652c2997ae4d217f25b63c5337a52fd2279736e97b832fa0a3cff" [[package]] name = "core-collections" -version = "1.1.112" +version = "1.1.113" dependencies = [ "has-sample-values", "indexmap 2.7.0", @@ -835,7 +835,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-misc" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "core-utils", @@ -855,7 +855,7 @@ dependencies = [ [[package]] name = "core-utils" -version = "1.1.112" +version = "1.1.113" dependencies = [ "error", "iso8601-timestamp", @@ -1084,7 +1084,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "drivers" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -1108,10 +1108,10 @@ dependencies = [ [[package]] name = "ecc" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", - "bytes 1.1.112", + "bytes 1.1.113", "derive_more", "enum-as-inner", "error", @@ -1210,11 +1210,11 @@ dependencies = [ [[package]] name = "encryption" -version = "1.1.112" +version = "1.1.113" dependencies = [ "aes-gcm", "assert-json", - "bytes 1.1.112", + "bytes 1.1.113", "derive_more", "error", "has-sample-values", @@ -1231,7 +1231,7 @@ dependencies = [ [[package]] name = "entity-by-address" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "error", @@ -1243,7 +1243,7 @@ dependencies = [ [[package]] name = "entity-foundation" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "derive_more", @@ -1318,7 +1318,7 @@ dependencies = [ [[package]] name = "error" -version = "1.1.112" +version = "1.1.113" dependencies = [ "derive_more", "log", @@ -1377,7 +1377,7 @@ dependencies = [ [[package]] name = "factor-instances-provider" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -1403,9 +1403,9 @@ dependencies = [ [[package]] name = "factors" -version = "1.1.112" +version = "1.1.113" dependencies = [ - "bytes 1.1.112", + "bytes 1.1.113", "cap26-models", "core-collections", "core-misc", @@ -1440,7 +1440,7 @@ dependencies = [ [[package]] name = "factors-supporting-types" -version = "1.1.112" +version = "1.1.113" dependencies = [ "async-trait", "error", @@ -1593,7 +1593,7 @@ dependencies = [ [[package]] name = "gateway-client-and-api" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -1613,7 +1613,7 @@ dependencies = [ [[package]] name = "gateway-models" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "assert-json", @@ -1718,7 +1718,7 @@ dependencies = [ [[package]] name = "has-sample-values" -version = "1.1.112" +version = "1.1.113" dependencies = [ "error", "indexmap 2.7.0", @@ -1729,9 +1729,9 @@ dependencies = [ [[package]] name = "hash" -version = "1.1.112" +version = "1.1.113" dependencies = [ - "bytes 1.1.112", + "bytes 1.1.113", "derive_more", "prelude", "radix-common", @@ -1795,11 +1795,11 @@ dependencies = [ [[package]] name = "hierarchical-deterministic" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "bip39", - "bytes 1.1.112", + "bytes 1.1.113", "cap26-models", "derive_more", "ecc", @@ -1842,13 +1842,13 @@ dependencies = [ [[package]] name = "home-cards" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", "async-trait", "base64", - "bytes 1.1.112", + "bytes 1.1.113", "core-utils", "derive_more", "drivers", @@ -1868,7 +1868,7 @@ dependencies = [ [[package]] name = "host-info" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "derive_more", @@ -1915,10 +1915,10 @@ dependencies = [ [[package]] name = "http-client" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", - "bytes 1.1.112", + "bytes 1.1.113", "core-utils", "drivers", "error", @@ -2143,7 +2143,7 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "identified-vec-of" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "derive_more", @@ -2216,7 +2216,7 @@ dependencies = [ [[package]] name = "interactors" -version = "1.1.112" +version = "1.1.113" dependencies = [ "async-trait", "derive_more", @@ -2336,7 +2336,7 @@ dependencies = [ [[package]] name = "key-derivation-traits" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "async-trait", @@ -2354,7 +2354,7 @@ dependencies = [ [[package]] name = "keys-collector" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -2443,7 +2443,7 @@ dependencies = [ [[package]] name = "manifests" -version = "1.1.112" +version = "1.1.113" dependencies = [ "account-for-display", "addresses", @@ -2483,7 +2483,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "metadata" -version = "1.1.112" +version = "1.1.113" dependencies = [ "derive_more", "has-sample-values", @@ -2583,7 +2583,7 @@ dependencies = [ [[package]] name = "network" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", "enum-iterator", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "next-derivation-index-ephemeral" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "assert-json", @@ -2675,9 +2675,9 @@ dependencies = [ [[package]] name = "numeric" -version = "1.1.112" +version = "1.1.113" dependencies = [ - "bytes 1.1.112", + "bytes 1.1.113", "delegate", "derive_more", "enum-iterator", @@ -2897,7 +2897,7 @@ dependencies = [ [[package]] name = "prelude" -version = "1.1.112" +version = "1.1.113" dependencies = [ "radix-engine", "radix-engine-toolkit", @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "profile" -version = "1.1.112" +version = "1.1.113" dependencies = [ "account-for-display", "addresses", @@ -2978,7 +2978,7 @@ dependencies = [ [[package]] name = "profile-account" -version = "1.1.112" +version = "1.1.113" dependencies = [ "account-for-display", "addresses", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "profile-account-or-persona" -version = "1.1.112" +version = "1.1.113" dependencies = [ "cap26-models", "derive_more", @@ -3015,7 +3015,7 @@ dependencies = [ [[package]] name = "profile-app-preferences" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "core-misc", @@ -3038,7 +3038,7 @@ dependencies = [ [[package]] name = "profile-base-entity" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "derive_more", @@ -3061,7 +3061,7 @@ dependencies = [ [[package]] name = "profile-gateway" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "assert-json", @@ -3085,7 +3085,7 @@ dependencies = [ [[package]] name = "profile-logic" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "derive_more", @@ -3107,7 +3107,7 @@ dependencies = [ [[package]] name = "profile-persona" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "cap26-models", @@ -3128,7 +3128,7 @@ dependencies = [ [[package]] name = "profile-persona-data" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "assert-json", @@ -3147,11 +3147,12 @@ dependencies = [ [[package]] name = "profile-security-structures" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "cap26-models", "core-collections", + "core-misc", "core-utils", "derive_more", "enum-as-inner", @@ -3174,7 +3175,7 @@ dependencies = [ [[package]] name = "profile-state-holder" -version = "1.1.112" +version = "1.1.113" dependencies = [ "derive_more", "error", @@ -3189,7 +3190,7 @@ dependencies = [ [[package]] name = "profile-supporting-types" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "derive_more", @@ -3278,14 +3279,14 @@ dependencies = [ [[package]] name = "radix-connect" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", "assert-json", "async-trait", "base64", - "bytes 1.1.112", + "bytes 1.1.113", "core-misc", "core-utils", "derive_more", @@ -3313,10 +3314,10 @@ dependencies = [ [[package]] name = "radix-connect-models" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", - "bytes 1.1.112", + "bytes 1.1.113", "core-misc", "derive_more", "error", @@ -3758,7 +3759,7 @@ dependencies = [ [[package]] name = "sargon" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -3822,7 +3823,7 @@ dependencies = [ [[package]] name = "sargon-os" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "async-trait", @@ -3849,7 +3850,7 @@ dependencies = [ [[package]] name = "sargon-os-accounts" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -3872,7 +3873,7 @@ dependencies = [ [[package]] name = "sargon-os-factors" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "async-trait", @@ -3895,7 +3896,7 @@ dependencies = [ [[package]] name = "sargon-os-security-center" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "derive_more", @@ -3911,7 +3912,7 @@ dependencies = [ [[package]] name = "sargon-os-signing" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "async-trait", @@ -3937,7 +3938,7 @@ dependencies = [ [[package]] name = "sargon-os-transaction" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "async-std", @@ -3966,7 +3967,7 @@ dependencies = [ [[package]] name = "sargon-uniffi" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", @@ -4023,7 +4024,7 @@ dependencies = [ [[package]] name = "sargon-uniffi-conversion-macros" -version = "1.1.112" +version = "1.1.113" dependencies = [ "proc-macro2", "quote", @@ -4196,7 +4197,7 @@ dependencies = [ [[package]] name = "security-center" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", "assert-json", @@ -4364,7 +4365,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "short-string" -version = "1.1.112" +version = "1.1.113" dependencies = [ "arraystring", "assert-json", @@ -4399,13 +4400,13 @@ dependencies = [ [[package]] name = "signing" -version = "1.1.112" +version = "1.1.113" dependencies = [ "actix-rt", "addresses", "assert-json", "async-trait", - "bytes 1.1.112", + "bytes 1.1.113", "cap26-models", "core-collections", "core-misc", @@ -4437,10 +4438,10 @@ dependencies = [ [[package]] name = "signing-traits" -version = "1.1.112" +version = "1.1.113" dependencies = [ "async-trait", - "bytes 1.1.112", + "bytes 1.1.113", "core-collections", "derive_more", "ecc", @@ -4605,7 +4606,7 @@ dependencies = [ [[package]] name = "sub-systems" -version = "1.1.112" +version = "1.1.113" dependencies = [ "derive_more", "drivers", @@ -4764,7 +4765,7 @@ dependencies = [ [[package]] name = "time-utils" -version = "1.1.112" +version = "1.1.113" dependencies = [ "iso8601-timestamp", "prelude", @@ -4914,10 +4915,10 @@ dependencies = [ [[package]] name = "transaction-foundation" -version = "1.1.112" +version = "1.1.113" dependencies = [ "assert-json", - "bytes 1.1.112", + "bytes 1.1.113", "derive_more", "has-sample-values", "paste", @@ -4929,10 +4930,10 @@ dependencies = [ [[package]] name = "transaction-models" -version = "1.1.112" +version = "1.1.113" dependencies = [ "addresses", - "bytes 1.1.112", + "bytes 1.1.113", "cargo_toml", "core-collections", "core-misc", diff --git a/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift b/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift index 9505791ab..cc1e8e817 100644 --- a/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift +++ b/apple/Tests/TestCases/Profile/MFA/SecurityShieldsBuilderTests.swift @@ -58,7 +58,7 @@ 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(SecurityShieldBuilderInvalidReason.PrimaryCannotContainTrustedContact)]) + #expect(builder.validationForAdditionOfFactorSourceToPrimaryOverrideForEach(factorSources: [TrustedContactFactorSource.sample.asGeneral.id]).compactMap(\.reasonIfInvalid) == [FactorSourceValidationStatusReasonIfInvalid.nonBasic(SecurityShieldBuilderRuleViolation.PrimaryCannotContainTrustedContact)]) } @Test("Auto lowering of threshold upon deletion") @@ -88,32 +88,6 @@ struct ShieldTests { #expect(builder.primaryRoleThresholdFactors == []) } - @Test("basic validation") - func basicValidation() throws { - var builder = SecurityShieldBuilder() - #expect(builder.validate() == .MissingAuthSigningFactor) - builder = builder.setAuthenticationSigningFactor(new: .sampleDevice) - #expect(builder.validate() == .PrimaryRoleMustHaveAtLeastOneFactor) - builder = builder.addFactorSourceToPrimaryThreshold(factorSourceId: .sampleDevice) - .addFactorSourceToPrimaryThreshold(factorSourceId: .sampleDevice) // did not get added, duplicates are not allowed - #expect(builder.primaryRoleThresholdFactors == [.sampleDevice]) - - builder = builder.addFactorSourceToPrimaryThreshold(factorSourceId: .sampleDeviceOther) // actually this is added - #expect(builder.validate() == .PrimaryCannotHaveMultipleDevices) - builder = builder.removeFactorFromPrimary(factorSourceId: .sampleDeviceOther, factorListKind: FactorListKind.threshold) - - #expect(builder.validate() == .RecoveryRoleMustHaveAtLeastOneFactor) - builder = builder.removeFactorFromPrimary(factorSourceId: .sampleDeviceOther, factorListKind: FactorListKind.threshold) - .addFactorSourceToRecoveryOverride(factorSourceId: .sampleLedger) - - #expect(builder.validate() == .ConfirmationRoleMustHaveAtLeastOneFactor) - builder = builder.addFactorSourceToConfirmationOverride(factorSourceId: .sampleArculus) - .setAuthenticationSigningFactor(new: .sampleDevice) - - #expect(builder.validate() == nil) - #expect((try? builder.build()) != nil) - } - @Test("cannot add forbidden FactorSourceKinds") func preventAddOfForbiddenFactorSourceKinds() throws { let builder = SecurityShieldBuilder() @@ -147,49 +121,17 @@ struct ShieldTests { #expect(builder.primaryRoleThresholdFactors == [other]) #expect(builder.primaryRoleOverrideFactors == [other, factor]) - // But when validated/built is err - #expect(builder.validate() != nil) + // But when statusd/built is err + #expect(builder.status() != nil) #expect((try? builder.build()) == nil) } - @Test("Primary password never alone") - func primaryPasswordNeverAlone() { - var builder = SecurityShieldBuilder() - .setAuthenticationSigningFactor(new: .sampleDevice) - .addFactorSourceToPrimaryOverride(factorSourceId: .samplePassword) // not allowed - #expect(builder.primaryRoleOverrideFactors.isEmpty) - - builder = builder.addFactorSourceToPrimaryThreshold(factorSourceId: .samplePassword) - #expect(builder.validate() == .PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor) - builder = builder.setThreshold(threshold: Threshold.all) - - builder = builder.setThreshold(threshold: Threshold.specific(1)) - #expect(builder.validate() == .PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor) - builder = builder.addFactorSourceToPrimaryThreshold(factorSourceId: .sampleLedger) - #expect(builder.validate() == .PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne) - builder = builder.setThreshold(threshold: Threshold.specific(2)) - - builder = builder.addFactorSourceToRecoveryOverride(factorSourceId: .sampleArculus) - .addFactorSourceToConfirmationOverride(factorSourceId: .sampleArculusOther) - - builder = builder.setAuthenticationSigningFactor(new: .sampleDevice) - - let shield = try! builder.build() - - #expect(shield.matrixOfFactors.primaryRole.overrideFactors.isEmpty) - #expect(shield.matrixOfFactors.primaryRole.threshold == Threshold.specific(2)) - #expect(shield.matrixOfFactors.primaryRole.thresholdFactors == [.samplePassword, .sampleLedger]) - } - @Test("Build") func build() throws { var builder = SecurityShieldBuilder() .setName(name: "S.H.I.E.L.D.") .setTimePeriodUntilAutoConfirm(timePeriod: TimePeriod(days: 42)) - - #expect(builder.validate() == .MissingAuthSigningFactor) - builder = builder.setAuthenticationSigningFactor(new: .sampleDevice) - #expect(builder.validate() == .PrimaryRoleMustHaveAtLeastOneFactor) + .setAuthenticationSigningFactor(new: .sampleDevice) // Primary #expect(builder.threshold == Threshold.all) @@ -208,8 +150,8 @@ struct ShieldTests { builder = builder.setAuthenticationSigningFactor(new: .sampleDevice) - // Validate - #expect(builder.validate() == nil) + // status + #expect(builder.status() == SecurityShieldBuilderStatus.strong) // Build let shield0 = try builder.build() diff --git a/crates/app/home-cards/Cargo.toml b/crates/app/home-cards/Cargo.toml index b94c7ec1a..9167e5bbc 100644 --- a/crates/app/home-cards/Cargo.toml +++ b/crates/app/home-cards/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "home-cards" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/app/key-derivation-traits/Cargo.toml b/crates/app/key-derivation-traits/Cargo.toml index 968deb2ff..aa2181e84 100644 --- a/crates/app/key-derivation-traits/Cargo.toml +++ b/crates/app/key-derivation-traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "key-derivation-traits" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/app/radix-connect-models/Cargo.toml b/crates/app/radix-connect-models/Cargo.toml index 46360cf89..6aaf12e66 100644 --- a/crates/app/radix-connect-models/Cargo.toml +++ b/crates/app/radix-connect-models/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "radix-connect-models" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/app/radix-connect/Cargo.toml b/crates/app/radix-connect/Cargo.toml index 1525a92b2..e77e607fe 100644 --- a/crates/app/radix-connect/Cargo.toml +++ b/crates/app/radix-connect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "radix-connect" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/app/security-center/Cargo.toml b/crates/app/security-center/Cargo.toml index 84c578372..4531b1bef 100644 --- a/crates/app/security-center/Cargo.toml +++ b/crates/app/security-center/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "security-center" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/app/signing-traits/Cargo.toml b/crates/app/signing-traits/Cargo.toml index 5ec057255..cead4d41e 100644 --- a/crates/app/signing-traits/Cargo.toml +++ b/crates/app/signing-traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "signing-traits" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/app/signing/Cargo.toml b/crates/app/signing/Cargo.toml index 3a583d966..c50c4d42b 100644 --- a/crates/app/signing/Cargo.toml +++ b/crates/app/signing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "signing" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/common/build-info/Cargo.toml b/crates/common/build-info/Cargo.toml index 10c74ce30..97114472b 100644 --- a/crates/common/build-info/Cargo.toml +++ b/crates/common/build-info/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "build-info" -version = "1.1.112" +version = "1.1.113" edition = "2021" build = "build.rs" diff --git a/crates/common/bytes/Cargo.toml b/crates/common/bytes/Cargo.toml index c4b0d4835..2f75a9121 100644 --- a/crates/common/bytes/Cargo.toml +++ b/crates/common/bytes/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bytes" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/entity-foundation/Cargo.toml b/crates/common/entity-foundation/Cargo.toml index a6fd11e1e..dcdf1d273 100644 --- a/crates/common/entity-foundation/Cargo.toml +++ b/crates/common/entity-foundation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "entity-foundation" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/host-info/Cargo.toml b/crates/common/host-info/Cargo.toml index 926b78a4b..55db36670 100644 --- a/crates/common/host-info/Cargo.toml +++ b/crates/common/host-info/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "host-info" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/identified-vec-of/Cargo.toml b/crates/common/identified-vec-of/Cargo.toml index 75b24a578..f5c64745c 100644 --- a/crates/common/identified-vec-of/Cargo.toml +++ b/crates/common/identified-vec-of/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "identified-vec-of" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/metadata/Cargo.toml b/crates/common/metadata/Cargo.toml index 61fa289ad..24d75367c 100644 --- a/crates/common/metadata/Cargo.toml +++ b/crates/common/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "metadata" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/network/Cargo.toml b/crates/common/network/Cargo.toml index 9bbef0ea7..8431092e3 100644 --- a/crates/common/network/Cargo.toml +++ b/crates/common/network/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "network" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/numeric/Cargo.toml b/crates/common/numeric/Cargo.toml index f4fc17bb8..55fb99efe 100644 --- a/crates/common/numeric/Cargo.toml +++ b/crates/common/numeric/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "numeric" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/common/short-string/Cargo.toml b/crates/common/short-string/Cargo.toml index 0e78c3af1..e93264a8b 100644 --- a/crates/common/short-string/Cargo.toml +++ b/crates/common/short-string/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "short-string" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/assert-json/Cargo.toml b/crates/core/assert-json/Cargo.toml index 7ed128574..980584767 100644 --- a/crates/core/assert-json/Cargo.toml +++ b/crates/core/assert-json/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "assert-json" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/collections/Cargo.toml b/crates/core/collections/Cargo.toml index f5c4c1fbe..911b7b174 100644 --- a/crates/core/collections/Cargo.toml +++ b/crates/core/collections/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core-collections" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/error/Cargo.toml b/crates/core/error/Cargo.toml index 013614eb4..f67bd3413 100644 --- a/crates/core/error/Cargo.toml +++ b/crates/core/error/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "error" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/error/src/common_error.rs b/crates/core/error/src/common_error.rs index d80aeb024..aaa82214a 100644 --- a/crates/core/error/src/common_error.rs +++ b/crates/core/error/src/common_error.rs @@ -859,6 +859,11 @@ pub enum CommonError { #[error("Signing failed due to too many factor sources were neglected.")] SigningFailedTooManyFactorSourcesNeglected = 10247, + + #[error( + "SecurityStructure already exists in profile, FactorSourceID {bad_value}." + )] + StructureAlreadyExists { bad_value: String } = 10248, } impl CommonError { diff --git a/crates/core/has-sample-values/Cargo.toml b/crates/core/has-sample-values/Cargo.toml index 8896ab05d..5d17cb24d 100644 --- a/crates/core/has-sample-values/Cargo.toml +++ b/crates/core/has-sample-values/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "has-sample-values" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/misc/Cargo.toml b/crates/core/misc/Cargo.toml index 357e17fa3..f45f31cb6 100644 --- a/crates/core/misc/Cargo.toml +++ b/crates/core/misc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core-misc" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/prelude/Cargo.toml b/crates/core/prelude/Cargo.toml index 383f8c14c..554402d1e 100644 --- a/crates/core/prelude/Cargo.toml +++ b/crates/core/prelude/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prelude" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/time-utils/Cargo.toml b/crates/core/time-utils/Cargo.toml index 069943ebb..eb5df8182 100644 --- a/crates/core/time-utils/Cargo.toml +++ b/crates/core/time-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "time-utils" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/utils/Cargo.toml b/crates/core/utils/Cargo.toml index 5418bcbcf..c8926192a 100644 --- a/crates/core/utils/Cargo.toml +++ b/crates/core/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core-utils" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/core/utils/src/constants.rs b/crates/core/utils/src/constants.rs index e54bea9f7..5841852c5 100644 --- a/crates/core/utils/src/constants.rs +++ b/crates/core/utils/src/constants.rs @@ -34,9 +34,6 @@ pub const MINUTES_PER_DAY: u32 = 24 * 60; /// Number of days per week. pub const DAYS_PER_WEEK: u16 = 7; -/// Number of days per year. -pub const DAYS_PER_YEAR: u16 = 365; - #[cfg(test)] mod tests { use super::*; diff --git a/crates/crypto/addresses/Cargo.toml b/crates/crypto/addresses/Cargo.toml index 1c89b4074..a6fb9aa1e 100644 --- a/crates/crypto/addresses/Cargo.toml +++ b/crates/crypto/addresses/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "addresses" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/crypto/cap26-models/Cargo.toml b/crates/crypto/cap26-models/Cargo.toml index e36456089..812e75e64 100644 --- a/crates/crypto/cap26-models/Cargo.toml +++ b/crates/crypto/cap26-models/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cap26-models" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/crypto/ecc/Cargo.toml b/crates/crypto/ecc/Cargo.toml index f97db86fb..91cddd586 100644 --- a/crates/crypto/ecc/Cargo.toml +++ b/crates/crypto/ecc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ecc" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/crypto/encryption/Cargo.toml b/crates/crypto/encryption/Cargo.toml index dd1bf1146..02215be71 100644 --- a/crates/crypto/encryption/Cargo.toml +++ b/crates/crypto/encryption/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "encryption" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/crypto/hash/Cargo.toml b/crates/crypto/hash/Cargo.toml index 902abfb24..378d1f3f1 100644 --- a/crates/crypto/hash/Cargo.toml +++ b/crates/crypto/hash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hash" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/crypto/hd/Cargo.toml b/crates/crypto/hd/Cargo.toml index 5e53bbe01..1c568e2ea 100644 --- a/crates/crypto/hd/Cargo.toml +++ b/crates/crypto/hd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hierarchical-deterministic" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/factors/factors/Cargo.toml b/crates/factors/factors/Cargo.toml index b6b758f99..cc141d5f7 100644 --- a/crates/factors/factors/Cargo.toml +++ b/crates/factors/factors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factors" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/factors/instances-provider/Cargo.toml b/crates/factors/instances-provider/Cargo.toml index 6d5203840..78e71d53e 100644 --- a/crates/factors/instances-provider/Cargo.toml +++ b/crates/factors/instances-provider/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factor-instances-provider" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/factors/keys-collector/Cargo.toml b/crates/factors/keys-collector/Cargo.toml index 26d97e7c4..c22ae26be 100644 --- a/crates/factors/keys-collector/Cargo.toml +++ b/crates/factors/keys-collector/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keys-collector" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/factors/next-derivation-index-ephemeral/Cargo.toml b/crates/factors/next-derivation-index-ephemeral/Cargo.toml index e10b7a1d5..1b0e5c3dd 100644 --- a/crates/factors/next-derivation-index-ephemeral/Cargo.toml +++ b/crates/factors/next-derivation-index-ephemeral/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "next-derivation-index-ephemeral" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/factors/supporting-types/Cargo.toml b/crates/factors/supporting-types/Cargo.toml index 2281c1b0d..47d542e19 100644 --- a/crates/factors/supporting-types/Cargo.toml +++ b/crates/factors/supporting-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factors-supporting-types" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/gateway/client-and-api/Cargo.toml b/crates/gateway/client-and-api/Cargo.toml index 45125d93c..a8754c2d5 100644 --- a/crates/gateway/client-and-api/Cargo.toml +++ b/crates/gateway/client-and-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gateway-client-and-api" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/gateway/models/Cargo.toml b/crates/gateway/models/Cargo.toml index 5a092ffe2..79c2260ce 100644 --- a/crates/gateway/models/Cargo.toml +++ b/crates/gateway/models/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gateway-models" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/profile/logic/logic_SPLIT_ME/Cargo.toml b/crates/profile/logic/logic_SPLIT_ME/Cargo.toml index 4a3ac9f1a..bf2d4d96a 100644 --- a/crates/profile/logic/logic_SPLIT_ME/Cargo.toml +++ b/crates/profile/logic/logic_SPLIT_ME/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-logic" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/account-for-display/Cargo.toml b/crates/profile/models/account-for-display/Cargo.toml index 97b036e8f..b1696eab4 100644 --- a/crates/profile/models/account-for-display/Cargo.toml +++ b/crates/profile/models/account-for-display/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "account-for-display" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/account-or-persona/Cargo.toml b/crates/profile/models/account-or-persona/Cargo.toml index 77499663e..ef3189974 100644 --- a/crates/profile/models/account-or-persona/Cargo.toml +++ b/crates/profile/models/account-or-persona/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-account-or-persona" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/account/Cargo.toml b/crates/profile/models/account/Cargo.toml index 89707b88e..0ad2f25e8 100644 --- a/crates/profile/models/account/Cargo.toml +++ b/crates/profile/models/account/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-account" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/app-preferences/Cargo.toml b/crates/profile/models/app-preferences/Cargo.toml index 41568fef4..a0b4fe3f7 100644 --- a/crates/profile/models/app-preferences/Cargo.toml +++ b/crates/profile/models/app-preferences/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-app-preferences" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/base-entity/Cargo.toml b/crates/profile/models/base-entity/Cargo.toml index e2e20c9ec..bbcd4252e 100644 --- a/crates/profile/models/base-entity/Cargo.toml +++ b/crates/profile/models/base-entity/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-base-entity" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/gateway/Cargo.toml b/crates/profile/models/gateway/Cargo.toml index 94729a404..8064ef8af 100644 --- a/crates/profile/models/gateway/Cargo.toml +++ b/crates/profile/models/gateway/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-gateway" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/persona-data/Cargo.toml b/crates/profile/models/persona-data/Cargo.toml index aec3711f5..b585c8a8c 100644 --- a/crates/profile/models/persona-data/Cargo.toml +++ b/crates/profile/models/persona-data/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-persona-data" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/persona/Cargo.toml b/crates/profile/models/persona/Cargo.toml index 61bf951ab..ea4802d95 100644 --- a/crates/profile/models/persona/Cargo.toml +++ b/crates/profile/models/persona/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-persona" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/models/profile_SPLIT_ME/Cargo.toml b/crates/profile/models/profile_SPLIT_ME/Cargo.toml index 54810f84a..574822919 100644 --- a/crates/profile/models/profile_SPLIT_ME/Cargo.toml +++ b/crates/profile/models/profile_SPLIT_ME/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/profile/models/security-structures/Cargo.toml b/crates/profile/models/security-structures/Cargo.toml index 35bdfd30c..13faf1591 100644 --- a/crates/profile/models/security-structures/Cargo.toml +++ b/crates/profile/models/security-structures/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-security-structures" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] @@ -18,7 +18,7 @@ core-collections = { workspace = true } time-utils = { workspace = true } short-string = { workspace = true } core-utils = { workspace = true } - +core-misc = { workspace = true } # decl_bool_type # === RADIX DEPENDENCIES === radix-engine-interface = { workspace = true } diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/matrices/builder/matrix_builder.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/matrices/builder/matrix_builder.rs index f83e083f6..402a3a3c8 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/matrices/builder/matrix_builder.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/matrices/builder/matrix_builder.rs @@ -37,19 +37,19 @@ impl MatrixBuilder { /// /// If valid it returns a "built" `MatrixOfFactorSourceIds`. pub fn build(&self) -> MatrixBuilderBuildResult { - self.validate_combination()?; + self.validate_number_of_days_until_auto_confirm()?; let primary = self .primary_role - .build() + .build_with_minimum_validation() .into_matrix_err(RoleKind::Primary)?; let recovery = self .recovery_role - .build() + .build_with_minimum_validation() .into_matrix_err(RoleKind::Recovery)?; let confirmation = self .confirmation_role - .build() + .build_with_minimum_validation() .into_matrix_err(RoleKind::Confirmation)?; let built = unsafe { diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/mod.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/mod.rs index 2dd09a83e..2f4515524 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/mod.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/mod.rs @@ -4,7 +4,8 @@ mod has_role_kind; mod matrices; mod roles; mod security_shield_builder; -mod security_shield_builder_invalid_reason; +mod security_shield_builder_rule_violation; +mod security_shield_builder_status; mod security_shield_prerequisites_status; mod security_structure_id; mod security_structure_metadata; @@ -17,7 +18,8 @@ pub use has_role_kind::*; pub use matrices::*; pub use roles::*; pub use security_shield_builder::*; -pub use security_shield_builder_invalid_reason::*; +pub use security_shield_builder_rule_violation::*; +pub use security_shield_builder_status::*; pub use security_shield_prerequisites_status::*; pub use security_structure_id::*; pub use security_structure_metadata::*; diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/primary_roles_builder_unit_tests.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/primary_roles_builder_unit_tests.rs index 24f0805e5..07255620f 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/primary_roles_builder_unit_tests.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/primary_roles_builder_unit_tests.rs @@ -413,6 +413,22 @@ mod threshold_suite { ); } + #[test] + fn set_threshold_from_one_to_all() { + // Arrange + let mut sut = make(); + + // Act + sut.add_factor_source_to_threshold(sample()).unwrap(); + sut.add_factor_source_to_threshold(sample_other()).unwrap(); + assert_eq!(sut.set_specific_threshold(2), Ok(())); + sut.remove_factor_source(&sample(), FactorListKind::Threshold) + .unwrap(); + + // Assert + assert_eq!(sut.set_threshold(Threshold::All), Ok(())); + } + #[test] fn validation_for_addition_of_factor_source_for_each_before_after_adding_a_factor( ) { diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/roles_builder.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/roles_builder.rs index 96a05667c..1502d03da 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/roles_builder.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/roles/builder/roles_builder.rs @@ -375,6 +375,18 @@ impl<const ROLE: u8> RoleBuilder<ROLE> { }) } + pub(crate) fn build_with_minimum_validation( + &self, + ) -> Result<RoleWithFactorSourceIds<ROLE>, RoleBuilderValidation> { + self.validate_minimum_factor_count().map(|_| { + RoleWithFactorSourceIds::with_factors_and_threshold( + self.get_threshold(), + self.get_threshold_factors().clone(), + self.get_override_factors().clone(), + ) + }) + } + pub(crate) fn set_specific_threshold( &mut self, threshold: u8, @@ -488,6 +500,12 @@ impl<const ROLE: u8> RoleBuilder<ROLE> { self.validation_for_addition_of_password_to_primary(Threshold)?; } + self.validate_minimum_factor_count()?; + + Ok(()) + } + + fn validate_minimum_factor_count(&self) -> RoleBuilderMutateResult { if self.all_factors().is_empty() { return RoleBuilderMutateResult::not_yet_valid( RoleMustHaveAtLeastOneFactor, diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder.rs index 7dd24bc9a..04ca46738 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder.rs @@ -489,7 +489,7 @@ impl SecurityShieldBuilder { ) -> RoleBuilderMutateResult { self.get(|builder| { builder.validation_for_addition_of_factor_source_of_kind_to_confirmation_override( - factor_source_kind + factor_source_kind, ) }) } @@ -500,7 +500,7 @@ impl SecurityShieldBuilder { ) -> RoleBuilderMutateResult { self.get(|builder| { builder.validation_for_addition_of_factor_source_of_kind_to_recovery_override( - factor_source_kind + factor_source_kind, ) }) } @@ -511,7 +511,7 @@ impl SecurityShieldBuilder { ) -> RoleBuilderMutateResult { self.get(|builder| { builder.validation_for_addition_of_factor_source_of_kind_to_primary_override( - factor_source_kind + factor_source_kind, ) }) } @@ -690,14 +690,14 @@ impl SecurityShieldBuilder { impl SecurityShieldBuilder { /// `None` means valid! - pub fn validate(&self) -> Option<SecurityShieldBuilderInvalidReason> { + pub fn validate(&self) -> Option<SecurityShieldBuilderRuleViolation> { if DisplayName::new(self.get_name()).is_err() { - return Some(SecurityShieldBuilderInvalidReason::ShieldNameInvalid); + return Some(SecurityShieldBuilderRuleViolation::ShieldNameInvalid); } if self.get_authentication_signing_factor().is_none() { return Some( - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor, + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor, ); } @@ -714,7 +714,7 @@ impl SecurityShieldBuilder { /// Validates **just** the primary role **in isolation**. pub fn validate_primary_role( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { self.validate_role_in_isolation(RoleKind::Primary) } @@ -722,7 +722,7 @@ impl SecurityShieldBuilder { pub fn validate_role_in_isolation( &self, role: RoleKind, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { self.get(|builder| { let validation = match role { RoleKind::Primary => { @@ -739,6 +739,47 @@ impl SecurityShieldBuilder { }) } + pub fn is_role_in_isolation_invalid(&self, role: RoleKind) -> bool { + self.validate_role_in_isolation(role).is_some_and(|reason| { + matches!( + reason, + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor | + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor | + SecurityShieldBuilderRuleViolation::RecoveryRoleMustHaveAtLeastOneFactor | + SecurityShieldBuilderRuleViolation::ConfirmationRoleMustHaveAtLeastOneFactor + ) + }) + } + + pub fn status(&self) -> SecurityShieldBuilderStatus { + let invalid_reason = SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty( + self.is_role_in_isolation_invalid(RoleKind::Primary), + ), + IsRecoveryRoleFactorListEmpty( + self.is_role_in_isolation_invalid(RoleKind::Recovery), + ), + IsConfirmationRoleFactorListEmpty( + self.is_role_in_isolation_invalid(RoleKind::Confirmation), + ), + IsAuthSigningFactorMissing( + self.get_authentication_signing_factor().is_none(), + ), + ); + + if let Some(invalid_reason) = invalid_reason { + SecurityShieldBuilderStatus::Invalid { + reason: invalid_reason, + } + } else if let Some(rule_violation_reason) = self.validate() { + SecurityShieldBuilderStatus::Weak { + reason: rule_violation_reason, + } + } else { + SecurityShieldBuilderStatus::Strong + } + } + pub fn selected_primary_threshold_factors_status( &self, ) -> SelectedPrimaryThresholdFactorsStatus { @@ -750,10 +791,10 @@ impl SecurityShieldBuilder { if let Some(reason) = reason { return match reason { - SecurityShieldBuilderInvalidReason::PrimaryRoleMustHaveAtLeastOneFactor => { + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor => { SelectedPrimaryThresholdFactorsStatus::Insufficient } - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor => { + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor => { SelectedPrimaryThresholdFactorsStatus::Invalid { reason: SelectedPrimaryThresholdFactorsStatusInvalidReason::CannotBeUsedAlone { factor_source_kind: FactorSourceKind::Password, @@ -801,11 +842,11 @@ impl SecurityShieldBuilder { &self, ) -> Result< SecurityStructureOfFactorSourceIds, - SecurityShieldBuilderInvalidReason, + SecurityShieldBuilderRuleViolation, > { let authentication_signing_factor = self.get_authentication_signing_factor().ok_or( - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor, + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor, )?; let matrix_result = self.get(|builder| builder.build()); @@ -821,7 +862,7 @@ impl SecurityShieldBuilder { let name = self.get_name(); let display_name = DisplayName::new(name).map_err(|e| { error!("Invalid DisplayName {:?}", e); - SecurityShieldBuilderInvalidReason::ShieldNameInvalid + SecurityShieldBuilderRuleViolation::ShieldNameInvalid })?; let metadata = SecurityStructureMetadata::with_details( @@ -1309,7 +1350,7 @@ mod tests { sut.selected_primary_threshold_factors_status(), SelectedPrimaryThresholdFactorsStatus::Invalid { reason: SelectedPrimaryThresholdFactorsStatusInvalidReason::Other { - underlying: SecurityShieldBuilderInvalidReason::PrimaryCannotHaveMultipleDevices + underlying: SecurityShieldBuilderRuleViolation::PrimaryCannotHaveMultipleDevices } } ); @@ -1342,7 +1383,7 @@ mod tests { pretty_assertions::assert_eq!( sut.validate(), Some( - SecurityShieldBuilderInvalidReason::FactorSourceAlreadyPresent + SecurityShieldBuilderRuleViolation::FactorSourceAlreadyPresent ) ); pretty_assertions::assert_eq!( @@ -1390,7 +1431,7 @@ mod test_invalid { let sut = SUT::strict(); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor ); } @@ -1409,7 +1450,7 @@ mod test_invalid { assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor ); } @@ -1418,11 +1459,11 @@ mod test_invalid { let sut = SUT::sample_strict_with_auth_signing(); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Primary).unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor ); } @@ -1436,11 +1477,11 @@ mod test_invalid { sut.set_threshold(Threshold::zero()); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero + SecurityShieldBuilderRuleViolation::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Primary).unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero + SecurityShieldBuilderRuleViolation::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero ); } @@ -1452,11 +1493,11 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::RecoveryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::RecoveryRoleMustHaveAtLeastOneFactor ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Recovery).unwrap(), - SecurityShieldBuilderInvalidReason::RecoveryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::RecoveryRoleMustHaveAtLeastOneFactor ); } @@ -1471,11 +1512,11 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::ConfirmationRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::ConfirmationRoleMustHaveAtLeastOneFactor ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Confirmation).unwrap(), - SecurityShieldBuilderInvalidReason::ConfirmationRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::ConfirmationRoleMustHaveAtLeastOneFactor ); } @@ -1493,7 +1534,7 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor ); assert!(sut.validate_role_in_isolation(RoleKind::Primary).is_none()); sut.set_authentication_signing_factor(Some( @@ -1541,7 +1582,7 @@ mod test_invalid { sut.set_name(""); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::ShieldNameInvalid + SecurityShieldBuilderRuleViolation::ShieldNameInvalid ); } @@ -1564,7 +1605,7 @@ mod test_invalid { sut.set_time_period_until_auto_confirm(TimePeriod::with_days(0)); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::NumberOfDaysUntilAutoConfirmMustBeGreaterThanZero + SecurityShieldBuilderRuleViolation::NumberOfDaysUntilAutoConfirmMustBeGreaterThanZero ); } @@ -1582,7 +1623,7 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::RecoveryAndConfirmationFactorsOverlap + SecurityShieldBuilderRuleViolation::RecoveryAndConfirmationFactorsOverlap ); } @@ -1601,7 +1642,7 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole + SecurityShieldBuilderRuleViolation::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole ); } @@ -1620,7 +1661,7 @@ mod test_invalid { ); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole + SecurityShieldBuilderRuleViolation::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole ); } @@ -1646,11 +1687,11 @@ mod test_invalid { assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Primary).unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne ); } @@ -1672,11 +1713,11 @@ mod test_invalid { assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Primary).unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor ); } @@ -1701,7 +1742,7 @@ mod test_invalid { assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor ); } @@ -1723,11 +1764,11 @@ mod test_invalid { assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor ); assert_eq!( sut.validate_role_in_isolation(RoleKind::Primary).unwrap(), - SecurityShieldBuilderInvalidReason::PrimaryRoleMustHaveAtLeastOneFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleMustHaveAtLeastOneFactor ); } @@ -1738,7 +1779,7 @@ mod test_invalid { sut.set_name(""); assert_eq!( sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::ShieldNameInvalid + SecurityShieldBuilderRuleViolation::ShieldNameInvalid ); } @@ -1791,11 +1832,170 @@ mod test_invalid { status, SelectedPrimaryThresholdFactorsStatus::Invalid { reason: Other { - underlying: SecurityShieldBuilderInvalidReason::PrimaryCannotHaveMultipleDevices + underlying: SecurityShieldBuilderRuleViolation::PrimaryCannotHaveMultipleDevices } } ); } + + #[test] + fn shield_status_strong() { + let sut = SUT::default(); + + let _ = sut + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_device(), + ) + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_password(), + ) + .set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )) + .add_factor_source_to_recovery_override( + FactorSourceID::sample_ledger(), + ) + .add_factor_source_to_confirmation_override( + FactorSourceID::sample_arculus(), + ); + + let status = sut.status(); + + pretty_assertions::assert_eq!( + status, + SecurityShieldBuilderStatus::Strong + ); + assert!(sut.build().is_ok()) + } + + #[test] + fn shield_status_weak() { + let sut = SUT::default(); + + let _ = sut + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_password(), + ) + .set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )) + .add_factor_source_to_recovery_override( + FactorSourceID::sample_ledger(), + ) + .add_factor_source_to_confirmation_override( + FactorSourceID::sample_arculus(), + ); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + } + ); + + let _ = sut + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_device(), + ) + .remove_factor_from_recovery(FactorSourceID::sample_ledger()) + .add_factor_source_to_recovery_override( + FactorSourceID::sample_arculus(), + ); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::RecoveryAndConfirmationFactorsOverlap + } + ); + + let _ = sut + .remove_factor_from_recovery(FactorSourceID::sample_password()) + .add_factor_source_to_recovery_override( + FactorSourceID::sample_ledger_other(), + ) + .add_factor_source_to_confirmation_override( + FactorSourceID::sample_ledger_other(), + ); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::RecoveryAndConfirmationFactorsOverlap + } + ); + assert!(sut.build().is_ok()) + } + + #[test] + fn shield_status_invalid() { + let sut = SUT::default(); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Invalid { + reason: SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(true), + IsRecoveryRoleFactorListEmpty(true), + IsConfirmationRoleFactorListEmpty(true), + IsAuthSigningFactorMissing(true), + ) + .unwrap() + } + ); + + let _ = sut.add_factor_source_to_primary_threshold( + FactorSourceID::sample_device(), + ); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Invalid { + reason: SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(false), + IsRecoveryRoleFactorListEmpty(true), + IsConfirmationRoleFactorListEmpty(true), + IsAuthSigningFactorMissing(true), + ) + .unwrap() + } + ); + + let _ = sut.set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Invalid { + reason: SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(false), + IsRecoveryRoleFactorListEmpty(true), + IsConfirmationRoleFactorListEmpty(true), + IsAuthSigningFactorMissing(false), + ) + .unwrap() + } + ); + + let _ = sut.add_factor_source_to_recovery_override( + FactorSourceID::sample_ledger(), + ); + + pretty_assertions::assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Invalid { + reason: SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(false), + IsRecoveryRoleFactorListEmpty(false), + IsConfirmationRoleFactorListEmpty(true), + IsAuthSigningFactorMissing(false), + ) + .unwrap() + } + ); + assert!(sut.build().is_err()) + } } #[cfg(test)] @@ -1904,4 +2104,152 @@ mod lenient { test(FactorListKind::Threshold); test(FactorListKind::Override); } + + #[test] + fn basic_validation() { + let sut = SUT::lenient(); + + let _ = sut + .set_authentication_signing_factor(Some( + FactorSourceID::sample_device(), + )) + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_device(), + ) + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_device(), + ); // did not get added, duplicates are not allowed + + assert_eq!( + sut.get_primary_threshold_factors(), + vec![FactorSourceID::sample_device()] + ); + + assert_eq!( + // Takes into consideration all the rules because it disregards the mode + // the builder was initialized with and always uses SecurityShieldBuilderMode::Strict + sut._validation_for_addition_of_factor_source_of_kind_to_primary_threshold( + FactorSourceKind::Device, + ), + Err( + RoleBuilderValidation::ForeverInvalid( + ForeverInvalidReason::PrimaryCannotHaveMultipleDevices + ) + ) + ); + + let _ = sut.add_factor_source_to_primary_threshold( + FactorSourceID::sample_device_other(), + ); // actually this is added because of the lenient mode + + assert_eq!( + sut.get_primary_threshold_factors(), + vec![ + FactorSourceID::sample_device(), + FactorSourceID::sample_device_other() + ] + ); + + let _ = sut + .add_factor_source_to_recovery_override( + FactorSourceID::sample_ledger(), + ) + .add_factor_source_to_confirmation_override( + FactorSourceID::sample_arculus(), + ); + + assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::PrimaryCannotHaveMultipleDevices + } + ); + assert!(sut.build().is_ok()); + } + + #[test] + fn primary_password_never_alone() { + let sut = SUT::lenient(); + + let _ = sut + .set_authentication_signing_factor(FactorSourceID::sample_device()) + .add_factor_source_to_primary_override( + FactorSourceID::sample_password(), + ); // not allowed + + assert!(sut.get_primary_override_factors().is_empty(),); + + let _ = sut + .add_factor_source_to_recovery_override( + FactorSourceID::sample_arculus(), + ) + .add_factor_source_to_confirmation_override( + FactorSourceID::sample_arculus_other(), + ) + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_password(), + ); + + assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + } + ); + + let _ = sut + .add_factor_source_to_primary_threshold( + FactorSourceID::sample_ledger(), + ) + .set_threshold(Threshold::Specific(1)); + + assert_eq!( + sut.status(), + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne + } + ); + + let _ = sut.set_threshold(Threshold::Specific(2)); + + assert_eq!(sut.status(), SecurityShieldBuilderStatus::Strong); + + let shield = sut.build().unwrap(); + assert!(shield + .matrix_of_factors + .primary_role + .get_override_factors() + .is_empty()); + assert_eq!( + shield.matrix_of_factors.primary_role.get_threshold(), + Threshold::Specific(2) + ); + assert_eq!( + shield + .matrix_of_factors + .primary_role + .get_threshold_factors() + .clone(), + vec![ + FactorSourceID::sample_password(), + FactorSourceID::sample_ledger() + ] + ); + } + + #[test] + fn validation_for_addition() { + let sut = SUT::lenient(); + + assert_eq!( + sut._validation_for_addition_of_factor_source_of_kind_to_primary_override( + FactorSourceKind::Password, + ), + Err( + RoleBuilderValidation::ForeverInvalid( + ForeverInvalidReason::PrimaryCannotHavePasswordInOverrideList + ) + ) + ); + } } diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_invalid_reason.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_rule_violation.rs similarity index 80% rename from crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_invalid_reason.rs rename to crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_rule_violation.rs index 0343284a0..fceab3cc0 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_invalid_reason.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_rule_violation.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub trait AsShieldBuilderViolation { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason>; + ) -> Option<SecurityShieldBuilderRuleViolation>; } impl<T: std::fmt::Debug> AsShieldBuilderViolation @@ -11,7 +11,7 @@ impl<T: std::fmt::Debug> AsShieldBuilderViolation { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { match self { Result::Err(err) => err.as_shield_validation(), Result::Ok(_) => None, @@ -21,7 +21,7 @@ impl<T: std::fmt::Debug> AsShieldBuilderViolation impl AsShieldBuilderViolation for MatrixBuilderValidation { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { match self { MatrixBuilderValidation::RoleInIsolation { role, violation } => { (*role, *violation).as_shield_validation() @@ -36,7 +36,7 @@ impl AsShieldBuilderViolation for MatrixBuilderValidation { impl AsShieldBuilderViolation for MatrixRolesInCombinationViolation { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { match self { Self::Basic(val) => val.as_shield_validation(), Self::ForeverInvalid(val) => val.as_shield_validation(), @@ -48,13 +48,13 @@ impl AsShieldBuilderViolation for MatrixRolesInCombinationViolation { impl AsShieldBuilderViolation for MatrixRolesInCombinationBasicViolation { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { use MatrixRolesInCombinationBasicViolation::*; match self { FactorSourceNotFoundInAnyRole => unreachable!("Cannot happen since this error is not returned by 'validate'/'build'."), NumberOfDaysUntilAutoConfirmMustBeGreaterThanZero => { - Some(SecurityShieldBuilderInvalidReason::NumberOfDaysUntilAutoConfirmMustBeGreaterThanZero) + Some(SecurityShieldBuilderRuleViolation::NumberOfDaysUntilAutoConfirmMustBeGreaterThanZero) } } } @@ -62,11 +62,11 @@ impl AsShieldBuilderViolation for MatrixRolesInCombinationBasicViolation { impl AsShieldBuilderViolation for MatrixRolesInCombinationForeverInvalid { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { use MatrixRolesInCombinationForeverInvalid::*; match self { RecoveryAndConfirmationFactorsOverlap => { - Some(SecurityShieldBuilderInvalidReason::RecoveryAndConfirmationFactorsOverlap) + Some(SecurityShieldBuilderRuleViolation::RecoveryAndConfirmationFactorsOverlap) } } } @@ -74,12 +74,12 @@ impl AsShieldBuilderViolation for MatrixRolesInCombinationForeverInvalid { impl AsShieldBuilderViolation for MatrixRolesInCombinationNotYetValid { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { use MatrixRolesInCombinationNotYetValid::*; match self { SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole => { - Some(SecurityShieldBuilderInvalidReason::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole) + Some(SecurityShieldBuilderRuleViolation::SingleFactorUsedInPrimaryMustNotBeUsedInAnyOtherRole) } } } @@ -88,7 +88,7 @@ impl AsShieldBuilderViolation for MatrixRolesInCombinationNotYetValid { impl AsShieldBuilderViolation for (RoleKind, RoleBuilderValidation) { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { let (role_kind, violation) = self; match violation { RoleBuilderValidation::BasicViolation(basic) => unreachable!("Programmer error. Should have prevented this from happening: '{:?}'", basic), @@ -105,37 +105,37 @@ impl AsShieldBuilderViolation for (RoleKind, RoleBuilderValidation) { impl AsShieldBuilderViolation for ForeverInvalidReason { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { use ForeverInvalidReason::*; let reason = match self { - FactorSourceAlreadyPresent => SecurityShieldBuilderInvalidReason::FactorSourceAlreadyPresent, + FactorSourceAlreadyPresent => SecurityShieldBuilderRuleViolation::FactorSourceAlreadyPresent, PrimaryCannotHaveMultipleDevices => { - SecurityShieldBuilderInvalidReason::PrimaryCannotHaveMultipleDevices + SecurityShieldBuilderRuleViolation::PrimaryCannotHaveMultipleDevices } PrimaryCannotHavePasswordInOverrideList => { - SecurityShieldBuilderInvalidReason::PrimaryCannotHavePasswordInOverrideList + SecurityShieldBuilderRuleViolation::PrimaryCannotHavePasswordInOverrideList } PrimaryCannotContainSecurityQuestions => { - SecurityShieldBuilderInvalidReason::PrimaryCannotContainSecurityQuestions + SecurityShieldBuilderRuleViolation::PrimaryCannotContainSecurityQuestions } PrimaryCannotContainTrustedContact => { - SecurityShieldBuilderInvalidReason::PrimaryCannotContainTrustedContact + SecurityShieldBuilderRuleViolation::PrimaryCannotContainTrustedContact } RecoveryRoleSecurityQuestionsNotSupported => { - SecurityShieldBuilderInvalidReason::RecoveryRoleSecurityQuestionsNotSupported + SecurityShieldBuilderRuleViolation::RecoveryRoleSecurityQuestionsNotSupported } RecoveryRolePasswordNotSupported => { - SecurityShieldBuilderInvalidReason::RecoveryRolePasswordNotSupported + SecurityShieldBuilderRuleViolation::RecoveryRolePasswordNotSupported } ConfirmationRoleTrustedContactNotSupported => { - SecurityShieldBuilderInvalidReason::ConfirmationRoleTrustedContactNotSupported + SecurityShieldBuilderRuleViolation::ConfirmationRoleTrustedContactNotSupported } }; Some(reason) } } -impl SecurityShieldBuilderInvalidReason { +impl SecurityShieldBuilderRuleViolation { pub(crate) fn role_must_have_at_least_one_factor( role_kind: &RoleKind, ) -> Self { @@ -152,33 +152,31 @@ impl SecurityShieldBuilderInvalidReason { impl AsShieldBuilderViolation for (RoleKind, NotYetValidReason) { fn as_shield_validation( &self, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { let (role_kind, violation) = self; use NotYetValidReason::*; let reason = match violation { - RoleMustHaveAtLeastOneFactor => SecurityShieldBuilderInvalidReason::role_must_have_at_least_one_factor(role_kind), + RoleMustHaveAtLeastOneFactor => SecurityShieldBuilderRuleViolation::role_must_have_at_least_one_factor(role_kind), PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor => { - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustHaveAnotherFactor } PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero => { - SecurityShieldBuilderInvalidReason::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero + SecurityShieldBuilderRuleViolation::PrimaryRoleWithThresholdFactorsCannotHaveAThresholdValueOfZero } PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne => { - SecurityShieldBuilderInvalidReason::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne + SecurityShieldBuilderRuleViolation::PrimaryRoleWithPasswordInThresholdListMustThresholdGreaterThanOne } ThresholdHigherThanThresholdFactorsLen => { - SecurityShieldBuilderInvalidReason::ThresholdHigherThanThresholdFactorsLen + SecurityShieldBuilderRuleViolation::ThresholdHigherThanThresholdFactorsLen } }; Some(reason) } } -// #[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)] - #[repr(u32)] #[derive(Clone, Debug, thiserror::Error, PartialEq)] -pub enum SecurityShieldBuilderInvalidReason { +pub enum SecurityShieldBuilderRuleViolation { #[error("Auth Signing Factor Missing")] MissingAuthSigningFactor, @@ -250,13 +248,13 @@ pub enum SecurityShieldBuilderInvalidReason { ConfirmationRoleTrustedContactNotSupported, } -impl HasSampleValues for SecurityShieldBuilderInvalidReason { +impl HasSampleValues for SecurityShieldBuilderRuleViolation { fn sample() -> Self { - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + SecurityShieldBuilderRuleViolation::MissingAuthSigningFactor } fn sample_other() -> Self { - SecurityShieldBuilderInvalidReason::ShieldNameInvalid + SecurityShieldBuilderRuleViolation::ShieldNameInvalid } } @@ -265,7 +263,7 @@ mod tests { use super::*; #[allow(clippy::upper_case_acronyms)] - type SUT = SecurityShieldBuilderInvalidReason; + type SUT = SecurityShieldBuilderRuleViolation; #[test] fn equality() { diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_status.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_status.rs new file mode 100644 index 000000000..c08646711 --- /dev/null +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/security_shield_builder_status.rs @@ -0,0 +1,165 @@ +use core_misc::decl_bool_type; +use std::ops::Not; + +use crate::prelude::*; + +/// Represents the status of `SecurityShieldBuilder`. +/// Used for UI representation in host applications. +#[derive(Clone, Debug, PartialEq)] +pub enum SecurityShieldBuilderStatus { + /// The selected factor sources form a strong combination + /// in the Security Shield building process. + Strong, + + /// The selected factor sources form a weak combination + /// in the Security Shield building process. + Weak { + /// The reason why the built shield would be weak. + reason: SecurityShieldBuilderRuleViolation, + }, + + /// The selected factor sources form an invalid combination + /// in the Security Shield building process. + /// Example: Each role must have at least one factor. + Invalid { + reason: SecurityShieldBuilderStatusInvalidReason, + }, +} + +impl HasSampleValues for SecurityShieldBuilderStatus { + fn sample() -> Self { + SecurityShieldBuilderStatus::Strong + } + + fn sample_other() -> Self { + SecurityShieldBuilderStatus::Weak { + reason: SecurityShieldBuilderRuleViolation::RecoveryAndConfirmationFactorsOverlap + } + } +} + +decl_bool_type!(IsPrimaryRoleFactorListEmpty, false); +decl_bool_type!(IsRecoveryRoleFactorListEmpty, false); +decl_bool_type!(IsConfirmationRoleFactorListEmpty, false); +decl_bool_type!(IsAuthSigningFactorMissing, false); + +/// Represents the reason why the `SecurityShieldBuilder` has an invalid status. +/// This struct contains the specific reasons for each component of the security shield builder +/// being invalid. The components include: +/// - Primary role +/// - Recovery role +/// - Confirmation role +/// - Authentication signing +#[derive(Clone, Debug, PartialEq)] +pub struct SecurityShieldBuilderStatusInvalidReason { + pub is_primary_role_factor_list_empty: IsPrimaryRoleFactorListEmpty, + pub is_recovery_role_factor_list_empty: IsRecoveryRoleFactorListEmpty, + pub is_confirmation_role_factor_list_empty: + IsConfirmationRoleFactorListEmpty, + pub is_auth_signing_factor_missing: IsAuthSigningFactorMissing, +} + +impl SecurityShieldBuilderStatusInvalidReason { + pub fn new( + is_primary_role_factor_list_empty: IsPrimaryRoleFactorListEmpty, + is_recovery_role_factor_list_empty: IsRecoveryRoleFactorListEmpty, + is_confirmation_role_factor_list_empty: IsConfirmationRoleFactorListEmpty, + is_auth_signing_factor_missing: IsAuthSigningFactorMissing, + ) -> Option<Self> { + if is_primary_role_factor_list_empty.not() + && is_recovery_role_factor_list_empty.not() + && is_confirmation_role_factor_list_empty.not() + && is_auth_signing_factor_missing.not() + { + return None; + } + + Some(Self { + is_primary_role_factor_list_empty, + is_recovery_role_factor_list_empty, + is_confirmation_role_factor_list_empty, + is_auth_signing_factor_missing, + }) + } +} + +impl HasSampleValues for SecurityShieldBuilderStatusInvalidReason { + fn sample() -> Self { + SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(true), + IsRecoveryRoleFactorListEmpty::default(), + IsConfirmationRoleFactorListEmpty::default(), + IsAuthSigningFactorMissing::default(), + ) + .unwrap() + } + + fn sample_other() -> Self { + SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty::default(), + IsRecoveryRoleFactorListEmpty(true), + IsConfirmationRoleFactorListEmpty(true), + IsAuthSigningFactorMissing::default(), + ) + .unwrap() + } +} + +#[cfg(test)] +mod status_tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = SecurityShieldBuilderStatus; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} + +#[cfg(test)] +mod reason_tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = SecurityShieldBuilderStatusInvalidReason; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } + + #[test] + fn new() { + let invalid_reason = SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty::default(), + IsRecoveryRoleFactorListEmpty::default(), + IsConfirmationRoleFactorListEmpty::default(), + IsAuthSigningFactorMissing::default(), + ); + + assert!(invalid_reason.is_none()); + + let invalid_reason = SecurityShieldBuilderStatusInvalidReason::new( + IsPrimaryRoleFactorListEmpty(true), + IsRecoveryRoleFactorListEmpty::default(), + IsConfirmationRoleFactorListEmpty::default(), + IsAuthSigningFactorMissing::default(), + ); + + assert!(invalid_reason.is_some()); + } +} diff --git a/crates/profile/models/security-structures/src/roles_matrices_structures/selected_primary_threshold_factors_status.rs b/crates/profile/models/security-structures/src/roles_matrices_structures/selected_primary_threshold_factors_status.rs index 7c2dbbecf..6effd04e5 100644 --- a/crates/profile/models/security-structures/src/roles_matrices_structures/selected_primary_threshold_factors_status.rs +++ b/crates/profile/models/security-structures/src/roles_matrices_structures/selected_primary_threshold_factors_status.rs @@ -36,7 +36,7 @@ pub enum SelectedPrimaryThresholdFactorsStatusInvalidReason { factor_source_kind: FactorSourceKind, }, Other { - underlying: SecurityShieldBuilderInvalidReason, + underlying: SecurityShieldBuilderRuleViolation, }, } @@ -49,7 +49,7 @@ impl HasSampleValues for SelectedPrimaryThresholdFactorsStatusInvalidReason { fn sample_other() -> Self { SelectedPrimaryThresholdFactorsStatusInvalidReason::Other { - underlying: SecurityShieldBuilderInvalidReason::PrimaryCannotHaveMultipleDevices, + underlying: SecurityShieldBuilderRuleViolation::PrimaryCannotHaveMultipleDevices, } } } diff --git a/crates/profile/models/security-structures/src/threshold.rs b/crates/profile/models/security-structures/src/threshold.rs index 1769ebe8c..ce84a8ffe 100644 --- a/crates/profile/models/security-structures/src/threshold.rs +++ b/crates/profile/models/security-structures/src/threshold.rs @@ -27,7 +27,11 @@ impl Threshold { /// Returns the selectable values for a threshold. pub fn values(max_threshold: u8) -> Vec<Threshold> { std::iter::once(Threshold::All) - .chain((1..=max_threshold - 1).rev().map(Threshold::Specific)) + .chain( + (1..=max_threshold.saturating_sub(1)) + .rev() + .map(Threshold::Specific), + ) .collect() } } @@ -78,5 +82,8 @@ mod tests { fn values() { let res = SUT::values(3); assert_eq!(res, vec![SUT::All, SUT::Specific(2), SUT::Specific(1)]); + + let res = SUT::values(0); + assert_eq!(res, vec![SUT::All]); } } diff --git a/crates/profile/models/security-structures/src/time_period.rs b/crates/profile/models/security-structures/src/time_period.rs index 4da860f68..fc1e81b27 100644 --- a/crates/profile/models/security-structures/src/time_period.rs +++ b/crates/profile/models/security-structures/src/time_period.rs @@ -11,12 +11,7 @@ pub struct TimePeriod { impl TimePeriod { pub fn with_days(value: u16) -> Self { - if (value % DAYS_PER_YEAR) == 0 { - Self { - value: value / DAYS_PER_YEAR, - unit: TimePeriodUnit::Years, - } - } else if (value % DAYS_PER_WEEK) == 0 { + if (value % DAYS_PER_WEEK) == 0 { Self { value: value / DAYS_PER_WEEK, unit: TimePeriodUnit::Weeks, @@ -33,7 +28,6 @@ impl TimePeriod { match self.unit { TimePeriodUnit::Days => self.value, TimePeriodUnit::Weeks => self.value * DAYS_PER_WEEK, - TimePeriodUnit::Years => self.value * DAYS_PER_YEAR, } } } @@ -74,17 +68,7 @@ mod tests { #[test] fn days_conversion() { - let mut sut = SUT::with_days(DAYS_PER_YEAR); - assert_eq!(sut.days(), DAYS_PER_YEAR); - assert_eq!(sut.value, 1); - assert_eq!(sut.unit, TimePeriodUnit::Years); - - sut = SUT::with_days(1095); - assert_eq!(sut.days(), 1095); - assert_eq!(sut.value, 3); - assert_eq!(sut.unit, TimePeriodUnit::Years); - - sut = SUT::with_days(DAYS_PER_WEEK); + let mut sut = SUT::with_days(DAYS_PER_WEEK); assert_eq!(sut.days(), DAYS_PER_WEEK); assert_eq!(sut.value, 1); assert_eq!(sut.unit, TimePeriodUnit::Weeks); diff --git a/crates/profile/models/security-structures/src/time_period_unit.rs b/crates/profile/models/security-structures/src/time_period_unit.rs index 12d34d177..4232ed9a5 100644 --- a/crates/profile/models/security-structures/src/time_period_unit.rs +++ b/crates/profile/models/security-structures/src/time_period_unit.rs @@ -7,7 +7,6 @@ use crate::prelude::*; pub enum TimePeriodUnit { Days, Weeks, - Years, } impl HasSampleValues for TimePeriodUnit { diff --git a/crates/profile/models/supporting-types/Cargo.toml b/crates/profile/models/supporting-types/Cargo.toml index fffa90954..64ccd85cc 100644 --- a/crates/profile/models/supporting-types/Cargo.toml +++ b/crates/profile/models/supporting-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-supporting-types" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/profile/traits/entity-by-address/Cargo.toml b/crates/profile/traits/entity-by-address/Cargo.toml index b2a08ac6e..6f45a8ba5 100644 --- a/crates/profile/traits/entity-by-address/Cargo.toml +++ b/crates/profile/traits/entity-by-address/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "entity-by-address" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index a850a7f52..4b6e6c6e5 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon" -version = "1.1.112" +version = "1.1.113" edition = "2021" resolver = "2" # features enabled in integration test diff --git a/crates/system/clients/clients/Cargo.toml b/crates/system/clients/clients/Cargo.toml index cb705272e..75532ec8e 100644 --- a/crates/system/clients/clients/Cargo.toml +++ b/crates/system/clients/clients/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clients" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/system/clients/http/Cargo.toml b/crates/system/clients/http/Cargo.toml index 1878d1308..476b3ea68 100644 --- a/crates/system/clients/http/Cargo.toml +++ b/crates/system/clients/http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http-client" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/drivers/Cargo.toml b/crates/system/drivers/Cargo.toml index 099b47978..33eec3c42 100644 --- a/crates/system/drivers/Cargo.toml +++ b/crates/system/drivers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drivers" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/system/interactors/Cargo.toml b/crates/system/interactors/Cargo.toml index 61490c10e..ca20538ea 100644 --- a/crates/system/interactors/Cargo.toml +++ b/crates/system/interactors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "interactors" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/accounts/Cargo.toml b/crates/system/os/accounts/Cargo.toml index c9ad805bf..a00b67434 100644 --- a/crates/system/os/accounts/Cargo.toml +++ b/crates/system/os/accounts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os-accounts" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/factors/Cargo.toml b/crates/system/os/factors/Cargo.toml index 3ba57b77d..fe75615cd 100644 --- a/crates/system/os/factors/Cargo.toml +++ b/crates/system/os/factors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os-factors" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/factors/src/sargon_os_security_structures.rs b/crates/system/os/factors/src/sargon_os_security_structures.rs index 5d0937460..5117eaf6e 100644 --- a/crates/system/os/factors/src/sargon_os_security_structures.rs +++ b/crates/system/os/factors/src/sargon_os_security_structures.rs @@ -34,7 +34,7 @@ pub trait OsSecurityStructuresQuerying { async fn add_security_structure_of_factor_source_ids( &self, structure_ids: &SecurityStructureOfFactorSourceIDs, - ) -> Result<bool>; + ) -> Result<()>; } #[async_trait::async_trait] @@ -97,7 +97,7 @@ impl OsSecurityStructuresQuerying for SargonOS { /// If `structure` references a FactorSource by ID which is unknown to Profile, /// `Err(CommonError::StructureReferencesUnknownFactorSource)` is returned. /// - /// If Profile already contains a structure with the same ID, `Ok(false)` is + /// If Profile already contains a structure with the same ID, `Err(CommonError::)` is /// returned **without** modifying the existing one. /// /// # Emits Events @@ -108,7 +108,7 @@ impl OsSecurityStructuresQuerying for SargonOS { async fn add_security_structure_of_factor_source_ids( &self, structure_ids: &SecurityStructureOfFactorSourceIDs, - ) -> Result<bool> { + ) -> Result<()> { let id = structure_ids.metadata.id; let ids_of_factors_in_profile = self.factor_source_ids()?; let ids_in_structure = structure_ids @@ -139,14 +139,18 @@ impl OsSecurityStructuresQuerying for SargonOS { }) .await?; - if inserted { - self.event_bus - .emit(EventNotification::profile_modified( - EventProfileModified::SecurityStructureAdded { id }, - )) - .await; + if !inserted { + return Err(CommonError::StructureAlreadyExists { + bad_value: id.to_string(), + }); } - Ok(inserted) + + self.event_bus + .emit(EventNotification::profile_modified( + EventProfileModified::SecurityStructureAdded { id }, + )) + .await; + Ok(()) } } @@ -217,7 +221,7 @@ mod tests { // ACT let structure_factor_id_level = SecurityStructureOfFactorSourceIDs::sample(); - let inserted = os + let _ = os .with_timeout(|x| { x.add_security_structure_of_factor_source_ids( &structure_factor_id_level, @@ -227,7 +231,6 @@ mod tests { .unwrap(); // ASSERT - assert!(inserted); assert!(os .profile() .unwrap() @@ -319,7 +322,7 @@ mod tests { // ACT let structure_ids = SecurityStructureOfFactorSourceIDs::sample(); let id = structure_ids.metadata.id; - let inserted = os + let _ = os .with_timeout(|x| { x.add_security_structure_of_factor_source_ids(&structure_ids) }) @@ -327,7 +330,6 @@ mod tests { .unwrap(); // ASSERT - assert!(inserted); assert!(event_bus_driver.recorded().iter().any(|e| e.event == Event::ProfileModified { change: EventProfileModified::SecurityStructureAdded { id } @@ -348,7 +350,7 @@ mod tests { SecurityStructureOfFactorSourceIDs::sample(); let structure_source_ids_sample_other = SecurityStructureOfFactorSourceIDs::sample_other(); - let inserted = os + let _ = os .with_timeout(|x| { x.add_security_structure_of_factor_source_ids( &structure_source_ids_sample, @@ -356,9 +358,22 @@ mod tests { }) .await .unwrap(); - assert!(inserted); - let inserted = os + let result = os + .with_timeout(|x| { + x.add_security_structure_of_factor_source_ids( + &structure_source_ids_sample, + ) + }) + .await; + assert_eq!( + result, + Err(CommonError::StructureAlreadyExists { + bad_value: structure_source_ids_sample.metadata.id.to_string() + }) + ); + + let _ = os .with_timeout(|x| { x.add_security_structure_of_factor_source_ids( &structure_source_ids_sample_other, @@ -366,7 +381,6 @@ mod tests { }) .await .unwrap(); - assert!(inserted); let structure_id_sample = SecurityStructureOfFactorSourceIDs::from( structure_source_ids_sample.clone(), diff --git a/crates/system/os/os/Cargo.toml b/crates/system/os/os/Cargo.toml index dd32d9198..273ab794a 100644 --- a/crates/system/os/os/Cargo.toml +++ b/crates/system/os/os/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/security-center/Cargo.toml b/crates/system/os/security-center/Cargo.toml index cb8366184..fb7a6f73b 100644 --- a/crates/system/os/security-center/Cargo.toml +++ b/crates/system/os/security-center/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os-security-center" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/signing/Cargo.toml b/crates/system/os/signing/Cargo.toml index 7b10495ec..dfa1138c4 100644 --- a/crates/system/os/signing/Cargo.toml +++ b/crates/system/os/signing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os-signing" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/os/transaction/Cargo.toml b/crates/system/os/transaction/Cargo.toml index 34b78845e..339fee854 100644 --- a/crates/system/os/transaction/Cargo.toml +++ b/crates/system/os/transaction/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-os-transaction" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/profile-state-holder/Cargo.toml b/crates/system/profile-state-holder/Cargo.toml index 59dc46744..f398c37f7 100644 --- a/crates/system/profile-state-holder/Cargo.toml +++ b/crates/system/profile-state-holder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "profile-state-holder" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/system/sub-systems/Cargo.toml b/crates/system/sub-systems/Cargo.toml index 899e082a1..569aeb37a 100644 --- a/crates/system/sub-systems/Cargo.toml +++ b/crates/system/sub-systems/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sub-systems" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/transaction/foundation/Cargo.toml b/crates/transaction/foundation/Cargo.toml index d1e30dedc..3c9352dfa 100644 --- a/crates/transaction/foundation/Cargo.toml +++ b/crates/transaction/foundation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "transaction-foundation" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/transaction/manifests/Cargo.toml b/crates/transaction/manifests/Cargo.toml index c1cb3146e..765e55948 100644 --- a/crates/transaction/manifests/Cargo.toml +++ b/crates/transaction/manifests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "manifests" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/transaction/models/Cargo.toml b/crates/transaction/models/Cargo.toml index 97c1e5a2b..8f594a363 100644 --- a/crates/transaction/models/Cargo.toml +++ b/crates/transaction/models/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "transaction-models" -version = "1.1.112" +version = "1.1.113" edition = "2021" diff --git a/crates/uniffi/conversion-macros/Cargo.toml b/crates/uniffi/conversion-macros/Cargo.toml index 7854a0219..233b5505e 100644 --- a/crates/uniffi/conversion-macros/Cargo.toml +++ b/crates/uniffi/conversion-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon-uniffi-conversion-macros" -version = "1.1.112" +version = "1.1.113" edition = "2021" [dependencies] diff --git a/crates/uniffi/uniffi_SPLIT_ME/Cargo.toml b/crates/uniffi/uniffi_SPLIT_ME/Cargo.toml index 66bb23381..0241262d5 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/Cargo.toml +++ b/crates/uniffi/uniffi_SPLIT_ME/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sargon-uniffi" -version = "1.1.112" +version = "1.1.113" edition = "2021" build = "build.rs" diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/core/error/common_error.rs b/crates/uniffi/uniffi_SPLIT_ME/src/core/error/common_error.rs index 55cb29acd..35f9627cc 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/core/error/common_error.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/core/error/common_error.rs @@ -102,6 +102,12 @@ pub enum CommonError { bad_value: String, }, SigningFailedTooManyFactorSourcesNeglected, + GatewaySubmitDuplicateTX { + intent_hash: String, + }, + UnableToLoadMnemonicFromSecureStorage { + bad_value: String, + }, } #[uniffi::export] @@ -307,6 +313,16 @@ impl CommonError { SigningFailedTooManyFactorSourcesNeglected => { InternalCommonError::SigningFailedTooManyFactorSourcesNeglected } + GatewaySubmitDuplicateTX { intent_hash } => { + InternalCommonError::GatewaySubmitDuplicateTX { + intent_hash: intent_hash.clone(), + } + } + UnableToLoadMnemonicFromSecureStorage { bad_value } => { + InternalCommonError::UnableToLoadMnemonicFromSecureStorage { + bad_value: bad_value.clone(), + } + } _ => InternalCommonError::Unknown, } } diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/mod.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/mod.rs index 8bb95fd1e..47c24732a 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/mod.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/mod.rs @@ -2,7 +2,8 @@ mod matrices; mod models; mod roles; mod security_shield_builder; -mod security_shield_builder_invalid_reason; +mod security_shield_builder_rule_violation; +mod security_shield_builder_status; mod security_shield_prerequisites_status; mod security_structure_id; mod security_structure_metadata; @@ -12,7 +13,8 @@ mod selected_primary_threshold_factors_status; pub use matrices::*; pub use models::*; pub use roles::*; -pub use security_shield_builder_invalid_reason::*; +pub use security_shield_builder_rule_violation::*; +pub use security_shield_builder_status::*; pub use security_shield_prerequisites_status::*; pub use security_structure_id::*; pub use security_structure_metadata::*; diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/factor_source_in_role_builder_validation_status.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/factor_source_in_role_builder_validation_status.rs index f00dabf0f..49badeaac 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/factor_source_in_role_builder_validation_status.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/factor_source_in_role_builder_validation_status.rs @@ -16,7 +16,7 @@ pub struct FactorSourceValidationStatus { #[derive(Clone, Debug, PartialEq, uniffi::Enum)] pub enum FactorSourceValidationStatusReasonIfInvalid { BasicViolation(String), - NonBasic(SecurityShieldBuilderInvalidReason), + NonBasic(SecurityShieldBuilderRuleViolation), } impl From<sargon::FactorSourceInRoleBuilderValidationStatus> @@ -35,7 +35,7 @@ impl From<sargon::FactorSourceInRoleBuilderValidationStatus> ), Err(sargon::RoleBuilderValidation::ForeverInvalid(v)) => v .as_shield_validation() - .map(SecurityShieldBuilderInvalidReason::from) + .map(SecurityShieldBuilderRuleViolation::from) .map(|x| { FactorSourceValidationStatusReasonIfInvalid::NonBasic(x) }), @@ -43,7 +43,7 @@ impl From<sargon::FactorSourceInRoleBuilderValidationStatus> val.role, v, ) .as_shield_validation() - .map(SecurityShieldBuilderInvalidReason::from) + .map(SecurityShieldBuilderRuleViolation::from) .map(|x| { FactorSourceValidationStatusReasonIfInvalid::NonBasic(x) }), diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/time_period_unit.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/time_period_unit.rs index 7a91bd6a1..11bd28a0a 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/time_period_unit.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/models/time_period_unit.rs @@ -9,5 +9,4 @@ use sargon::TimePeriodUnit as InternalTimePeriodUnit; pub enum TimePeriodUnit { Days, Weeks, - Years, } diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder.rs index 3f8bad36e..c80a19c99 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder.rs @@ -457,14 +457,10 @@ impl SecurityShieldBuilder { #[uniffi::export] impl SecurityShieldBuilder { - pub fn validate(&self) -> Option<SecurityShieldBuilderInvalidReason> { - self.get(|builder| builder.validate().map(|x| x.into())) - } - pub fn validate_role_in_isolation( &self, role: RoleKind, - ) -> Option<SecurityShieldBuilderInvalidReason> { + ) -> Option<SecurityShieldBuilderRuleViolation> { self.get(|builder| { builder .validate_role_in_isolation(role.into_internal()) @@ -472,6 +468,10 @@ impl SecurityShieldBuilder { }) } + pub fn status(&self) -> SecurityShieldBuilderStatus { + self.get(|builder| builder.status().into()) + } + pub fn selected_primary_threshold_factors_status( &self, ) -> SelectedPrimaryThresholdFactorsStatus { @@ -497,7 +497,7 @@ impl SecurityShieldBuilder { &self, ) -> Result< SecurityStructureOfFactorSourceIDs, - SecurityShieldBuilderInvalidReason, + SecurityShieldBuilderRuleViolation, > { self.get(|builder| builder.build()) .map(|shield| shield.into()) @@ -906,8 +906,16 @@ mod tests { assert_eq!(xs, sut.clone().get_confirmation_factors()); assert_eq!( - sut.validate().unwrap(), - SecurityShieldBuilderInvalidReason::MissingAuthSigningFactor + sut.status(), + SecurityShieldBuilderStatus::Invalid { + reason: SecurityShieldBuilderStatusInvalidReason { + is_primary_role_factor_list_empty: false, + is_recovery_role_factor_list_empty: false, + is_confirmation_role_factor_list_empty: false, + is_auth_signing_factor_missing: true + } + } + .into() ); sut = sut.set_authentication_signing_factor(Some( FactorSourceID::sample_device_other(), @@ -917,9 +925,9 @@ mod tests { Some(FactorSourceID::sample_device_other()) ); - let v0 = sut.validate(); - let v1 = sut.validate(); // can call validate many times! - assert_eq!(v0, v1); + let s0 = sut.status(); + let s1 = sut.status(); // can call status many times! + assert_eq!(s0, s1); let shield0 = sut.clone().build().unwrap(); let shield = sut.clone().build().unwrap(); // can call build many times! diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_rule_violation.rs similarity index 95% rename from crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs rename to crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_rule_violation.rs index 56eb64369..6fddd6ad2 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_invalid_reason.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_rule_violation.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use sargon::SecurityShieldBuilderInvalidReason as InternalSecurityShieldBuilderInvalidReason; +use sargon::SecurityShieldBuilderRuleViolation as InternalSecurityShieldBuilderRuleViolation; use thiserror::Error as ThisError; @@ -7,7 +7,7 @@ use thiserror::Error as ThisError; #[derive( Clone, Debug, ThisError, PartialEq, InternalConversion, uniffi::Error, )] -pub enum SecurityShieldBuilderInvalidReason { +pub enum SecurityShieldBuilderRuleViolation { #[error("Auth Signing Factor Missing")] MissingAuthSigningFactor, diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_status.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_status.rs new file mode 100644 index 000000000..380661f94 --- /dev/null +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/security_shield_builder_status.rs @@ -0,0 +1,41 @@ +use crate::prelude::*; +use sargon::SecurityShieldBuilderStatus as InternalSecurityShieldBuilderStatus; +use sargon::SecurityShieldBuilderStatusInvalidReason as InternalSecurityShieldBuilderStatusInvalidReason; + +/// Represents the status of `SecurityShieldBuilder`. +/// Used for UI representation in host applications. +#[derive(Clone, Debug, PartialEq, InternalConversion, uniffi::Enum)] +pub enum SecurityShieldBuilderStatus { + /// The selected factor sources form a strong combination + /// in the Security Shield building process. + Strong, + + /// The selected factor sources form a weak combination + /// in the Security Shield building process. + Weak { + /// The reason why the built shield would be weak. + reason: SecurityShieldBuilderRuleViolation, + }, + + /// The selected factor sources form an invalid combination + /// in the Security Shield building process. + /// Example: Each role must have at least one factor. + Invalid { + reason: SecurityShieldBuilderStatusInvalidReason, + }, +} + +/// Represents the reason why the `SecurityShieldBuilder` has an invalid status. +/// This struct contains the specific reasons for each component of the security shield builder +/// being invalid. The components include: +/// - Primary role +/// - Recovery role +/// - Confirmation role +/// - Authentication signing +#[derive(Clone, Debug, PartialEq, InternalConversion, uniffi::Record)] +pub struct SecurityShieldBuilderStatusInvalidReason { + pub is_primary_role_factor_list_empty: bool, + pub is_recovery_role_factor_list_empty: bool, + pub is_confirmation_role_factor_list_empty: bool, + pub is_auth_signing_factor_missing: bool, +} diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/selected_primary_threshold_factors_status.rs b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/selected_primary_threshold_factors_status.rs index 20cf7fe0d..a51214ac7 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/selected_primary_threshold_factors_status.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/profile/mfa/security_structures/selected_primary_threshold_factors_status.rs @@ -38,6 +38,6 @@ pub enum SelectedPrimaryThresholdFactorsStatusInvalidReason { factor_source_kind: FactorSourceKind, }, Other { - underlying: SecurityShieldBuilderInvalidReason, + underlying: SecurityShieldBuilderRuleViolation, }, } diff --git a/crates/uniffi/uniffi_SPLIT_ME/src/system/sargon_os/sargon_os_security_structures.rs b/crates/uniffi/uniffi_SPLIT_ME/src/system/sargon_os/sargon_os_security_structures.rs index 0a691663a..a8c375820 100644 --- a/crates/uniffi/uniffi_SPLIT_ME/src/system/sargon_os/sargon_os_security_structures.rs +++ b/crates/uniffi/uniffi_SPLIT_ME/src/system/sargon_os/sargon_os_security_structures.rs @@ -52,7 +52,7 @@ impl SargonOS { pub async fn add_security_structure_of_factor_source_ids( &self, structure_ids: &SecurityStructureOfFactorSourceIDs, - ) -> Result<bool> { + ) -> Result<()> { self.wrapped .add_security_structure_of_factor_source_ids( &structure_ids.into_internal(), diff --git a/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/SharedConstants.kt b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/SharedConstants.kt index 6aeaccd2b..213122ffc 100644 --- a/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/SharedConstants.kt +++ b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/SharedConstants.kt @@ -25,5 +25,6 @@ val Account.Companion.nameMaxLength: Long val Persona.Companion.nameMaxLength: Long get() = entityNameMaxLength +@KoverIgnore val DisplayName.Companion.maxLength: Long get() = displayNameMaxLength \ No newline at end of file