Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajjon committed Nov 22, 2024
1 parent 75b8643 commit b8570a9
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 61 deletions.
2 changes: 1 addition & 1 deletion crates/rules/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(associated_type_defaults)]
// #![feature(inherent_associated_types)]
#![feature(inherent_associated_types)]

mod rules;

Expand Down
8 changes: 1 addition & 7 deletions crates/rules/src/rules/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,4 @@

use crate::prelude::*;

pub type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Clone, Copy, Debug, PartialEq, Eq, ThisError)]
pub enum Error {
#[error("Unknown")]
Unknown,
}
pub type Result<T, E> = std::result::Result<T, FactorRulesViolation<E>>;
49 changes: 19 additions & 30 deletions crates/rules/src/rules/factor_rules_violation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,42 @@
use crate::prelude::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FactorRulesViolation<N, F> {
NotYetValid(N),
ForeverInvalid(F),
pub enum FactorRulesViolation<E> {
NotYetValid(E),
ForeverInvalid(E),
}

pub trait CanBeNotYetValid<N, F> {
fn not_yet_valid(violation: N) -> FactorBuilderResult<N, F>;
pub trait CanBeNotYetValid<E> {
fn not_yet_valid(violation: E) -> Self;
}

pub trait CanBeForeverInvalid<N, F> {
fn forever_invalid(violation: F) -> FactorBuilderResult<N, F>;
pub trait CanBeForeverInvalid<E> {
fn forever_invalid(violation: E) -> Self;
}

pub type FactorBuilderResult<N, F> = std::result::Result<(), FactorRulesViolation<N, F>>;
pub type FactorBuilderResult<E> = std::result::Result<(), FactorRulesViolation<E>>;

impl<N, F> CanBeNotYetValid<N, F> for FactorBuilderResult<N, F> {
fn not_yet_valid(violation: N) -> FactorBuilderResult<N, F> {
FactorBuilderResult::Err(FactorRulesViolation::NotYetValid(violation))
impl<T, E> CanBeNotYetValid<E> for std::result::Result<T, FactorRulesViolation<E>> {
fn not_yet_valid(violation: E) -> Self {
std::result::Result::Err(FactorRulesViolation::NotYetValid(violation))
}
}

impl<N, F> CanBeForeverInvalid<N, F> for FactorBuilderResult<N, F> {
fn forever_invalid(violation: F) -> FactorBuilderResult<N, F> {
FactorBuilderResult::Err(FactorRulesViolation::ForeverInvalid(violation))
impl<T, E> CanBeForeverInvalid<E> for std::result::Result<T, FactorRulesViolation<E>> {
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<PrimaryNotYetValid, PrimaryForeverInvalid>;
pub struct PrimaryRoleViolation;
impl CanBeForeverInvalid<PrimaryNotYetValid, PrimaryForeverInvalid> for PrimaryRoleViolation {
fn forever_invalid(violation: PrimaryForeverInvalid) -> PRV {
PRV::Err(FactorRulesViolation::ForeverInvalid(violation))
}
}
23 changes: 19 additions & 4 deletions crates/rules/src/rules/has_rule_set_for_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub trait HasRuleSetForRole<F: IsFactor>: 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<Self::Violation>;


fn violation_if_add_factor_to_list_of_kind(
context: RoleWithFactorsBuilt<F, Self>,
Expand All @@ -20,10 +21,12 @@ pub trait HasRuleSetForRole<F: IsFactor>: 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(())
}
Expand All @@ -33,4 +36,16 @@ pub trait HasRuleSetForRole<F: IsFactor>: Sized + IsRole {
factor: &F,
list_kind: FactorListKind,
) -> FactorBuilderResult<Self::Violation>;

fn violation_if_password_factor_to_list_of_kind(
context: &RoleWithFactorsBuilt<F, Self>,
factor: &F,
list_kind: FactorListKind,
) -> FactorBuilderResult<Self::Violation>;

fn violation_if_ledger_factor_to_list_of_kind(
context: &RoleWithFactorsBuilt<F, Self>,
factor: &F,
list_kind: FactorListKind,
) -> FactorBuilderResult<Self::Violation>;
}
35 changes: 35 additions & 0 deletions crates/rules/src/rules/primary_role_with_factor_source_rule_set.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::prelude::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrimaryRoleWithFactorSourceRuleSet;
impl IsRole for PrimaryRoleWithFactorSourceRuleSet {
fn role_kind() -> RoleKind {
Expand Down Expand Up @@ -29,4 +30,38 @@ impl HasRuleSetForRole<FactorSource> for PrimaryRoleWithFactorSourceRuleSet {
}
Ok(())
}

fn violation_if_password_factor_to_list_of_kind(
context: &RoleWithFactorsBuilt<FactorSource, Self>,
factor: &FactorSource,
list_kind: FactorListKind,
) -> FactorBuilderResult<Self::Violation> {
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<FactorSource, Self>,
factor: &FactorSource,
_list_kind: FactorListKind,
) -> FactorBuilderResult<Self::Violation> {
let kind = factor.get_factor_source_kind();
assert_eq!(kind, FactorSourceKind::Ledger);
// No restrictions
Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);
}
}
48 changes: 42 additions & 6 deletions crates/rules/src/rules/role_builder_or_built.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ impl<A> TyEq<A> for A {}

pub type RoleWithFactorsBuilder<F, R> = RoleBuilderOrBuilt<F, R, RoleWithFactorsBuilt<F, R>>;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RoleBuilderOrBuilt<F: IsFactor, R: IsRoleObjectSafe, B> {
role: PhantomData<R>,
built_type: PhantomData<B>,
Expand All @@ -30,11 +31,14 @@ where
}
}

pub fn build(self) -> Result<RoleWithFactorsBuilt<F, R>> {
pub type Built = RoleWithFactorsBuilt<F, R>;
pub type BuildResult = Result<Self::Built, R::Violation>;

pub fn build(self) -> Self::BuildResult {
Ok(self.snapshot())
}

fn snapshot(&self) -> RoleWithFactorsBuilt<F, R> {
fn snapshot(&self) -> Self::Built {
RoleWithFactorsBuilt::new(
self.threshold,
self.threshold_factors.clone(),
Expand Down Expand Up @@ -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<Option<FactorListKind>>) -> Vec<&F> {
pub(crate) fn factors_in_list_of_kind(&self, list_kind: impl Into<Option<FactorListKind>>) -> Vec<&F> {
match list_kind.into() {
Some(FactorListKind::Threshold) => self.threshold_factors.iter().collect(),
Some(FactorListKind::Override) => self.override_factors.iter().collect(),
Expand All @@ -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<Option<FactorListKind>>,
Expand All @@ -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<Option<FactorListKind>>,
) -> 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<Option<FactorListKind>>,
Expand All @@ -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<Option<FactorListKind>>,
) -> 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<Option<FactorListKind>>,
Expand All @@ -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<Option<FactorListKind>>,
) -> 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()
}
}
25 changes: 13 additions & 12 deletions crates/rules/src/rules/sargon_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ pub enum FactorSourceKind {
Device,
Ledger,
Password,
OffDeviceMnemonic,
SecurityQuestions,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -61,8 +59,11 @@ impl<T: HasFactorSourceKind> HasFactorSourceKindObjectSafe for T {
}
}

pub trait IsFactor: HasFactorSourceKindObjectSafe + Clone {}
impl<T: HasFactorSourceKindObjectSafe + Clone> IsFactor for T {}
pub trait IsFactor:
HasFactorSourceKindObjectSafe + Clone + std::fmt::Debug + PartialEq + Eq
{
}
impl<T: HasFactorSourceKindObjectSafe + Clone + std::fmt::Debug + PartialEq + Eq> IsFactor for T {}

impl HasFactorSourceKindObjectSafe for FactorSourceKind {
fn get_factor_source_kind(&self) -> FactorSourceKind {
Expand Down Expand Up @@ -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)
// }
}

0 comments on commit b8570a9

Please sign in to comment.