crypto: Encode our keys in the sled cryptostore as well
parent
fc085a7391
commit
71a087c379
|
@ -46,6 +46,55 @@ use crate::{
|
||||||
/// panic once we try to pickle a Signing object.
|
/// panic once we try to pickle a Signing object.
|
||||||
const DEFAULT_PICKLE: &str = "DEFAULT_PICKLE_PASSPHRASE_123456";
|
const DEFAULT_PICKLE: &str = "DEFAULT_PICKLE_PASSPHRASE_123456";
|
||||||
|
|
||||||
|
trait EncodeKey {
|
||||||
|
const SEPARATOR: u8 = 0xff;
|
||||||
|
fn encode(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for &UserId {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
self.as_str().encode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for &RoomId {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
self.as_str().encode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for &str {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[self.as_bytes(), &[Self::SEPARATOR]].concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for (&str, &str) {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.0.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.1.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for (&str, &str, &str) {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.0.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.1.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.2.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An in-memory only store that will forget all the E2EE key once it's dropped.
|
/// An in-memory only store that will forget all the E2EE key once it's dropped.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SledStore {
|
pub struct SledStore {
|
||||||
|
@ -143,7 +192,7 @@ impl SledStore {
|
||||||
|
|
||||||
fn get_or_create_pickle_key(passphrase: &str, database: &Db) -> Result<PickleKey> {
|
fn get_or_create_pickle_key(passphrase: &str, database: &Db) -> Result<PickleKey> {
|
||||||
let key = if let Some(key) = database
|
let key = if let Some(key) = database
|
||||||
.get("pickle_key")?
|
.get("pickle_key".encode())?
|
||||||
.map(|v| serde_json::from_slice(&v))
|
.map(|v| serde_json::from_slice(&v))
|
||||||
{
|
{
|
||||||
PickleKey::from_encrypted(passphrase, key?)
|
PickleKey::from_encrypted(passphrase, key?)
|
||||||
|
@ -151,7 +200,7 @@ impl SledStore {
|
||||||
} else {
|
} else {
|
||||||
let key = PickleKey::new();
|
let key = PickleKey::new();
|
||||||
let encrypted = key.encrypt(passphrase);
|
let encrypted = key.encrypt(passphrase);
|
||||||
database.insert("pickle_key", serde_json::to_vec(&encrypted)?)?;
|
database.insert("pickle_key".encode(), serde_json::to_vec(&encrypted)?)?;
|
||||||
key
|
key
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,7 +244,7 @@ impl SledStore {
|
||||||
let identity_keys = account.identity_keys;
|
let identity_keys = account.identity_keys;
|
||||||
|
|
||||||
self.outbound_group_sessions
|
self.outbound_group_sessions
|
||||||
.get(room_id.as_str())?
|
.get(room_id.encode())?
|
||||||
.map(|p| serde_json::from_slice(&p).map_err(CryptoStoreError::Serialization))
|
.map(|p| serde_json::from_slice(&p).map_err(CryptoStoreError::Serialization))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
|
@ -231,7 +280,7 @@ impl SledStore {
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
|
|
||||||
let pickle = session.pickle(self.get_pickle_mode()).await;
|
let pickle = session.pickle(self.get_pickle_mode()).await;
|
||||||
let key = format!("{}{}", sender_key, session_id);
|
let key = (sender_key, session_id).encode();
|
||||||
|
|
||||||
self.session_cache.add(session).await;
|
self.session_cache.add(session).await;
|
||||||
session_changes.insert(key, pickle);
|
session_changes.insert(key, pickle);
|
||||||
|
@ -243,7 +292,7 @@ impl SledStore {
|
||||||
let room_id = session.room_id();
|
let room_id = session.room_id();
|
||||||
let sender_key = session.sender_key();
|
let sender_key = session.sender_key();
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
let key = format!("{}{}{}", room_id, sender_key, session_id);
|
let key = (room_id.as_str(), sender_key, session_id).encode();
|
||||||
let pickle = session.pickle(self.get_pickle_mode()).await;
|
let pickle = session.pickle(self.get_pickle_mode()).await;
|
||||||
|
|
||||||
inbound_session_changes.insert(key, pickle);
|
inbound_session_changes.insert(key, pickle);
|
||||||
|
@ -284,33 +333,33 @@ impl SledStore {
|
||||||
)| {
|
)| {
|
||||||
if let Some(a) = &account_pickle {
|
if let Some(a) = &account_pickle {
|
||||||
account.insert(
|
account.insert(
|
||||||
"account",
|
"account".encode(),
|
||||||
serde_json::to_vec(a).map_err(ConflictableTransactionError::Abort)?,
|
serde_json::to_vec(a).map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(i) = &private_identity_pickle {
|
if let Some(i) = &private_identity_pickle {
|
||||||
private_identity.insert(
|
private_identity.insert(
|
||||||
"identity",
|
"identity".encode(),
|
||||||
serde_json::to_vec(&i).map_err(ConflictableTransactionError::Abort)?,
|
serde_json::to_vec(&i).map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for device in device_changes.new.iter().chain(&device_changes.changed) {
|
for device in device_changes.new.iter().chain(&device_changes.changed) {
|
||||||
let key = format!("{}{}", device.user_id(), device.device_id());
|
let key = (device.user_id().as_str(), device.device_id().as_str()).encode();
|
||||||
let device = serde_json::to_vec(&device)
|
let device = serde_json::to_vec(&device)
|
||||||
.map_err(ConflictableTransactionError::Abort)?;
|
.map_err(ConflictableTransactionError::Abort)?;
|
||||||
devices.insert(key.as_str(), device)?;
|
devices.insert(key, device)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for device in &device_changes.deleted {
|
for device in &device_changes.deleted {
|
||||||
let key = format!("{}{}", device.user_id(), device.device_id());
|
let key = (device.user_id().as_str(), device.device_id().as_str()).encode();
|
||||||
devices.remove(key.as_str())?;
|
devices.remove(key)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for identity in identity_changes.changed.iter().chain(&identity_changes.new) {
|
for identity in identity_changes.changed.iter().chain(&identity_changes.new) {
|
||||||
identities.insert(
|
identities.insert(
|
||||||
identity.user_id().as_str(),
|
identity.user_id().encode(),
|
||||||
serde_json::to_vec(&identity)
|
serde_json::to_vec(&identity)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -318,7 +367,7 @@ impl SledStore {
|
||||||
|
|
||||||
for (key, session) in &session_changes {
|
for (key, session) in &session_changes {
|
||||||
sessions.insert(
|
sessions.insert(
|
||||||
key.as_str(),
|
key.as_slice(),
|
||||||
serde_json::to_vec(&session)
|
serde_json::to_vec(&session)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -326,7 +375,7 @@ impl SledStore {
|
||||||
|
|
||||||
for (key, session) in &inbound_session_changes {
|
for (key, session) in &inbound_session_changes {
|
||||||
inbound_sessions.insert(
|
inbound_sessions.insert(
|
||||||
key.as_str(),
|
key.as_slice(),
|
||||||
serde_json::to_vec(&session)
|
serde_json::to_vec(&session)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -334,7 +383,7 @@ impl SledStore {
|
||||||
|
|
||||||
for (key, session) in &outbound_session_changes {
|
for (key, session) in &outbound_session_changes {
|
||||||
outbound_sessions.insert(
|
outbound_sessions.insert(
|
||||||
key.as_str(),
|
key.encode(),
|
||||||
serde_json::to_vec(&session)
|
serde_json::to_vec(&session)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -362,7 +411,7 @@ impl SledStore {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CryptoStore for SledStore {
|
impl CryptoStore for SledStore {
|
||||||
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>> {
|
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>> {
|
||||||
if let Some(pickle) = self.account.get("account")? {
|
if let Some(pickle) = self.account.get("account".encode())? {
|
||||||
let pickle = serde_json::from_slice(&pickle)?;
|
let pickle = serde_json::from_slice(&pickle)?;
|
||||||
|
|
||||||
self.load_tracked_users().await?;
|
self.load_tracked_users().await?;
|
||||||
|
@ -379,7 +428,7 @@ impl CryptoStore for SledStore {
|
||||||
async fn save_account(&self, account: ReadOnlyAccount) -> Result<()> {
|
async fn save_account(&self, account: ReadOnlyAccount) -> Result<()> {
|
||||||
let pickle = account.pickle(self.get_pickle_mode()).await;
|
let pickle = account.pickle(self.get_pickle_mode()).await;
|
||||||
self.account
|
self.account
|
||||||
.insert("account", serde_json::to_vec(&pickle)?)?;
|
.insert("account".encode(), serde_json::to_vec(&pickle)?)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -397,7 +446,7 @@ impl CryptoStore for SledStore {
|
||||||
if self.session_cache.get(sender_key).is_none() {
|
if self.session_cache.get(sender_key).is_none() {
|
||||||
let sessions: Result<Vec<Session>> = self
|
let sessions: Result<Vec<Session>> = self
|
||||||
.sessions
|
.sessions
|
||||||
.scan_prefix(sender_key)
|
.scan_prefix(sender_key.encode())
|
||||||
.map(|s| serde_json::from_slice(&s?.1).map_err(CryptoStoreError::Serialization))
|
.map(|s| serde_json::from_slice(&s?.1).map_err(CryptoStoreError::Serialization))
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
Session::from_pickle(
|
Session::from_pickle(
|
||||||
|
@ -423,7 +472,7 @@ impl CryptoStore for SledStore {
|
||||||
sender_key: &str,
|
sender_key: &str,
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
) -> Result<Option<InboundGroupSession>> {
|
) -> Result<Option<InboundGroupSession>> {
|
||||||
let key = format!("{}{}{}", room_id, sender_key, session_id);
|
let key = (room_id.as_str(), sender_key, session_id).encode();
|
||||||
let pickle = self
|
let pickle = self
|
||||||
.inbound_group_sessions
|
.inbound_group_sessions
|
||||||
.get(&key)?
|
.get(&key)?
|
||||||
|
@ -487,7 +536,7 @@ impl CryptoStore for SledStore {
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
device_id: &DeviceId,
|
device_id: &DeviceId,
|
||||||
) -> Result<Option<ReadOnlyDevice>> {
|
) -> Result<Option<ReadOnlyDevice>> {
|
||||||
let key = format!("{}{}", user_id, device_id);
|
let key = (user_id.as_str(), device_id.as_str()).encode();
|
||||||
|
|
||||||
if let Some(d) = self.devices.get(key)? {
|
if let Some(d) = self.devices.get(key)? {
|
||||||
Ok(Some(serde_json::from_slice(&d)?))
|
Ok(Some(serde_json::from_slice(&d)?))
|
||||||
|
@ -501,7 +550,7 @@ impl CryptoStore for SledStore {
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
) -> Result<HashMap<DeviceIdBox, ReadOnlyDevice>> {
|
) -> Result<HashMap<DeviceIdBox, ReadOnlyDevice>> {
|
||||||
self.devices
|
self.devices
|
||||||
.scan_prefix(user_id.as_str())
|
.scan_prefix(user_id.encode())
|
||||||
.map(|d| serde_json::from_slice(&d?.1).map_err(CryptoStoreError::Serialization))
|
.map(|d| serde_json::from_slice(&d?.1).map_err(CryptoStoreError::Serialization))
|
||||||
.map(|d| {
|
.map(|d| {
|
||||||
let d: ReadOnlyDevice = d?;
|
let d: ReadOnlyDevice = d?;
|
||||||
|
@ -513,13 +562,13 @@ impl CryptoStore for SledStore {
|
||||||
async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentities>> {
|
async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentities>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.identities
|
.identities
|
||||||
.get(user_id.as_str())?
|
.get(user_id.encode())?
|
||||||
.map(|i| serde_json::from_slice(&i))
|
.map(|i| serde_json::from_slice(&i))
|
||||||
.transpose()?)
|
.transpose()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_value(&self, key: String, value: String) -> Result<()> {
|
async fn save_value(&self, key: String, value: String) -> Result<()> {
|
||||||
self.values.insert(key.as_str(), value.as_str())?;
|
self.values.insert(key.as_str().encode(), value.as_str())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,12 +580,12 @@ impl CryptoStore for SledStore {
|
||||||
async fn get_value(&self, key: &str) -> Result<Option<String>> {
|
async fn get_value(&self, key: &str) -> Result<Option<String>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.values
|
.values
|
||||||
.get(key)?
|
.get(key.encode())?
|
||||||
.map(|v| String::from_utf8_lossy(&v).to_string()))
|
.map(|v| String::from_utf8_lossy(&v).to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_identity(&self) -> Result<Option<PrivateCrossSigningIdentity>> {
|
async fn load_identity(&self) -> Result<Option<PrivateCrossSigningIdentity>> {
|
||||||
if let Some(i) = self.private_identity.get("identity")? {
|
if let Some(i) = self.private_identity.get("identity".encode())? {
|
||||||
let pickle = serde_json::from_slice(&i)?;
|
let pickle = serde_json::from_slice(&i)?;
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
PrivateCrossSigningIdentity::from_pickle(pickle, self.get_pickle_key())
|
PrivateCrossSigningIdentity::from_pickle(pickle, self.get_pickle_key())
|
||||||
|
|
Loading…
Reference in New Issue