use matrix_sdk_common::deserialized_responses::{AlgorithmInfo, EncryptionInfo}; use matrix_sdk_crypto::IncomingResponse; use napi_derive::*; pub(crate) use ruma::api::client::{ backup::add_backup_keys::v3::Response as KeysBackupResponse, keys::{ claim_keys::v3::Response as KeysClaimResponse, get_keys::v3::Response as KeysQueryResponse, upload_keys::v3::Response as KeysUploadResponse, upload_signatures::v3::Response as SignatureUploadResponse, }, message::send_message_event::v3::Response as RoomMessageResponse, to_device::send_event_to_device::v3::Response as ToDeviceResponse, }; use ruma::api::IncomingResponse as RumaIncomingResponse; use crate::{encryption, identifiers, into_err, requests::RequestType}; pub(crate) fn response_from_string(body: &str) -> http::Result>> { http::Response::builder().status(200).body(body.as_bytes().to_vec()) } /// Intermediate private type to store an incoming owned response, /// without the need to manage lifetime. pub(crate) enum OwnedResponse { KeysUpload(KeysUploadResponse), KeysQuery(KeysQueryResponse), KeysClaim(KeysClaimResponse), ToDevice(ToDeviceResponse), SignatureUpload(SignatureUploadResponse), RoomMessage(RoomMessageResponse), KeysBackup(KeysBackupResponse), } impl From for OwnedResponse { fn from(response: KeysUploadResponse) -> Self { OwnedResponse::KeysUpload(response) } } impl From for OwnedResponse { fn from(response: KeysQueryResponse) -> Self { OwnedResponse::KeysQuery(response) } } impl From for OwnedResponse { fn from(response: KeysClaimResponse) -> Self { OwnedResponse::KeysClaim(response) } } impl From for OwnedResponse { fn from(response: ToDeviceResponse) -> Self { OwnedResponse::ToDevice(response) } } impl From for OwnedResponse { fn from(response: SignatureUploadResponse) -> Self { Self::SignatureUpload(response) } } impl From for OwnedResponse { fn from(response: RoomMessageResponse) -> Self { OwnedResponse::RoomMessage(response) } } impl From for OwnedResponse { fn from(r: KeysBackupResponse) -> Self { Self::KeysBackup(r) } } impl TryFrom<(RequestType, http::Response>)> for OwnedResponse { type Error = napi::Error; fn try_from( (request_type, response): (RequestType, http::Response>), ) -> Result { match request_type { RequestType::KeysUpload => { KeysUploadResponse::try_from_http_response(response).map(Into::into) } RequestType::KeysQuery => { KeysQueryResponse::try_from_http_response(response).map(Into::into) } RequestType::KeysClaim => { KeysClaimResponse::try_from_http_response(response).map(Into::into) } RequestType::ToDevice => { ToDeviceResponse::try_from_http_response(response).map(Into::into) } RequestType::SignatureUpload => { SignatureUploadResponse::try_from_http_response(response).map(Into::into) } RequestType::RoomMessage => { RoomMessageResponse::try_from_http_response(response).map(Into::into) } RequestType::KeysBackup => { KeysBackupResponse::try_from_http_response(response).map(Into::into) } } .map_err(into_err) } } impl<'a> From<&'a OwnedResponse> for IncomingResponse<'a> { fn from(response: &'a OwnedResponse) -> Self { match response { OwnedResponse::KeysUpload(response) => IncomingResponse::KeysUpload(response), OwnedResponse::KeysQuery(response) => IncomingResponse::KeysQuery(response), OwnedResponse::KeysClaim(response) => IncomingResponse::KeysClaim(response), OwnedResponse::ToDevice(response) => IncomingResponse::ToDevice(response), OwnedResponse::SignatureUpload(response) => IncomingResponse::SignatureUpload(response), OwnedResponse::RoomMessage(response) => IncomingResponse::RoomMessage(response), OwnedResponse::KeysBackup(response) => IncomingResponse::KeysBackup(response), } } } /// A decrypted room event. #[napi] pub struct DecryptedRoomEvent { /// The JSON-encoded decrypted event. #[napi(readonly)] pub event: String, encryption_info: Option, } #[napi] impl DecryptedRoomEvent { /// The user ID of the event sender, note this is untrusted data /// unless the `verification_state` is as well trusted. #[napi(getter)] pub fn sender(&self) -> Option { Some(identifiers::UserId::from(self.encryption_info.as_ref()?.sender.clone())) } /// The device ID of the device that sent us the event, note this /// is untrusted data unless `verification_state` is as well /// trusted. #[napi(getter)] pub fn sender_device(&self) -> Option { Some(self.encryption_info.as_ref()?.sender_device.as_ref()?.clone().into()) } /// The Curve25519 key of the device that created the megolm /// decryption key originally. #[napi(getter)] pub fn sender_curve25519_key(&self) -> Option { Some(match &self.encryption_info.as_ref()?.algorithm_info { AlgorithmInfo::MegolmV1AesSha2 { curve25519_key, .. } => curve25519_key.clone(), }) } /// The signing Ed25519 key that have created the megolm key that /// was used to decrypt this session. #[napi(getter)] pub fn sender_claimed_ed25519_key(&self) -> Option { match &self.encryption_info.as_ref()?.algorithm_info { AlgorithmInfo::MegolmV1AesSha2 { sender_claimed_keys, .. } => { sender_claimed_keys.get(&ruma::DeviceKeyAlgorithm::Ed25519).cloned() } } } /// Chain of Curve25519 keys through which this session was /// forwarded, via `m.forwarded_room_key` events. #[napi(getter)] pub fn forwarding_curve25519_key_chain(&self) -> Vec { vec![] } /// The verification state of the device that sent us the event, /// note this is the state of the device at the time of /// decryption. It may change in the future if a device gets /// verified or deleted. #[napi] pub fn shield_state(&self, strict: bool) -> Option { let state = &self.encryption_info.as_ref()?.verification_state; if strict { Some(state.to_shield_state_strict().into()) } else { Some(state.to_shield_state_lax().into()) } } } impl From for DecryptedRoomEvent { fn from(value: matrix_sdk_common::deserialized_responses::TimelineEvent) -> Self { Self { event: value.event.json().get().to_owned(), encryption_info: value.encryption_info } } }