refactor: drop /web/ URL prefix from browser routes
The /web/ prefix predated the /api/ split; today it just clutters every URL
without disambiguating anything. All 16 browser routes move to the apex
(/cases, /login, /magic, /events, /audio/...). The 6 /api/* routes are
unchanged. A new /->>/cases redirect closes the apex 404.
The open-redirect guard in magic.rs and case_actions.rs flips from a
positive whitelist (starts_with("/web/")) to a deny-list: same-origin path,
not protocol-relative, not under /api/, no \. The /api/ exclusion is now
load-bearing and covered by tests.
Pre-production: no transition redirects.
This commit is contained in:
@@ -340,7 +340,7 @@ impl DoctateApp {
|
||||
let server_url = cfg.server_url.clone();
|
||||
let api_key = cfg.api_key.clone();
|
||||
let http = self.http_client.clone();
|
||||
let return_to = format!("/web/cases/{case_id}");
|
||||
let return_to = format!("/cases/{case_id}");
|
||||
let fallback_url = join_url(&server_url, &return_to);
|
||||
|
||||
// Fire-and-forget on the runtime. Blocking the egui UI thread on
|
||||
|
||||
@@ -35,7 +35,7 @@ pub enum MagicLinkError {
|
||||
|
||||
/// Request a magic-link token and build the full URL to open. The
|
||||
/// `return_to` path is what the browser lands on **after** the token
|
||||
/// is consumed; must start with `/web/` (server enforces this too).
|
||||
/// is consumed; must start with `/` (server enforces this too).
|
||||
pub async fn build_magic_url(
|
||||
http: &reqwest::Client,
|
||||
server_url: &str,
|
||||
@@ -56,7 +56,7 @@ pub async fn build_magic_url(
|
||||
let parsed: CreateResponse = resp.json().await?;
|
||||
Ok(join_url(
|
||||
server_url,
|
||||
&format!("/web/magic?token={}", parsed.token),
|
||||
&format!("/magic?token={}", parsed.token),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -80,10 +80,10 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let http = reqwest::Client::new();
|
||||
let url = build_magic_url(&http, &server.uri(), "test-key", "/web/cases/abc")
|
||||
let url = build_magic_url(&http, &server.uri(), "test-key", "/cases/abc")
|
||||
.await
|
||||
.expect("magic url");
|
||||
assert_eq!(url, format!("{}/web/magic?token={token}", server.uri()));
|
||||
assert_eq!(url, format!("{}/magic?token={token}", server.uri()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -96,7 +96,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let http = reqwest::Client::new();
|
||||
let err = build_magic_url(&http, &server.uri(), "wrong-key", "/web/cases/abc")
|
||||
let err = build_magic_url(&http, &server.uri(), "wrong-key", "/cases/abc")
|
||||
.await
|
||||
.expect_err("should error");
|
||||
assert!(matches!(err, MagicLinkError::Status(s) if s.as_u16() == 401));
|
||||
@@ -113,9 +113,9 @@ mod tests {
|
||||
|
||||
let http = reqwest::Client::new();
|
||||
let url_with_slash = format!("{}/", server.uri());
|
||||
let url = build_magic_url(&http, &url_with_slash, "k", "/web/cases/abc")
|
||||
let url = build_magic_url(&http, &url_with_slash, "k", "/cases/abc")
|
||||
.await
|
||||
.expect("magic url");
|
||||
assert!(!url.contains("//web/"), "double slash leaked: {url}");
|
||||
assert!(!url.contains("//magic"), "double slash leaked: {url}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user