Skip to content
22 changes: 22 additions & 0 deletions keystore/src/entities/general.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// Consumers of this library can use this to specify data to be persisted at the end of
/// a transaction.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(target_family = "wasm", feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
pub struct ConsumerData {
pub content: Vec<u8>,
}

impl From<Vec<u8>> for ConsumerData {
fn from(content: Vec<u8>) -> Self {
Self { content }
}
}

impl From<ConsumerData> for Vec<u8> {
fn from(consumer_data: ConsumerData) -> Self {
consumer_data.content
}
}
3 changes: 3 additions & 0 deletions keystore/src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

pub(crate) mod general;
pub(crate) mod mls;

pub use self::general::*;
pub use self::mls::*;

cfg_if::cfg_if! {
Expand Down
49 changes: 49 additions & 0 deletions keystore/src/entities/platform/generic/general.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::{
connection::KeystoreDatabaseConnection,
entities::{ConsumerData, Entity, EntityBase, EntityFindParams, StringEntityId, UniqueEntity},
CryptoKeystoreResult, MissingKeyErrorKind,
};

impl Entity for ConsumerData {
fn id_raw(&self) -> &[u8] {
&[Self::ID as u8]
}
}

#[async_trait::async_trait]
impl UniqueEntity for ConsumerData {
fn new(content: Vec<u8>) -> Self {
Self { content }
}

fn content(&self) -> &[u8] {
&self.content
}
}

#[async_trait::async_trait]
impl EntityBase for ConsumerData {
type ConnectionType = KeystoreDatabaseConnection;
type AutoGeneratedFields = ();
const COLLECTION_NAME: &'static str = "consumer_data";

fn to_missing_key_err_kind() -> MissingKeyErrorKind {
MissingKeyErrorKind::ConsumerData
}

fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity {
crate::transaction::dynamic_dispatch::Entity::ConsumerData(self)
}

async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
<Self as UniqueEntity>::find_all(conn, params).await
}

async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
<Self as UniqueEntity>::find_one(conn).await
}

async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
<Self as UniqueEntity>::count(conn).await
}
}
2 changes: 2 additions & 0 deletions keystore/src/entities/platform/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

mod general;
mod mls;

pub use self::mls::*;

cfg_if::cfg_if! {
Expand Down
56 changes: 56 additions & 0 deletions keystore/src/entities/platform/wasm/general.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::connection::DatabaseConnection;
use crate::entities::Entity;
use crate::{
connection::KeystoreDatabaseConnection,
entities::{ConsumerData, EntityBase, EntityFindParams, StringEntityId, UniqueEntity},
CryptoKeystoreResult, MissingKeyErrorKind,
};

#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
impl EntityBase for ConsumerData {
type ConnectionType = KeystoreDatabaseConnection;
type AutoGeneratedFields = ();
const COLLECTION_NAME: &'static str = "consumer_data";

fn to_missing_key_err_kind() -> MissingKeyErrorKind {
MissingKeyErrorKind::ConsumerData
}

fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity {
crate::transaction::dynamic_dispatch::Entity::ConsumerData(self)
}

async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
<Self as UniqueEntity>::find_all(conn, params).await
}

async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
<Self as UniqueEntity>::find_one(conn).await
}

async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
<Self as UniqueEntity>::count(conn).await
}
}

impl Entity for ConsumerData {
fn id_raw(&self) -> &[u8] {
&Self::ID
}

fn encrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()> {
self.content = self.encrypt_data(cipher, self.content.as_slice())?;
Self::ConnectionType::check_buffer_size(self.content.len())?;
Ok(())
}

fn decrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()> {
self.content = self.decrypt_data(cipher, self.content.as_slice())?;
Ok(())
}
}

#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
impl UniqueEntity for ConsumerData {}
2 changes: 2 additions & 0 deletions keystore/src/entities/platform/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

mod general;
mod mls;

pub use self::mls::*;

