Skip to content

Commit 5011881

Browse files
committed
enable remote encryption support for remote and synced databases
1 parent 84961b8 commit 5011881

8 files changed

Lines changed: 97 additions & 48 deletions

File tree

libsql/examples/encryption_sync.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Example of using offline writes with encryption
22

3-
use libsql::{params, Builder, EncryptionContext, EncryptionKey};
3+
use libsql::{params, Builder};
4+
use libsql::{EncryptionContext, EncryptionKey};
45

56
#[tokio::main]
67
async fn main() {
@@ -24,7 +25,8 @@ async fn main() {
2425
None
2526
};
2627

27-
let db_builder = Builder::new_synced_database(db_path, sync_url, auth_token, encryption);
28+
let db_builder =
29+
Builder::new_synced_database(db_path, sync_url, auth_token).remote_encryption(encryption);
2830

2931
let db = match db_builder.build().await {
3032
Ok(db) => db,

libsql/src/database.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub use builder::Builder;
88
pub use libsql_sys::{Cipher, EncryptionConfig};
99

1010
use crate::{Connection, Result};
11+
use base64::engine::general_purpose;
12+
use base64::Engine;
1113
use std::fmt;
1214
use std::sync::atomic::AtomicU64;
1315

@@ -100,7 +102,7 @@ enum DbType {
100102
auth_token: String,
101103
connector: crate::util::ConnectorService,
102104
_bg_abort: Option<std::sync::Arc<crate::sync::DropAbort>>,
103-
remote_encryption: Option<crate::sync::EncryptionContext>,
105+
remote_encryption: Option<EncryptionContext>,
104106
},
105107
#[cfg(feature = "remote")]
106108
Remote {
@@ -109,6 +111,7 @@ enum DbType {
109111
connector: crate::util::ConnectorService,
110112
version: Option<String>,
111113
namespace: Option<String>,
114+
remote_encryption: Option<EncryptionContext>,
112115
},
113116
}
114117

@@ -545,6 +548,7 @@ cfg_remote! {
545548
connector: crate::util::ConnectorService::new(svc),
546549
version,
547550
namespace: None,
551+
remote_encryption: None
548552
},
549553
max_write_replication_index: Default::default(),
550554
})
@@ -733,6 +737,7 @@ impl Database {
733737
connector,
734738
version,
735739
namespace,
740+
remote_encryption,
736741
} => {
737742
let conn = std::sync::Arc::new(
738743
crate::hrana::connection::HttpConnection::new_with_connector(
@@ -741,7 +746,7 @@ impl Database {
741746
connector.clone(),
742747
version.as_ref().map(|s| s.as_str()),
743748
namespace.as_ref().map(|s| s.as_str()),
744-
None,
749+
remote_encryption.clone(),
745750
),
746751
);
747752

@@ -785,3 +790,26 @@ impl std::fmt::Debug for Database {
785790
f.debug_struct("Database").finish()
786791
}
787792
}
793+
794+
#[derive(Debug, Clone)]
795+
pub enum EncryptionKey {
796+
/// The key is a base64-encoded string.
797+
Base64Encoded(String),
798+
/// The key is a byte array.
799+
Bytes(Vec<u8>),
800+
}
801+
802+
impl EncryptionKey {
803+
pub fn as_string(&self) -> String {
804+
match self {
805+
EncryptionKey::Base64Encoded(s) => s.clone(),
806+
EncryptionKey::Bytes(b) => general_purpose::STANDARD.encode(b),
807+
}
808+
}
809+
}
810+
811+
#[derive(Debug, Clone)]
812+
pub struct EncryptionContext {
813+
/// The base64-encoded key for the encryption, sent on every request.
814+
pub key: EncryptionKey,
815+
}

libsql/src/database/builder.rs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cfg_core! {
55
use super::DbType;
66
use crate::{Database, Result};
77

8-
pub use crate::sync::EncryptionContext;
8+
pub use crate::database::EncryptionContext;
99

1010
/// A builder for [`Database`]. This struct can be used to build
1111
/// all variants of [`Database`]. These variants include:
@@ -52,8 +52,6 @@ impl Builder<()> {
5252
path: impl AsRef<std::path::Path>,
5353
url: String,
5454
auth_token: String,
55-
#[cfg(feature = "sync")]
56-
remote_encryption: Option<crate::sync::EncryptionContext>,
5755
) -> Builder<RemoteReplica> {
5856
Builder {
5957
inner: RemoteReplica {
@@ -64,6 +62,7 @@ impl Builder<()> {
6462
connector: None,
6563
version: None,
6664
namespace: None,
65+
remote_encryption: None
6766
},
6867
encryption_config: None,
6968
read_your_writes: true,
@@ -73,7 +72,7 @@ impl Builder<()> {
7372
#[cfg(feature = "sync")]
7473
sync_protocol: Default::default(),
7574
#[cfg(feature = "sync")]
76-
remote_encryption,
75+
remote_encryption: None
7776
},
7877
}
7978
}
@@ -98,7 +97,6 @@ impl Builder<()> {
9897
path: impl AsRef<std::path::Path>,
9998
url: String,
10099
auth_token: String,
101-
remote_encryption: Option<EncryptionContext>,
102100
) -> Builder<SyncedDatabase> {
103101
Builder {
104102
inner: SyncedDatabase {
@@ -110,13 +108,14 @@ impl Builder<()> {
110108
connector: None,
111109
version: None,
112110
namespace: None,
111+
remote_encryption: None,
113112
},
114113
connector: None,
115114
read_your_writes: true,
116115
remote_writes: false,
117116
push_batch_size: 0,
118117
sync_interval: None,
119-
remote_encryption,
118+
remote_encryption: None,
120119
},
121120
}
122121
}
@@ -132,6 +131,7 @@ impl Builder<()> {
132131
connector: None,
133132
version: None,
134133
namespace: None,
134+
remote_encryption: None,
135135
},
136136
}
137137
}
@@ -146,6 +146,7 @@ cfg_replication_or_remote_or_sync! {
146146
connector: Option<crate::util::ConnectorService>,
147147
version: Option<String>,
148148
namespace: Option<String>,
149+
remote_encryption: Option<EncryptionContext>,
149150
}
150151
}
151152

