Skip to content

Commit 205c0ec

Browse files
committed
Use cookie crate
1 parent 2947895 commit 205c0ec

3 files changed

Lines changed: 24 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/quarto-hub/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ axum-jwt-auth = "0.6"
3131
jsonwebtoken = "10"
3232
tokio-util = { workspace = true }
3333

34+
# Cookie building (already transitive via axum-jwt-auth)
35+
cookie = "0.18"
36+
time = "0.3"
37+
3438
# Automerge (via samod for JS compatibility)
3539
automerge = "0.7"
3640
samod = { version = "0.7", features = ["tokio", "axum", "tungstenite"] }

crates/quarto-hub/src/server.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use tokio::net::TcpListener;
2020
use tokio::sync::watch;
2121
use tower_http::set_header::SetResponseHeaderLayer;
2222
use tower_http::trace::TraceLayer;
23+
use cookie::SameSite;
2324
use tracing::{debug, info};
2425

2526
use crate::auth;
@@ -130,19 +131,30 @@ fn cookie_token(headers: &HeaderMap) -> Option<&str> {
130131
/// same-site requests and top-level navigations), scoped to `Path=/`,
131132
/// and expires after `AUTH_COOKIE_MAX_AGE` seconds. The `Secure` flag
132133
/// is included unless `allow_insecure` is true (HTTP dev mode).
134+
///
135+
/// Uses the `cookie` crate for correct value encoding, preventing
136+
/// injection of extra attributes via malformed token values.
133137
fn build_auth_cookie(token: &str, secure: bool) -> String {
134-
let mut cookie = format!(
135-
"{AUTH_COOKIE_NAME}={token}; HttpOnly; SameSite=Lax; Path=/; Max-Age={AUTH_COOKIE_MAX_AGE}"
136-
);
138+
let mut builder = cookie::Cookie::build((AUTH_COOKIE_NAME, token))
139+
.http_only(true)
140+
.same_site(SameSite::Lax)
141+
.path("/")
142+
.max_age(time::Duration::seconds(AUTH_COOKIE_MAX_AGE as i64));
137143
if secure {
138-
cookie.push_str("; Secure");
144+
builder = builder.secure(true);
139145
}
140-
cookie
146+
builder.build().to_string()
141147
}
142148

143149
/// Build a `Set-Cookie` header value that clears the auth cookie.
144150
fn build_clear_cookie() -> String {
145-
format!("{AUTH_COOKIE_NAME}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0")
151+
cookie::Cookie::build((AUTH_COOKIE_NAME, ""))
152+
.http_only(true)
153+
.same_site(SameSite::Lax)
154+
.path("/")
155+
.max_age(time::Duration::ZERO)
156+
.build()
157+
.to_string()
146158
}
147159

148160
/// Verify that a state-mutating request includes the CSRF protection header.

0 commit comments

Comments
 (0)