mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-07-22 17:18:35 +00:00
Refactor appservices, pusher, timeline, transactionids, users
This commit is contained in:
parent
5108ce52c2
commit
d1138204a6
18 changed files with 1452 additions and 736 deletions
74
src/database/key_value/appservice.rs
Normal file
74
src/database/key_value/appservice.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
impl service::appservice::Data for KeyValueDatabase {
|
||||
/// Registers an appservice and returns the ID to the caller
|
||||
pub fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<String> {
|
||||
// TODO: Rumaify
|
||||
let id = yaml.get("id").unwrap().as_str().unwrap();
|
||||
self.id_appserviceregistrations.insert(
|
||||
id.as_bytes(),
|
||||
serde_yaml::to_string(&yaml).unwrap().as_bytes(),
|
||||
)?;
|
||||
self.cached_registrations
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(id.to_owned(), yaml.to_owned());
|
||||
|
||||
Ok(id.to_owned())
|
||||
}
|
||||
|
||||
/// Remove an appservice registration
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `service_name` - the name you send to register the service previously
|
||||
fn unregister_appservice(&self, service_name: &str) -> Result<()> {
|
||||
self.id_appserviceregistrations
|
||||
.remove(service_name.as_bytes())?;
|
||||
self.cached_registrations
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(service_name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>> {
|
||||
self.cached_registrations
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(id)
|
||||
.map_or_else(
|
||||
|| {
|
||||
self.id_appserviceregistrations
|
||||
.get(id.as_bytes())?
|
||||
.map(|bytes| {
|
||||
serde_yaml::from_slice(&bytes).map_err(|_| {
|
||||
Error::bad_database(
|
||||
"Invalid registration bytes in id_appserviceregistrations.",
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
},
|
||||
|r| Ok(Some(r.clone())),
|
||||
)
|
||||
}
|
||||
|
||||
fn iter_ids(&self) -> Result<impl Iterator<Item = Result<String>> + '_> {
|
||||
Ok(self.id_appserviceregistrations.iter().map(|(id, _)| {
|
||||
utils::string_from_bytes(&id)
|
||||
.map_err(|_| Error::bad_database("Invalid id bytes in id_appserviceregistrations."))
|
||||
}))
|
||||
}
|
||||
|
||||
fn all(&self) -> Result<Vec<(String, serde_yaml::Value)>> {
|
||||
self.iter_ids()?
|
||||
.filter_map(|id| id.ok())
|
||||
.map(move |id| {
|
||||
Ok((
|
||||
id.clone(),
|
||||
self.get_registration(&id)?
|
||||
.expect("iter_ids only returns appservices that exist"),
|
||||
))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
56
src/database/key_value/pusher.rs
Normal file
56
src/database/key_value/pusher.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
impl service::pusher::Data for KeyValueDatabase {
|
||||
fn set_pusher(&self, sender: &UserId, pusher: set_pusher::v3::Pusher) -> Result<()> {
|
||||
let mut key = sender.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(pusher.pushkey.as_bytes());
|
||||
|
||||
// There are 2 kinds of pushers but the spec says: null deletes the pusher.
|
||||
if pusher.kind.is_none() {
|
||||
return self
|
||||
.senderkey_pusher
|
||||
.remove(&key)
|
||||
.map(|_| ())
|
||||
.map_err(Into::into);
|
||||
}
|
||||
|
||||
self.senderkey_pusher.insert(
|
||||
&key,
|
||||
&serde_json::to_vec(&pusher).expect("Pusher is valid JSON value"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pusher(&self, senderkey: &[u8]) -> Result<Option<get_pushers::v3::Pusher>> {
|
||||
self.senderkey_pusher
|
||||
.get(senderkey)?
|
||||
.map(|push| {
|
||||
serde_json::from_slice(&*push)
|
||||
.map_err(|_| Error::bad_database("Invalid Pusher in db."))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn get_pushers(&self, sender: &UserId) -> Result<Vec<get_pushers::v3::Pusher>> {
|
||||
let mut prefix = sender.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
||||
self.senderkey_pusher
|
||||
.scan_prefix(prefix)
|
||||
.map(|(_, push)| {
|
||||
serde_json::from_slice(&*push)
|
||||
.map_err(|_| Error::bad_database("Invalid Pusher in db."))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_pusher_senderkeys<'a>(
|
||||
&'a self,
|
||||
sender: &UserId,
|
||||
) -> impl Iterator<Item = Vec<u8>> + 'a {
|
||||
let mut prefix = sender.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
||||
self.senderkey_pusher.scan_prefix(prefix).map(|(k, _)| k)
|
||||
}
|
||||
}
|
282
src/database/key_value/rooms/timeline.rs
Normal file
282
src/database/key_value/rooms/timeline.rs
Normal file
|
@ -0,0 +1,282 @@
|
|||
impl service::room::timeline::Data for KeyValueDatabase {
|
||||
fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<u64> {
|
||||
match self
|
||||
.lasttimelinecount_cache
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(room_id.to_owned())
|
||||
{
|
||||
hash_map::Entry::Vacant(v) => {
|
||||
if let Some(last_count) = self
|
||||
.pdus_until(&sender_user, &room_id, u64::MAX)?
|
||||
.filter_map(|r| {
|
||||
// Filter out buggy events
|
||||
if r.is_err() {
|
||||
error!("Bad pdu in pdus_since: {:?}", r);
|
||||
}
|
||||
r.ok()
|
||||
})
|
||||
.map(|(pduid, _)| self.pdu_count(&pduid))
|
||||
.next()
|
||||
{
|
||||
Ok(*v.insert(last_count?))
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
hash_map::Entry::Occupied(o) => Ok(*o.get()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `count` of this pdu's id.
|
||||
fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>> {
|
||||
self.eventid_pduid
|
||||
.get(event_id.as_bytes())?
|
||||
.map(|pdu_id| self.pdu_count(&pdu_id))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Returns the json of a pdu.
|
||||
pub fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
|
||||
self.eventid_pduid
|
||||
.get(event_id.as_bytes())?
|
||||
.map_or_else(
|
||||
|| self.eventid_outlierpdu.get(event_id.as_bytes()),
|
||||
|pduid| {
|
||||
Ok(Some(self.pduid_pdu.get(&pduid)?.ok_or_else(|| {
|
||||
Error::bad_database("Invalid pduid in eventid_pduid.")
|
||||
})?))
|
||||
},
|
||||
)?
|
||||
.map(|pdu| {
|
||||
serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db."))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Returns the json of a pdu.
|
||||
pub fn get_non_outlier_pdu_json(
|
||||
&self,
|
||||
event_id: &EventId,
|
||||
) -> Result<Option<CanonicalJsonObject>> {
|
||||
self.eventid_pduid
|
||||
.get(event_id.as_bytes())?
|
||||
.map(|pduid| {
|
||||
self.pduid_pdu
|
||||
.get(&pduid)?
|
||||
.ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid."))
|
||||
})
|
||||
.transpose()?
|
||||
.map(|pdu| {
|
||||
serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db."))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Returns the pdu's id.
|
||||
pub fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>> {
|
||||
self.eventid_pduid.get(event_id.as_bytes())
|
||||
}
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
|
||||
pub fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
|
||||
self.eventid_pduid
|
||||
.get(event_id.as_bytes())?
|
||||
.map(|pduid| {
|
||||
self.pduid_pdu
|
||||
.get(&pduid)?
|
||||
.ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid."))
|
||||
})
|
||||
.transpose()?
|
||||
.map(|pdu| {
|
||||
serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db."))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
|
||||
pub fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>> {
|
||||
if let Some(p) = self.pdu_cache.lock().unwrap().get_mut(event_id) {
|
||||
return Ok(Some(Arc::clone(p)));
|
||||
}
|
||||
|
||||
if let Some(pdu) = self
|
||||
.eventid_pduid
|
||||
.get(event_id.as_bytes())?
|
||||
.map_or_else(
|
||||
|| self.eventid_outlierpdu.get(event_id.as_bytes()),
|
||||
|pduid| {
|
||||
Ok(Some(self.pduid_pdu.get(&pduid)?.ok_or_else(|| {
|
||||
Error::bad_database("Invalid pduid in eventid_pduid.")
|
||||
})?))
|
||||
},
|
||||
)?
|
||||
.map(|pdu| {
|
||||
serde_json::from_slice(&pdu)
|
||||
.map_err(|_| Error::bad_database("Invalid PDU in db."))
|
||||
.map(Arc::new)
|
||||
})
|
||||
.transpose()?
|
||||
{
|
||||
self.pdu_cache
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(event_id.to_owned(), Arc::clone(&pdu));
|
||||
Ok(Some(pdu))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// This does __NOT__ check the outliers `Tree`.
|
||||
pub fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>> {
|
||||
self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| {
|
||||
Ok(Some(
|
||||
serde_json::from_slice(&pdu)
|
||||
.map_err(|_| Error::bad_database("Invalid PDU in db."))?,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the pdu as a `BTreeMap<String, CanonicalJsonValue>`.
|
||||
pub fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>> {
|
||||
self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| {
|
||||
Ok(Some(
|
||||
serde_json::from_slice(&pdu)
|
||||
.map_err(|_| Error::bad_database("Invalid PDU in db."))?,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the `count` of this pdu's id.
|
||||
pub fn pdu_count(&self, pdu_id: &[u8]) -> Result<u64> {
|
||||
utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::<u64>()..])
|
||||
.map_err(|_| Error::bad_database("PDU has invalid count bytes."))
|
||||
}
|
||||
|
||||
/// Removes a pdu and creates a new one with the same id.
|
||||
fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()> {
|
||||
if self.pduid_pdu.get(pdu_id)?.is_some() {
|
||||
self.pduid_pdu.insert(
|
||||
pdu_id,
|
||||
&serde_json::to_vec(pdu).expect("PduEvent::to_vec always works"),
|
||||
)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"PDU does not exist.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all events in a room that happened after the event with id `since`
|
||||
/// in chronological order.
|
||||
pub fn pdus_since<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
since: u64,
|
||||
) -> Result<impl Iterator<Item = Result<(Vec<u8>, PduEvent)>> + 'a> {
|
||||
let prefix = self
|
||||
.get_shortroomid(room_id)?
|
||||
.expect("room exists")
|
||||
.to_be_bytes()
|
||||
.to_vec();
|
||||
|
||||
// Skip the first pdu if it's exactly at since, because we sent that last time
|
||||
let mut first_pdu_id = prefix.clone();
|
||||
first_pdu_id.extend_from_slice(&(since + 1).to_be_bytes());
|
||||
|
||||
let user_id = user_id.to_owned();
|
||||
|
||||
Ok(self
|
||||
.pduid_pdu
|
||||
.iter_from(&first_pdu_id, false)
|
||||
.take_while(move |(k, _)| k.starts_with(&prefix))
|
||||
.map(move |(pdu_id, v)| {
|
||||
let mut pdu = serde_json::from_slice::<PduEvent>(&v)
|
||||
.map_err(|_| Error::bad_database("PDU in db is invalid."))?;
|
||||
if pdu.sender != user_id {
|
||||
pdu.remove_transaction_id()?;
|
||||
}
|
||||
Ok((pdu_id, pdu))
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns an iterator over all events and their tokens in a room that happened before the
|
||||
/// event with id `until` in reverse-chronological order.
|
||||
pub fn pdus_until<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
until: u64,
|
||||
) -> Result<impl Iterator<Item = Result<(Vec<u8>, PduEvent)>> + 'a> {
|
||||
// Create the first part of the full pdu id
|
||||
let prefix = self
|
||||
.get_shortroomid(room_id)?
|
||||
.expect("room exists")
|
||||
.to_be_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut current = prefix.clone();
|
||||
current.extend_from_slice(&(until.saturating_sub(1)).to_be_bytes()); // -1 because we don't want event at `until`
|
||||
|
||||
let current: &[u8] = ¤t;
|
||||
|
||||
let user_id = user_id.to_owned();
|
||||
|
||||
Ok(self
|
||||
.pduid_pdu
|
||||
.iter_from(current, true)
|
||||
.take_while(move |(k, _)| k.starts_with(&prefix))
|
||||
.map(move |(pdu_id, v)| {
|
||||
let mut pdu = serde_json::from_slice::<PduEvent>(&v)
|
||||
.map_err(|_| Error::bad_database("PDU in db is invalid."))?;
|
||||
if pdu.sender != user_id {
|
||||
pdu.remove_transaction_id()?;
|
||||
}
|
||||
Ok((pdu_id, pdu))
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn pdus_after<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
from: u64,
|
||||
) -> Result<impl Iterator<Item = Result<(Vec<u8>, PduEvent)>> + 'a> {
|
||||
// Create the first part of the full pdu id
|
||||
let prefix = self
|
||||
.get_shortroomid(room_id)?
|
||||
.expect("room exists")
|
||||
.to_be_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut current = prefix.clone();
|
||||
current.extend_from_slice(&(from + 1).to_be_bytes()); // +1 so we don't send the base event
|
||||
|
||||
let current: &[u8] = ¤t;
|
||||
|
||||
let user_id = user_id.to_owned();
|
||||
|
||||
Ok(self
|
||||
.pduid_pdu
|
||||
.iter_from(current, false)
|
||||
.take_while(move |(k, _)| k.starts_with(&prefix))
|
||||
.map(move |(pdu_id, v)| {
|
||||
let mut pdu = serde_json::from_slice::<PduEvent>(&v)
|
||||
.map_err(|_| Error::bad_database("PDU in db is invalid."))?;
|
||||
if pdu.sender != user_id {
|
||||
pdu.remove_transaction_id()?;
|
||||
}
|
||||
Ok((pdu_id, pdu))
|
||||
}))
|
||||
}
|
||||
}
|
35
src/database/key_value/transaction_ids.rs
Normal file
35
src/database/key_value/transaction_ids.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
impl service::pusher::Data for KeyValueDatabase {
|
||||
pub fn add_txnid(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: Option<&DeviceId>,
|
||||
txn_id: &TransactionId,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(device_id.map(|d| d.as_bytes()).unwrap_or_default());
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(txn_id.as_bytes());
|
||||
|
||||
self.userdevicetxnid_response.insert(&key, data)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn existing_txnid(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: Option<&DeviceId>,
|
||||
txn_id: &TransactionId,
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(device_id.map(|d| d.as_bytes()).unwrap_or_default());
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(txn_id.as_bytes());
|
||||
|
||||
// If there's no entry, this is a new transaction
|
||||
self.userdevicetxnid_response.get(&key)
|
||||
}
|
||||
}
|
955
src/database/key_value/users.rs
Normal file
955
src/database/key_value/users.rs
Normal file
|
@ -0,0 +1,955 @@
|
|||
impl service::users::Data for KeyValueDatabase {
|
||||
/// Check if a user has an account on this homeserver.
|
||||
pub fn exists(&self, user_id: &UserId) -> Result<bool> {
|
||||
Ok(self.userid_password.get(user_id.as_bytes())?.is_some())
|
||||
}
|
||||
|
||||
/// Check if account is deactivated
|
||||
pub fn is_deactivated(&self, user_id: &UserId) -> Result<bool> {
|
||||
Ok(self
|
||||
.userid_password
|
||||
.get(user_id.as_bytes())?
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"User does not exist.",
|
||||
))?
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
/// Check if a user is an admin
|
||||
pub fn is_admin(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<bool> {
|
||||
let admin_room_alias_id = RoomAliasId::parse(format!("#admins:{}", globals.server_name()))
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias."))?;
|
||||
let admin_room_id = rooms.id_from_alias(&admin_room_alias_id)?.unwrap();
|
||||
|
||||
rooms.is_joined(user_id, &admin_room_id)
|
||||
}
|
||||
|
||||
/// Create a new user account on this homeserver.
|
||||
pub fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
|
||||
self.set_password(user_id, password)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the number of users registered on this server.
|
||||
pub fn count(&self) -> Result<usize> {
|
||||
Ok(self.userid_password.iter().count())
|
||||
}
|
||||
|
||||
/// Find out which user an access token belongs to.
|
||||
pub fn find_from_token(&self, token: &str) -> Result<Option<(Box<UserId>, String)>> {
|
||||
self.token_userdeviceid
|
||||
.get(token.as_bytes())?
|
||||
.map_or(Ok(None), |bytes| {
|
||||
let mut parts = bytes.split(|&b| b == 0xff);
|
||||
let user_bytes = parts.next().ok_or_else(|| {
|
||||
Error::bad_database("User ID in token_userdeviceid is invalid.")
|
||||
})?;
|
||||
let device_bytes = parts.next().ok_or_else(|| {
|
||||
Error::bad_database("Device ID in token_userdeviceid is invalid.")
|
||||
})?;
|
||||
|
||||
Ok(Some((
|
||||
UserId::parse(utils::string_from_bytes(user_bytes).map_err(|_| {
|
||||
Error::bad_database("User ID in token_userdeviceid is invalid unicode.")
|
||||
})?)
|
||||
.map_err(|_| {
|
||||
Error::bad_database("User ID in token_userdeviceid is invalid.")
|
||||
})?,
|
||||
utils::string_from_bytes(device_bytes).map_err(|_| {
|
||||
Error::bad_database("Device ID in token_userdeviceid is invalid.")
|
||||
})?,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over all users on this homeserver.
|
||||
pub fn iter(&self) -> impl Iterator<Item = Result<Box<UserId>>> + '_ {
|
||||
self.userid_password.iter().map(|(bytes, _)| {
|
||||
UserId::parse(utils::string_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("User ID in userid_password is invalid unicode.")
|
||||
})?)
|
||||
.map_err(|_| Error::bad_database("User ID in userid_password is invalid."))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a list of local users as list of usernames.
|
||||
///
|
||||
/// A user account is considered `local` if the length of it's password is greater then zero.
|
||||
pub fn list_local_users(&self) -> Result<Vec<String>> {
|
||||
let users: Vec<String> = self
|
||||
.userid_password
|
||||
.iter()
|
||||
.filter_map(|(username, pw)| self.get_username_with_valid_password(&username, &pw))
|
||||
.collect();
|
||||
Ok(users)
|
||||
}
|
||||
|
||||
/// Will only return with Some(username) if the password was not empty and the
|
||||
/// username could be successfully parsed.
|
||||
/// If utils::string_from_bytes(...) returns an error that username will be skipped
|
||||
/// and the error will be logged.
|
||||
fn get_username_with_valid_password(&self, username: &[u8], password: &[u8]) -> Option<String> {
|
||||
// A valid password is not empty
|
||||
if password.is_empty() {
|
||||
None
|
||||
} else {
|
||||
match utils::string_from_bytes(username) {
|
||||
Ok(u) => Some(u),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to parse username while calling get_local_users(): {}",
|
||||
e.to_string()
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the password hash for the given user.
|
||||
pub fn password_hash(&self, user_id: &UserId) -> Result<Option<String>> {
|
||||
self.userid_password
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |bytes| {
|
||||
Ok(Some(utils::string_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("Password hash in db is not valid string.")
|
||||
})?))
|
||||
})
|
||||
}
|
||||
|
||||
/// Hash and set the user's password to the Argon2 hash
|
||||
pub fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
|
||||
if let Some(password) = password {
|
||||
if let Ok(hash) = utils::calculate_hash(password) {
|
||||
self.userid_password
|
||||
.insert(user_id.as_bytes(), hash.as_bytes())?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Password does not meet the requirements.",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
self.userid_password.insert(user_id.as_bytes(), b"")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the displayname of a user on this homeserver.
|
||||
pub fn displayname(&self, user_id: &UserId) -> Result<Option<String>> {
|
||||
self.userid_displayname
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |bytes| {
|
||||
Ok(Some(utils::string_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("Displayname in db is invalid.")
|
||||
})?))
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets a new displayname or removes it if displayname is None. You still need to nofify all rooms of this change.
|
||||
pub fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()> {
|
||||
if let Some(displayname) = displayname {
|
||||
self.userid_displayname
|
||||
.insert(user_id.as_bytes(), displayname.as_bytes())?;
|
||||
} else {
|
||||
self.userid_displayname.remove(user_id.as_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the avatar_url of a user.
|
||||
pub fn avatar_url(&self, user_id: &UserId) -> Result<Option<Box<MxcUri>>> {
|
||||
self.userid_avatarurl
|
||||
.get(user_id.as_bytes())?
|
||||
.map(|bytes| {
|
||||
let s = utils::string_from_bytes(&bytes)
|
||||
.map_err(|_| Error::bad_database("Avatar URL in db is invalid."))?;
|
||||
s.try_into()
|
||||
.map_err(|_| Error::bad_database("Avatar URL in db is invalid."))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Sets a new avatar_url or removes it if avatar_url is None.
|
||||
pub fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<Box<MxcUri>>) -> Result<()> {
|
||||
if let Some(avatar_url) = avatar_url {
|
||||
self.userid_avatarurl
|
||||
.insert(user_id.as_bytes(), avatar_url.to_string().as_bytes())?;
|
||||
} else {
|
||||
self.userid_avatarurl.remove(user_id.as_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the blurhash of a user.
|
||||
pub fn blurhash(&self, user_id: &UserId) -> Result<Option<String>> {
|
||||
self.userid_blurhash
|
||||
.get(user_id.as_bytes())?
|
||||
.map(|bytes| {
|
||||
let s = utils::string_from_bytes(&bytes)
|
||||
.map_err(|_| Error::bad_database("Avatar URL in db is invalid."))?;
|
||||
|
||||
Ok(s)
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Sets a new avatar_url or removes it if avatar_url is None.
|
||||
pub fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()> {
|
||||
if let Some(blurhash) = blurhash {
|
||||
self.userid_blurhash
|
||||
.insert(user_id.as_bytes(), blurhash.as_bytes())?;
|
||||
} else {
|
||||
self.userid_blurhash.remove(user_id.as_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a new device to a user.
|
||||
pub fn create_device(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
token: &str,
|
||||
initial_device_display_name: Option<String>,
|
||||
) -> Result<()> {
|
||||
// This method should never be called for nonexistent users.
|
||||
assert!(self.exists(user_id)?);
|
||||
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
self.userid_devicelistversion
|
||||
.increment(user_id.as_bytes())?;
|
||||
|
||||
self.userdeviceid_metadata.insert(
|
||||
&userdeviceid,
|
||||
&serde_json::to_vec(&Device {
|
||||
device_id: device_id.into(),
|
||||
display_name: initial_device_display_name,
|
||||
last_seen_ip: None, // TODO
|
||||
last_seen_ts: Some(MilliSecondsSinceUnixEpoch::now()),
|
||||
})
|
||||
.expect("Device::to_string never fails."),
|
||||
)?;
|
||||
|
||||
self.set_token(user_id, device_id, token)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a device from a user.
|
||||
pub fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
// Remove tokens
|
||||
if let Some(old_token) = self.userdeviceid_token.get(&userdeviceid)? {
|
||||
self.userdeviceid_token.remove(&userdeviceid)?;
|
||||
self.token_userdeviceid.remove(&old_token)?;
|
||||
}
|
||||
|
||||
// Remove todevice events
|
||||
let mut prefix = userdeviceid.clone();
|
||||
prefix.push(0xff);
|
||||
|
||||
for (key, _) in self.todeviceid_events.scan_prefix(prefix) {
|
||||
self.todeviceid_events.remove(&key)?;
|
||||
}
|
||||
|
||||
// TODO: Remove onetimekeys
|
||||
|
||||
self.userid_devicelistversion
|
||||
.increment(user_id.as_bytes())?;
|
||||
|
||||
self.userdeviceid_metadata.remove(&userdeviceid)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an iterator over all device ids of this user.
|
||||
pub fn all_device_ids<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
) -> impl Iterator<Item = Result<Box<DeviceId>>> + 'a {
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
// All devices have metadata
|
||||
self.userdeviceid_metadata
|
||||
.scan_prefix(prefix)
|
||||
.map(|(bytes, _)| {
|
||||
Ok(utils::string_from_bytes(
|
||||
bytes
|
||||
.rsplit(|&b| b == 0xff)
|
||||
.next()
|
||||
.ok_or_else(|| Error::bad_database("UserDevice ID in db is invalid."))?,
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Device ID in userdeviceid_metadata is invalid."))?
|
||||
.into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Replaces the access token of one device.
|
||||
pub fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
// All devices have metadata
|
||||
assert!(self.userdeviceid_metadata.get(&userdeviceid)?.is_some());
|
||||
|
||||
// Remove old token
|
||||
if let Some(old_token) = self.userdeviceid_token.get(&userdeviceid)? {
|
||||
self.token_userdeviceid.remove(&old_token)?;
|
||||
// It will be removed from userdeviceid_token by the insert later
|
||||
}
|
||||
|
||||
// Assign token to user device combination
|
||||
self.userdeviceid_token
|
||||
.insert(&userdeviceid, token.as_bytes())?;
|
||||
self.token_userdeviceid
|
||||
.insert(token.as_bytes(), &userdeviceid)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_one_time_key(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
one_time_key_key: &DeviceKeyId,
|
||||
one_time_key_value: &Raw<OneTimeKey>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
// All devices have metadata
|
||||
// Only existing devices should be able to call this.
|
||||
assert!(self.userdeviceid_metadata.get(&key)?.is_some());
|
||||
|
||||
key.push(0xff);
|
||||
// TODO: Use DeviceKeyId::to_string when it's available (and update everything,
|
||||
// because there are no wrapping quotation marks anymore)
|
||||
key.extend_from_slice(
|
||||
serde_json::to_string(one_time_key_key)
|
||||
.expect("DeviceKeyId::to_string always works")
|
||||
.as_bytes(),
|
||||
);
|
||||
|
||||
self.onetimekeyid_onetimekeys.insert(
|
||||
&key,
|
||||
&serde_json::to_vec(&one_time_key_value).expect("OneTimeKey::to_vec always works"),
|
||||
)?;
|
||||
|
||||
self.userid_lastonetimekeyupdate
|
||||
.insert(user_id.as_bytes(), &globals.next_count()?.to_be_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64> {
|
||||
self.userid_lastonetimekeyupdate
|
||||
.get(user_id.as_bytes())?
|
||||
.map(|bytes| {
|
||||
utils::u64_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("Count in roomid_lastroomactiveupdate is invalid.")
|
||||
})
|
||||
})
|
||||
.unwrap_or(Ok(0))
|
||||
}
|
||||
|
||||
pub fn take_one_time_key(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
key_algorithm: &DeviceKeyAlgorithm,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<Option<(Box<DeviceKeyId>, Raw<OneTimeKey>)>> {
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
prefix.extend_from_slice(device_id.as_bytes());
|
||||
prefix.push(0xff);
|
||||
prefix.push(b'"'); // Annoying quotation mark
|
||||
prefix.extend_from_slice(key_algorithm.as_ref().as_bytes());
|
||||
prefix.push(b':');
|
||||
|
||||
self.userid_lastonetimekeyupdate
|
||||
.insert(user_id.as_bytes(), &globals.next_count()?.to_be_bytes())?;
|
||||
|
||||
self.onetimekeyid_onetimekeys
|
||||
.scan_prefix(prefix)
|
||||
.next()
|
||||
.map(|(key, value)| {
|
||||
self.onetimekeyid_onetimekeys.remove(&key)?;
|
||||
|
||||
Ok((
|
||||
serde_json::from_slice(
|
||||
&*key
|
||||
.rsplit(|&b| b == 0xff)
|
||||
.next()
|
||||
.ok_or_else(|| Error::bad_database("OneTimeKeyId in db is invalid."))?,
|
||||
)
|
||||
.map_err(|_| Error::bad_database("OneTimeKeyId in db is invalid."))?,
|
||||
serde_json::from_slice(&*value)
|
||||
.map_err(|_| Error::bad_database("OneTimeKeys in db are invalid."))?,
|
||||
))
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
pub fn count_one_time_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<BTreeMap<DeviceKeyAlgorithm, UInt>> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
let mut counts = BTreeMap::new();
|
||||
|
||||
for algorithm in
|
||||
self.onetimekeyid_onetimekeys
|
||||
.scan_prefix(userdeviceid)
|
||||
.map(|(bytes, _)| {
|
||||
Ok::<_, Error>(
|
||||
serde_json::from_slice::<Box<DeviceKeyId>>(
|
||||
&*bytes.rsplit(|&b| b == 0xff).next().ok_or_else(|| {
|
||||
Error::bad_database("OneTimeKey ID in db is invalid.")
|
||||
})?,
|
||||
)
|
||||
.map_err(|_| Error::bad_database("DeviceKeyId in db is invalid."))?
|
||||
.algorithm(),
|
||||
)
|
||||
})
|
||||
{
|
||||
*counts.entry(algorithm?).or_default() += UInt::from(1_u32);
|
||||
}
|
||||
|
||||
Ok(counts)
|
||||
}
|
||||
|
||||
pub fn add_device_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
device_keys: &Raw<DeviceKeys>,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
self.keyid_key.insert(
|
||||
&userdeviceid,
|
||||
&serde_json::to_vec(&device_keys).expect("DeviceKeys::to_vec always works"),
|
||||
)?;
|
||||
|
||||
self.mark_device_key_update(user_id, rooms, globals)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_cross_signing_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
master_key: &Raw<CrossSigningKey>,
|
||||
self_signing_key: &Option<Raw<CrossSigningKey>>,
|
||||
user_signing_key: &Option<Raw<CrossSigningKey>>,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
// TODO: Check signatures
|
||||
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
||||
// 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
|
||||
.insert(&master_key_key, master_key.json().get().as_bytes())?;
|
||||
|
||||
self.userid_masterkeyid
|
||||
.insert(user_id.as_bytes(), &master_key_key)?;
|
||||
|
||||
// Self-signing key
|
||||
if let Some(self_signing_key) = self_signing_key {
|
||||
let mut self_signing_key_ids = self_signing_key
|
||||
.deserialize()
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Invalid self signing key")
|
||||
})?
|
||||
.keys
|
||||
.into_values();
|
||||
|
||||
let self_signing_key_id = self_signing_key_ids.next().ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Self signing key contained no key.",
|
||||
))?;
|
||||
|
||||
if self_signing_key_ids.next().is_some() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Self signing key contained more than one key.",
|
||||
));
|
||||
}
|
||||
|
||||
let mut self_signing_key_key = prefix.clone();
|
||||
self_signing_key_key.extend_from_slice(self_signing_key_id.as_bytes());
|
||||
|
||||
self.keyid_key.insert(
|
||||
&self_signing_key_key,
|
||||
self_signing_key.json().get().as_bytes(),
|
||||
)?;
|
||||
|
||||
self.userid_selfsigningkeyid
|
||||
.insert(user_id.as_bytes(), &self_signing_key_key)?;
|
||||
}
|
||||
|
||||
// User-signing key
|
||||
if let Some(user_signing_key) = user_signing_key {
|
||||
let mut user_signing_key_ids = user_signing_key
|
||||
.deserialize()
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Invalid user signing key")
|
||||
})?
|
||||
.keys
|
||||
.into_values();
|
||||
|
||||
let user_signing_key_id = user_signing_key_ids.next().ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"User signing key contained no key.",
|
||||
))?;
|
||||
|
||||
if user_signing_key_ids.next().is_some() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"User signing key contained more than one key.",
|
||||
));
|
||||
}
|
||||
|
||||
let mut user_signing_key_key = prefix;
|
||||
user_signing_key_key.extend_from_slice(user_signing_key_id.as_bytes());
|
||||
|
||||
self.keyid_key.insert(
|
||||
&user_signing_key_key,
|
||||
user_signing_key.json().get().as_bytes(),
|
||||
)?;
|
||||
|
||||
self.userid_usersigningkeyid
|
||||
.insert(user_id.as_bytes(), &user_signing_key_key)?;
|
||||
}
|
||||
|
||||
self.mark_device_key_update(user_id, rooms, globals)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sign_key(
|
||||
&self,
|
||||
target_id: &UserId,
|
||||
key_id: &str,
|
||||
signature: (String, String),
|
||||
sender_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut key = target_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(key_id.as_bytes());
|
||||
|
||||
let mut cross_signing_key: serde_json::Value =
|
||||
serde_json::from_slice(&self.keyid_key.get(&key)?.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to sign nonexistent key.",
|
||||
))?)
|
||||
.map_err(|_| Error::bad_database("key in keyid_key is invalid."))?;
|
||||
|
||||
let signatures = cross_signing_key
|
||||
.get_mut("signatures")
|
||||
.ok_or_else(|| Error::bad_database("key in keyid_key has no signatures field."))?
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| Error::bad_database("key in keyid_key has invalid signatures field."))?
|
||||
.entry(sender_id.to_owned())
|
||||
.or_insert_with(|| serde_json::Map::new().into());
|
||||
|
||||
signatures
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| Error::bad_database("signatures in keyid_key for a user is invalid."))?
|
||||
.insert(signature.0, signature.1.into());
|
||||
|
||||
self.keyid_key.insert(
|
||||
&key,
|
||||
&serde_json::to_vec(&cross_signing_key).expect("CrossSigningKey::to_vec always works"),
|
||||
)?;
|
||||
|
||||
// TODO: Should we notify about this change?
|
||||
self.mark_device_key_update(target_id, rooms, globals)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn keys_changed<'a>(
|
||||
&'a self,
|
||||
user_or_room_id: &str,
|
||||
from: u64,
|
||||
to: Option<u64>,
|
||||
) -> impl Iterator<Item = Result<Box<UserId>>> + 'a {
|
||||
let mut prefix = user_or_room_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
||||
let mut start = prefix.clone();
|
||||
start.extend_from_slice(&(from + 1).to_be_bytes());
|
||||
|
||||
let to = to.unwrap_or(u64::MAX);
|
||||
|
||||
self.keychangeid_userid
|
||||
.iter_from(&start, false)
|
||||
.take_while(move |(k, _)| {
|
||||
k.starts_with(&prefix)
|
||||
&& if let Some(current) = k.splitn(2, |&b| b == 0xff).nth(1) {
|
||||
if let Ok(c) = utils::u64_from_bytes(current) {
|
||||
c <= to
|
||||
} else {
|
||||
warn!("BadDatabase: Could not parse keychangeid_userid bytes");
|
||||
false
|
||||
}
|
||||
} else {
|
||||
warn!("BadDatabase: Could not parse keychangeid_userid");
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|(_, bytes)| {
|
||||
UserId::parse(utils::string_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("User ID in devicekeychangeid_userid is invalid unicode.")
|
||||
})?)
|
||||
.map_err(|_| Error::bad_database("User ID in devicekeychangeid_userid is invalid."))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mark_device_key_update(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let count = globals.next_count()?.to_be_bytes();
|
||||
for room_id in rooms.rooms_joined(user_id).filter_map(|r| r.ok()) {
|
||||
// Don't send key updates to unencrypted rooms
|
||||
if rooms
|
||||
.room_state_get(&room_id, &StateEventType::RoomEncryption, "")?
|
||||
.is_none()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut key = room_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(&count);
|
||||
|
||||
self.keychangeid_userid.insert(&key, user_id.as_bytes())?;
|
||||
}
|
||||
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(&count);
|
||||
self.keychangeid_userid.insert(&key, user_id.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_device_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Option<Raw<DeviceKeys>>> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
|
||||
Ok(Some(serde_json::from_slice(&bytes).map_err(|_| {
|
||||
Error::bad_database("DeviceKeys in db are invalid.")
|
||||
})?))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_master_key<F: Fn(&UserId) -> bool>(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||
self.userid_masterkeyid
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |key| {
|
||||
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, user_id, allowed_signatures)?;
|
||||
|
||||
Ok(Some(Raw::from_json(
|
||||
serde_json::value::to_raw_value(&cross_signing_key)
|
||||
.expect("Value to RawValue serialization"),
|
||||
)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_self_signing_key<F: Fn(&UserId) -> bool>(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||
self.userid_selfsigningkeyid
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |key| {
|
||||
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, user_id, allowed_signatures)?;
|
||||
|
||||
Ok(Some(Raw::from_json(
|
||||
serde_json::value::to_raw_value(&cross_signing_key)
|
||||
.expect("Value to RawValue serialization"),
|
||||
)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||
self.userid_usersigningkeyid
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |key| {
|
||||
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
|
||||
Ok(Some(serde_json::from_slice(&bytes).map_err(|_| {
|
||||
Error::bad_database("CrossSigningKey in db is invalid.")
|
||||
})?))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_to_device_event(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
target_user_id: &UserId,
|
||||
target_device_id: &DeviceId,
|
||||
event_type: &str,
|
||||
content: serde_json::Value,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut key = target_user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(target_device_id.as_bytes());
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(&globals.next_count()?.to_be_bytes());
|
||||
|
||||
let mut json = serde_json::Map::new();
|
||||
json.insert("type".to_owned(), event_type.to_owned().into());
|
||||
json.insert("sender".to_owned(), sender.to_string().into());
|
||||
json.insert("content".to_owned(), content);
|
||||
|
||||
let value = serde_json::to_vec(&json).expect("Map::to_vec always works");
|
||||
|
||||
self.todeviceid_events.insert(&key, &value)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_to_device_events(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Vec<Raw<AnyToDeviceEvent>>> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
prefix.extend_from_slice(device_id.as_bytes());
|
||||
prefix.push(0xff);
|
||||
|
||||
for (_, value) in self.todeviceid_events.scan_prefix(prefix) {
|
||||
events.push(
|
||||
serde_json::from_slice(&value)
|
||||
.map_err(|_| Error::bad_database("Event in todeviceid_events is invalid."))?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
pub fn remove_to_device_events(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
until: u64,
|
||||
) -> Result<()> {
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
prefix.extend_from_slice(device_id.as_bytes());
|
||||
prefix.push(0xff);
|
||||
|
||||
let mut last = prefix.clone();
|
||||
last.extend_from_slice(&until.to_be_bytes());
|
||||
|
||||
for (key, _) in self
|
||||
.todeviceid_events
|
||||
.iter_from(&last, true) // this includes last
|
||||
.take_while(move |(k, _)| k.starts_with(&prefix))
|
||||
.map(|(key, _)| {
|
||||
Ok::<_, Error>((
|
||||
key.clone(),
|
||||
utils::u64_from_bytes(&key[key.len() - mem::size_of::<u64>()..key.len()])
|
||||
.map_err(|_| Error::bad_database("ToDeviceId has invalid count bytes."))?,
|
||||
))
|
||||
})
|
||||
.filter_map(|r| r.ok())
|
||||
.take_while(|&(_, count)| count <= until)
|
||||
{
|
||||
self.todeviceid_events.remove(&key)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_device_metadata(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
device: &Device,
|
||||
) -> Result<()> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
// Only existing devices should be able to call this.
|
||||
assert!(self.userdeviceid_metadata.get(&userdeviceid)?.is_some());
|
||||
|
||||
self.userid_devicelistversion
|
||||
.increment(user_id.as_bytes())?;
|
||||
|
||||
self.userdeviceid_metadata.insert(
|
||||
&userdeviceid,
|
||||
&serde_json::to_vec(device).expect("Device::to_string always works"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get device metadata.
|
||||
pub fn get_device_metadata(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Option<Device>> {
|
||||
let mut userdeviceid = user_id.as_bytes().to_vec();
|
||||
userdeviceid.push(0xff);
|
||||
userdeviceid.extend_from_slice(device_id.as_bytes());
|
||||
|
||||
self.userdeviceid_metadata
|
||||
.get(&userdeviceid)?
|
||||
.map_or(Ok(None), |bytes| {
|
||||
Ok(Some(serde_json::from_slice(&bytes).map_err(|_| {
|
||||
Error::bad_database("Metadata in userdeviceid_metadata is invalid.")
|
||||
})?))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
|
||||
self.userid_devicelistversion
|
||||
.get(user_id.as_bytes())?
|
||||
.map_or(Ok(None), |bytes| {
|
||||
utils::u64_from_bytes(&bytes)
|
||||
.map_err(|_| Error::bad_database("Invalid devicelistversion in db."))
|
||||
.map(Some)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn all_devices_metadata<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
) -> impl Iterator<Item = Result<Device>> + 'a {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
|
||||
self.userdeviceid_metadata
|
||||
.scan_prefix(key)
|
||||
.map(|(_, bytes)| {
|
||||
serde_json::from_slice::<Device>(&bytes)
|
||||
.map_err(|_| Error::bad_database("Device in userdeviceid_metadata is invalid."))
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a new sync filter. Returns the filter id.
|
||||
pub fn create_filter(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
filter: &IncomingFilterDefinition,
|
||||
) -> Result<String> {
|
||||
let filter_id = utils::random_string(4);
|
||||
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(filter_id.as_bytes());
|
||||
|
||||
self.userfilterid_filter.insert(
|
||||
&key,
|
||||
&serde_json::to_vec(&filter).expect("filter is valid json"),
|
||||
)?;
|
||||
|
||||
Ok(filter_id)
|
||||
}
|
||||
|
||||
pub fn get_filter(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
filter_id: &str,
|
||||
) -> Result<Option<IncomingFilterDefinition>> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(filter_id.as_bytes());
|
||||
|
||||
let raw = self.userfilterid_filter.get(&key)?;
|
||||
|
||||
if let Some(raw) = raw {
|
||||
serde_json::from_slice(&raw)
|
||||
.map_err(|_| Error::bad_database("Invalid filter event in db."))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue