Skip to content

Commit fc8d2c6

Browse files
Nicklas Warming JacobsenBennett Hardwick
authored andcommitted
Move fn EncryptedTable::prepare_record to it's own trait Preparable which is blanke implement for R: Searchable + Identifiable
1 parent 511256a commit fc8d2c6

File tree

5 files changed

+85
-64
lines changed

5 files changed

+85
-64
lines changed

src/crypto/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ mod unsealed;
66
use std::borrow::Cow;
77

88
use crate::{
9-
traits::{
10-
Encryptable, PrimaryKeyError, PrimaryKeyParts, ReadConversionError, Searchable,
11-
WriteConversionError,
12-
},
9+
traits::{PrimaryKeyError, PrimaryKeyParts, ReadConversionError, WriteConversionError},
1310
Identifiable, IndexType, PrimaryKey,
1411
};
1512
use cipherstash_client::{

src/crypto/sealer.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use super::{
2-
b64_encode, encrypt_primary_key, format_term_key, hmac, SealError, SealedTableEntry,
3-
UnsealSpec, Unsealed, MAX_TERMS_PER_INDEX,
2+
b64_encode, format_term_key, hmac, SealError, SealedTableEntry, Unsealed, MAX_TERMS_PER_INDEX,
43
};
54
use crate::{
65
encrypted_table::{TableAttribute, TableEntry},
76
traits::PrimaryKeyParts,
8-
Identifiable, IndexType, Searchable,
7+
IndexType,
98
};
109
use cipherstash_client::{
1110
credentials::{service_credentials::ServiceToken, Credentials},
1211
encryption::{
1312
compound_indexer::{ComposableIndex, ComposablePlaintext, CompoundIndex},
14-
Encryption, IndexTerm, Plaintext,
13+
Encryption, IndexTerm,
1514
},
1615
};
1716
use itertools::Itertools;

src/encrypted_table/mod.rs

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ pub use self::{
88
use crate::{
99
crypto::*,
1010
errors::*,
11-
traits::{Decryptable, PrimaryKeyParts, Searchable},
12-
Identifiable, IndexType, PrimaryKey,
11+
traits::{Decryptable, Preparable, PrimaryKeyParts, Searchable},
12+
Identifiable, IndexType,
1313
};
1414
use aws_sdk_dynamodb::types::{AttributeValue, Delete, Put, TransactWriteItem};
1515
use cipherstash_client::{
@@ -103,6 +103,20 @@ pub struct PreparedRecord {
103103
sealer: Sealer,
104104
}
105105

106+
impl PreparedRecord {
107+
pub(crate) fn new(
108+
protected_indexes: Cow<'static, [(Cow<'static, str>, IndexType)]>,
109+
protected_attributes: Cow<'static, [Cow<'static, str>]>,
110+
sealer: Sealer,
111+
) -> Self {
112+
Self {
113+
protected_indexes,
114+
protected_attributes,
115+
sealer,
116+
}
117+
}
118+
}
119+
106120
impl DynamoRecordPatch {
107121
/// Consume the [`DynamoRecordPatch`] and create a list of [`TransactWriteItem`] used to put
108122
/// and delete records from DynamoDB.
@@ -224,55 +238,6 @@ impl<D> EncryptedTable<D> {
224238
})
225239
}
226240

