1 Commits

Author SHA1 Message Date
ae6daea227 chore(deps): update rust crate ipnet to 2.12.0
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-05 00:16:44 +00:00
10 changed files with 640 additions and 1079 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -6,10 +6,10 @@ edition = "2024"
[dependencies] [dependencies]
env_logger = "0.11.9" env_logger = "0.11.9"
log = "0.4.29" log = "0.4.29"
clap = { version = "4.6.0", features = ["derive", "env"] } clap = { version = "4.5.60", features = ["derive", "env"] }
anyhow = "1.0.102" anyhow = "1.0.102"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.50.0", features = ["full"] } tokio = { version = "1.49.0", features = ["full"] }
actix-web = "4.13.0" actix-web = "4.13.0"
actix-session = { version = "0.11.0", features = ["redis-session"] } actix-session = { version = "0.11.0", features = ["redis-session"] }
actix-remote-ip = "0.1.0" actix-remote-ip = "0.1.0"
@@ -22,19 +22,18 @@ base16ct = { version = "1.0.0", features = ["alloc"] }
futures-util = "0.3.32" futures-util = "0.3.32"
jwt-simple = { version = "0.12.14", default-features = false, features = ["pure-rust"] } jwt-simple = { version = "0.12.14", default-features = false, features = ["pure-rust"] }
thiserror = "2.0.18" thiserror = "2.0.18"
uuid = { version = "1.22.0", features = ["v4", "serde"] } uuid = { version = "1.21.0", features = ["v4", "serde"] }
ipnet = { version = "2.12.0", features = ["serde"] } ipnet = { version = "2.12.0", features = ["serde"] }
rand = "0.10.0" rand = "0.10.0"
hex = "0.4.3" hex = "0.4.3"
mailchecker = "6.0.20" mailchecker = "6.0.19"
matrix-sdk = { version = "0.16.0", features = ["e2e-encryption"] } matrix-sdk = { version = "0.16.0", features = ["e2e-encryption"] }
matrix-sdk-ui = "0.16.0" matrix-sdk-ui = "0.16.0"
url = "2.5.8" url = "2.5.8"
ractor = "0.15.12" ractor = "0.15.10"
serde_json = "1.0.149" serde_json = "1.0.149"
lazy-regex = "3.6.0" lazy-regex = "3.6.0"
actix-ws = "0.4.0" actix-ws = "0.4.0"
infer = "0.19.0" infer = "0.19.0"
rust-embed = "8.11.0" rust-embed = "8.11.0"
mime_guess = "2.0.5" mime_guess = "2.0.5"
image = "0.25.10"

View File

@@ -1,9 +0,0 @@
use crate::controllers::HttpResult;
use crate::extractors::matrix_client_extractor::MatrixClientExtractor;
use actix_web::HttpResponse;
/// Get the list of devices for the account
pub async fn get_list(client: MatrixClientExtractor) -> HttpResult {
let devices = client.client.client.devices().await?.devices;
Ok(HttpResponse::Ok().json(devices))
}

View File

