#[cfg(any(feature = "ffi", target_arch = "wasm32"))]
pub(crate) mod wire;
use std::collections::HashMap;
use crate::{
primitives::discovery::response::SecretVersionEntry,
protocol::types::{Target, UserSecret},
types::{ChannelId, SharedKey},
};
use derec_proto::{
ContactMessage, GetSecretIdsVersionsRequestMessage, GetShareRequestMessage, PairRequestMessage,
PrePairRequestMessage, SenderKind, StoreShareRequestMessage, TransportProtocol,
UnpairRequestMessage, UpdateChannelInfoRequestMessage, VerifyShareRequestMessage,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PendingActionKind {
Pairing,
PrePair,
StoreShare,
VerifyShare,
Discovery,
GetShare,
Unpair,
UpdateChannelInfo,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct AutoAcceptPolicy {
pub pairing: bool,
pub pre_pair: bool,
pub store_share: bool,
pub verify_share: bool,
pub discovery: bool,
pub get_share: bool,
pub unpair: bool,
pub update_channel_info: bool,
}
impl AutoAcceptPolicy {
pub fn all() -> Self {
Self {
pairing: true,
pre_pair: true,
store_share: true,
verify_share: true,
discovery: true,
get_share: true,
unpair: true,
update_channel_info: true,
}
}
pub fn allows(&self, action: &PendingAction) -> bool {
match action.kind() {
PendingActionKind::Pairing => self.pairing,
PendingActionKind::PrePair => self.pre_pair,
PendingActionKind::StoreShare => self.store_share,
PendingActionKind::VerifyShare => self.verify_share,
PendingActionKind::Discovery => self.discovery,
PendingActionKind::GetShare => self.get_share,
PendingActionKind::Unpair => self.unpair,
PendingActionKind::UpdateChannelInfo => self.update_channel_info,
}
}
}
pub enum PendingAction {
Pairing {
channel_id: ChannelId,
request: PairRequestMessage,
kind: SenderKind,
peer_communication_info: HashMap<String, String>,
trace_id: u64,
},
PrePair {
channel_id: ChannelId,
request: PrePairRequestMessage,
trace_id: u64,
},
StoreShare {
channel_id: ChannelId,
request: StoreShareRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
VerifyShare {
channel_id: ChannelId,
request: VerifyShareRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
Discovery {
channel_id: ChannelId,
request: GetSecretIdsVersionsRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
GetShare {
channel_id: ChannelId,
request: GetShareRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
Unpair {
channel_id: ChannelId,
request: UnpairRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
UpdateChannelInfo {
channel_id: ChannelId,
request: UpdateChannelInfoRequestMessage,
shared_key: SharedKey,
trace_id: u64,
},
}
impl std::fmt::Debug for PendingAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let channel_id = match self {
PendingAction::Pairing { channel_id, .. }
| PendingAction::PrePair { channel_id, .. }
| PendingAction::StoreShare { channel_id, .. }
| PendingAction::VerifyShare { channel_id, .. }
| PendingAction::Discovery { channel_id, .. }
| PendingAction::GetShare { channel_id, .. }
| PendingAction::Unpair { channel_id, .. }
| PendingAction::UpdateChannelInfo { channel_id, .. } => channel_id,
};
f.debug_struct("PendingAction")
.field("kind", &self.kind())
.field("channel_id", &channel_id.0)
.finish()
}
}
impl PendingAction {
pub fn kind(&self) -> PendingActionKind {
match self {
PendingAction::Pairing { .. } => PendingActionKind::Pairing,
PendingAction::PrePair { .. } => PendingActionKind::PrePair,
PendingAction::StoreShare { .. } => PendingActionKind::StoreShare,
PendingAction::VerifyShare { .. } => PendingActionKind::VerifyShare,
PendingAction::Discovery { .. } => PendingActionKind::Discovery,
PendingAction::GetShare { .. } => PendingActionKind::GetShare,
PendingAction::Unpair { .. } => PendingActionKind::Unpair,
PendingAction::UpdateChannelInfo { .. } => PendingActionKind::UpdateChannelInfo,
}
}
}
pub enum DeRecFlow {
Pairing {
kind: SenderKind,
contact: ContactMessage,
peer_communication_info: std::collections::HashMap<String, String>,
},
Discovery {
target: Target,
},
ProtectSecret {
secrets: Vec<UserSecret>,
description: Option<String>,
},
VerifyShares {
secret_id: u64,
version: u32,
target: Target,
},
RecoverSecret {
secret_id: u64,
version: u32,
},
Unpair {
channel_id: ChannelId,
memo: Option<String>,
},
UpdateChannelInfo {
target: Target,
communication_info: Option<std::collections::HashMap<String, String>>,
transport_protocol: Option<TransportProtocol>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum UnpairAck {
#[default]
Required,
NotRequired,
}
#[non_exhaustive]
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum DeRecEvent {
PairingCompleted {
channel_id: ChannelId,
pairing_channel_id: ChannelId,
kind: SenderKind,
peer_communication_info: HashMap<String, String>,
},
ReplicaPaired {
channel_id: ChannelId,
peer_replica_id: u64,
},
ShareStored {
channel_id: ChannelId,
version: u32,
replica_id: Option<u64>,
},
ReplicaSecretReceived {
channel_id: ChannelId,
from_replica_id: u64,
secret_id: u64,
version: u32,
secret: crate::protocol::types::Secret,
shares: Vec<crate::protocol::types::ChannelShare>,
},
ReplicaSecretAcked {
channel_id: ChannelId,
from_replica_id: u64,
secret_id: u64,
version: u32,
status: i32,
memo: String,
},
ShareConfirmed { channel_id: ChannelId, version: u32 },
ShareRejected {
channel_id: ChannelId,
version: u32,
status: i32,
memo: String,
},
SharingComplete {
version: u32,
confirmed_count: usize,
failed_count: usize,
threshold_met: bool,
},
ShareVerified { channel_id: ChannelId, version: u32 },
SecretsDiscovered {
channel_id: ChannelId,
secrets: Vec<SecretVersionEntry>,
},
RecoveryShareReceived {
channel_id: ChannelId,
shares_received: usize,
},
RecoveryShareError {
channel_id: ChannelId,
shares_received: usize,
error: String,
},
SecretRecovered {
secret: crate::protocol::types::Secret,
},
ActionRequired {
channel_id: ChannelId,
action: PendingAction,
},
AutoAccepted {
channel_id: ChannelId,
action_kind: PendingActionKind,
},
Unpaired { channel_id: ChannelId },
UnpairRejected {
channel_id: ChannelId,
status: i32,
memo: String,
},
PrePairRejected {
channel_id: ChannelId,
status: i32,
memo: String,
},
ChannelInfoUpdated { channel_id: ChannelId },
ChannelInfoUpdateRejected {
channel_id: ChannelId,
status: i32,
memo: String,
},
NoOp,
PairingStarted {
channel_id: ChannelId,
kind: SenderKind,
},
DiscoveryStarted { channel_id: ChannelId },
DiscoveryFailed {
channel_id: ChannelId,
error: String,
},
ProtectSecretStarted { channel_id: ChannelId, version: u32 },
ProtectSecretFailed {
channel_id: ChannelId,
version: u32,
error: String,
},
VerifySharesStarted { channel_id: ChannelId, version: u32 },
VerifySharesFailed {
channel_id: ChannelId,
version: u32,
error: String,
},
RecoverSecretStarted { channel_id: ChannelId, version: u32 },
RecoverSecretFailed {
channel_id: ChannelId,
version: u32,
error: String,
},
UnpairStarted { channel_id: ChannelId },
UpdateChannelInfoStarted { channel_id: ChannelId },
UpdateChannelInfoFailed {
channel_id: ChannelId,
error: String,
},
}
#[cfg(test)]
mod tests {
use super::*;
use derec_proto::{
GetSecretIdsVersionsRequestMessage, GetShareRequestMessage, PrePairRequestMessage,
StoreShareRequestMessage, UnpairRequestMessage, UpdateChannelInfoRequestMessage,
VerifyShareRequestMessage,
};
fn store_share_action() -> PendingAction {
PendingAction::StoreShare {
channel_id: ChannelId(1),
request: StoreShareRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn verify_share_action() -> PendingAction {
PendingAction::VerifyShare {
channel_id: ChannelId(1),
request: VerifyShareRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn discovery_action() -> PendingAction {
PendingAction::Discovery {
channel_id: ChannelId(1),
request: GetSecretIdsVersionsRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn get_share_action() -> PendingAction {
PendingAction::GetShare {
channel_id: ChannelId(1),
request: GetShareRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn unpair_action() -> PendingAction {
PendingAction::Unpair {
channel_id: ChannelId(1),
request: UnpairRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn update_channel_info_action() -> PendingAction {
PendingAction::UpdateChannelInfo {
channel_id: ChannelId(1),
request: UpdateChannelInfoRequestMessage::default(),
shared_key: [0u8; 32],
trace_id: 0,
}
}
fn pre_pair_action() -> PendingAction {
PendingAction::PrePair {
channel_id: ChannelId(1),
request: PrePairRequestMessage::default(),
trace_id: 0,
}
}
#[test]
fn pending_action_kind_round_trips_each_variant() {
assert_eq!(store_share_action().kind(), PendingActionKind::StoreShare);
assert_eq!(verify_share_action().kind(), PendingActionKind::VerifyShare);
assert_eq!(discovery_action().kind(), PendingActionKind::Discovery);
assert_eq!(get_share_action().kind(), PendingActionKind::GetShare);
assert_eq!(unpair_action().kind(), PendingActionKind::Unpair);
assert_eq!(
update_channel_info_action().kind(),
PendingActionKind::UpdateChannelInfo
);
assert_eq!(pre_pair_action().kind(), PendingActionKind::PrePair);
}
#[test]
fn auto_accept_policy_default_is_all_false() {
let p = AutoAcceptPolicy::default();
assert!(!p.pairing);
assert!(!p.pre_pair);
assert!(!p.store_share);
assert!(!p.verify_share);
assert!(!p.discovery);
assert!(!p.get_share);
assert!(!p.unpair);
assert!(!p.update_channel_info);
}
#[test]
fn auto_accept_policy_all_is_all_true() {
let p = AutoAcceptPolicy::all();
assert!(p.pairing);
assert!(p.pre_pair);
assert!(p.store_share);
assert!(p.verify_share);
assert!(p.discovery);
assert!(p.get_share);
assert!(p.unpair);
assert!(p.update_channel_info);
}
#[test]
fn auto_accept_policy_allows_dispatches_per_flow() {
let only_store = AutoAcceptPolicy {
store_share: true,
..Default::default()
};
assert!(only_store.allows(&store_share_action()));
assert!(!only_store.allows(&verify_share_action()));
assert!(!only_store.allows(&discovery_action()));
assert!(!only_store.allows(&get_share_action()));
assert!(!only_store.allows(&unpair_action()));
assert!(!only_store.allows(&update_channel_info_action()));
assert!(!only_store.allows(&pre_pair_action()));
let none = AutoAcceptPolicy::default();
assert!(!none.allows(&store_share_action()));
let all = AutoAcceptPolicy::all();
assert!(all.allows(&store_share_action()));
assert!(all.allows(&verify_share_action()));
assert!(all.allows(&discovery_action()));
assert!(all.allows(&get_share_action()));
assert!(all.allows(&unpair_action()));
assert!(all.allows(&update_channel_info_action()));
assert!(all.allows(&pre_pair_action()));
}
}