use cfg_if::cfg_if;
use ockam_core::compat::sync::Arc;
use ockam_core::compat::vec::Vec;
use ockam_core::flow_control::{FlowControlId, FlowControlOutgoingAccessControl, FlowControls};
use ockam_core::{Address, OutgoingAccessControl, Result};
use crate::models::CredentialAndPurposeKey;
use crate::secure_channel::Addresses;
use crate::{
CredentialRetrieverCreator, Identifier, IdentityError, MemoryCredentialRetrieverCreator,
TrustEveryonePolicy, TrustPolicy,
};
use core::fmt;
use core::fmt::Formatter;
use core::time::Duration;
#[cfg(feature = "std")]
use ockam_core::env::get_env_with_default;
pub(super) const DEFAULT_TIMEOUT: Duration = Duration::from_secs(120);
pub const OCKAM_DEFAULT_TIMEOUT: &str = "OCKAM_DEFAULT_TIMEOUT";
pub struct SecureChannelOptions {
pub(crate) flow_control_id: FlowControlId,
pub(crate) trust_policy: Arc<dyn TrustPolicy>,
pub(crate) authority: Option<Identifier>,
pub(crate) credential_retriever_creator: Option<Arc<dyn CredentialRetrieverCreator>>,
pub(crate) timeout: Duration,
pub(crate) key_exchange_only: bool,
pub(crate) is_persistent: bool,
}
impl fmt::Debug for SecureChannelOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "FlowId: {}", self.flow_control_id)
}
}
impl SecureChannelOptions {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
flow_control_id: FlowControls::generate_flow_control_id(),
trust_policy: Arc::new(TrustEveryonePolicy),
authority: None,
credential_retriever_creator: None,
timeout: DEFAULT_TIMEOUT,
key_exchange_only: false,
is_persistent: false,
}
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn with_credential_retriever_creator(
mut self,
credential_retriever_creator: Arc<dyn CredentialRetrieverCreator>,
) -> Result<Self> {
if self.credential_retriever_creator.is_some() {
return Err(IdentityError::CredentialRetrieverCreatorAlreadySet.into());
}
self.credential_retriever_creator = Some(credential_retriever_creator);
Ok(self)
}
pub fn with_credential(self, credential: CredentialAndPurposeKey) -> Result<Self> {
self.with_credential_retriever_creator(Arc::new(MemoryCredentialRetrieverCreator::new(
credential,
)))
}
pub fn with_authority(mut self, authority: Identifier) -> Self {
self.authority = Some(authority);
self
}
pub fn with_trust_policy(mut self, trust_policy: impl TrustPolicy) -> Self {
self.trust_policy = Arc::new(trust_policy);
self
}
pub fn producer_flow_control_id(&self) -> FlowControlId {
self.flow_control_id.clone()
}
pub fn key_exchange_only(mut self) -> Self {
self.key_exchange_only = true;
self
}
pub fn persist(mut self) -> Result<Self> {
if !self.key_exchange_only {
return Err(IdentityError::PersistentSupportIsLimited.into());
}
self.is_persistent = true;
Ok(self)
}
}
impl SecureChannelOptions {
pub(crate) fn setup_flow_control_producer(
flow_control_id: &FlowControlId,
flow_controls: &FlowControls,
addresses: &Addresses,
) {
flow_controls.add_producer(
&addresses.decryptor_internal,
flow_control_id,
None,
vec![addresses.encryptor.clone()],
);
}
pub(crate) fn setup_flow_control_consumer(
flow_controls: &FlowControls,
addresses: &Addresses,
next: &Address,
) {
if let Some(flow_control_id) = flow_controls
.find_flow_control_with_producer_address(next)
.map(|x| x.flow_control_id().clone())
{
flow_controls.add_consumer(&addresses.decryptor_remote, &flow_control_id);
}
}
pub(crate) fn setup_flow_control(
&self,
flow_controls: &FlowControls,
addresses: &Addresses,
next: &Address,
) {
Self::setup_flow_control_consumer(flow_controls, addresses, next);
Self::setup_flow_control_producer(&self.flow_control_id, flow_controls, addresses);
}
pub(crate) fn create_decryptor_outgoing_access_control(
&self,
flow_controls: &FlowControls,
) -> Arc<dyn OutgoingAccessControl> {
let ac = FlowControlOutgoingAccessControl::new(
flow_controls,
self.flow_control_id.clone(),
None,
);
Arc::new(ac)
}
}
pub struct SecureChannelListenerOptions {
pub(crate) consumer: Vec<FlowControlId>,
pub(crate) flow_control_id: FlowControlId,
pub(crate) trust_policy: Arc<dyn TrustPolicy>,
pub(crate) authority: Option<Identifier>,
pub(crate) credential_retriever_creator: Option<Arc<dyn CredentialRetrieverCreator>>,
pub(crate) key_exchange_only: bool,
pub(crate) is_persistent: bool,
}
impl fmt::Debug for SecureChannelListenerOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "SpawnerFlowId: {}", self.flow_control_id)
}
}
impl SecureChannelListenerOptions {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
consumer: vec![],
flow_control_id: FlowControls::generate_flow_control_id(),
trust_policy: Arc::new(TrustEveryonePolicy),
authority: None,
credential_retriever_creator: None,
key_exchange_only: false,
is_persistent: false,
}
}
pub fn as_consumer(mut self, id: &FlowControlId) -> Self {
self.consumer.push(id.clone());
self
}
pub fn with_credential_retriever_creator(
mut self,
credential_retriever_creator: Arc<dyn CredentialRetrieverCreator>,
) -> Result<Self> {
if self.credential_retriever_creator.is_some() {
return Err(IdentityError::CredentialRetrieverCreatorAlreadySet.into());
}
self.credential_retriever_creator = Some(credential_retriever_creator);
Ok(self)
}
pub fn with_credential(self, credential: CredentialAndPurposeKey) -> Result<Self> {
self.with_credential_retriever_creator(Arc::new(MemoryCredentialRetrieverCreator::new(
credential,
)))
}
pub fn with_authority(mut self, authority: Identifier) -> Self {
self.authority = Some(authority);
self
}
pub fn with_trust_policy(mut self, trust_policy: impl TrustPolicy) -> Self {
self.trust_policy = Arc::new(trust_policy);
self
}
pub fn spawner_flow_control_id(&self) -> FlowControlId {
self.flow_control_id.clone()
}
pub fn key_exchange_only(mut self) -> Self {
self.key_exchange_only = true;
self
}
pub fn persist(mut self) -> Result<Self> {
if !self.key_exchange_only {
return Err(IdentityError::PersistentSupportIsLimited.into());
}
self.is_persistent = true;
Ok(self)
}
}
impl SecureChannelListenerOptions {
pub(crate) fn setup_flow_control_for_listener(
&self,
flow_controls: &FlowControls,
address: &Address,
) {
for id in &self.consumer {
flow_controls.add_consumer(address, id);
}
flow_controls.add_spawner(address, &self.flow_control_id);
}
pub(crate) fn setup_flow_control_for_channel(
&self,
flow_controls: &FlowControls,
listener_address: &Address,
addresses: &Addresses,
) -> FlowControlId {
for id in flow_controls.get_flow_control_ids_for_consumer(listener_address) {
flow_controls.add_consumer(&addresses.decryptor_remote, &id);
}
let flow_control_id = FlowControls::generate_flow_control_id();
flow_controls.add_producer(
&addresses.decryptor_internal,
&flow_control_id,
Some(&self.flow_control_id),
vec![addresses.encryptor.clone()],
);
flow_control_id
}
pub(crate) fn create_decryptor_outgoing_access_control(
&self,
flow_controls: &FlowControls,
flow_control_id: FlowControlId,
) -> Arc<dyn OutgoingAccessControl> {
let ac = FlowControlOutgoingAccessControl::new(
flow_controls,
flow_control_id,
Some(self.flow_control_id.clone()),
);
Arc::new(ac)
}
}
pub fn get_default_timeout() -> Duration {
cfg_if! {
if #[cfg(feature = "std")] {
get_env_with_default::<Duration>(OCKAM_DEFAULT_TIMEOUT, DEFAULT_TIMEOUT)
.ok()
.unwrap_or(DEFAULT_TIMEOUT)
} else {
DEFAULT_TIMEOUT
}
}
}