Add license, update readme and add docs for event_auth functions
This commit is contained in:
parent
789c814089
commit
ce2d5a0d9b
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Devin Ragotzy
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
30
README.md
30
README.md
@ -12,20 +12,24 @@ struct StateEvent {
|
|||||||
/// A mapping of event type and state_key to some value `T`, usually an `EventId`.
|
/// A mapping of event type and state_key to some value `T`, usually an `EventId`.
|
||||||
pub type StateMap<T> = BTreeMap<(EventType, String), T>;
|
pub type StateMap<T> = BTreeMap<(EventType, String), T>;
|
||||||
|
|
||||||
|
/// A mapping of `EventId` to `T`, usually a `StateEvent`.
|
||||||
|
pub type EventMap<T> = BTreeMap<EventId, T>;
|
||||||
|
|
||||||
struct StateResolution {
|
struct StateResolution {
|
||||||
// Should any information be kept or should all of it be fetched from the
|
// For now the StateResolution struct is empty. If "caching `event_map` between `resolve` calls
|
||||||
// StateStore trait?
|
// ends up being more efficient it may have an `event_map` field.
|
||||||
event_map: BTreeMap<EventId, StateEvent>,
|
|
||||||
|
|
||||||
// fields for temp storage during resolution??
|
|
||||||
/// The events that conflict and their auth chains.
|
|
||||||
conflicting_events: StateMap<Vec<EventId>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StateResolution {
|
impl StateResolution {
|
||||||
/// The point of this all. Resolve the conflicting set of .
|
/// The point of this all, resolve the possibly conflicting sets of events.
|
||||||
fn resolve(&mut self, events: Vec<StateMap<EventId>>) -> StateMap<EventId> { }
|
pub fn resolve(
|
||||||
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
room_version: &RoomVersionId,
|
||||||
|
state_sets: &[StateMap<EventId>],
|
||||||
|
event_map: Option<EventMap<StateEvent>>,
|
||||||
|
store: &dyn StateStore,
|
||||||
|
) -> Result<ResolutionResult>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,11 +38,9 @@ trait StateStore {
|
|||||||
/// Return a single event based on the EventId.
|
/// Return a single event based on the EventId.
|
||||||
fn get_event(&self, event_id: &EventId) -> Result<StateEvent, String>;
|
fn get_event(&self, event_id: &EventId) -> Result<StateEvent, String>;
|
||||||
|
|
||||||
/// Returns the events that correspond to the `event_ids` sorted in the same order.
|
// There are 3 methods that have default implementations `get_events`, `auth_event_ids` and
|
||||||
fn get_events(&self, event_ids: &[EventId]) -> Result<Vec<StateEvent>, String>;
|
// `auth_chain_diff`. Each could be overridden if the user has an optimization with their database of
|
||||||
|
// choice.
|
||||||
/// Returns a Vec of the related auth events to the given `event`.
|
|
||||||
fn auth_event_ids(&self, room_id: &RoomId, event_ids: &[EventId]) -> Result<Vec<EventId>, String>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -26,6 +26,8 @@ pub enum RedactAllowed {
|
|||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For the given event `kind` what are the relevant auth events
|
||||||
|
/// that are needed to authenticate this `content`.
|
||||||
pub fn auth_types_for_event(
|
pub fn auth_types_for_event(
|
||||||
kind: EventType,
|
kind: EventType,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
@ -71,6 +73,10 @@ pub fn auth_types_for_event(
|
|||||||
auth_types
|
auth_types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Authenticate the incoming `event`. The steps of authentication are:
|
||||||
|
/// * check that the event is being authenticated for the correct room
|
||||||
|
/// * check that the events signatures are valid
|
||||||
|
/// * then there are checks for specific event types
|
||||||
pub fn auth_check(
|
pub fn auth_check(
|
||||||
room_version: &RoomVersionId,
|
room_version: &RoomVersionId,
|
||||||
event: &StateEvent,
|
event: &StateEvent,
|
||||||
@ -107,7 +113,7 @@ pub fn auth_check(
|
|||||||
|
|
||||||
// TODO do_size_check is false when called by `iterative_auth_check`
|
// TODO do_size_check is false when called by `iterative_auth_check`
|
||||||
// do_size_check is also mostly accomplished by ruma with the exception of checking event_type,
|
// do_size_check is also mostly accomplished by ruma with the exception of checking event_type,
|
||||||
// state_key, and json are below a certain size (255 and 65536 respectivly)
|
// state_key, and json are below a certain size (255 and 65536 respectively)
|
||||||
|
|
||||||
// Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules
|
// Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules
|
||||||
//
|
//
|
||||||
@ -129,7 +135,7 @@ pub fn auth_check(
|
|||||||
.get("room_version")
|
.get("room_version")
|
||||||
.cloned()
|
.cloned()
|
||||||
// synapse defaults to version 1
|
// synapse defaults to version 1
|
||||||
.unwrap_or(serde_json::json!("1")),
|
.unwrap_or_else(|| serde_json::json!("1")),
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@ -446,7 +452,7 @@ pub fn check_event_sender_in_room(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the user allowed to send a specific event.
|
/// Is the user allowed to send a specific event based on the rooms power levels.
|
||||||
pub fn can_send_event(event: &StateEvent, auth_events: &StateMap<StateEvent>) -> Option<bool> {
|
pub fn can_send_event(event: &StateEvent, auth_events: &StateMap<StateEvent>) -> Option<bool> {
|
||||||
let ple = auth_events.get(&(EventType::RoomPowerLevels, Some("".into())));
|
let ple = auth_events.get(&(EventType::RoomPowerLevels, Some("".into())));
|
||||||
|
|
||||||
@ -661,6 +667,8 @@ pub fn check_membership(member_event: Option<&StateEvent>, state: MembershipStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch a field, `name`, from a "m.room.power_level" event's content.
|
||||||
|
/// or return `default` if no power level event is found or zero if no field matches `name`.
|
||||||
pub fn get_named_level(auth_events: &StateMap<StateEvent>, name: &str, default: i64) -> i64 {
|
pub fn get_named_level(auth_events: &StateMap<StateEvent>, name: &str, default: i64) -> i64 {
|
||||||
let power_level_event = auth_events.get(&(EventType::RoomPowerLevels, Some("".into())));
|
let power_level_event = auth_events.get(&(EventType::RoomPowerLevels, Some("".into())));
|
||||||
if let Some(pl) = power_level_event {
|
if let Some(pl) = power_level_event {
|
||||||
@ -675,6 +683,8 @@ pub fn get_named_level(auth_events: &StateMap<StateEvent>, name: &str, default:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch a users default power level from a "m.room.power_level" event's `users`
|
||||||
|
/// object.
|
||||||
pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap<StateEvent>) -> i64 {
|
pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap<StateEvent>) -> i64 {
|
||||||
if let Some(pl) = auth_events.get(&(EventType::RoomPowerLevels, Some("".into()))) {
|
if let Some(pl) = auth_events.get(&(EventType::RoomPowerLevels, Some("".into()))) {
|
||||||
if let Ok(content) = pl.deserialize_content::<room::power_levels::PowerLevelsEventContent>()
|
if let Ok(content) = pl.deserialize_content::<room::power_levels::PowerLevelsEventContent>()
|
||||||
@ -706,6 +716,8 @@ pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap<StateEvent>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch the power level needed to send an event of type
|
||||||
|
/// `e_type` based on the rooms "m.room.power_level" event.
|
||||||
pub fn get_send_level(
|
pub fn get_send_level(
|
||||||
e_type: EventType,
|
e_type: EventType,
|
||||||
state_key: Option<String>,
|
state_key: Option<String>,
|
||||||
@ -720,7 +732,7 @@ pub fn get_send_level(
|
|||||||
.events
|
.events
|
||||||
.get(&e_type)
|
.get(&e_type)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(js_int::int!(50))
|
.unwrap_or_else(|| js_int::int!(50))
|
||||||
.into();
|
.into();
|
||||||
let state_def: i64 = content.state_default.into();
|
let state_def: i64 = content.state_default.into();
|
||||||
let event_def: i64 = content.events_default.into();
|
let event_def: i64 = content.events_default.into();
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![allow(clippy::or_fun_call)]
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::{BTreeMap, BTreeSet, BinaryHeap},
|
collections::{BTreeMap, BTreeSet, BinaryHeap},
|
||||||
@ -266,7 +264,7 @@ impl StateResolution {
|
|||||||
"SEP {:?}",
|
"SEP {:?}",
|
||||||
event_ids
|
event_ids
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| i.map(ToString::to_string).unwrap_or("None".into()))
|
.map(|i| i.map(ToString::to_string).unwrap_or_else(|| "None".into()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -560,7 +558,7 @@ impl StateResolution {
|
|||||||
tracing::debug!("event to check {:?}", event.event_id().to_string());
|
tracing::debug!("event to check {:?}", event.event_id().to_string());
|
||||||
|
|
||||||
if event_auth::auth_check(room_version, &event, auth_events, false)
|
if event_auth::auth_check(room_version, &event, auth_events, false)
|
||||||
.ok_or("Auth check failed due to deserialization most likely".to_string())
|
.ok_or_else(|| "Auth check failed due to deserialization most likely".to_string())
|
||||||
.map_err(Error::TempString)?
|
.map_err(Error::TempString)?
|
||||||
{
|
{
|
||||||
// add event to resolved state map
|
// add event to resolved state map
|
||||||
@ -713,7 +711,7 @@ impl StateResolution {
|
|||||||
while !state.is_empty() {
|
while !state.is_empty() {
|
||||||
// we just checked if it was empty so unwrap is fine
|
// we just checked if it was empty so unwrap is fine
|
||||||
let eid = state.pop().unwrap();
|
let eid = state.pop().unwrap();
|
||||||
graph.entry(eid.clone()).or_insert(vec![]);
|
graph.entry(eid.clone()).or_insert_with(Vec::new);
|
||||||
// prefer the store to event as the store filters dedups the events
|
// prefer the store to event as the store filters dedups the events
|
||||||
// otherwise it seems we can loop forever
|
// otherwise it seems we can loop forever
|
||||||
for aid in self
|
for aid in self
|
||||||
|
Loading…
x
Reference in New Issue
Block a user