mirror of
https://gitlab.com/famedly/conduit.git
synced 2024-11-11 20:21:04 +01:00
fix: e2ee over federation
This commit is contained in:
parent
24402312c5
commit
a9ba067e77
7 changed files with 137 additions and 63 deletions
|
@ -20,7 +20,6 @@ use ruma::{
|
||||||
guest_access::{GuestAccess, RoomGuestAccessEventContent},
|
guest_access::{GuestAccess, RoomGuestAccessEventContent},
|
||||||
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
|
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
|
||||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||||
name::RoomNameEventContent,
|
|
||||||
topic::RoomTopicEventContent,
|
topic::RoomTopicEventContent,
|
||||||
},
|
},
|
||||||
StateEventType,
|
StateEventType,
|
||||||
|
|
|
@ -311,15 +311,17 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(master_key) = services()
|
if let Some(master_key) =
|
||||||
.users
|
services()
|
||||||
.get_master_key(user_id, &allowed_signatures)?
|
.users
|
||||||
|
.get_master_key(sender_user, user_id, &allowed_signatures)?
|
||||||
{
|
{
|
||||||
master_keys.insert(user_id.to_owned(), master_key);
|
master_keys.insert(user_id.to_owned(), master_key);
|
||||||
}
|
}
|
||||||
if let Some(self_signing_key) = services()
|
if let Some(self_signing_key) =
|
||||||
.users
|
services()
|
||||||
.get_self_signing_key(user_id, &allowed_signatures)?
|
.users
|
||||||
|
.get_self_signing_key(sender_user, user_id, &allowed_signatures)?
|
||||||
{
|
{
|
||||||
self_signing_keys.insert(user_id.to_owned(), self_signing_key);
|
self_signing_keys.insert(user_id.to_owned(), self_signing_key);
|
||||||
}
|
}
|
||||||
|
@ -357,7 +359,25 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
||||||
while let Some((server, response)) = futures.next().await {
|
while let Some((server, response)) = futures.next().await {
|
||||||
match response {
|
match response {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
master_keys.extend(response.master_keys);
|
for (user, masterkey) in response.master_keys {
|
||||||
|
let (master_key_id, mut master_key) =
|
||||||
|
services().users.parse_master_key(&user, &masterkey)?;
|
||||||
|
|
||||||
|
if let Some(our_master_key) = services().users.get_key(
|
||||||
|
&master_key_id,
|
||||||
|
sender_user,
|
||||||
|
&user,
|
||||||
|
&allowed_signatures,
|
||||||
|
)? {
|
||||||
|
let (_, our_master_key) =
|
||||||
|
services().users.parse_master_key(&user, &our_master_key)?;
|
||||||
|
master_key.signatures.extend(our_master_key.signatures);
|
||||||
|
}
|
||||||
|
let json = serde_json::to_value(master_key).expect("to_value always works");
|
||||||
|
let raw = serde_json::from_value(json).expect("Raw::from_value always works");
|
||||||
|
master_keys.insert(user, raw);
|
||||||
|
}
|
||||||
|
|
||||||
self_signing_keys.extend(response.self_signing_keys);
|
self_signing_keys.extend(response.self_signing_keys);
|
||||||
device_keys.extend(response.device_keys);
|
device_keys.extend(response.device_keys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1806,12 +1806,14 @@ pub async fn get_devices_route(
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
master_key: services()
|
master_key: services().users.get_master_key(None, &body.user_id, &|u| {
|
||||||
.users
|
u.server_name() == sender_servername
|
||||||
.get_master_key(&body.user_id, &|u| u.server_name() == sender_servername)?,
|
})?,
|
||||||
self_signing_key: services()
|
self_signing_key: services()
|
||||||
.users
|
.users
|
||||||
.get_self_signing_key(&body.user_id, &|u| u.server_name() == sender_servername)?,
|
.get_self_signing_key(None, &body.user_id, &|u| {
|
||||||
|
u.server_name() == sender_servername
|
||||||
|
})?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -451,31 +451,10 @@ impl service::users::Data for KeyValueDatabase {
|
||||||
user_signing_key: &Option<Raw<CrossSigningKey>>,
|
user_signing_key: &Option<Raw<CrossSigningKey>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO: Check signatures
|
// TODO: Check signatures
|
||||||
|
|
||||||
let mut prefix = user_id.as_bytes().to_vec();
|
let mut prefix = user_id.as_bytes().to_vec();
|
||||||
prefix.push(0xff);
|
prefix.push(0xff);
|
||||||
|
|
||||||
// Master key
|
let (master_key_key, _) = self.parse_master_key(user_id, master_key)?;
|
||||||
let mut master_key_ids = master_key
|
|
||||||
.deserialize()
|
|
||||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid master key"))?
|
|
||||||
.keys
|
|
||||||
.into_values();
|
|
||||||
|
|
||||||
let master_key_id = master_key_ids.next().ok_or(Error::BadRequest(
|
|
||||||
ErrorKind::InvalidParam,
|
|
||||||
"Master key contained no key.",
|
|
||||||
))?;
|
|
||||||
|
|
||||||
if master_key_ids.next().is_some() {
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::InvalidParam,
|
|
||||||
"Master key contained more than one key.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut master_key_key = prefix.clone();
|
|
||||||
master_key_key.extend_from_slice(master_key_id.as_bytes());
|
|
||||||
|
|
||||||
self.keyid_key
|
self.keyid_key
|
||||||
.insert(&master_key_key, master_key.json().get().as_bytes())?;
|
.insert(&master_key_key, master_key.json().get().as_bytes())?;
|
||||||
|
@ -690,45 +669,80 @@ impl service::users::Data for KeyValueDatabase {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_master_key(
|
||||||
|
&self,
|
||||||
|
user_id: &UserId,
|
||||||
|
master_key: &Raw<CrossSigningKey>,
|
||||||
|
) -> Result<(Vec<u8>, CrossSigningKey)> {
|
||||||
|
let mut prefix = user_id.as_bytes().to_vec();
|
||||||
|
prefix.push(0xff);
|
||||||
|
|
||||||
|
let master_key = master_key
|
||||||
|
.deserialize()
|
||||||
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid master key"))?;
|
||||||
|
let mut master_key_ids = master_key.keys.values();
|
||||||
|
let master_key_id = master_key_ids.next().ok_or(Error::BadRequest(
|
||||||
|
ErrorKind::InvalidParam,
|
||||||
|
"Master key contained no key.",
|
||||||
|
))?;
|
||||||
|
if master_key_ids.next().is_some() {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::InvalidParam,
|
||||||
|
"Master key contained more than one key.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut master_key_key = prefix.clone();
|
||||||
|
master_key_key.extend_from_slice(master_key_id.as_bytes());
|
||||||
|
Ok((master_key_key, master_key))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(
|
||||||
|
&self,
|
||||||
|
key: &[u8],
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
|
user_id: &UserId,
|
||||||
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
|
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
|
||||||
|
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
|
||||||
|
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
|
||||||
|
clean_signatures(
|
||||||
|
&mut cross_signing_key,
|
||||||
|
sender_user,
|
||||||
|
user_id,
|
||||||
|
allowed_signatures,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Some(Raw::from_json(
|
||||||
|
serde_json::value::to_raw_value(&cross_signing_key)
|
||||||
|
.expect("Value to RawValue serialization"),
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn get_master_key(
|
fn get_master_key(
|
||||||
&self,
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
self.userid_masterkeyid
|
self.userid_masterkeyid
|
||||||
.get(user_id.as_bytes())?
|
.get(user_id.as_bytes())?
|
||||||
.map_or(Ok(None), |key| {
|
.map_or(Ok(None), |key| {
|
||||||
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
|
self.get_key(&key, sender_user, user_id, allowed_signatures)
|
||||||
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
|
|
||||||
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
|
|
||||||
clean_signatures(&mut cross_signing_key, user_id, allowed_signatures)?;
|
|
||||||
|
|
||||||
Ok(Some(Raw::from_json(
|
|
||||||
serde_json::value::to_raw_value(&cross_signing_key)
|
|
||||||
.expect("Value to RawValue serialization"),
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_self_signing_key(
|
fn get_self_signing_key(
|
||||||
&self,
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
self.userid_selfsigningkeyid
|
self.userid_selfsigningkeyid
|
||||||
.get(user_id.as_bytes())?
|
.get(user_id.as_bytes())?
|
||||||
.map_or(Ok(None), |key| {
|
.map_or(Ok(None), |key| {
|
||||||
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
|
self.get_key(&key, sender_user, user_id, allowed_signatures)
|
||||||
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
|
|
||||||
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
|
|
||||||
clean_signatures(&mut cross_signing_key, user_id, allowed_signatures)?;
|
|
||||||
|
|
||||||
Ok(Some(Raw::from_json(
|
|
||||||
serde_json::value::to_raw_value(&cross_signing_key)
|
|
||||||
.expect("Value to RawValue serialization"),
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,6 +943,8 @@ impl service::users::Data for KeyValueDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl KeyValueDatabase {}
|
||||||
|
|
||||||
/// Will only return with Some(username) if the password was not empty and the
|
/// Will only return with Some(username) if the password was not empty and the
|
||||||
/// username could be successfully parsed.
|
/// username could be successfully parsed.
|
||||||
/// If utils::string_from_bytes(...) returns an error that username will be skipped
|
/// If utils::string_from_bytes(...) returns an error that username will be skipped
|
||||||
|
|
|
@ -13,10 +13,7 @@ use ruma::{
|
||||||
},
|
},
|
||||||
IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken,
|
IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken,
|
||||||
},
|
},
|
||||||
events::{
|
events::{room::power_levels::RoomPowerLevelsEventContent, StateEventType, TimelineEventType},
|
||||||
room::{name::RoomNameEventContent, power_levels::RoomPowerLevelsEventContent},
|
|
||||||
StateEventType, TimelineEventType,
|
|
||||||
},
|
|
||||||
push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak},
|
push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak},
|
||||||
serde::Raw,
|
serde::Raw,
|
||||||
uint, RoomId, UInt, UserId,
|
uint, RoomId, UInt, UserId,
|
||||||
|
|
|
@ -136,14 +136,30 @@ pub trait Data: Send + Sync {
|
||||||
device_id: &DeviceId,
|
device_id: &DeviceId,
|
||||||
) -> Result<Option<Raw<DeviceKeys>>>;
|
) -> Result<Option<Raw<DeviceKeys>>>;
|
||||||
|
|
||||||
|
fn parse_master_key(
|
||||||
|
&self,
|
||||||
|
user_id: &UserId,
|
||||||
|
master_key: &Raw<CrossSigningKey>,
|
||||||
|
) -> Result<(Vec<u8>, CrossSigningKey)>;
|
||||||
|
|
||||||
|
fn get_key(
|
||||||
|
&self,
|
||||||
|
key: &[u8],
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
|
user_id: &UserId,
|
||||||
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
|
) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||||
|
|
||||||
fn get_master_key(
|
fn get_master_key(
|
||||||
&self,
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>>;
|
) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||||
|
|
||||||
fn get_self_signing_key(
|
fn get_self_signing_key(
|
||||||
&self,
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>>;
|
) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||||
|
|
|
@ -226,20 +226,43 @@ impl Service {
|
||||||
self.db.get_device_keys(user_id, device_id)
|
self.db.get_device_keys(user_id, device_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_master_key(
|
pub fn parse_master_key(
|
||||||
&self,
|
&self,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
|
master_key: &Raw<CrossSigningKey>,
|
||||||
|
) -> Result<(Vec<u8>, CrossSigningKey)> {
|
||||||
|
self.db.parse_master_key(user_id, master_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_key(
|
||||||
|
&self,
|
||||||
|
key: &[u8],
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
self.db.get_master_key(user_id, allowed_signatures)
|
self.db
|
||||||
|
.get_key(key, sender_user, user_id, allowed_signatures)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_master_key(
|
||||||
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
|
user_id: &UserId,
|
||||||
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
|
self.db
|
||||||
|
.get_master_key(sender_user, user_id, allowed_signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_self_signing_key(
|
pub fn get_self_signing_key(
|
||||||
&self,
|
&self,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
allowed_signatures: &dyn Fn(&UserId) -> bool,
|
||||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
self.db.get_self_signing_key(user_id, allowed_signatures)
|
self.db
|
||||||
|
.get_self_signing_key(sender_user, user_id, allowed_signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
|
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||||
|
@ -342,6 +365,7 @@ impl Service {
|
||||||
/// Ensure that a user only sees signatures from themselves and the target user
|
/// Ensure that a user only sees signatures from themselves and the target user
|
||||||
pub fn clean_signatures<F: Fn(&UserId) -> bool>(
|
pub fn clean_signatures<F: Fn(&UserId) -> bool>(
|
||||||
cross_signing_key: &mut serde_json::Value,
|
cross_signing_key: &mut serde_json::Value,
|
||||||
|
sender_user: Option<&UserId>,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
allowed_signatures: F,
|
allowed_signatures: F,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
@ -355,9 +379,9 @@ pub fn clean_signatures<F: Fn(&UserId) -> bool>(
|
||||||
for (user, signature) in
|
for (user, signature) in
|
||||||
mem::replace(signatures, serde_json::Map::with_capacity(new_capacity))
|
mem::replace(signatures, serde_json::Map::with_capacity(new_capacity))
|
||||||
{
|
{
|
||||||
let id = <&UserId>::try_from(user.as_str())
|
let sid = <&UserId>::try_from(user.as_str())
|
||||||
.map_err(|_| Error::bad_database("Invalid user ID in database."))?;
|
.map_err(|_| Error::bad_database("Invalid user ID in database."))?;
|
||||||
if id == user_id || allowed_signatures(id) {
|
if sender_user == Some(user_id) || sid == user_id || allowed_signatures(sid) {
|
||||||
signatures.insert(user, signature);
|
signatures.insert(user, signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue