forked from mirror/grapevine
Compare commits
3 commits
custom
...
benjamin/d
Author | SHA1 | Date | |
---|---|---|---|
|
9b38bd5940 | ||
|
ba4c5edc7f | ||
|
276d73f471 |
2 changed files with 112 additions and 6 deletions
|
@ -1,4 +1,9 @@
|
||||||
use std::{collections::BTreeMap, fmt::Write, sync::Arc, time::Instant};
|
use std::{
|
||||||
|
collections::{BTreeMap, HashSet},
|
||||||
|
fmt::Write,
|
||||||
|
sync::Arc,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -121,6 +126,23 @@ enum AdminCommand {
|
||||||
event_id: Box<EventId>,
|
event_id: Box<EventId>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Dump auth chain events stored in the db in graphviz DOT format
|
||||||
|
///
|
||||||
|
/// Does not validate anything. Events that are missing or generate an
|
||||||
|
/// error when we try to load them from the db are marked in red.
|
||||||
|
GetAuthChainGraph {
|
||||||
|
/// An event ID (the $ character followed by the base64 reference hash)
|
||||||
|
event_ids: Vec<Box<EventId>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Dump all events in a given events auth chain in jsonl format
|
||||||
|
///
|
||||||
|
/// Does not validate anything.
|
||||||
|
GetAuthChainEvents {
|
||||||
|
/// An event ID (the $ character followed by the base64 reference hash)
|
||||||
|
event_ids: Vec<Box<EventId>>,
|
||||||
|
},
|
||||||
|
|
||||||
#[command(verbatim_doc_comment)]
|
#[command(verbatim_doc_comment)]
|
||||||
/// Parse and print a PDU from a JSON
|
/// Parse and print a PDU from a JSON
|
||||||
///
|
///
|
||||||
|
@ -536,6 +558,92 @@ impl Service {
|
||||||
RoomMessageEventContent::text_plain("Event not found.")
|
RoomMessageEventContent::text_plain("Event not found.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AdminCommand::GetAuthChainGraph {
|
||||||
|
event_ids,
|
||||||
|
} => {
|
||||||
|
let mut dot = String::new();
|
||||||
|
writeln!(&mut dot, "digraph G {{").unwrap();
|
||||||
|
let mut todo = event_ids
|
||||||
|
.into_iter()
|
||||||
|
.map(Arc::<EventId>::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut done = HashSet::new();
|
||||||
|
let mut edges = HashSet::new();
|
||||||
|
while let Some(event_id) = todo.pop() {
|
||||||
|
done.insert(event_id.clone());
|
||||||
|
if let Ok(Some(pdu)) =
|
||||||
|
services().rooms.timeline.get_pdu(&event_id)
|
||||||
|
{
|
||||||
|
writeln!(&mut dot, " {event_id:?};").unwrap();
|
||||||
|
for auth_event in &pdu.auth_events {
|
||||||
|
let edge = (
|
||||||
|
Arc::clone(auth_event),
|
||||||
|
Arc::clone(&event_id),
|
||||||
|
);
|
||||||
|
if !edges.contains(&edge) {
|
||||||
|
writeln!(
|
||||||
|
&mut dot,
|
||||||
|
" {auth_event:?} -> {event_id:?};"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
edges.insert(edge);
|
||||||
|
}
|
||||||
|
if !done.contains(&**auth_event) {
|
||||||
|
todo.push(Arc::clone(auth_event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(&mut dot, " {event_id:?}[color=\"red\"];")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(&mut dot, "}}").unwrap();
|
||||||
|
RoomMessageEventContent::text_html(
|
||||||
|
format!("\n```dot\n{dot}\n```"),
|
||||||
|
format!(
|
||||||
|
"<pre><code class=\"language-dot\">{}\n</code></pre>\n",
|
||||||
|
html_escape::encode_safe(&dot)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AdminCommand::GetAuthChainEvents {
|
||||||
|
event_ids,
|
||||||
|
} => {
|
||||||
|
let mut jsonl = String::new();
|
||||||
|
let mut todo = event_ids
|
||||||
|
.into_iter()
|
||||||
|
.map(Arc::<EventId>::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut done = HashSet::new();
|
||||||
|
while let Some(event_id) = todo.pop() {
|
||||||
|
done.insert(event_id.clone());
|
||||||
|
if let Ok(Some(pdu_json)) =
|
||||||
|
services().rooms.timeline.get_pdu_json(&event_id)
|
||||||
|
{
|
||||||
|
jsonl.push_str(
|
||||||
|
&serde_json::to_string(&pdu_json).unwrap(),
|
||||||
|
);
|
||||||
|
jsonl.push('\n');
|
||||||
|
}
|
||||||
|
if let Ok(Some(pdu)) =
|
||||||
|
services().rooms.timeline.get_pdu(&event_id)
|
||||||
|
{
|
||||||
|
for auth_event in &pdu.auth_events {
|
||||||
|
if !done.contains(&**auth_event) {
|
||||||
|
todo.push(Arc::clone(auth_event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RoomMessageEventContent::text_html(
|
||||||
|
format!("\n```json\n{jsonl}\n```"),
|
||||||
|
format!(
|
||||||
|
"<pre><code \
|
||||||
|
class=\"language-json\">{}\n</code></pre>\n",
|
||||||
|
html_escape::encode_safe(&jsonl)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
AdminCommand::ParsePdu => {
|
AdminCommand::ParsePdu => {
|
||||||
if body.len() > 2
|
if body.len() > 2
|
||||||
&& body[0].trim() == "```"
|
&& body[0].trim() == "```"
|
||||||
|
|
|
@ -31,10 +31,7 @@ impl Service {
|
||||||
self.db.cache_auth_chain(key, auth_chain)
|
self.db.cache_auth_chain(key, auth_chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(skip(self))]
|
||||||
skip(self, starting_events),
|
|
||||||
fields(starting_events = debug_slice_truncated(&starting_events, 5)),
|
|
||||||
)]
|
|
||||||
pub(crate) async fn get_auth_chain<'a>(
|
pub(crate) async fn get_auth_chain<'a>(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
|
@ -154,9 +151,10 @@ impl Service {
|
||||||
match services().rooms.timeline.get_pdu(&event_id) {
|
match services().rooms.timeline.get_pdu(&event_id) {
|
||||||
Ok(Some(pdu)) => {
|
Ok(Some(pdu)) => {
|
||||||
if pdu.room_id != room_id {
|
if pdu.room_id != room_id {
|
||||||
|
warn!(bad_room_id = %pdu.room_id, "Event referenced in auth chain has incorrect room id");
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::forbidden(),
|
ErrorKind::forbidden(),
|
||||||
"Evil event in db",
|
"Event has incorrect room id",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
for auth_event in &pdu.auth_events {
|
for auth_event in &pdu.auth_events {
|
||||||
|
|
Loading…
Reference in a new issue