@@ -238,7 +239,7 @@ cfg_replication! {
238239
#[cfg(feature = "sync")]
239240
sync_protocol: super::SyncProtocol,
240241
#[cfg(feature = "sync")]
241-
remote_encryption: Option<crate::sync::EncryptionContext>,
242+
remote_encryption: Option<EncryptionContext>,
242243
}
243244

244245
/// Local replica configuration type in [`Builder`].
@@ -300,6 +301,13 @@ cfg_replication! {
300301
self
301302
}
302303

304+
/// Set the encryption context if the database is encrypted in remote server.
305+
#[cfg(feature = "sync")]
306+
pub fn remote_encryption(mut self, encryption_context: EncryptionContext) -> Builder<RemoteReplica> {
307+
self.inner.remote_encryption = Some(encryption_context);
308+
self
309+
}
310+
303311
pub fn http_request_callback<F>(mut self, f: F) -> Builder<RemoteReplica>
304312
where
305313
F: Fn(&mut http::Request<()>) + Send + Sync + 'static
@@ -347,6 +355,7 @@ cfg_replication! {
347355
connector,
348356
version,
349357
namespace,
358+
..
350359
},
351360
encryption_config,
352361
read_your_writes,
@@ -415,10 +424,11 @@ cfg_replication! {
415424

416425
if res.status().is_success() {
417426
tracing::trace!("Using sync protocol v2 for {}", url);
418-
let builder = Builder::new_synced_database(path, url, auth_token, remote_encryption)
427+
let builder = Builder::new_synced_database(path, url, auth_token)
419428
.connector(connector)
420429
.remote_writes(true)
421-
.read_your_writes(read_your_writes);
430+
.read_your_writes(read_your_writes)
431+
.remote_encryption(remote_encryption);
422432

423433
let builder = if let Some(sync_interval) = sync_interval {
424434
builder.sync_interval(sync_interval)
@@ -475,7 +485,10 @@ cfg_replication! {
475485

476486

477487
Ok(Database {
478-
db_type: DbType::Sync { db, encryption_config },
488+
db_type: DbType::Sync {
489+
db,
490+
encryption_config,
491+
},
479492
max_write_replication_index: Default::default(),
480493
})
481494
}
@@ -515,6 +528,7 @@ cfg_replication! {
515528
connector,
516529
version,
517530
namespace,
531+
..
518532
}) = remote
519533
{
520534
let connector = if let Some(connector) = connector {
@@ -565,7 +579,7 @@ cfg_sync! {
565579
read_your_writes: bool,
566580
push_batch_size: u32,
567581
sync_interval: Option<std::time::Duration>,
568-
remote_encryption: Option<crate::sync::EncryptionContext>,
582+
remote_encryption: Option<EncryptionContext>,
569583
}
570584

571585
impl Builder<SyncedDatabase> {
@@ -598,6 +612,12 @@ cfg_sync! {
598612
self
599613
}
600614

615+
/// Set the encryption context if the database is encrypted in remote server.
616+
pub fn remote_encryption(mut self, encryption_context: Option<EncryptionContext>) -> Builder<SyncedDatabase> {
617+
self.inner.remote_encryption = encryption_context;
618+
self
619+
}
620+
601621
/// Provide a custom http connector that will be used to create http connections.
602622
pub fn connector<C>(mut self, connector: C) -> Builder<SyncedDatabase>
603623
where
@@ -624,6 +644,7 @@ cfg_sync! {
624644
connector: _,
625645
version: _,
626646
namespace: _,
647+
..
627648
},
628649
connector,
629650
remote_writes,
@@ -759,6 +780,12 @@ cfg_remote! {
759780
self
760781
}
761782

783+
/// Set the encryption context if the database is encrypted in remote server.
784+
pub fn remote_encryption(mut self, encryption_context: EncryptionContext) -> Builder<Remote> {
785+
self.inner.remote_encryption = Some(encryption_context);
786+
self
787+
}
788+
762789
/// Build the remote database client.
763790
pub async fn build(self) -> Result<Database> {
764791
let Remote {
@@ -767,6 +794,7 @@ cfg_remote! {
767794
connector,
768795
version,
769796
namespace,
797+
remote_encryption,
770798
} = self.inner;
771799

772800
let connector = if let Some(connector) = connector {
@@ -789,6 +817,7 @@ cfg_remote! {
789817
connector,
790818
version,
791819
namespace,
820+
remote_encryption
792821
},
793822
max_write_replication_index: Default::default(),
794823
})

libsql/src/hrana/hyper.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ pub struct HttpSender {
2828
version: HeaderValue,
2929
namespace: Option<HeaderValue>,
3030
#[cfg(feature = "sync")]
31-
remote_encryption: Option<crate::sync::EncryptionContext>,
31+
remote_encryption: Option<crate::database::EncryptionContext>,
3232
}
3333

3434
impl HttpSender {
3535
pub fn new(
3636
connector: ConnectorService,
3737
version: Option<&str>,
3838
namespace: Option<&str>,
39-
#[cfg(feature = "sync")] remote_encryption: Option<crate::sync::EncryptionContext>,
39+
#[cfg(feature = "sync")] remote_encryption: Option<crate::database::EncryptionContext>,
4040
) -> Self {
4141
let ver = version.unwrap_or(env!("CARGO_PKG_VERSION"));
4242

@@ -135,7 +135,7 @@ impl HttpConnection<HttpSender> {
135135
connector: ConnectorService,
136136
version: Option<&str>,
137137
namespace: Option<&str>,
138-
#[cfg(feature = "sync")] remote_encryption: Option<crate::sync::EncryptionContext>,
138+
#[cfg(feature = "sync")] remote_encryption: Option<crate::database::EncryptionContext>,
139139
) -> Self {
140140
let inner = HttpSender::new(
141141
connector,

libsql/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ pub mod params;
132132
cfg_sync! {
133133
mod sync;
134134
pub use database::SyncProtocol;
135-
pub use sync::EncryptionContext;
136-
pub use sync::EncryptionKey;
135+
pub use database::EncryptionContext;
136+
pub use database::EncryptionKey;
137137
}
138138

139139
cfg_replication! {

libsql/src/local/database.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl Database {
212212
flags: OpenFlags,
213213
endpoint: String,
214214
auth_token: String,
215-
remote_encryption: Option<crate::sync::EncryptionContext>,
215+
remote_encryption: Option<crate::database::EncryptionContext>,
216216
) -> Result<Database> {
217217
let db_path = db_path.into();
218218
let endpoint = if endpoint.starts_with("libsql:") {
@@ -222,8 +222,14 @@ impl Database {
222222
};
223223
let mut db = Database::open(&db_path, flags)?;
224224

225-
let sync_ctx =
226-
SyncContext::new(connector, db_path.into(), endpoint, Some(auth_token), remote_encryption).await?;
225+
let sync_ctx = SyncContext::new(
226+
connector,
227+
db_path.into(),
228+
endpoint,
229+
Some(auth_token),
230+
remote_encryption,
231+
)
232+
.await?;
227233
db.sync_ctx = Some(Arc::new(Mutex::new(sync_ctx)));
228234

229235
Ok(db)

libsql/src/sync.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::{local::Connection, util::ConnectorService, Error, Result};
22

3-
use base64::engine::general_purpose;
4-
use base64::Engine;
3+
use crate::database::EncryptionContext;
54
use bytes::Bytes;
65
use chrono::Utc;
76
use http::{HeaderValue, StatusCode};
@@ -119,29 +118,6 @@ struct PushFramesResult {
119118
baton: Option<String>,
120119
}
121120

122-
#[derive(Debug, Clone)]
123-
pub enum EncryptionKey {
124-
/// The key is a base64-encoded string.
125-
Base64Encoded(String),
126-
/// The key is a byte array.
127-
Bytes(Vec<u8>),
128-
}
129-
130-
impl EncryptionKey {
131-
pub fn as_string(&self) -> String {
132-
match self {
133-
EncryptionKey::Base64Encoded(s) => s.clone(),
134-
EncryptionKey::Bytes(b) => general_purpose::STANDARD.encode(b),
135-
}
136-
}
137-
}
138-
139-
#[derive(Debug, Clone)]
140-
pub struct EncryptionContext {
141-
/// The base64-encoded key for the encryption, sent on every request.
142-
pub key: EncryptionKey,
143-
}
144-
145121
pub struct SyncContext {
146122
db_path: String,
147123
client: hyper::Client<ConnectorService, Body>,

0 commit comments

Comments
 (0)