Fix code-review findings on multi-tenant branch
- images.rs: scope /api/img and /api/photos/{id}/original by album owner —
close the cross-tenant original/thumbnail leak (tenancy test now covers
these routes)
- migration 0003: refuse to run when albums exist and users != 1 instead of
silently reassigning every album to the oldest user
- Gallery: callback-ref ResizeObserver so a gallery mounted empty still
lays out once photos arrive (was permanently blank)
- upload dedup: re-uploading identical content whose photo is in 'error'
resets and re-enqueues it instead of returning the broken row
- client hashing: skip (and fall back to plain upload) above 512MB to avoid
whole-file arrayBuffer OOM / the ~2GiB cap
- zip: always spool each entry (no unread prefetched S3 body held across a
slow client stream) and backfill BOTH sha256 and crc32 for legacy photos
- tests/auth: share one session_payload builder instead of re-implementing
the cookie format in the test and mint_session
This commit is contained in:
+20
-1
@@ -44,10 +44,12 @@ fn test_config(database_url: String) -> Config {
|
||||
fn session_for(user_id: Uuid, email: &str) -> String {
|
||||
let key = Key::from(&Sha512::digest(SECRET.as_bytes()));
|
||||
let exp = chrono::Utc::now().timestamp() + 3600;
|
||||
// Use the production payload builder so the test can't drift from what
|
||||
// user_from_jar parses.
|
||||
let mut jar = CookieJar::new();
|
||||
jar.signed_mut(&key).add(Cookie::new(
|
||||
"photos_session",
|
||||
format!("{user_id}|{exp}|{email}"),
|
||||
photos::auth::session_payload(user_id, email, exp),
|
||||
));
|
||||
format!("photos_session={}", jar.get("photos_session").unwrap().value())
|
||||
}
|
||||
@@ -184,6 +186,23 @@ async fn tenant_isolation_matrix() {
|
||||
assert_eq!(status, StatusCode::OK);
|
||||
assert_eq!(list.as_array().unwrap().len(), 0, "bob must see no albums");
|
||||
|
||||
// ---- Dual-auth image routes must ALSO reject a non-owning photographer.
|
||||
// Bob owns no share and doesn't own the album, so authorize_photo falls
|
||||
// through to the share-cookie path and 401s BEFORE any S3 access — the
|
||||
// cross-tenant original leak these routes previously allowed. ----
|
||||
for path in [
|
||||
format!("/api/img/{photo_id}/thumb"),
|
||||
format!("/api/img/{photo_id}/preview"),
|
||||
format!("/api/photos/{photo_id}/original"),
|
||||
] {
|
||||
let (status, _) = request(&router, "GET", &path, Some(&cookie_b), None).await;
|
||||
assert_eq!(
|
||||
status,
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"cross-tenant image GET {path} must not authorize"
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Alice keeps full access to her own resources. ----
|
||||
let (status, list) = request(&router, "GET", "/api/albums", Some(&cookie_a), None).await;
|
||||
assert_eq!(status, StatusCode::OK);
|
||||
|
||||
Reference in New Issue
Block a user