Skip to content

Commit 7216d14

Browse files
author
Bennett Hardwick
committed
Actually get things working
1 parent 34b3314 commit 7216d14

File tree

10 files changed

+319
-30
lines changed

10 files changed

+319
-30
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ To delete a record, use the [`EncryptedTable::delete`] method:
253253

254254
```rust
255255
#
256-
table.delete::<User>("jane@smith.org", User::type_name()).await?;
256+
table.delete::<User>("jane@smith.org", None).await?;
257257
```
258258

259259
#### Querying Records

examples/delete_user.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mod common;
22
use crate::common::User;
3-
use cryptonamo::{Encryptable, EncryptedTable};
3+
use cryptonamo::EncryptedTable;
44

55
#[tokio::main]
66
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -21,15 +21,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2121

2222
let table = EncryptedTable::init(client, "users").await?;
2323

24-
table
25-
.delete::<User>("jane@smith.org", User::type_name())
26-
.await?;
27-
table
28-
.delete::<User>("dan@coderdan.co", User::type_name())
29-
.await?;
30-
table
31-
.delete::<User>("daniel@example.com", User::type_name())
32-
.await?;
24+
table.delete::<User>("jane@smith.org", None).await?;
25+
table.delete::<User>("dan@coderdan.co", None).await?;
26+
table.delete::<User>("daniel@example.com", None).await?;
3327

3428
Ok(())
3529
}

examples/get_license.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2020
let client = aws_sdk_dynamodb::Client::new(&config);
2121

2222
let table = EncryptedTable::init(client, "users").await?;
23-
let license: Option<License> = table.get("dan@coderdan.co").await?;
23+
let license: Option<License> = table.get("dan@coderdan.co", None).await?;
2424

2525
dbg!(license);
2626

examples/get_user.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2020
let client = aws_sdk_dynamodb::Client::new(&config);
2121

2222
let table = EncryptedTable::init(client, "users").await?;
23-
let user: Option<User> = table.get("dan@coderdan.co").await?;
23+
let user: Option<User> = table.get("dan@coderdan.co", None).await?;
2424

2525
dbg!(user);
2626

src/crypto/sealer.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,10 @@ impl<T> Sealer<T> {
6060
T: Searchable,
6161
{
6262
let pk = encrypt_partition_key(&self.inner.partition_key(), cipher).unwrap(); // FIXME
63+
let sk = self.inner.sort_key();
6364

64-
let mut table_entry = TableEntry::new_with_attributes(
65-
pk.clone(),
66-
T::type_name().to_string(),
67-
None,
68-
self.unsealed.unprotected(),
69-
);
65+
let mut table_entry =
66+
TableEntry::new_with_attributes(pk.clone(), sk, None, self.unsealed.unprotected());
7067

7168
let protected = T::protected_attributes()
7269
.iter()
@@ -84,6 +81,8 @@ impl<T> Sealer<T> {
8481
}
8582
});
8683

84+
let sort_key = self.inner.sort_key();
85+
8786
let protected_indexes = T::protected_indexes();
8887
let terms: Vec<(&&str, Vec<u8>)> = protected_indexes
8988
.iter()
@@ -126,7 +125,7 @@ impl<T> Sealer<T> {
126125
.clone()
127126
.set_term(hex::encode(term))
128127
// TODO: HMAC the sort key, too (users#index_name#pk)
129-
.set_sk(format!("{}#{}#{}", T::type_name(), index_name, i)),
128+
.set_sk(format!("{}#{}#{}", &sort_key, index_name, i)),
130129
)
131130
})
132131
.chain(once(Sealed(table_entry.clone())))

src/encrypted_table/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,14 @@ impl EncryptedTable {
112112
QueryBuilder::new(self)
113113
}
114114

