use core::sync::atomic::AtomicBool;
use ockam_core::compat::sync::Arc;
use ockam_core::flow_control::FlowControls;
use ockam_core::Result;
use ockam_core::{Address, Route};
use ockam_node::{Context, WorkerBuilder};
use tracing::info;
use crate::identities::Identities;
use crate::models::Identifier;
use crate::secure_channel::handshake_worker::HandshakeWorker;
use crate::secure_channel::{
Addresses, DecryptorHandler, RemoteRoute, Role, SecureChannelListenerOptions,
SecureChannelListenerWorker, SecureChannelOptions, SecureChannelRegistry,
SecureChannelSharedState,
};
#[cfg(feature = "storage")]
use crate::SecureChannelsBuilder;
use crate::{
IdentityError, SecureChannel, SecureChannelListener, SecureChannelRegistryEntry,
SecureChannelRepository, Vault,
};
#[derive(Clone)]
pub struct SecureChannels {
pub(crate) identities: Arc<Identities>,
pub(crate) secure_channel_registry: SecureChannelRegistry,
pub(crate) secure_channel_repository: Arc<dyn SecureChannelRepository>,
}
impl SecureChannels {
pub fn new(
identities: Arc<Identities>,
secure_channel_registry: SecureChannelRegistry,
secure_channel_repository: Arc<dyn SecureChannelRepository>,
) -> Self {
Self {
identities,
secure_channel_registry,
secure_channel_repository,
}
}
pub fn from_identities(
identities: Arc<Identities>,
secure_channel_repository: Arc<dyn SecureChannelRepository>,
) -> Arc<Self> {
Arc::new(Self::new(
identities,
SecureChannelRegistry::default(),
secure_channel_repository,
))
}
pub fn identities(&self) -> Arc<Identities> {
self.identities.clone()
}
pub fn vault(&self) -> Vault {
self.identities.vault()
}
pub fn secure_channel_registry(&self) -> SecureChannelRegistry {
self.secure_channel_registry.clone()
}
pub fn secure_channel_repository(&self) -> Arc<dyn SecureChannelRepository> {
self.secure_channel_repository.clone()
}
#[cfg(feature = "storage")]
pub async fn builder() -> Result<SecureChannelsBuilder> {
Ok(SecureChannelsBuilder {
identities_builder: Identities::builder().await?,
registry: SecureChannelRegistry::new(),
secure_channel_repository: Arc::new(crate::SecureChannelSqlxDatabase::create().await?),
})
}
}
impl SecureChannels {
pub fn create_secure_channel_listener(
&self,
ctx: &Context,
identifier: &Identifier,
address: impl Into<Address>,
options: impl Into<SecureChannelListenerOptions>,
) -> Result<SecureChannelListener> {
let address = address.into();
let options = options.into();
let key_exchange_only = options.key_exchange_only;
let flow_control_id = options.flow_control_id.clone();
SecureChannelListenerWorker::create(
ctx,
Arc::new(self.clone()),
identifier,
address.clone(),
options,
)?;
Ok(SecureChannelListener::new(
address,
key_exchange_only,
flow_control_id,
))
}
pub async fn create_secure_channel(
&self,
ctx: &Context,
identifier: &Identifier,
route: impl Into<Route>,
options: impl Into<SecureChannelOptions>,
) -> Result<SecureChannel> {
let addresses = Addresses::generate(Role::Initiator);
let options = options.into();
let flow_control_id = options.flow_control_id.clone();
let route = route.into();
let next = route.next()?;
options.setup_flow_control(ctx.flow_controls(), &addresses, next);
let decryptor_outgoing_access_control =
options.create_decryptor_outgoing_access_control(ctx.flow_controls());
let purpose_key = self
.identities
.purpose_keys()
.purpose_keys_creation()
.get_or_create_secure_channel_purpose_key(identifier)
.await?;
let credential_retriever = match &options.credential_retriever_creator {
Some(credential_retriever_creator) => {
let credential_retriever = credential_retriever_creator.create(identifier).await?;
credential_retriever.initialize().await?;
Some(credential_retriever)
}
None => None,
};
let secure_channel_repository = if options.is_persistent {
Some(self.secure_channel_repository())
} else {
None
};
let encryptor_remote_route = RemoteRoute::create();
let Some(their_identifier) = HandshakeWorker::create(
ctx,
Arc::new(self.clone()),
addresses.clone(),
identifier.clone(),
purpose_key,
options.trust_policy,
decryptor_outgoing_access_control,
credential_retriever,
options.authority,
Some(route),
Some(options.timeout),
Role::Initiator,
options.key_exchange_only,
secure_channel_repository,
encryptor_remote_route.clone(),
)
.await?
else {
return Err(IdentityError::HandshakeInternalError)?;
};
Ok(SecureChannel::new(
ctx.flow_controls().clone(),
their_identifier,
encryptor_remote_route,
addresses,
options.key_exchange_only,
flow_control_id,
))
}
pub async fn start_persisted_secure_channel_decryptor(
&self,
ctx: &Context,
decryptor_remote_address: &Address,
) -> Result<SecureChannel> {
info!(
"Starting persisted secure channel: {}",
decryptor_remote_address
);
let Some(persisted_secure_channel) = self
.secure_channel_repository
.get(decryptor_remote_address)
.await?
else {
return Err(IdentityError::PersistentSecureChannelNotFound)?;
};
let decryption_key = persisted_secure_channel.decryption_key_handle().clone();
self.vault()
.secure_channel_vault
.load_aead_key(&decryption_key)
.await?;
let my_identifier = persisted_secure_channel.my_identifier();
let their_identifier = persisted_secure_channel.their_identifier();
let role = persisted_secure_channel.role();
let shared_state = SecureChannelSharedState {
remote_route: RemoteRoute::create(), should_send_close: Arc::new(AtomicBool::new(false)), };
let mut addresses = Addresses::generate(role);
addresses.decryptor_remote = persisted_secure_channel.decryptor_remote().clone();
addresses.decryptor_api = persisted_secure_channel.decryptor_api().clone();
let decryptor_handler = DecryptorHandler::new(
self.identities(),
None, role,
true,
addresses.clone(),
decryption_key,
self.vault().secure_channel_vault.clone(),
their_identifier.clone(),
shared_state.clone(),
);
let decryptor_worker = HandshakeWorker::new(
Arc::new(self.clone()),
None, None,
my_identifier.clone(),
addresses.clone(),
role,
true,
None, Some(decryptor_handler),
None, self.identities.change_history_repository(),
None, None,
shared_state.clone(),
);
WorkerBuilder::new(decryptor_worker)
.with_address(addresses.decryptor_api.clone()) .start(ctx)?;
let sc = SecureChannel::new(
ctx.flow_controls().clone(),
their_identifier.clone(),
shared_state.remote_route,
addresses.clone(),
true,
FlowControls::generate_flow_control_id(), );
let info = SecureChannelRegistryEntry::new(
addresses.encryptor.clone(),
addresses.encryptor_api.clone(),
addresses.decryptor_remote.clone(),
addresses.decryptor_api.clone(),
role.is_initiator(),
my_identifier.clone(),
their_identifier.clone(),
Address::random_local(), );
self.secure_channel_registry.register_channel(info)?;
Ok(sc)
}
pub fn stop_secure_channel(&self, ctx: &Context, channel: &Address) -> Result<()> {
ctx.stop_address(channel)
}
}