core_crypto/mls/session/
config.rs1use core_crypto_keystore::ConnectionType;
2use mls_crypto_provider::{DatabaseKey, EntropySeed};
3use typed_builder::TypedBuilder;
4
5use crate::{
6 MlsError,
7 mls::{
8 ciphersuite::MlsCiphersuite,
9 error::{Error, Result},
10 },
11 prelude::{ClientId, INITIAL_KEYING_MATERIAL_COUNT},
12};
13
14#[derive(Debug, Clone, TypedBuilder)]
18pub struct SessionConfig<'a> {
19 pub db_connection_type: ConnectionType<'a>,
21 pub database_key: DatabaseKey,
23 #[builder(default, setter(strip_option(fallback = client_id_opt)))]
27 pub client_id: Option<ClientId>,
28 #[builder(default, setter(strip_option(fallback = external_entropy_opt)))]
30 pub external_entropy: Option<&'a [u8]>,
31 #[builder(default, setter(transform = |iter: impl IntoIterator<Item = MlsCiphersuite>| iter.into_iter().collect()))]
33 pub ciphersuites: Vec<MlsCiphersuite>,
34 #[builder(default)]
38 pub nb_key_packages: Option<usize>,
39}
40impl<'a, Key, ClientId, ExternalEntropy, Ciphersuites, KPs>
41 SessionConfigBuilder<'a, ((), Key, ClientId, ExternalEntropy, Ciphersuites, KPs)>
42{
43 pub fn in_memory(
45 self,
46 ) -> SessionConfigBuilder<'a, ((ConnectionType<'a>,), Key, ClientId, ExternalEntropy, Ciphersuites, KPs)> {
47 self.db_connection_type(ConnectionType::InMemory)
48 }
49
50 pub fn persistent(
52 self,
53 path: &'a str,
54 ) -> SessionConfigBuilder<'a, ((ConnectionType<'a>,), Key, ClientId, ExternalEntropy, Ciphersuites, KPs)> {
55 self.db_connection_type(ConnectionType::Persistent(path))
56 }
57}
58
59#[derive(Debug)]
63pub struct ValidatedSessionConfig<'a> {
64 pub(super) db_connection_type: ConnectionType<'a>,
65 pub(super) database_key: DatabaseKey,
66 pub(super) client_id: Option<ClientId>,
67 pub(super) external_entropy: Option<EntropySeed>,
68 pub(super) ciphersuites: Vec<MlsCiphersuite>,
69 pub(super) nb_key_packages: usize,
70}
71
72impl<'a> SessionConfig<'a> {
73 pub fn validate(self) -> Result<ValidatedSessionConfig<'a>> {
77 let Self {
78 db_connection_type,
79 database_key,
80 client_id,
81 external_entropy,
82 ciphersuites,
83 nb_key_packages,
84 } = self;
85
86 if let ConnectionType::Persistent(path) = &db_connection_type
87 && path.trim().is_empty()
88 {
89 return Err(Error::MalformedIdentifier("persistent db path"));
90 }
91 if let Some(client_id) = &client_id
92 && client_id.is_empty()
93 {
94 return Err(Error::MalformedIdentifier("client_id"));
95 }
96
97 if client_id.is_some() && ciphersuites.is_empty() {
98 return Err(Error::MalformedIdentifier(
99 "ciphersuites must be non-empty if initializing (i.e. client_id is set)",
100 ));
101 }
102
103 let external_entropy = external_entropy
104 .map(EntropySeed::try_from_slice)
105 .transpose()
106 .map_err(MlsError::wrap("gathering external entropy"))?;
107
108 let nb_key_packages = nb_key_packages.unwrap_or(INITIAL_KEYING_MATERIAL_COUNT);
109
110 Ok(ValidatedSessionConfig {
111 db_connection_type,
112 database_key,
113 client_id,
114 external_entropy,
115 ciphersuites,
116 nb_key_packages,
117 })
118 }
119}
120
121impl<'a> TryFrom<SessionConfig<'a>> for ValidatedSessionConfig<'a> {
122 type Error = Error;
123
124 fn try_from(value: SessionConfig<'a>) -> std::result::Result<Self, Self::Error> {
125 value.validate()
126 }
127}