115-
pub async fn get<T>(&self, pk: &str) -> Result<Option<T>, GetError>
115+
pub async fn get<T>(&self, pk: &str, sk: Option<&str>) -> Result<Option<T>, GetError>
116116
where
117117
T: Decryptable,
118118
{
119119
let pk = encrypt_partition_key(pk, &self.cipher)?;
120-
let sk = T::type_name().to_string();
120+
let sk = sk
121+
.map(|sk| format!("{}#{}", T::type_name(), sk))
122+
.unwrap_or_else(|| T::type_name().to_string());
121123

122124
let result = self
123125
.db
@@ -142,10 +144,12 @@ impl EncryptedTable {
142144
pub async fn delete<E: Searchable>(
143145
&self,
144146
pk: &str,
145-
sk: impl Into<String>,
147+
sk: Option<&str>,
146148
) -> Result<(), DeleteError> {
147149
let pk = AttributeValue::S(encrypt_partition_key(pk, &self.cipher)?);
148-
let sk: String = sk.into();
150+
let sk = sk
151+
.map(|sk| format!("{}#{}", E::type_name(), sk))
152+
.unwrap_or_else(|| E::type_name().to_string());
149153

150154
let sk_to_delete = all_index_keys::<E>(&sk).into_iter().into_iter().chain([sk]);
151155

tests/common.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use aws_sdk_dynamodb::{
2+
types::{
3+
AttributeDefinition, GlobalSecondaryIndex, KeySchemaElement, KeyType, Projection,
4+
ProjectionType, ProvisionedThroughput, ScalarAttributeType,
5+
},
6+
Client,
7+
};
8+
9+
pub async fn create_table(client: &Client, table_name: &str) {
10+
let _ = client.delete_table().table_name(table_name).send().await;
11+
12+
client
13+
.create_table()
14+
.table_name(table_name)
15+
.attribute_definitions(
16+
AttributeDefinition::builder()
17+
.attribute_name("pk")
18+
.attribute_type(ScalarAttributeType::S)
19+
.build(),
20+
)
21+
.attribute_definitions(
22+
AttributeDefinition::builder()
23+
.attribute_name("sk")
24+
.attribute_type(ScalarAttributeType::S)
25+
.build(),
26+
)
27+
.attribute_definitions(
28+
AttributeDefinition::builder()
29+
.attribute_name("term")
30+
.attribute_type(ScalarAttributeType::S)
31+
.build(),
32+
)
33+
.key_schema(
34+
KeySchemaElement::builder()
35+
.attribute_name("pk")
36+
.key_type(KeyType::Hash)
37+
.build(),
38+
)
39+
.key_schema(
40+
KeySchemaElement::builder()
41+
.attribute_name("sk")
42+
.key_type(KeyType::Range)
43+
.build(),
44+
)
45+
.provisioned_throughput(
46+
ProvisionedThroughput::builder()
47+
.read_capacity_units(5)
48+
.write_capacity_units(5)
49+
.build(),
50+
)
51+
.global_secondary_indexes(
52+
GlobalSecondaryIndex::builder()
53+
.index_name("TermIndex")
54+
.key_schema(
55+
KeySchemaElement::builder()
56+
.attribute_name("term")
57+
.key_type(KeyType::Hash)
58+
.build(),
59+
)
60+
.projection(
61+
Projection::builder()
62+
.projection_type(ProjectionType::All)
63+
.build(),
64+
)
65+
.provisioned_throughput(
66+
ProvisionedThroughput::builder()
67+
.read_capacity_units(5)
68+
.write_capacity_units(5)
69+
.build(),
70+
)
71+
.build(),
72+
)
73+
.send()
74+
.await
75+
.expect("Failed to create table");
76+
}

tests/query_tests.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use cryptonamo::{Decryptable, Encryptable, EncryptedTable, Searchable};
1+
use cryptonamo::{Encryptable, EncryptedTable};
2+
use cryptonamo_derive::{Decryptable, Searchable};
23
use itertools::Itertools;
34
use serial_test::serial;
45
use std::future::Future;
56

7+
mod common;
8+
69
#[derive(Encryptable, Decryptable, Searchable, Debug, PartialEq, Ord, PartialOrd, Eq)]
710
#[cryptonamo(sort_key_prefix = "user")]
811
pub struct User {
@@ -23,7 +26,7 @@ pub struct User {
2326
}
2427

2528
impl User {
26-
fn new(email: impl Into<String>, name: impl Into<String>, tag: impl Into<String>) -> Self {
29+
pub fn new(email: impl Into<String>, name: impl Into<String>, tag: impl Into<String>) -> Self {
2730
Self {
2831
name: name.into(),
2932
email: email.into(),
@@ -41,7 +44,11 @@ async fn run_test<F: Future<Output = ()>>(mut f: impl FnMut(EncryptedTable) -> F
4144

4245
let client = aws_sdk_dynamodb::Client::new(&config);
4346

44-
let table = EncryptedTable::init(client, "users")
47+
let table_name = "test-users";
48+
49+
common::create_table(&client, table_name).await;
50+
51+
let table = EncryptedTable::init(client, table_name)
4552
.await
4653
.expect("Failed to init table");
4754

@@ -131,7 +138,10 @@ async fn test_query_compound() {
131138
#[serial]
132139
async fn test_get_by_partition_key() {
133140
run_test(|table| async move {
134-
let res: Option<User> = table.get("dan@coderdan.co").await.expect("Failed to send");
141+
let res: Option<User> = table
142+
.get("dan@coderdan.co", None)
143+
.await
144+
.expect("Failed to send");
135145
assert_eq!(
136146
res,
137147
Some(User::new("dan@coderdan.co", "Dan Draper", "blue"))
@@ -145,12 +155,12 @@ async fn test_get_by_partition_key() {
145155
async fn test_delete() {
146156
run_test(|table| async move {
147157
table
148-
.delete::<User>("dan@coderdan.co", User::type_name())
158+
.delete::<User>("dan@coderdan.co", None)
149159
.await
150160
.expect("Failed to send");
151161

152162
let res = table
153-
.get::<User>("dan@coderdan.co")
163+
.get::<User>("dan@coderdan.co", None)
154164
.await
155165
.expect("Failed to send");
156166
assert_eq!(res, None);

tests/tenant_query_tests.rs

Whitespace-only changes.

0 commit comments

Comments
 (0)