Add Prd Request handling

This commit is contained in:
NicolasCantu 2025-01-30 16:07:05 +01:00
parent e92384fc93
commit c0adce2b31

View File

@ -997,6 +997,116 @@ fn handle_prd(
..Default::default() ..Default::default()
}); });
} }
PrdType::Request => {
// We are being requested encrypted data for one or more states, to be uploaded on storage
let states: Vec<[u8; 32]> = serde_json::from_str(&prd.payload)?;
let requester: Member = serde_json::from_str(&prd.sender)?;
// diffs will trigger upload of the encrypted data on storage
let mut diffs = vec![];
// This will notify the requester and provide relevant information if needed
let mut ciphers = vec![];
for state_id in states {
let state = match relevant_process.get_state_for_id(&state_id.to_lower_hex_string()) {
Ok(state) => state,
Err(_) => {
debug!("Ignoring request for unknown state {}", state_id.to_lower_hex_string());
continue;
}
};
let decrypted_map = state.decrypt_pcd()?;
let roles = Value::Object(decrypted_map.clone()).extract_roles()?;
let local_device = lock_local_device()?;
let sp_wallet = local_device.get_wallet();
let local_address = sp_wallet.get_client().get_receiving_address();
let mut relevant_fields: HashSet<String> = HashSet::new();
let shared_secrets = lock_shared_secrets()?;
for (name, role) in &roles {
if !role.members.contains(&requester) {
// This role doesn't concern requester
continue;
}
let fields: Vec<String> = role
.validation_rules
.iter()
.flat_map(|rule| rule.fields.clone())
.collect();
if let Some(no_secret_address) = requester.get_addresses().iter()
.find(|a| shared_secrets.get_secret_for_address(a.as_str().try_into().unwrap()).is_none())
{
// We ignore it if we don't have a secret with ourselves
if *no_secret_address != local_address {
// for now we return an error to keep it simple
return Err(AnyhowError::msg(format!("No shared secret for all addresses of {:?}\nPlease first connect", requester)));
}
}
relevant_fields.extend(fields);
}
let sender: Member = local_device
.to_member();
let mut full_prd = Prd::new_update(
outpoint,
sender,
roles,
state.keys.clone(),
state.pcd_commitment.clone(),
);
full_prd.filter_keys(&relevant_fields);
let prd_msg = full_prd.to_network_msg(sp_wallet)?;
let addresses = requester.get_addresses();
for sp_address in addresses.into_iter() {
// We skip our own device address, no point sending ourself a cipher
if sp_address == local_address {
continue;
}
// We shouldn't ever have error here since we already checked above
let shared_secret = shared_secrets.get_secret_for_address(sp_address.as_str().try_into()?).unwrap();
let cipher = encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?;
ciphers.push(cipher.to_lower_hex_string());
}
let pcd_commitment: HashMap<String, String> = serde_json::from_value(state.pcd_commitment.clone())?;
for (field, hash) in pcd_commitment {
// We only need field that are visible by requester
if !relevant_fields.contains(&field) {
continue;
}
let diff = UserDiff {
process_id: outpoint.to_string(),
state_id: state_id.to_lower_hex_string(),
value_commitment: hash,
new_value: decrypted_map[&field].clone(),
field,
..Default::default()
};
diffs.push(diff);
}
}
let updated_process = Some(UpdatedProcess {
process_id: outpoint,
current_process: relevant_process.clone(),
diffs,
..Default::default()
});
return Ok(ApiReturn {
updated_process,
ciphers_to_send: ciphers,
..Default::default()
});
}
_ => unimplemented!(), _ => unimplemented!(),
} }
} }