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
|
engage). The absent
|
||||||
`yes_i_am_very_very_sure_…_open_registration_…` flag keeps the
|
`yes_i_am_very_very_sure_…_open_registration_…` flag keeps the
|
||||||
server closed to anyone without the token.
|
server closed to anyone without the token.
|
||||||
- `allow_encryption = false` per operator call; E2EE re-enabling is
|
- `allow_encryption = true` — E2EE enabled. Agent clients use the
|
||||||
deferred to a follow-up.
|
`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
|
## 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 {
|
pub async fn send_message(client: &Client, room_ref: &str, body: &str) -> DaemonResponse {
|
||||||
let room = match resolve_room(client, room_ref).await {
|
let room = match resolve_room(client, room_ref).await {
|
||||||
Ok(r) => r,
|
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 {
|
pub async fn read_room(client: &Client, room_ref: &str, limit: Option<usize>) -> DaemonResponse {
|
||||||
use matrix_sdk::ruma::api::Direction;
|
use matrix_sdk::room::MessagesOptions;
|
||||||
use matrix_sdk::ruma::api::client::message::get_message_events;
|
|
||||||
|
|
||||||
let room = match resolve_room(client, room_ref).await {
|
let room = match resolve_room(client, room_ref).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return e,
|
Err(e) => return e,
|
||||||
};
|
};
|
||||||
let limit = limit.unwrap_or(50).min(200);
|
let limit_val = u32::try_from(limit.unwrap_or(50).min(200)).unwrap_or(50);
|
||||||
let mut req =
|
let mut opts = MessagesOptions::backward();
|
||||||
get_message_events::v3::Request::new(room.room_id().to_owned(), Direction::Backward);
|
opts.limit = matrix_sdk::ruma::UInt::from(limit_val);
|
||||||
req.limit = matrix_sdk::ruma::UInt::try_from(limit as u64)
|
// room.messages() transparently decrypts events in encrypted rooms.
|
||||||
.unwrap_or(matrix_sdk::ruma::UInt::from(50u32));
|
// UTD (unable to decrypt) events surface via `ev.kind.is_utd()` and
|
||||||
let resp = match client.send(req).await {
|
// get a sentinel body so claude knows decryption failed rather than
|
||||||
Ok(r) => r,
|
// seeing the raw encrypted blob.
|
||||||
Err(e) => return DaemonResponse::error(format!("get_message_events: {e}")),
|
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
|
.chunk
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|raw| {
|
.filter_map(|ev| {
|
||||||
let parsed = raw.deserialize().ok()?;
|
let parsed = ev.raw().deserialize().ok()?;
|
||||||
let event_id = parsed.event_id().to_string();
|
let event_id = parsed.event_id().to_string();
|
||||||
let sender = parsed.sender().to_string();
|
let sender = parsed.sender().to_string();
|
||||||
let origin_server_ts: i64 = parsed.origin_server_ts().0.into();
|
let origin_server_ts: i64 = parsed.origin_server_ts().0.into();
|
||||||
let event_type = parsed.event_type().to_string();
|
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 {
|
Some(TimelineEvent {
|
||||||
event_id,
|
event_id,
|
||||||
sender,
|
sender,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue