From b8570a94fadc8344179ff92929dad66157147a74 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 22 Nov 2024 14:41:10 +0100 Subject: [PATCH] WIP --- crates/rules/src/lib.rs | 2 +- crates/rules/src/rules/error.rs | 8 +-- .../rules/src/rules/factor_rules_violation.rs | 49 +++++++------------ .../rules/src/rules/has_rule_set_for_role.rs | 23 +++++++-- ...rimary_role_with_factor_source_rule_set.rs | 35 +++++++++++++ ...rimary_role_with_factor_sources_builder.rs | 7 ++- .../rules/src/rules/role_builder_or_built.rs | 48 +++++++++++++++--- crates/rules/src/rules/sargon_types.rs | 25 +++++----- 8 files changed, 136 insertions(+), 61 deletions(-) diff --git a/crates/rules/src/lib.rs b/crates/rules/src/lib.rs index 56519251..637be208 100644 --- a/crates/rules/src/lib.rs +++ b/crates/rules/src/lib.rs @@ -1,5 +1,5 @@ #![feature(associated_type_defaults)] -// #![feature(inherent_associated_types)] +#![feature(inherent_associated_types)] mod rules; diff --git a/crates/rules/src/rules/error.rs b/crates/rules/src/rules/error.rs index 72d10ef4..404b5778 100644 --- a/crates/rules/src/rules/error.rs +++ b/crates/rules/src/rules/error.rs @@ -2,10 +2,4 @@ use crate::prelude::*; -pub type Result = std::result::Result; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, ThisError)] -pub enum Error { - #[error("Unknown")] - Unknown, -} +pub type Result = std::result::Result>; diff --git a/crates/rules/src/rules/factor_rules_violation.rs b/crates/rules/src/rules/factor_rules_violation.rs index 764a86c5..8437896b 100644 --- a/crates/rules/src/rules/factor_rules_violation.rs +++ b/crates/rules/src/rules/factor_rules_violation.rs @@ -3,53 +3,42 @@ use crate::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FactorRulesViolation { - NotYetValid(N), - ForeverInvalid(F), +pub enum FactorRulesViolation { + NotYetValid(E), + ForeverInvalid(E), } -pub trait CanBeNotYetValid { - fn not_yet_valid(violation: N) -> FactorBuilderResult; +pub trait CanBeNotYetValid { + fn not_yet_valid(violation: E) -> Self; } -pub trait CanBeForeverInvalid { - fn forever_invalid(violation: F) -> FactorBuilderResult; +pub trait CanBeForeverInvalid { + fn forever_invalid(violation: E) -> Self; } -pub type FactorBuilderResult = std::result::Result<(), FactorRulesViolation>; +pub type FactorBuilderResult = std::result::Result<(), FactorRulesViolation>; -impl CanBeNotYetValid for FactorBuilderResult { - fn not_yet_valid(violation: N) -> FactorBuilderResult { - FactorBuilderResult::Err(FactorRulesViolation::NotYetValid(violation)) +impl CanBeNotYetValid for std::result::Result> { + fn not_yet_valid(violation: E) -> Self { + std::result::Result::Err(FactorRulesViolation::NotYetValid(violation)) } } - -impl CanBeForeverInvalid for FactorBuilderResult { - fn forever_invalid(violation: F) -> FactorBuilderResult { - FactorBuilderResult::Err(FactorRulesViolation::ForeverInvalid(violation)) +impl CanBeForeverInvalid for std::result::Result> { + fn forever_invalid(violation: E) -> Self { + std::result::Result::Err(FactorRulesViolation::ForeverInvalid(violation)) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, ThisError)] -pub enum PrimaryForeverInvalid { +pub enum PrimaryRoleViolation { + // ====== FOREVER INVALID ======= #[error("More than one device factor is not supported")] MoreThanOneDeviceFactorIsNotSupported, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, ThisError)] -pub enum PrimaryNotYetValid { + // ====== NOT YET VALID ======= #[error("Password must not be alone")] PasswordMustNotBeAlone, - #[error("Password requires threshold to be at least two")] - PasswordRequiresThresholdToBeAtLeastTwo, + #[error("Password requires a threshold of at at least two")] + PasswordRequiresThresholdOfAtLeastTwo, } - -pub type PRV = FactorBuilderResult; -pub struct PrimaryRoleViolation; -impl CanBeForeverInvalid for PrimaryRoleViolation { - fn forever_invalid(violation: PrimaryForeverInvalid) -> PRV { - PRV::Err(FactorRulesViolation::ForeverInvalid(violation)) - } -} \ No newline at end of file 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 ffc1ef38..57e86e76 100644 --- a/crates/rules/src/rules/has_rule_set_for_role.rs +++ b/crates/rules/src/rules/has_rule_set_for_role.rs @@ -6,6 +6,7 @@ pub trait HasRuleSetForRole: Sized + IsRole { /// Neither Recovery nor Confirmation roles can have factors added to their threshold /// factor list. Only Primary supports it. fn violation_if_adding_factors_to_threshold() -> Option; + fn violation_if_add_factor_to_list_of_kind( context: RoleWithFactorsBuilt, @@ -20,10 +21,12 @@ pub trait HasRuleSetForRole: Sized + IsRole { FactorSourceKind::Device => { Self::violation_if_device_factor_to_list_of_kind(&context, factor, list_kind)? } - FactorSourceKind::Ledger => {} - FactorSourceKind::Password => {} - FactorSourceKind::SecurityQuestions => {} - FactorSourceKind::OffDeviceMnemonic => {} + FactorSourceKind::Ledger => { + Self::violation_if_ledger_factor_to_list_of_kind(&context, factor, list_kind)? + } + FactorSourceKind::Password => { + Self::violation_if_password_factor_to_list_of_kind(&context, factor, list_kind)? + } } Ok(()) } @@ -33,4 +36,16 @@ pub trait HasRuleSetForRole: Sized + IsRole { factor: &F, list_kind: FactorListKind, ) -> FactorBuilderResult; + + fn violation_if_password_factor_to_list_of_kind( + context: &RoleWithFactorsBuilt, + factor: &F, + list_kind: FactorListKind, + ) -> FactorBuilderResult; + + fn violation_if_ledger_factor_to_list_of_kind( + context: &RoleWithFactorsBuilt, + factor: &F, + list_kind: FactorListKind, + ) -> FactorBuilderResult; } 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 index 1e1f1c8c..30d7a1ae 100644 --- 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 @@ -1,5 +1,6 @@ use crate::prelude::*; +#[derive(Clone, Debug, PartialEq, Eq)] pub struct PrimaryRoleWithFactorSourceRuleSet; impl IsRole for PrimaryRoleWithFactorSourceRuleSet { fn role_kind() -> RoleKind { @@ -29,4 +30,38 @@ impl HasRuleSetForRole for PrimaryRoleWithFactorSourceRuleSet { } Ok(()) } + + fn violation_if_password_factor_to_list_of_kind( + context: &RoleWithFactorsBuilt, + factor: &FactorSource, + list_kind: FactorListKind, + ) -> FactorBuilderResult { + let kind = factor.get_factor_source_kind(); + assert_eq!(kind, FactorSourceKind::Password); + + 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 violation_if_ledger_factor_to_list_of_kind( + _context: &RoleWithFactorsBuilt, + factor: &FactorSource, + _list_kind: FactorListKind, + ) -> FactorBuilderResult { + let kind = factor.get_factor_source_kind(); + assert_eq!(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 b9e19e30..c2c233f5 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 @@ -25,10 +25,15 @@ mod tests { fn add_password_to_override_then_build() { type F = FactorSource; type SUT = PrimaryRoleWithFactorSourcesBuilder; + type Result = SUT::BuildResult; + let mut sut = SUT::new(); let f = F::sample_password(); sut.add_to_override(&f).unwrap(); - assert_eq!(sut.build(), FactorBuilderResult::not_yet_valid(PrimaryRoleViolation::MoreThanOneDeviceFactorIsNotSupported)) + assert_eq!( + sut.build(), + Result::not_yet_valid(PrimaryRoleViolation::PasswordMustNotBeAlone) + ); } } diff --git a/crates/rules/src/rules/role_builder_or_built.rs b/crates/rules/src/rules/role_builder_or_built.rs index eed3cbb4..0149192b 100644 --- a/crates/rules/src/rules/role_builder_or_built.rs +++ b/crates/rules/src/rules/role_builder_or_built.rs @@ -7,6 +7,7 @@ impl TyEq for A {} pub type RoleWithFactorsBuilder = RoleBuilderOrBuilt>; +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RoleBuilderOrBuilt { role: PhantomData, built_type: PhantomData, @@ -30,11 +31,14 @@ where } } - pub fn build(self) -> Result> { + pub type Built = RoleWithFactorsBuilt; + pub type BuildResult = Result; + + pub fn build(self) -> Self::BuildResult { Ok(self.snapshot()) } - fn snapshot(&self) -> RoleWithFactorsBuilt { + fn snapshot(&self) -> Self::Built { RoleWithFactorsBuilt::new( self.threshold, self.threshold_factors.clone(), @@ -97,7 +101,7 @@ where self.has_factor_of_kind_in_list_of_kind(factor_source_kind, None) } - fn factors_in_list_of_kind(&self, list_kind: impl Into>) -> Vec<&F> { + pub(crate) fn factors_in_list_of_kind(&self, list_kind: impl Into>) -> Vec<&F> { match list_kind.into() { Some(FactorListKind::Threshold) => self.threshold_factors.iter().collect(), Some(FactorListKind::Override) => self.override_factors.iter().collect(), @@ -108,7 +112,8 @@ where .collect(), } } - fn has_factor_of_kind_in_list_of_kind( + + pub(crate) fn has_factor_of_kind_in_list_of_kind( &self, factor_source_kind: FactorSourceKind, list_kind: impl Into>, @@ -118,7 +123,17 @@ where .is_empty() } - fn count_factors_of_kind_in_list_of_kind( + pub(crate) fn has_factor_not_of_kind_in_list_of_kind( + &self, + factor_source_kind: FactorSourceKind, + list_kind: impl Into>, + ) -> bool { + !self + .factors_not_of_kind_in_list_of_kind(factor_source_kind, list_kind) + .is_empty() + } + + pub(crate) fn count_factors_of_kind_in_list_of_kind( &self, factor_source_kind: FactorSourceKind, list_kind: impl Into>, @@ -127,7 +142,16 @@ where .len() } - fn factors_of_kind_in_list_of_kind( + pub(crate) fn count_factors_not_of_kind_in_list_of_kind( + &self, + factor_source_kind: FactorSourceKind, + list_kind: impl Into>, + ) -> usize { + self.factors_not_of_kind_in_list_of_kind(factor_source_kind, list_kind) + .len() + } + + pub(crate) fn factors_of_kind_in_list_of_kind( &self, factor_source_kind: FactorSourceKind, list_kind: impl Into>, @@ -138,4 +162,16 @@ where .filter(|f| f.get_factor_source_kind() == factor_source_kind) .collect() } + + pub(crate) fn factors_not_of_kind_in_list_of_kind( + &self, + factor_source_kind: FactorSourceKind, + list_kind: impl Into>, + ) -> Vec<&F> { + let factors = self.factors_in_list_of_kind(list_kind); + factors + .into_iter() + .filter(|f| f.get_factor_source_kind() != factor_source_kind) + .collect() + } } diff --git a/crates/rules/src/rules/sargon_types.rs b/crates/rules/src/rules/sargon_types.rs index e36a7d45..347149eb 100644 --- a/crates/rules/src/rules/sargon_types.rs +++ b/crates/rules/src/rules/sargon_types.rs @@ -8,8 +8,6 @@ pub enum FactorSourceKind { Device, Ledger, Password, - OffDeviceMnemonic, - SecurityQuestions, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -61,8 +59,11 @@ impl HasFactorSourceKindObjectSafe for T { } } -pub trait IsFactor: HasFactorSourceKindObjectSafe + Clone {} -impl IsFactor for T {} +pub trait IsFactor: + HasFactorSourceKindObjectSafe + Clone + std::fmt::Debug + PartialEq + Eq +{ +} +impl IsFactor for T {} impl HasFactorSourceKindObjectSafe for FactorSourceKind { fn get_factor_source_kind(&self) -> FactorSourceKind { @@ -112,18 +113,18 @@ impl FactorSource { Self::other(FactorSourceKind::Ledger) } - pub fn sample_off_device_mnemonic() -> Self { - Self::new(FactorSourceKind::OffDeviceMnemonic) - } - - pub fn sample_off_device_mnemonic_other() -> Self { - Self::other(FactorSourceKind::OffDeviceMnemonic) - } - pub fn sample_password() -> Self { Self::new(FactorSourceKind::Password) } pub fn sample_password_other() -> Self { Self::other(FactorSourceKind::Password) } + + // pub fn sample_off_device_mnemonic() -> Self { + // Self::new(FactorSourceKind::OffDeviceMnemonic) + // } + + // pub fn sample_off_device_mnemonic_other() -> Self { + // Self::other(FactorSourceKind::OffDeviceMnemonic) + // } }