Skip to content

Commit 80d558d

Browse files
authored
feat: Add media config endpoint (#30)
* Add media config endpoint * Add trusted cdn url to config
1 parent 5d50e8f commit 80d558d

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

backend/src/routes/v1/media.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use crate::{
1717
const MAX_IMAGE_SIZE_BYTES: i64 = 5 * 1024 * 1024;
1818
/// 15 MB Video size limit
1919
const MAX_VIDEO_SIZE_BYTES: i64 = 15 * 1024 * 1024;
20+
/// Maximum count of assets per message
21+
const MAX_ASSETS_PER_MESSAGE: usize = 10;
2022

2123
#[derive(Debug, Deserialize, JsonSchema)]
2224
#[schemars(deny_unknown_fields)]
@@ -167,3 +169,27 @@ fn validate_asset_size(content_type: &Mime, content_length: i64) -> Result<(), A
167169
_ => Ok(()),
168170
}
169171
}
172+
173+
#[derive(Serialize, JsonSchema)]
174+
pub struct MediaConfigResponse {
175+
/// Maximum count of assets per message
176+
max_assets_per_message: usize,
177+
/// Maximum image size in bytes
178+
max_image_size_bytes: i64,
179+
/// Maximum video size in bytes
180+
max_video_size_bytes: i64,
181+
/// Trusted CDN URL
182+
trusted_cdn_url: String,
183+
}
184+
185+
#[instrument]
186+
pub async fn get_media_config(
187+
Extension(environment): Extension<Environment>,
188+
) -> Json<MediaConfigResponse> {
189+
Json(MediaConfigResponse {
190+
max_assets_per_message: MAX_ASSETS_PER_MESSAGE,
191+
max_image_size_bytes: MAX_IMAGE_SIZE_BYTES,
192+
max_video_size_bytes: MAX_VIDEO_SIZE_BYTES,
193+
trusted_cdn_url: environment.cdn_url(),
194+
})
195+
}

backend/src/routes/v1/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod auth;
22
pub mod media;
33

44
use aide::axum::{
5-
routing::{post, post_with},
5+
routing::{get, post, post_with},
66
ApiRouter,
77
};
88
use axum_jsonschema::Json;
@@ -17,5 +17,6 @@ pub fn handler() -> ApiRouter {
1717
.response::<409, Json<media::ConflictResponse>>()
1818
}),
1919
)
20+
.api_route("/media/config", get(media::get_media_config))
2021
.api_route("/authorize", post(auth::authorize_handler))
2122
}

backend/tests/upload_tests.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,38 @@ pub fn create_upload_request(
2525
request
2626
}
2727

28+
#[tokio::test]
29+
async fn test_config_enforced_max_image_size_plus_one_fails() {
30+
let setup = TestSetup::new(None).await;
31+
32+
// Fetch media config
33+
let response = setup
34+
.send_get_request("/v1/media/config")
35+
.await
36+
.expect("Failed to send GET /v1/media/config");
37+
assert_eq!(response.status(), StatusCode::OK);
38+
let body = parse_response_body(response).await;
39+
40+
let max_image_size_bytes = body["max_image_size_bytes"]
41+
.as_i64()
42+
.expect("max_image_size_bytes should be an integer");
43+
44+
// Prepare an upload one byte larger than allowed
45+
let content_digest_sha256 = create_valid_sha256();
46+
let payload = create_upload_request(
47+
content_digest_sha256,
48+
max_image_size_bytes + 1,
49+
Some("image/png".to_string()),
50+
);
51+
52+
let response = setup
53+
.send_post_request("/v1/media/presigned-urls", payload)
54+
.await
55+
.expect("Failed to send POST /v1/media/presigned-urls");
56+
57+
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
58+
}
59+
2860
// Happy path tests
2961

3062
#[tokio::test]
@@ -413,6 +445,21 @@ async fn test_upload_media_extra_fields() {
413445
async fn test_e2e_upload_happy_path() {
414446
let setup = TestSetup::new(None).await;
415447

448+
// Fetch config to validate CDN URL
449+
let response = setup
450+
.send_get_request("/v1/media/config")
451+
.await
452+
.expect("Failed to send GET /v1/media/config");
453+
assert_eq!(response.status(), StatusCode::OK);
454+
let response_body = setup
455+
.parse_response_body(response)
456+
.await
457+
.expect("Failed to parse response body");
458+
let trusted_cdn_url = response_body["trusted_cdn_url"]
459+
.as_str()
460+
.expect("Missing trusted_cdn_url in response");
461+
println!("Trusted CDN URL: {}", trusted_cdn_url);
462+
416463
// Step 1: Generate test image data with known SHA-256
417464
let (image_data, sha256) = generate_test_encrypted_image(2048);
418465
println!(
@@ -460,6 +507,11 @@ async fn test_e2e_upload_happy_path() {
460507
.as_str()
461508
.expect("Missing asset_url in response");
462509

510+
assert!(
511+
asset_url.starts_with(trusted_cdn_url),
512+
"Asset URL should start with trusted CDN URL"
513+
);
514+
463515
// Verify response format
464516
assert!(
465517
presigned_url.contains("localhost:4566"),

0 commit comments

Comments
 (0)