227-
pub fn prepare_record<E: Searchable + Identifiable>(
228-
&self,
229-
record: E,
230-
) -> Result<PreparedRecord, SealError> {
231-
let type_name = E::type_name();
232-
233-
let PrimaryKeyParts { pk, sk } = record
234-
.get_primary_key()
235-
.into_parts(&type_name, E::sort_key_prefix().as_deref());
236-
237-
let protected_indexes = E::protected_indexes();
238-
let protected_attributes = E::protected_attributes();
239-
240-
let unsealed_indexes = protected_indexes
241-
.iter()
242-
.map(|(index_name, index_type)| {
243-
record
244-
.attribute_for_index(index_name, *index_type)
245-
.and_then(|attr| {
246-
E::index_by_name(index_name, *index_type)
247-
.map(|index| (attr, index, index_name.clone(), *index_type))
248-
})
249-
.ok_or(SealError::MissingAttribute(index_name.to_string()))
250-
})
251-
.collect::<Result<Vec<_>, _>>()?;
252-
253-
let unsealed = record.into_unsealed();
254-
255-
let sealer = Sealer {
256-
pk,
257-
sk,
258-
259-
is_sk_encrypted: E::is_sk_encrypted(),
260-
is_pk_encrypted: E::is_pk_encrypted(),
261-
262-
type_name,
263-
264-
unsealed_indexes,
265-
266-
unsealed,
267-
};
268-
269-
Ok(PreparedRecord {
270-
protected_indexes,
271-
protected_attributes,
272-
sealer,
273-
})
274-
}
275-
276241
/// Create a [`DynamoRecordPatch`] used to insert records into DynamoDB.
277242
///
278243
/// This will create a root record with all attributes and index records that only include
@@ -401,7 +366,7 @@ impl EncryptedTable<Dynamo> {
401366
where
402367
T: Searchable + Identifiable,
403368
{
404-
let record = self.prepare_record(record)?;
369+
let record = record.prepare_record()?;
405370

406371
let transact_items = self
407372
.create_put_patch(

src/traits/mod.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use crate::crypto::{SealError, Sealer, Unsealed};
21
pub use crate::encrypted_table::{TableAttribute, TryFromTableAttr};
2+
use crate::{
3+
crypto::{SealError, Sealer, Unsealed},
4+
encrypted_table::PreparedRecord,
5+
};
36
use cipherstash_client::encryption::EncryptionError;
47
pub use cipherstash_client::{
58
credentials::{service_credentials::ServiceToken, Credentials},
@@ -148,3 +151,57 @@ pub trait Decryptable: Sized {
148151
/// Must be equal to or a subset of protected_attributes on the [`Encryptable`] type.
149152
fn plaintext_attributes() -> Cow<'static, [Cow<'static, str>]>;
150153
}
154+
155+
pub trait Preparable {
156+
fn prepare_record(self) -> Result<PreparedRecord, SealError>;
157+
}
158+
159+
impl<R> Preparable for R
160+
where
161+
R: Searchable + Identifiable,
162+
{
163+
fn prepare_record(self) -> Result<PreparedRecord, SealError> {
164+
let type_name = Self::type_name();
165+
166+
let PrimaryKeyParts { pk, sk } = self
167+
.get_primary_key()
168+
.into_parts(&type_name, Self::sort_key_prefix().as_deref());
169+
170+
let protected_indexes = Self::protected_indexes();
171+
let protected_attributes = Self::protected_attributes();
172+
173+
let unsealed_indexes = protected_indexes
174+
.iter()
175+
.map(|(index_name, index_type)| {
176+
self.attribute_for_index(index_name, *index_type)
177+
.and_then(|attr| {
178+
Self::index_by_name(index_name, *index_type)
179+
.map(|index| (attr, index, index_name.clone(), *index_type))
180+
})
181+
.ok_or(SealError::MissingAttribute(index_name.to_string()))
182+
})
183+
.collect::<Result<Vec<_>, _>>()?;
184+
185+
let unsealed = self.into_unsealed();
186+
187+
let sealer = Sealer {
188+
pk,
189+
sk,
190+
191+
is_sk_encrypted: Self::is_sk_encrypted(),
192+
is_pk_encrypted: Self::is_pk_encrypted(),
193+
194+
type_name,
195+
196+
unsealed_indexes,
197+
198+
unsealed,
199+
};
200+
201+
Ok(PreparedRecord::new(
202+
protected_indexes,
203+
protected_attributes,
204+
sealer,
205+
))
206+
}
207+
}

tests/headless_tests.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use aws_sdk_dynamodb::Client;
2-
use cipherstash_dynamodb::{Decryptable, Encryptable, EncryptedTable, Identifiable, Searchable};
2+
use cipherstash_dynamodb::{
3+
traits::Preparable, Decryptable, Encryptable, EncryptedTable, Identifiable, Searchable,
4+
};
35
use serial_test::serial;
46
use std::future::Future;
57

@@ -58,8 +60,9 @@ async fn test_headless_roundtrip() {
5860
.await
5961
.expect("failed to init table");
6062

61-
let user_record = table
62-
.prepare_record(user.clone())
63+
let user_record = user
64+
.clone()
65+
.prepare_record()
6366
.expect("failed to prepare record");
6467

6568
let patch = table

0 commit comments

Comments
 (0)