@@ -4,12 +4,9 @@ use crate::utils::crypt_utils::sha512;
use actix_web::dev::Payload; use actix_web::dev::Payload;
use actix_web::http::header; use actix_web::http::header;
use actix_web::{FromRequest, HttpRequest, HttpResponse, web}; use actix_web::{FromRequest, HttpRequest, HttpResponse, web};
use image::imageops::FilterType;
use image::{ImageFormat, ImageReader};
use matrix_sdk::media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings}; use matrix_sdk::media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings};
use matrix_sdk::ruma::events::room::MediaSource; use matrix_sdk::ruma::events::room::MediaSource;
use matrix_sdk::ruma::{OwnedMxcUri, UInt}; use matrix_sdk::ruma::{OwnedMxcUri, UInt};
use std::io::Cursor;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct MediaMXCInPath { pub struct MediaMXCInPath {
@@ -32,44 +29,11 @@ pub async fn serve_mxc_file(req: HttpRequest, media: OwnedMxcUri) -> HttpResult
serve_media(req, MediaSource::Plain(media), query.thumbnail).await serve_media(req, MediaSource::Plain(media), query.thumbnail).await
} }
#[derive(serde::Deserialize, Default, Copy, Clone)]
#[serde(rename_all(deserialize = "lowercase"))]
enum ConvertFormat {
#[default]
Png,
Jpeg,
Gif,
Bmp,
Tga,
Tiff,
}
#[derive(serde::Deserialize)]
struct ServeMediaQuery {
#[serde(skip_serializing_if = "Option::is_none")]
max_width: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
max_height: Option<u32>,
#[serde(default)]
grayscale: bool,
#[serde(skip_serializing_if = "Option::is_none")]
format: Option<ConvertFormat>,
}
impl ServeMediaQuery {
pub fn operation_needed(&self) -> bool {
self.max_width.is_some()
|| self.max_height.is_some()
|| self.format.is_some()
|| self.grayscale
}
}
/// Serve a media file /// Serve a media file
pub async fn serve_media(req: HttpRequest, source: MediaSource, thumbnail: bool) -> HttpResult { pub async fn serve_media(req: HttpRequest, source: MediaSource, thumbnail: bool) -> HttpResult {
let client = MatrixClientExtractor::from_request(&req, &mut Payload::None).await?; let client = MatrixClientExtractor::from_request(&req, &mut Payload::None).await?;
let mut media = client let media = client
.client .client
.client .client
.media() .media()
@@ -88,44 +52,11 @@ pub async fn serve_media(req: HttpRequest, source: MediaSource, thumbnail: bool)
) )
.await?; .await?;
let digest = sha512(&media);
let mime_type = infer::get(&media).map(|x| x.mime_type()); let mime_type = infer::get(&media).map(|x| x.mime_type());
// Check if the media needs to be converted before being returned
let query = web::Query::<ServeMediaQuery>::from_request(&req, &mut Payload::None).await?;
if query.operation_needed() {
let mut img = ImageReader::new(Cursor::new(&media))
.with_guessed_format()?
.decode()?;
// Resize image if required
if query.max_width.is_some() || query.max_height.is_some() {
img = img.resize(
query.max_width.unwrap_or(img.width()),
query.max_height.unwrap_or(img.height()),
FilterType::Lanczos3,
);
}
// Apply grayscal if needed
if query.grayscale {
img = img.grayscale();
}
// Serialize new image
let format = match query.format.unwrap_or_default() {
ConvertFormat::Png => ImageFormat::Png,
ConvertFormat::Jpeg => ImageFormat::Jpeg,
ConvertFormat::Gif => ImageFormat::Gif,
ConvertFormat::Bmp => ImageFormat::Bmp,
ConvertFormat::Tga => ImageFormat::Tga,
ConvertFormat::Tiff => ImageFormat::Tiff,
};
media.clear();
img.write_to(&mut Cursor::new(&mut media), format)?;
}
// Check if the browser already knows the etag // Check if the browser already knows the etag
let digest = sha512(&media);
if let Some(c) = req.headers().get(header::IF_NONE_MATCH) if let Some(c) = req.headers().get(header::IF_NONE_MATCH)
&& c.to_str().unwrap_or("") == digest && c.to_str().unwrap_or("") == digest
{ {

View File

@@ -115,31 +115,17 @@ pub struct RoomIdInPath {
pub(crate) room_id: OwnedRoomId, pub(crate) room_id: OwnedRoomId,
} }
#[derive(serde::Deserialize)]
pub struct SingleRoomQuery {
#[serde(default)]
pub with_latest_event: bool,
}
/// Get the list of joined rooms of the user /// Get the list of joined rooms of the user
pub async fn single_room_info( pub async fn single_room_info(
client: MatrixClientExtractor, client: MatrixClientExtractor,
path: web::Path<RoomIdInPath>, path: web::Path<RoomIdInPath>,
query: web::Query<SingleRoomQuery>,
) -> HttpResult { ) -> HttpResult {
let notifs = client.client.client.notification_settings().await; let notifs = client.client.client.notification_settings().await;
let Some(room) = client.client.client.get_room(&path.room_id) else { Ok(match client.client.client.get_room(&path.room_id) {
return Ok(HttpResponse::NotFound().json("Room not found")); None => HttpResponse::NotFound().json("Room not found"),
}; Some(r) => HttpResponse::Ok().json(APIRoomInfo::from_room(&r, &notifs).await?),
})
let mut room_info = APIRoomInfo::from_room(&room, &notifs).await?;
if !query.with_latest_event {
room_info.latest_event = None;
}
Ok(HttpResponse::Ok().json(room_info))
} }
/// Get room avatar /// Get room avatar

View File

@@ -1,4 +1,3 @@
pub mod matrix_devices_controller;
pub mod matrix_event_controller; pub mod matrix_event_controller;
pub mod matrix_media_controller; pub mod matrix_media_controller;
pub mod matrix_profile_controller; pub mod matrix_profile_controller;

View File

@@ -25,16 +25,12 @@ pub enum HttpFailure {
ActixError(#[from] actix_web::Error), ActixError(#[from] actix_web::Error),
#[error("Matrix error: {0}")] #[error("Matrix error: {0}")]
MatrixError(#[from] matrix_sdk::Error), MatrixError(#[from] matrix_sdk::Error),
#[error("Matrix HTTP error: {0}")]
MatrixHTTPError(#[from] matrix_sdk::HttpError),
#[error("Matrix decryptor error: {0}")] #[error("Matrix decryptor error: {0}")]
MatrixDecryptorError(#[from] matrix_sdk::encryption::DecryptorError), MatrixDecryptorError(#[from] matrix_sdk::encryption::DecryptorError),
#[error("Serde JSON error: {0}")] #[error("Serde JSON error: {0}")]
SerdeJSON(#[from] serde_json::Error), SerdeJSON(#[from] serde_json::Error),
#[error("Standard library error: {0}")] #[error("Standard library error: {0}")]
StdLibError(#[from] std::io::Error), StdLibError(#[from] std::io::Error),
#[error("Image error: {0}")]
ImageDecode(#[from] image::ImageError),
} }
impl ResponseError for HttpFailure { impl ResponseError for HttpFailure {

View File

@@ -10,8 +10,8 @@ use matrixgw_backend::app_config::AppConfig;
use matrixgw_backend::broadcast_messages::BroadcastMessage; use matrixgw_backend::broadcast_messages::BroadcastMessage;
use matrixgw_backend::constants; use matrixgw_backend::constants;
use matrixgw_backend::controllers::matrix::{ use matrixgw_backend::controllers::matrix::{
matrix_devices_controller, matrix_event_controller, matrix_media_controller, matrix_event_controller, matrix_media_controller, matrix_profile_controller,
matrix_profile_controller, matrix_room_controller, matrix_space_controller, matrix_room_controller, matrix_space_controller,
}; };
use matrixgw_backend::controllers::server_controller::ServerConstraints; use matrixgw_backend::controllers::server_controller::ServerConstraints;
use matrixgw_backend::controllers::{ use matrixgw_backend::controllers::{
@@ -142,11 +142,6 @@ async fn main() -> std::io::Result<()> {
web::get().to(matrix_sync_thread_controller::status), web::get().to(matrix_sync_thread_controller::status),
) )
.service(web::resource("/api/ws").route(web::get().to(ws_controller::ws))) .service(web::resource("/api/ws").route(web::get().to(ws_controller::ws)))
// Matrix connection status
.route(
"/api/matrix/devices",
web::get().to(matrix_devices_controller::get_list),
)
// Matrix spaces controller // Matrix spaces controller
.route( .route(
"/api/matrix/space/hierarchy", "/api/matrix/space/hierarchy",

File diff suppressed because it is too large Load Diff

View File

@@ -13,12 +13,12 @@
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
"@fontsource/roboto": "^5.2.10", "@fontsource/roboto": "^5.2.10",
"@mui/icons-material": "^7.3.9", "@mui/icons-material": "^7.3.8",
"@mui/material": "^7.3.9", "@mui/material": "^7.3.8",
"@mui/x-data-grid": "^8.27.5", "@mui/x-data-grid": "^8.27.3",
"@mui/x-date-pickers": "^8.27.2", "@mui/x-date-pickers": "^8.27.2",
"date-and-time": "^4.3.1", "date-and-time": "^4.3.0",
"dayjs": "^1.11.20", "dayjs": "^1.11.19",
"emoji-picker-react": "^4.18.0", "emoji-picker-react": "^4.18.0",
"filesize": "^11.0.13", "filesize": "^11.0.13",
"is-cidr": "^6.0.3", "is-cidr": "^6.0.3",
@@ -31,16 +31,16 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@types/node": "^25.5.0", "@types/node": "^25.3.3",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1", "@vitejs/plugin-react": "^5.1.4",
"eslint": "^10.0.3", "eslint": "^9.39.3",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0", "globals": "^17.4.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"typescript-eslint": "^8.57.1", "typescript-eslint": "^8.56.1",
"vite": "npm:rolldown-vite@7.3.1" "vite": "npm:rolldown-vite@7.3.1"
}, },
"overrides": { "overrides": {