feat(#551): switch read_room to room.messages() for e2ee decryption, add UTD sentinel, update docs
This commit is contained in:
parent
f51402a867
commit
78317b9cac
2 changed files with 46 additions and 16 deletions
|
|
@ -119,8 +119,15 @@ Initial rollout settings:
|
|||
engage). The absent
|
||||
`yes_i_am_very_very_sure_…_open_registration_…` flag keeps the
|
||||
server closed to anyone without the token.
|
||||
- `allow_encryption = false` per operator call; E2EE re-enabling is
|
||||
deferred to a follow-up.
|
||||
- `allow_encryption = true` — E2EE enabled. Agent clients use the
|
||||
`e2e-encryption` feature of `matrix-sdk`; crypto keys are stored in
|
||||
the per-agent sqlite store under the state dir and persist across
|
||||
restarts (lost on `--purge`). `read_room` decrypts via
|
||||
`room.messages()` — UTD events surface as `event_type =
|
||||
"m.room.encrypted"` with `body = "[unable to decrypt]"`.
|
||||
Cross-signing and automatic key backup are not enabled for the first
|
||||
pass: static bearer-token bot accounts can't bootstrap cross-signing
|
||||
without MSC3967.
|
||||
|
||||
## Hive Matrix Space
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,24 @@ fn extract_body(event: &matrix_sdk::ruma::events::AnyTimelineEvent) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Same as [`extract_body`] but for the `AnySyncTimelineEvent` variant
|
||||
/// returned by `TimelineEvent::raw()` (the sdk-level decrypted form from
|
||||
/// `room.messages()`).
|
||||
fn extract_body_sync(event: &matrix_sdk::ruma::events::AnySyncTimelineEvent) -> String {
|
||||
use matrix_sdk::ruma::events::{AnySyncMessageLikeEvent, AnySyncTimelineEvent};
|
||||
match event {
|
||||
AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(ev)) => ev
|
||||
.as_original()
|
||||
.map_or_else(String::new, |orig| match &orig.content.msgtype {
|
||||
MessageType::Text(t) => t.body.clone(),
|
||||
MessageType::Notice(n) => n.body.clone(),
|
||||
MessageType::Emote(e) => format!("* {}", e.body),
|
||||
_ => String::new(),
|
||||
}),
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_message(client: &Client, room_ref: &str, body: &str) -> DaemonResponse {
|
||||
let room = match resolve_room(client, room_ref).await {
|
||||
Ok(r) => r,
|
||||
|
|
@ -408,32 +426,37 @@ pub async fn invite_user(client: &Client, room_ref: &str, user_id: &str) -> Daem
|
|||
}
|
||||
|
||||
pub async fn read_room(client: &Client, room_ref: &str, limit: Option<usize>) -> DaemonResponse {
|
||||
use matrix_sdk::ruma::api::Direction;
|
||||
use matrix_sdk::ruma::api::client::message::get_message_events;
|
||||
use matrix_sdk::room::MessagesOptions;
|
||||
|
||||
let room = match resolve_room(client, room_ref).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let limit = limit.unwrap_or(50).min(200);
|
||||
let mut req =
|
||||
get_message_events::v3::Request::new(room.room_id().to_owned(), Direction::Backward);
|
||||
req.limit = matrix_sdk::ruma::UInt::try_from(limit as u64)
|
||||
.unwrap_or(matrix_sdk::ruma::UInt::from(50u32));
|
||||
let resp = match client.send(req).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => return DaemonResponse::error(format!("get_message_events: {e}")),
|
||||
let limit_val = u32::try_from(limit.unwrap_or(50).min(200)).unwrap_or(50);
|
||||
let mut opts = MessagesOptions::backward();
|
||||
opts.limit = matrix_sdk::ruma::UInt::from(limit_val);
|
||||
// room.messages() transparently decrypts events in encrypted rooms.
|
||||
// UTD (unable to decrypt) events surface via `ev.kind.is_utd()` and
|
||||
// get a sentinel body so claude knows decryption failed rather than
|
||||
// seeing the raw encrypted blob.
|
||||
let msgs = match room.messages(opts).await {
|
||||
Ok(m) => m,
|
||||
Err(e) => return DaemonResponse::error(format!("messages: {e}")),
|
||||
};
|
||||
let events: Vec<TimelineEvent> = resp
|
||||
let events: Vec<TimelineEvent> = msgs
|
||||
.chunk
|
||||
.iter()
|
||||
.filter_map(|raw| {
|
||||
let parsed = raw.deserialize().ok()?;
|
||||
.filter_map(|ev| {
|
||||
let parsed = ev.raw().deserialize().ok()?;
|
||||
let event_id = parsed.event_id().to_string();
|
||||
let sender = parsed.sender().to_string();
|
||||
let origin_server_ts: i64 = parsed.origin_server_ts().0.into();
|
||||
let event_type = parsed.event_type().to_string();
|
||||
let body = extract_body(&parsed);
|
||||
let body = if ev.kind.is_utd() {
|
||||
"[unable to decrypt]".to_owned()
|
||||
} else {
|
||||
extract_body_sync(&parsed)
|
||||
};
|
||||
Some(TimelineEvent {
|
||||
event_id,
|
||||
sender,
|
||||
|
|
|
|||
Loading…
Reference in a new issue