cfg_if::cfg_if! {
Expand Down
2 changes: 2 additions & 0 deletions keystore/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
/// Error to represent when a key is not present in the KeyStore
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum MissingKeyErrorKind {
#[error("Consumer Data")]
ConsumerData,
#[error("MLS KeyPackageBundle")]
MlsKeyPackageBundle,
#[error("MLS SignatureKeyPair")]
Expand Down
10 changes: 6 additions & 4 deletions keystore/src/transaction/dynamic_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

use crate::connection::TransactionWrapper;
use crate::entities::{
E2eiAcmeCA, E2eiCrl, E2eiEnrollment, E2eiIntermediateCert, E2eiRefreshToken, EntityBase, EntityTransactionExt,
MlsCredential, MlsEncryptionKeyPair, MlsEpochEncryptionKeyPair, MlsHpkePrivateKey, MlsKeyPackage,
MlsPendingMessage, MlsPskBundle, MlsSignatureKeyPair, PersistedMlsGroup, PersistedMlsPendingGroup, StringEntityId,
UniqueEntity,
ConsumerData, E2eiAcmeCA, E2eiCrl, E2eiEnrollment, E2eiIntermediateCert, E2eiRefreshToken, EntityBase,
EntityTransactionExt, MlsCredential, MlsEncryptionKeyPair, MlsEpochEncryptionKeyPair, MlsHpkePrivateKey,
MlsKeyPackage, MlsPendingMessage, MlsPskBundle, MlsSignatureKeyPair, PersistedMlsGroup, PersistedMlsPendingGroup,
StringEntityId, UniqueEntity,
};
#[cfg(feature = "proteus-keystore")]
use crate::entities::{ProteusIdentity, ProteusPrekey, ProteusSession};
use crate::{CryptoKeystoreError, CryptoKeystoreResult};

#[derive(Debug)]
pub enum Entity {
ConsumerData(ConsumerData),
SignatureKeyPair(MlsSignatureKeyPair),
HpkePrivateKey(MlsHpkePrivateKey),
KeyPackage(MlsKeyPackage),
Expand Down Expand Up @@ -146,6 +147,7 @@ impl EntityId {

pub async fn execute_save(tx: &TransactionWrapper<'_>, entity: &Entity) -> CryptoKeystoreResult<()> {
match entity {
Entity::ConsumerData(consumer_data) => consumer_data.replace(tx).await,
Entity::SignatureKeyPair(mls_signature_key_pair) => mls_signature_key_pair.save(tx).await,
Entity::HpkePrivateKey(mls_hpke_private_key) => mls_hpke_private_key.save(tx).await,
Entity::KeyPackage(mls_key_package) => mls_key_package.save(tx).await,
Expand Down
11 changes: 6 additions & 5 deletions keystore/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub mod dynamic_dispatch;
use crate::entities::mls::*;
#[cfg(feature = "proteus-keystore")]
use crate::entities::proteus::*;
use crate::entities::{EntityBase, EntityFindParams, EntityTransactionExt, UniqueEntity};
use crate::entities::{ConsumerData, EntityBase, EntityFindParams, EntityTransactionExt, UniqueEntity};
use crate::transaction::dynamic_dispatch::EntityId;
use crate::{
connection::{Connection, DatabaseConnection, FetchFromDatabase, KeystoreDatabaseConnection},
Expand Down Expand Up @@ -341,12 +341,13 @@ impl KeystoreTransaction {
(identifier_12, E2eiRefreshToken),
(identifier_13, E2eiAcmeCA),
(identifier_14, E2eiIntermediateCert),
(identifier_15, E2eiCrl)
(identifier_15, E2eiCrl),
(identifier_16, ConsumerData)
],
proteus_types: [
(identifier_16, ProteusPrekey),
(identifier_17, ProteusIdentity),
(identifier_18, ProteusSession)
(identifier_17, ProteusPrekey),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how these identifiers are used. Are these identifiers persisted at all? Can anything go wrong by moving identifier_16 from ProteusPrekey to ConsumerData?

Copy link
Contributor Author

@SimonThormeyer SimonThormeyer Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These identifiers are merely used to hold the data from the in-memory cache before it is committed. So it doesn't matter what their name is/was at all.

If we can create them internally in the macro instead of passing them in, I would like doing so!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating idents like this within a macro is tricky but not impossible.

In the future, it will be easier: combine the ${index()} metafunction with the paste! macro and we should be able to generate all these idents automatically.

For now, ${index()} is still not stable, so you have to use recursive macro tricks to build up a unary number for each index and then count how many symbols appear in that number. This approach is complicated and opaque enough I'd recommend not reworking the existing macro until ${index()} stabilizes.

(identifier_18, ProteusIdentity),
(identifier_19, ProteusSession)
]
);

Expand Down