Update prd/pcd
This commit is contained in:
parent
0ea4c5f118
commit
97df8ea13d
@ -1,10 +1,9 @@
|
|||||||
use serde_json::Value;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tsify::Tsify;
|
use tsify::Tsify;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use sp_client::{silentpayments::utils::SilentPaymentAddress, spclient::SpWallet};
|
use sp_client::spclient::SpWallet;
|
||||||
|
|
||||||
use crate::pcd::Member;
|
use crate::pcd::Member;
|
||||||
|
|
||||||
@ -13,8 +12,7 @@ use crate::pcd::Member;
|
|||||||
pub struct Device {
|
pub struct Device {
|
||||||
sp_wallet: SpWallet,
|
sp_wallet: SpWallet,
|
||||||
pairing_process_uuid: Option<String>,
|
pairing_process_uuid: Option<String>,
|
||||||
paired_devices: Vec<String>, // map an address to the pairing process
|
paired_member: Option<Member>,
|
||||||
latest_known_state: Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
@ -22,8 +20,7 @@ impl Device {
|
|||||||
Self {
|
Self {
|
||||||
sp_wallet,
|
sp_wallet,
|
||||||
pairing_process_uuid: None,
|
pairing_process_uuid: None,
|
||||||
paired_devices: vec![],
|
paired_member: None,
|
||||||
latest_known_state: Value::Null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,33 +40,12 @@ impl Device {
|
|||||||
self.pairing_process_uuid.clone()
|
self.pairing_process_uuid.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_process_uuid(&mut self, uuid: Uuid) {
|
pub fn pair(&mut self, uuid: Uuid, member: Member) {
|
||||||
self.pairing_process_uuid = Some(uuid.to_string());
|
self.pairing_process_uuid = Some(uuid.to_string());
|
||||||
|
self.paired_member = Some(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_paired_devices(&self) -> Vec<String> {
|
pub fn to_member(&self) -> Option<Member> {
|
||||||
self.paired_devices.clone()
|
self.paired_member.clone()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_paired_device(&mut self, new_device_address: SilentPaymentAddress) {
|
|
||||||
self.paired_devices.push(new_device_address.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_member(&self) -> anyhow::Result<Member> {
|
|
||||||
if !self.is_linked() {
|
|
||||||
return Err(anyhow::Error::msg("device is not linked"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let member = self.latest_known_state.as_object().unwrap().get("member").unwrap().clone();
|
|
||||||
let res: Member = serde_json::from_value(member)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_latest_state(&self) -> Value {
|
|
||||||
self.latest_known_state.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_latest_state(&mut self, update: Value) {
|
|
||||||
self.latest_known_state = update;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
100
src/pcd.rs
100
src/pcd.rs
@ -1,4 +1,4 @@
|
|||||||
use std::str::FromStr;
|
use std::{collections::{HashMap, HashSet}, str::FromStr};
|
||||||
use anyhow::{Result, Error};
|
use anyhow::{Result, Error};
|
||||||
|
|
||||||
use aes_gcm::{aead::{Aead, Payload}, AeadCore, Aes256Gcm, KeyInit};
|
use aes_gcm::{aead::{Aead, Payload}, AeadCore, Aes256Gcm, KeyInit};
|
||||||
@ -11,47 +11,38 @@ use tsify::Tsify;
|
|||||||
|
|
||||||
use crate::crypto::AAD;
|
use crate::crypto::AAD;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Tsify, PartialEq, Eq, Hash, PartialOrd)]
|
|
||||||
pub enum Role {
|
|
||||||
User,
|
|
||||||
Manager,
|
|
||||||
Admin,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Tsify)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Tsify)]
|
||||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||||
pub struct Member {
|
pub struct Member {
|
||||||
nym: String,
|
sp_addresses: Vec<String>
|
||||||
sp_address_a: String,
|
|
||||||
sp_address_b: String,
|
|
||||||
role: Role,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Member {
|
impl Member {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
nym: String,
|
sp_addresses: Vec<SilentPaymentAddress>,
|
||||||
sp_address_a: SilentPaymentAddress,
|
) -> Result<Self> {
|
||||||
sp_address_b: SilentPaymentAddress,
|
if sp_addresses.is_empty() {
|
||||||
role: Role,
|
return Err(Error::msg("empty address set"));
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
nym,
|
|
||||||
sp_address_a: sp_address_a.into(),
|
|
||||||
sp_address_b: sp_address_b.into(),
|
|
||||||
role,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
for s in sp_addresses.iter() {
|
||||||
|
if !seen.insert(s.clone()) {
|
||||||
|
return Err(Error::msg("Duplicate addresses found"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res: Vec<String> = sp_addresses.iter()
|
||||||
|
.map(|a| Into::<String>::into(*a))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
sp_addresses: res
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_nym(&self) -> String {
|
pub fn get_addresses(&self) -> Vec<String> {
|
||||||
self.nym.clone()
|
self.sp_addresses.clone()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_addresses(&self) -> (String, String) {
|
|
||||||
(self.sp_address_a.clone(), self.sp_address_b.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_role(&self) -> Role {
|
|
||||||
self.role
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,3 +136,48 @@ pub trait Pcd<'a>: Serialize + Deserialize<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pcd<'_> for Value {}
|
impl Pcd<'_> for Value {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
||||||
|
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||||
|
pub struct ValidationRule {
|
||||||
|
quorum: f32, // Must be >= 0.0, <= 1.0, 0.0 means reading right
|
||||||
|
pub fields: Vec<String>, // Which fields are concerned by this rule
|
||||||
|
min_sig_member: f32, // Must be >= 0.0, <= 1.0, does each member need to sign with all it's devices?
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidationRule {
|
||||||
|
pub fn new(quorum: f32, fields: Vec<String>, min_sig_member: f32) -> Result<Self> {
|
||||||
|
if quorum < 0.0 || quorum > 1.0 {
|
||||||
|
return Err(Error::msg("quorum must be 0.0 < quorum <= 1.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if min_sig_member < 0.0 || min_sig_member > 1.0 {
|
||||||
|
return Err(Error::msg("min_signatures_member must be 0.0 < min_signatures_member <= 1.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if fields.is_empty() {
|
||||||
|
return Err(Error::msg("Fields can't be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = Self {
|
||||||
|
quorum,
|
||||||
|
fields,
|
||||||
|
min_sig_member,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
||||||
|
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||||
|
pub struct RoleDefinition {
|
||||||
|
pub members: Vec<Member>,
|
||||||
|
pub validation_rules: Vec<ValidationRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
||||||
|
// #[tsify(into_wasm_abi, from_wasm_abi)]
|
||||||
|
// pub struct Roles {
|
||||||
|
// pub roles: HashMap<String, RoleDefinition>
|
||||||
|
// }
|
||||||
|
28
src/prd.rs
28
src/prd.rs
@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{Result, Error};
|
use anyhow::{Result, Error};
|
||||||
@ -5,6 +6,7 @@ use serde::{Serialize, Deserialize};
|
|||||||
|
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use sp_client::bitcoin::secp256k1::SecretKey;
|
use sp_client::bitcoin::secp256k1::SecretKey;
|
||||||
|
use sp_client::bitcoin::XOnlyPublicKey;
|
||||||
use sp_client::silentpayments::utils::SilentPaymentAddress;
|
use sp_client::silentpayments::utils::SilentPaymentAddress;
|
||||||
use sp_client::spclient::SpWallet;
|
use sp_client::spclient::SpWallet;
|
||||||
use sp_client::bitcoin::secp256k1::schnorr::Signature;
|
use sp_client::bitcoin::secp256k1::schnorr::Signature;
|
||||||
@ -77,8 +79,7 @@ impl AnkValidationNoHash {
|
|||||||
pub struct ValidationToken {
|
pub struct ValidationToken {
|
||||||
member: Member,
|
member: Member,
|
||||||
message: [u8; 32],
|
message: [u8; 32],
|
||||||
sig_a: Signature,
|
sigs: Vec<Signature>, // User must sign with the requested number of devices
|
||||||
sig_b: Signature, // User must sign with its 2 paired devices
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sha256t_hash_newtype! {
|
sha256t_hash_newtype! {
|
||||||
@ -146,13 +147,22 @@ impl Prd {
|
|||||||
// check that the proof is consistent
|
// check that the proof is consistent
|
||||||
let sender: Member = serde_json::from_str(&prd.sender)?;
|
let sender: Member = serde_json::from_str(&prd.sender)?;
|
||||||
if let Some(proof) = prd.proof {
|
if let Some(proof) = prd.proof {
|
||||||
// take the 2 spending keys in sender
|
// take the spending keys in sender
|
||||||
let (address_a, address_b) = sender.get_addresses();
|
let addresses = sender.get_addresses();
|
||||||
let spend_key_a = <SilentPaymentAddress>::try_from(address_a)?.get_spend_key().x_only_public_key().0;
|
let mut spend_keys: Vec<XOnlyPublicKey> = vec![];
|
||||||
let spend_key_b = <SilentPaymentAddress>::try_from(address_b)?.get_spend_key().x_only_public_key().0;
|
for address in addresses {
|
||||||
// The key in proof must be one of the 2 sender keys
|
spend_keys.push(<SilentPaymentAddress>::try_from(address)?.get_spend_key().x_only_public_key().0);
|
||||||
|
}
|
||||||
|
// The key in proof must be one of the sender keys
|
||||||
let proof_key = proof.get_key();
|
let proof_key = proof.get_key();
|
||||||
if spend_key_a != proof_key && spend_key_b != proof_key {
|
let mut known_key = false;
|
||||||
|
for key in spend_keys {
|
||||||
|
if key == proof_key {
|
||||||
|
known_key = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !known_key {
|
||||||
return Err(anyhow::Error::msg("Proof signed with an unknown key"));
|
return Err(anyhow::Error::msg("Proof signed with an unknown key"));
|
||||||
}
|
}
|
||||||
proof.verify()?;
|
proof.verify()?;
|
||||||
@ -168,7 +178,7 @@ impl Prd {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter_keys(&mut self, to_keep: Vec<String>) {
|
pub fn filter_keys(&mut self, to_keep: HashSet<String>) {
|
||||||
let current_keys = self.keys.clone();
|
let current_keys = self.keys.clone();
|
||||||
let filtered_keys: Map<String, Value> = current_keys.into_iter()
|
let filtered_keys: Map<String, Value> = current_keys.into_iter()
|
||||||
.filter(|(field, _)| to_keep.contains(field))
|
.filter(|(field, _)| to_keep.contains(field))
|
||||||
|
@ -1,59 +1,35 @@
|
|||||||
use std::str::FromStr;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::{Map, Value};
|
||||||
use sp_client::{bitcoin::OutPoint, silentpayments::utils::SilentPaymentAddress};
|
use sp_client::bitcoin::OutPoint;
|
||||||
use tsify::Tsify;
|
use tsify::Tsify;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use crate::pcd::Role;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
|
||||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
|
||||||
pub struct ValidationRules {
|
|
||||||
quorum: f32, // Must be > 0.0, <= 1.0
|
|
||||||
min_permission: Role, // Only users with at least that Role can send a token
|
|
||||||
min_signatures_member: f32, // Must be > 0.0, <= 1.0, does each member need to sign with all it's devices?
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValidationRules {
|
|
||||||
pub fn new(quorum: f32, min_permission: Role, min_signatures_member: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
quorum,
|
|
||||||
min_permission,
|
|
||||||
min_signatures_member,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
|
||||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||||
pub struct Process {
|
pub struct Process {
|
||||||
pub uuid: String,
|
pub uuid: String,
|
||||||
pub name: String,
|
|
||||||
pub validation_rules: ValidationRules,
|
|
||||||
pub html: String,
|
pub html: String,
|
||||||
pub style: String,
|
pub style: String,
|
||||||
pub script: String,
|
pub script: String,
|
||||||
pub init_state: Value,
|
pub init_state: Map<String, Value>,
|
||||||
pub commited_in: OutPoint,
|
pub commited_in: OutPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: String,
|
|
||||||
validation_rules: ValidationRules,
|
|
||||||
html: String,
|
html: String,
|
||||||
style: String,
|
style: String,
|
||||||
script: String,
|
script: String,
|
||||||
init_state: Value,
|
init_state: Map<String, Value>,
|
||||||
commited_in: OutPoint,
|
commited_in: OutPoint,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
uuid: Uuid::new_v4().to_string(),
|
uuid: Uuid::new_v4().to_string(),
|
||||||
name,
|
|
||||||
validation_rules,
|
|
||||||
html,
|
html,
|
||||||
style,
|
style,
|
||||||
script,
|
script,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user