diff --git a/crates/rules/src/rules/has_rule_set_for_role.rs b/crates/rules/src/rules/has_rule_set_for_role.rs index bdf63110..79d8d016 100644 --- a/crates/rules/src/rules/has_rule_set_for_role.rs +++ b/crates/rules/src/rules/has_rule_set_for_role.rs @@ -1,7 +1,22 @@ use crate::prelude::*; +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FactorRulesFailure { + Specific(E), + + Basic(FactorRulesFailureBasic), +} + +#[derive(Clone, Debug, PartialEq, Eq, ThisError)] +pub enum FactorRulesFailureBasic { + #[error("Threshold may not be larger than the number of factors in the threshold list")] + ThresholdTooLarge, +} + pub trait HasRuleSetForRole: Sized + IsRole + Clone { - type Violation; + type Violation: std::fmt::Debug; + type Failure = FactorRulesFailure; + type Result = std::result::Result<(), Self::Failure>; /// Neither Recovery nor Confirmation roles can have factors added to their threshold /// factor list. Only Primary supports it. @@ -54,10 +69,24 @@ pub trait HasRuleSetForRole: Sized + IsRole + Clone { Self::_do_validate(context, Self::validate_password_in_factors_list_of_kind) } - fn validate(context: &RoleWithFactorsBuilt) -> FactorBuilderResult { - Self::validate_device(context)?; - Self::validate_ledger(context)?; - Self::validate_password(context)?; - Ok(()) + fn validate(context: &RoleWithFactorsBuilt) -> Self::Result { + if context.threshold > context.threshold_factors.len() as u8 { + // return FactorBuilderResult::not_yet_valid( + // Self::violation_if_adding_factors_to_threshold().unwrap(), + // ); + // return Self::Result::Err(Self::Failure::Basic( + // FactorRulesFailureBasic::ThresholdTooLarge, + // )); + let basic: FactorBuilderResult<> + let failure: Self::Failure = + Self::Failure::Basic(FactorRulesFailureBasic::ThresholdTooLarge); + let res: Self::Result = Self::Result::Err(failure); + return res; + } + + // Self::validate_device(context)?; + // Self::validate_ledger(context)?; + // Self::validate_password(context)?; + Self::Result::Ok(()) } } diff --git a/crates/rules/src/rules/mod.rs b/crates/rules/src/rules/mod.rs index 866a11f4..b2d1233e 100644 --- a/crates/rules/src/rules/mod.rs +++ b/crates/rules/src/rules/mod.rs @@ -3,7 +3,6 @@ mod factor_rules_violation; mod has_rule_set_for_role; mod is_role; // mod matrix; -mod primary_role_with_factor_source_rule_set; mod primary_role_with_factor_sources_builder; mod role_builder_or_built; mod role_kind; @@ -15,7 +14,6 @@ pub use factor_rules_violation::*; pub use has_rule_set_for_role::*; pub use is_role::*; // pub use matrix::*; -pub use primary_role_with_factor_source_rule_set::*; #[allow(unused_imports)] pub use primary_role_with_factor_sources_builder::*; diff --git a/crates/rules/src/rules/primary_role_with_factor_source_rule_set.rs b/crates/rules/src/rules/primary_role_with_factor_source_rule_set.rs deleted file mode 100644 index 73832999..00000000 --- a/crates/rules/src/rules/primary_role_with_factor_source_rule_set.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PrimaryRoleWithFactorSourceRuleSet; -impl IsRole for PrimaryRoleWithFactorSourceRuleSet { - fn role_kind() -> RoleKind { - RoleKind::Primary - } -} - -impl HasRuleSetForRole for PrimaryRoleWithFactorSourceRuleSet { - type Violation = PrimaryRoleViolation; - - fn violation_if_adding_factors_to_threshold() -> Option { - None - } - - fn validate_device_in_factors_list_of_kind( - context: &RoleWithFactorsBuilt, - _list_kind: FactorListKind, - ) -> FactorBuilderResult { - let kind = FactorSourceKind::Device; - if context.count_factors_of_kind_in_any_list(kind) > 1 { - return Err(FactorRulesViolation::ForeverInvalid( - Self::Violation::MoreThanOneDeviceFactorIsNotSupported, - )); - } - Ok(()) - } - - fn validate_password_in_factors_list_of_kind( - context: &RoleWithFactorsBuilt, - list_kind: FactorListKind, - ) -> FactorBuilderResult { - let kind = FactorSourceKind::Password; - - if context.has_factor_of_kind_in_list_of_kind(kind, list_kind) { - if list_kind == FactorListKind::Override { - return FactorBuilderResult::not_yet_valid( - PrimaryRoleViolation::PasswordNotAllowedInOverrideListSinceItWouldBeAlone, - ); - } - - if !context.has_factor_not_of_kind_in_list_of_kind(kind, list_kind) { - return FactorBuilderResult::not_yet_valid( - PrimaryRoleViolation::PasswordMustNotBeAlone, - ); - } - - if list_kind == FactorListKind::Threshold && context.threshold < 2 { - return FactorBuilderResult::not_yet_valid( - PrimaryRoleViolation::PasswordRequiresThresholdOfAtLeastTwo, - ); - } - } - - Ok(()) - } - - fn validate_ledger_in_factors_list_of_kind( - _context: &RoleWithFactorsBuilt, - _list_kind: FactorListKind, - ) -> FactorBuilderResult { - // let kind = FactorSourceKind::Ledger; - // No restrictions - Ok(()) - } -} diff --git a/crates/rules/src/rules/primary_role_with_factor_sources_builder.rs b/crates/rules/src/rules/primary_role_with_factor_sources_builder.rs index 96053d66..7ea21efb 100644 --- a/crates/rules/src/rules/primary_role_with_factor_sources_builder.rs +++ b/crates/rules/src/rules/primary_role_with_factor_sources_builder.rs @@ -2,6 +2,70 @@ use crate::prelude::*; +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PrimaryRoleWithFactorSourceRuleSet; +impl IsRole for PrimaryRoleWithFactorSourceRuleSet { + fn role_kind() -> RoleKind { + RoleKind::Primary + } +} + +impl HasRuleSetForRole for PrimaryRoleWithFactorSourceRuleSet { + type Violation = PrimaryRoleViolation; + + fn violation_if_adding_factors_to_threshold() -> Option { + None + } + + fn validate_device_in_factors_list_of_kind( + context: &RoleWithFactorsBuilt, + _list_kind: FactorListKind, + ) -> FactorBuilderResult { + let kind = FactorSourceKind::Device; + if context.count_factors_of_kind_in_any_list(kind) > 1 { + return Err(FactorRulesViolation::ForeverInvalid( + Self::Violation::MoreThanOneDeviceFactorIsNotSupported, + )); + } + Ok(()) + } + + fn validate_password_in_factors_list_of_kind( + context: &RoleWithFactorsBuilt, + list_kind: FactorListKind, + ) -> FactorBuilderResult { + let kind = FactorSourceKind::Password; + + if context.has_factor_of_kind_in_list_of_kind(kind, list_kind) { + if list_kind == FactorListKind::Override { + return FactorBuilderResult::forever_invalid( + PrimaryRoleViolation::PasswordNotAllowedInOverrideListSinceItWouldBeAlone, + ); + } + + if !context.has_factor_not_of_kind_in_list_of_kind(kind, list_kind) { + return FactorBuilderResult::not_yet_valid( + PrimaryRoleViolation::PasswordMustNotBeAlone, + ); + } + + if list_kind == FactorListKind::Threshold && context.threshold < 2 { + return FactorBuilderResult::not_yet_valid( + PrimaryRoleViolation::PasswordRequiresThresholdOfAtLeastTwo, + ); + } + } + Ok(()) + } + + fn validate_ledger_in_factors_list_of_kind( + _context: &RoleWithFactorsBuilt, + _list_kind: FactorListKind, + ) -> FactorBuilderResult { + Ok(()) // No restrictions + } +} + pub type PrimaryRoleWithFactorSourcesBuilder = RoleWithFactorsBuilder; @@ -10,30 +74,43 @@ mod tests { use super::*; #[test] - fn add_device_to_threshold_then_build() { + fn single_device_in_threshold_is_ok() { + type F = FactorSource; + type SUT = PrimaryRoleWithFactorSourcesBuilder; + let mut sut = SUT::new(); + + let f = F::sample_device(); + sut.add_to_threshold(&f).unwrap(); + let built = sut.build().unwrap(); + assert_eq!(built.threshold_factors, vec![f]) + } + + #[test] + fn threshold_cannot_be_larger_than_threshold_factor_count() { type F = FactorSource; type SUT = PrimaryRoleWithFactorSourcesBuilder; let mut sut = SUT::new(); let f = F::sample_device(); sut.add_to_threshold(&f).unwrap(); + sut.set_threshold(2); let built = sut.build().unwrap(); assert_eq!(built.threshold_factors, vec![f]) } + #[test] fn add_password_to_override_then_build() { type F = FactorSource; type SUT = PrimaryRoleWithFactorSourcesBuilder; - type Result = SUT::BuildResult; + type MutResult = SUT::MutateResult; let mut sut = SUT::new(); let f = F::sample_password(); - sut.add_to_override(&f).unwrap(); assert_eq!( - sut.build(), - Result::not_yet_valid( + sut.add_to_override(&f), + MutResult::forever_invalid( PrimaryRoleViolation::PasswordNotAllowedInOverrideListSinceItWouldBeAlone ) ); diff --git a/crates/rules/src/rules/role_builder_or_built.rs b/crates/rules/src/rules/role_builder_or_built.rs index eae976fc..73bc85a5 100644 --- a/crates/rules/src/rules/role_builder_or_built.rs +++ b/crates/rules/src/rules/role_builder_or_built.rs @@ -32,6 +32,7 @@ where } pub type Built = RoleWithFactorsBuilt; + pub type MutateResult = FactorBuilderResult; pub type BuildResult = Result; pub fn build(self) -> Self::BuildResult { @@ -47,28 +48,32 @@ where ) } - pub fn add_to_override(&mut self, factor: impl Borrow) -> FactorBuilderResult { + pub fn add_to_override(&mut self, factor: impl Borrow) -> Self::MutateResult { self.add_to_list(factor, FactorListKind::Override) } - pub fn add_to_threshold( - &mut self, - factor: impl Borrow, - ) -> FactorBuilderResult { + pub fn add_to_threshold(&mut self, factor: impl Borrow) -> Self::MutateResult { self.add_to_list(factor, FactorListKind::Threshold) } - fn validate(&self) -> FactorBuilderResult { - R::validate(&self.snapshot()) + pub fn set_threshold(&mut self, threshold: u8) -> Self::MutateResult { + let mut simulation = self.clone(); + simulation.threshold = threshold; + simulation.validate() + } + + fn validate(&self) -> Self::MutateResult { + // R::validate(&self.snapshot()) + todo!() } fn violation_if_add_factor_to_list_of_kind( &self, factor: &F, list_kind: FactorListKind, - ) -> FactorBuilderResult { + ) -> Self::MutateResult { if let Some(violation) = R::violation_if_adding_factors_to_threshold() { - return FactorBuilderResult::Err(FactorRulesViolation::ForeverInvalid(violation)); + return Self::MutateResult::Err(FactorRulesViolation::ForeverInvalid(violation)); } let factor = factor.clone(); @@ -85,7 +90,7 @@ where &mut self, factor: impl Borrow, list_kind: FactorListKind, - ) -> FactorBuilderResult { + ) -> Self::MutateResult { let factor = factor.borrow(); let outcome = self.violation_if_add_factor_to_list_of_kind(factor, list_kind); match outcome.as_ref() { @@ -100,7 +105,7 @@ where FactorListKind::Override => self.override_factors.push(factor), FactorListKind::Threshold => self.threshold_factors.push(factor), } - FactorBuilderResult::Ok(()) + Self::MutateResult::Ok(()) } }