Update process states validation logic
This commit is contained in:
parent
7a4344608e
commit
4744740303
112
src/process.rs
112
src/process.rs
@ -24,49 +24,65 @@ pub struct ProcessState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessState {
|
impl ProcessState {
|
||||||
/// A state is valid if the attached validation_tokens satisfy the updated conditions defined in the encrypted_pcd
|
fn compute_modified_fields(&self, previous_state: Option<&ProcessState>) -> Vec<String> {
|
||||||
pub fn is_valid(&self, previous_state: Option<&ProcessState>) -> Result<bool, anyhow::Error> {
|
let new_state = &self.encrypted_pcd;
|
||||||
// Determine modified fields
|
|
||||||
let modified_fields: Vec<String> = if let Some(previous_state) = previous_state {
|
// Ensure the new state is a JSON object
|
||||||
let res: Vec<String> = self
|
let new_state_obj = new_state
|
||||||
|
.as_object()
|
||||||
|
.expect("New state should be a JSON object");
|
||||||
|
|
||||||
|
if let Some(prev_state) = previous_state {
|
||||||
|
// Previous state exists; compute differences
|
||||||
|
let previous_state_obj = prev_state
|
||||||
.encrypted_pcd
|
.encrypted_pcd
|
||||||
.as_object()
|
.as_object()
|
||||||
.unwrap()
|
.expect("Previous state should be a JSON object");
|
||||||
|
|
||||||
|
// Compute modified fields by comparing with previous state
|
||||||
|
new_state_obj
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(key, value)| {
|
.filter_map(|(key, value)| {
|
||||||
let previous_value = previous_state.encrypted_pcd.get(key);
|
let previous_value = previous_state_obj.get(key);
|
||||||
if previous_value.is_none() || value != previous_value.unwrap() {
|
if previous_value.is_none() || value != previous_value.unwrap() {
|
||||||
Some(key.clone())
|
Some(key.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
|
||||||
|
|
||||||
if res.is_empty() {
|
|
||||||
return Err(anyhow::anyhow!("State is identical to the previous state"));
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
} else {
|
|
||||||
self.encrypted_pcd
|
|
||||||
.as_object()
|
|
||||||
.unwrap()
|
|
||||||
.keys()
|
|
||||||
.cloned()
|
|
||||||
.collect()
|
.collect()
|
||||||
};
|
} else {
|
||||||
|
// No previous state; all fields are considered modified
|
||||||
|
new_state_obj.keys().cloned().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(
|
||||||
|
&self,
|
||||||
|
previous_state: Option<&ProcessState>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if self.validation_tokens.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("Can't validate a state with no proofs attached"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute modified fields
|
||||||
|
let modified_fields = self.compute_modified_fields(previous_state);
|
||||||
|
|
||||||
|
if modified_fields.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("State is identical to the previous state"));
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("modified fields: {:?}", modified_fields);
|
||||||
|
|
||||||
|
// Compute the hash of the new state
|
||||||
|
let new_state_hash = AnkPcdHash::from_value(&self.encrypted_pcd);
|
||||||
|
|
||||||
// Extract roles and their definitions
|
|
||||||
let mut fields2plains = Map::new();
|
let mut fields2plains = Map::new();
|
||||||
self.encrypted_pcd
|
self.encrypted_pcd
|
||||||
.decrypt_fields(&self.keys, &mut fields2plains)?;
|
.decrypt_fields(&self.keys, &mut fields2plains)?;
|
||||||
|
|
||||||
let mut roles2rules: HashMap<String, RoleDefinition> = HashMap::new();
|
let mut roles2rules: HashMap<String, RoleDefinition> = HashMap::new();
|
||||||
if let Some(roles) = fields2plains.get("roles") {
|
if let Some(roles) = fields2plains.get("roles") {
|
||||||
if roles.is_null() {
|
|
||||||
return Err(anyhow::anyhow!("Can't decrypt roles in the encrypted pcd"));
|
|
||||||
}
|
|
||||||
if let Some(roles_map) = roles.as_object() {
|
if let Some(roles_map) = roles.as_object() {
|
||||||
for (role, conditions) in roles_map {
|
for (role, conditions) in roles_map {
|
||||||
let role_def = serde_json::from_value::<RoleDefinition>(conditions.clone())?;
|
let role_def = serde_json::from_value::<RoleDefinition>(conditions.clone())?;
|
||||||
@ -81,31 +97,43 @@ impl ProcessState {
|
|||||||
|
|
||||||
// Check if each modified field satisfies at least one applicable rule across all roles
|
// Check if each modified field satisfies at least one applicable rule across all roles
|
||||||
let all_fields_validated = modified_fields.iter().all(|field| {
|
let all_fields_validated = modified_fields.iter().all(|field| {
|
||||||
let applicable_rules: Vec<(&RoleDefinition, &ValidationRule)> = roles2rules
|
println!("validating field: {}", field);
|
||||||
.values()
|
// Collect applicable rules from all roles for the current field
|
||||||
.flat_map(|role_def| {
|
let applicable_roles: Vec<RoleDefinition> = roles2rules.iter()
|
||||||
role_def
|
.map(|(_, role_def)| {
|
||||||
.get_applicable_rules(field)
|
let mut filtered_role_def = role_def.clone();
|
||||||
.into_iter()
|
let rules = filtered_role_def.get_applicable_rules(field);
|
||||||
.map(move |rule| (role_def, rule))
|
filtered_role_def.validation_rules = rules.into_iter().map(|r| r.clone()).collect();
|
||||||
})
|
filtered_role_def
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if applicable_rules.is_empty() {
|
if applicable_roles.is_empty() {
|
||||||
return false; // No rules apply to this field, consider it invalid
|
return false; // No rules apply to this field, consider it invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
applicable_rules.into_iter().any(|(role_def, rule)| {
|
println!("applicable_roles: {:?}", applicable_roles);
|
||||||
rule.is_satisfied(
|
|
||||||
field,
|
// Check if any applicable rule is satisfied
|
||||||
AnkPcdHash::from_value(&self.encrypted_pcd),
|
applicable_roles.into_iter().any(|role_def| {
|
||||||
&self.validation_tokens,
|
let res = false;
|
||||||
&role_def.members,
|
for rule in role_def.validation_rules {
|
||||||
)
|
rule.is_satisfied(
|
||||||
|
field,
|
||||||
|
new_state_hash.clone(),
|
||||||
|
&self.validation_tokens,
|
||||||
|
&role_def.members,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
res
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(all_fields_validated)
|
if all_fields_validated {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Not enough valid proofs"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user