From b1b42aec270d719a5782b0d8ea12886450fb7b7e Mon Sep 17 00:00:00 2001 From: mikoto Date: Wed, 28 Feb 2024 17:25:55 +0000 Subject: [PATCH] feat: handler addition, one to rule them all --- crates/core/src/lib.rs | 14 +- crates/core/src/{account => session}/error.rs | 0 crates/core/src/{account => session}/mod.rs | 0 crates/core/src/{account => session}/model.rs | 0 .../core/src/{account => session}/service.rs | 0 crates/matrix/Cargo.toml | 11 +- crates/matrix/src/admin/mod.rs | 6 +- crates/matrix/src/admin/room.rs | 6 +- crates/matrix/src/admin/room/delete_room.rs | 4 +- crates/matrix/src/admin/room/get_rooms.rs | 12 +- crates/matrix/src/admin/session.rs | 8 +- crates/matrix/src/admin/session/get_nonce.rs | 2 +- crates/matrix/src/client/room/create_room.rs | 2 +- crates/matrix/src/lib.rs | 56 ++++++ crates/matrix/src/token/mod.rs | 1 - crates/matrix/src/token/shared_secret.rs | 173 ------------------ 16 files changed, 90 insertions(+), 205 deletions(-) rename crates/core/src/{account => session}/error.rs (100%) rename crates/core/src/{account => session}/mod.rs (100%) rename crates/core/src/{account => session}/model.rs (100%) rename crates/core/src/{account => session}/service.rs (100%) delete mode 100644 crates/matrix/src/token/mod.rs delete mode 100644 crates/matrix/src/token/shared_secret.rs diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index afc2a0a..f0f9183 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,4 +1,7 @@ -pub mod account; +//! This library deals with our core logic, such as authorizing user interactions, +//! forwarding regular events and constructing custom requests. + +pub mod session; pub mod auth; pub mod error; pub mod mail; @@ -9,14 +12,11 @@ pub use error::{Error, HttpStatusCode, Result}; use mail::service::MailService; use room::service::RoomService; +use tokio::sync::mpsc::Receiver; use url::Url; use std::{fmt::Debug, str::FromStr, sync::Arc}; -use matrix::Client as MatrixAdminClient; - -use self::{account::service::AccountService, auth::service::AuthService}; - pub mod env { pub const COMMUNE_SYNAPSE_HOST: &str = "COMMUNE_SYNAPSE_HOST"; pub const COMMUNE_SYNAPSE_ADMIN_TOKEN: &str = "COMMUNE_SYNAPSE_ADMIN_TOKEN"; @@ -92,9 +92,7 @@ impl CommuneConfig { } pub struct Commune { - pub account: Arc, - pub auth: Arc, - pub room: Arc, + } impl Commune { diff --git a/crates/core/src/account/error.rs b/crates/core/src/session/error.rs similarity index 100% rename from crates/core/src/account/error.rs rename to crates/core/src/session/error.rs diff --git a/crates/core/src/account/mod.rs b/crates/core/src/session/mod.rs similarity index 100% rename from crates/core/src/account/mod.rs rename to crates/core/src/session/mod.rs diff --git a/crates/core/src/account/model.rs b/crates/core/src/session/model.rs similarity index 100% rename from crates/core/src/account/model.rs rename to crates/core/src/session/model.rs diff --git a/crates/core/src/account/service.rs b/crates/core/src/session/service.rs similarity index 100% rename from crates/core/src/account/service.rs rename to crates/core/src/session/service.rs diff --git a/crates/matrix/Cargo.toml b/crates/matrix/Cargo.toml index 8d24aca..82ee55f 100644 --- a/crates/matrix/Cargo.toml +++ b/crates/matrix/Cargo.toml @@ -5,12 +5,16 @@ edition = "2021" publish = false [dependencies] -ruma-events = { version = "0.27.11", features = ["html", "markdown"] } +ruma-events = { version = "0.27.11", default_features = false, features = [ + "html", + "markdown", +] } ruma-common = { version = "0.12.0", default_features = false, features = [ "api", "rand", ] } -ruma-macros = "0.12.0" +ruma-macros = { version = "0.12.0", default_features = false } +ruma-client = { version = "0.12.0", default_features = false } # Workspace Dependencies mime = { workspace = true } @@ -22,6 +26,9 @@ sha1 = { workspace = true } url = { workspace = true, features = ["serde"] } hex = { workspace = true } hmac = { workspace = true } +http.workspace = true +bytes = "1.5.0" +async-trait = "0.1.77" [features] client = [] diff --git a/crates/matrix/src/admin/mod.rs b/crates/matrix/src/admin/mod.rs index dcb275b..75a9d6d 100644 --- a/crates/matrix/src/admin/mod.rs +++ b/crates/matrix/src/admin/mod.rs @@ -2,6 +2,6 @@ //! //! reference: https://matrix-org.github.io/synapse/latest/usage/administration/admin_api/index.html -mod room; -mod session; -mod user; +pub mod room; +pub mod session; +pub mod user; diff --git a/crates/matrix/src/admin/room.rs b/crates/matrix/src/admin/room.rs index 39b3a22..38a3738 100644 --- a/crates/matrix/src/admin/room.rs +++ b/crates/matrix/src/admin/room.rs @@ -9,11 +9,11 @@ use ruma_common::{ use ruma_events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule}; use serde::Deserialize; -mod delete_room; -mod get_members; +pub mod delete_room; +pub mod get_members; pub mod get_room; pub mod get_rooms; -mod get_state; +pub mod get_state; #[derive(Clone, Debug, Deserialize)] pub struct Room { diff --git a/crates/matrix/src/admin/room/delete_room.rs b/crates/matrix/src/admin/room/delete_room.rs index 2774f1e..578a334 100644 --- a/crates/matrix/src/admin/room/delete_room.rs +++ b/crates/matrix/src/admin/room/delete_room.rs @@ -22,19 +22,17 @@ pub struct Request { #[serde(flatten, skip_serializing_if = "Option::is_none")] pub new_room: Option, - #[serde(skip_serializing_if = "ruma_common::serde::is_default")] pub block: bool, #[serde(skip_serializing_if = "ruma_common::serde::is_true")] pub purge: bool, - #[serde(skip_serializing_if = "ruma_common::serde::is_default")] pub force_purge: bool, } #[response(error = crate::Error)] pub struct Response { - delete_id: String, + pub delete_id: String, } #[derive(Clone, Debug, Serialize)] diff --git a/crates/matrix/src/admin/room/get_rooms.rs b/crates/matrix/src/admin/room/get_rooms.rs index 5607c2b..08a792c 100644 --- a/crates/matrix/src/admin/room/get_rooms.rs +++ b/crates/matrix/src/admin/room/get_rooms.rs @@ -1,5 +1,5 @@ use ruma_common::{ - api::{request, response, Metadata, Direction}, + api::{request, response, Direction, Metadata}, metadata, }; use serde::Serialize; @@ -39,16 +39,16 @@ pub struct Request { #[response(error = crate::Error)] pub struct Response { - rooms: Vec, + pub rooms: Vec, - offset: u64, + pub offset: u64, #[serde(rename = "total_rooms")] - total: u64, + pub total: u64, - next_batch: Option, + pub next_batch: Option, - prev_batch: Option, + pub prev_batch: Option, } #[derive(Clone, Default, Debug, Serialize)] diff --git a/crates/matrix/src/admin/session.rs b/crates/matrix/src/admin/session.rs index 88cabf2..84ee0f7 100644 --- a/crates/matrix/src/admin/session.rs +++ b/crates/matrix/src/admin/session.rs @@ -4,8 +4,8 @@ use hmac::Mac; -mod get_nonce; -mod register; +pub mod get_nonce; +pub mod register; #[derive(Clone, Debug)] pub struct Hmac { @@ -13,7 +13,7 @@ pub struct Hmac { } impl Hmac { - fn new( + pub fn new( shared_secret: &str, nonce: &str, username: &str, @@ -39,7 +39,7 @@ impl Hmac { }) } - fn get(&self) -> String { + pub fn get(&self) -> String { hex::encode(&self.inner) } } diff --git a/crates/matrix/src/admin/session/get_nonce.rs b/crates/matrix/src/admin/session/get_nonce.rs index d5f5c00..0388987 100644 --- a/crates/matrix/src/admin/session/get_nonce.rs +++ b/crates/matrix/src/admin/session/get_nonce.rs @@ -18,5 +18,5 @@ pub struct Request {} #[response(error = crate::Error)] pub struct Response { - nonce: String, + pub nonce: String, } diff --git a/crates/matrix/src/client/room/create_room.rs b/crates/matrix/src/client/room/create_room.rs index f27009a..140bfed 100644 --- a/crates/matrix/src/client/room/create_room.rs +++ b/crates/matrix/src/client/room/create_room.rs @@ -11,7 +11,7 @@ const METADATA: Metadata = metadata! { rate_limited: true, authentication: AccessToken, history: { - 1.9 => "/_matrix/client/v3/createRoom", + unstable => "/_matrix/client/v3/createRoom", } }; diff --git a/crates/matrix/src/lib.rs b/crates/matrix/src/lib.rs index ace15fb..1ae34a5 100644 --- a/crates/matrix/src/lib.rs +++ b/crates/matrix/src/lib.rs @@ -9,5 +9,61 @@ pub mod admin; pub mod client; +use async_trait::async_trait; +use bytes::{Bytes, BytesMut}; +use ruma_client::{DefaultConstructibleHttpClient, HttpClient, HttpClientExt}; + #[allow(unused_imports)] use ruma_common::api::error::MatrixError as Error; + +#[derive(Debug)] +pub struct Handle { + inner: reqwest::Client, +} + +impl Handle { + pub async fn new() { + self.send_matrix_request(, access_token, for_versions, request) + } + + pub async fn dispatch(&self) { + self.send_matrix_request(, access_token, for_versions, request) + } +} + +#[async_trait] +impl HttpClient for Handle { + type RequestBody = BytesMut; + type ResponseBody = Bytes; + type Error = reqwest::Error; + + async fn send_http_request( + &self, + req: http::Request, + ) -> Result, reqwest::Error> { + let req = req.map(|body| body.freeze()).try_into()?; + let mut res = self.inner.execute(req).await?; + + let mut http_builder = http::Response::builder() + .status(res.status()) + .version(res.version()); + std::mem::swap( + http_builder + .headers_mut() + .expect("http::response::Builder to be usable"), + res.headers_mut(), + ); + + Ok(http_builder + .body(res.bytes().await?) + .expect("http::Response construction to work")) + } +} + +impl DefaultConstructibleHttpClient for Handle { + fn default() -> Self { + Self { + inner: reqwest::Client::new(), + } + } +} diff --git a/crates/matrix/src/token/mod.rs b/crates/matrix/src/token/mod.rs deleted file mode 100644 index 24b2441..0000000 --- a/crates/matrix/src/token/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod shared_secret; diff --git a/crates/matrix/src/token/shared_secret.rs b/crates/matrix/src/token/shared_secret.rs deleted file mode 100644 index 1bba14c..0000000 --- a/crates/matrix/src/token/shared_secret.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! [Shared-Secret Registration API](https://matrix-org.github.io/synapse/latest/admin_api/register_api.html#) -//! -//! # Important -//! -//! This API is disabled when MSC3861 is enabled. See [#15582](https://github.com/matrix-org/synapse/pull/15582) -//! -//! This API allows for the creation of users in an administrative and -//! non-interactive way. This is generally used for bootstrapping a Synapse -//! instance with administrator accounts. -//! -//! To authenticate yourself to the server, you will need both the shared secret -//! (registration_shared_secret in the homeserver configuration), and a one-time -//! nonce. If the registration shared secret is not configured, this API is not -//! enabled. - -use anyhow::Result; -use hex; -use hmac::{Hmac, Mac}; -use serde::{Deserialize, Serialize}; -use sha1::Sha1; - -use crate::{error::MatrixError, http::Client}; - -type HmacSha1 = Hmac; - -#[derive(Debug, Serialize, Deserialize)] -pub struct Nonce { - pub nonce: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct SharedSecretRegistrationDto { - pub nonce: String, - pub username: String, - pub displayname: Option, - pub password: String, - pub admin: bool, - /// The MAC is the hex digest output of the HMAC-SHA1 algorithm, with the - /// key being the shared secret and the content being the nonce, user, - /// password, either the string "admin" or "notadmin", and optionally the - /// user_type each separated by NULs. - pub mac: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct SharedSecretRegistration { - pub access_token: String, - pub user_id: String, - pub home_server: String, - pub device_id: String, -} - -impl SharedSecretRegistration { - /// Fetches the `Nonce` from the server. - /// - /// Refer: https://matrix-org.github.io/synapse/latest/admin_api/register_api.html#shared-secret-registration - pub async fn get_nonce(client: &Client) -> Result { - let resp = client.get("/_synapse/admin/v1/register").await?; - - if resp.status().is_success() { - return Ok(resp.json().await?); - } - - let error = resp.json::().await?; - - Err(anyhow::anyhow!(error.error)) - } - - /// Creates the [`SharedSecretRegistration`] instance. - /// - /// Refer: https://matrix-org.github.io/synapse/latest/admin_api/register_api.html#shared-secret-registration - pub async fn create(client: &Client, dto: SharedSecretRegistrationDto) -> Result { - let resp = client - .post_json("/_synapse/admin/v1/register", &dto) - .await?; - - if resp.status().is_success() { - return Ok(resp.json().await?); - } - - let error = resp.json::().await?; - - Err(anyhow::anyhow!(error.error)) - } - - /// Generates the MAC. - /// - /// # Inspiration - /// - /// This implementation is inspired by the following Python code from the - /// Synapse documentation on `Shared-Secret Registration`. - /// - /// ```python - /// import hmac, hashlib - /// - /// def generate_mac(nonce, user, password, admin=False, user_type=None): - /// - /// mac = hmac.new( - /// key=shared_secret, - /// digestmod=hashlib.sha1, - /// ) - /// - /// mac.update(nonce.encode('utf8')) - /// mac.update(b"\x00") - /// mac.update(user.encode('utf8')) - /// mac.update(b"\x00") - /// mac.update(password.encode('utf8')) - /// mac.update(b"\x00") - /// mac.update(b"admin" if admin else b"notadmin") - /// if user_type: - /// mac.update(b"\x00") - /// mac.update(user_type.encode('utf8')) - /// - /// return mac.hexdigest() - /// ``` - /// [Source](https://matrix-org.github.io/synapse/latest/admin_api/register_api.html#shared-secret-registration) - pub fn generate_mac>( - shared_secret: S, - nonce: S, - user: S, - password: S, - admin: bool, - user_type: Option, - ) -> Result { - let mut mac = HmacSha1::new_from_slice(shared_secret.as_ref().as_bytes())?; - - mac.update(nonce.as_ref().as_bytes()); - mac.update(b"\x00"); - - mac.update(user.as_ref().as_bytes()); - mac.update(b"\x00"); - - mac.update(password.as_ref().as_bytes()); - mac.update(b"\x00"); - - if admin { - mac.update("admin".as_bytes()); - } else { - mac.update("notadmin".as_bytes()); - } - - if let Some(user_type) = user_type { - mac.update(b"\x00"); - mac.update(user_type.as_ref().as_bytes()); - } - - let result = mac.finalize(); - let code_bytes = result.into_bytes(); - - Ok(hex::encode(code_bytes)) - } -} - -#[cfg(test)] -mod test { - use super::SharedSecretRegistration; - - #[test] - fn generates_mac_accordingly() { - let want = "c272fb1c287c795ff5ce238c4dba57cf95db5eff"; - let have = SharedSecretRegistration::generate_mac( - "m@;wYOUOh0f:CH5XA65sJB1^q01~DmIriOysRImot,OR_vzN&B", - "1234567890", - "groot", - "imroot!1234", - true, - None, - ) - .unwrap(); - - assert_eq!(have, want); - } -}