// Rust 2021. BOTH peers, typed ports scaffold. No networking/crates required. // Begin_verified locks and verifies per examples/README.md. Close rolls back unless // committed. A production Tx implementation should also use RAII/Drop on panic. #[derive(Clone, Copy)] pub enum Op { Register, Use, Revoke, Retract } #[derive(Clone)] pub struct Envelope { pub fields: Vec, pub signature: String } pub struct Outcome { pub receipt: Envelope, pub fresh: bool } pub trait Transaction { fn operation(&self) -> Op; fn cached(&self) -> Option; fn register_new_key(&mut self) -> Result<(),String>; fn require_current_entitlement(&mut self) -> Result<(),String>; fn revoke_target(&mut self) -> Result<(),String>; fn retract_relationship(&mut self) -> Result<(),String>; fn sign_result(&mut self) -> Result; fn commit_once(&mut self, result: &Envelope) -> Result<(),String>; fn close(&mut self); } pub trait Ports { fn challenge(&self, op: Op, rid: &str, target: &str, context: &str) -> Result; fn verify_provider_and_approve(&self, q: &Envelope) -> Result<(),String>; fn sign_proof(&self, q: &Envelope) -> Result; fn verify_result_and_apply(&self, r: &Envelope) -> Result<(),String>; fn begin_verified(&self, p: &Envelope, context: &str) -> Result,String>; fn recover_revoke(&self, rid: &str, target: &str, context: &str) -> Result; } pub struct TokenSide<'a> { pub ports: &'a dyn Ports } impl TokenSide<'_> { pub fn respond(&self, q: &Envelope) -> Result { self.ports.verify_provider_and_approve(q)?; self.ports.sign_proof(q) } pub fn accept(&self, r: &Envelope) -> Result<(),String> { self.ports.verify_result_and_apply(r) } } pub struct ProviderSide<'a> { pub ports: &'a dyn Ports } impl ProviderSide<'_> { pub fn start(&self, op: Op, rid: &str, target: &str, context: &str) -> Result { self.ports.challenge(op,rid,target,context) } pub fn finish(&self, proof: &Envelope, context: &str) -> Result { let mut tx = self.ports.begin_verified(proof,context)?; let result = (|| { if let Some(old) = tx.cached() { return Ok(Outcome { receipt: old, fresh: false }); } match tx.operation() { Op::Register => tx.register_new_key()?, Op::Use => tx.require_current_entitlement()?, Op::Revoke => tx.revoke_target()?, Op::Retract => tx.retract_relationship()?, } let receipt = tx.sign_result()?; tx.commit_once(&receipt)?; Ok(Outcome { receipt, fresh: true }) })(); tx.close(); result } pub fn lost(&self, rid: &str, target: &str, context: &str) -> Result { self.ports.recover_revoke(rid,target,context) } } pub fn legacy_value(value: &str, approved: bool, selected: bool) -> Result<&str,String> { if !approved || !selected || value.is_empty() { return Err("Local approval/selection required".into()); } Ok(value) // Standard renderer/driver only, no new BringPass reader command. }