fix(web): set secure cookie flag only for https (#4345)

This commit is contained in:
Aram Drevekenin 2025-08-07 10:23:06 +02:00 committed by GitHub
parent a3cfa0316f
commit 9fdb4ac727
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 35 additions and 14 deletions

View file

@ -20,22 +20,36 @@ pub async fn auth_middleware(request: Request, next: Next) -> Result<Response, S
}, },
Ok(false) | Err(_) => { Ok(false) | Err(_) => {
// revoke session_token as if it exists it's no longer valid // revoke session_token as if it exists it's no longer valid
let clear_cookie = Cookie::build(("session_token", ""))
.http_only(true)
.secure(true)
.same_site(SameSite::Strict)
.path("/")
.max_age(time::Duration::seconds(0))
.build();
let mut response = Response::builder() let mut response = Response::builder()
.status(StatusCode::UNAUTHORIZED) .status(StatusCode::UNAUTHORIZED)
.body(Body::empty()) .body(Body::empty())
.unwrap(); .unwrap();
response // Clear both secure and non-secure versions
.headers_mut() // in case the user was on http before and is now on https
.insert(SET_COOKIE, clear_cookie.to_string().parse().unwrap()); // or vice versa
let clear_cookies = [
Cookie::build(("session_token", ""))
.http_only(true)
.secure(false)
.same_site(SameSite::Strict)
.path("/")
.max_age(time::Duration::seconds(0))
.build(),
Cookie::build(("session_token", ""))
.http_only(true)
.secure(true)
.same_site(SameSite::Strict)
.path("/")
.max_age(time::Duration::seconds(0))
.build(),
];
for cookie in clear_cookies {
response
.headers_mut()
.append(SET_COOKIE, cookie.to_string().parse().unwrap());
}
Ok(response) Ok(response)
}, },

View file

@ -27,17 +27,21 @@ pub async fn serve_html(request: Request) -> Html<String> {
html html
} }
pub async fn login_handler(Json(login_request): Json<LoginRequest>) -> impl IntoResponse { pub async fn login_handler(
State(state): State<AppState>,
Json(login_request): Json<LoginRequest>,
) -> impl IntoResponse {
match create_session_token( match create_session_token(
&login_request.auth_token, &login_request.auth_token,
login_request.remember_me.unwrap_or(false), login_request.remember_me.unwrap_or(false),
) { ) {
Ok(session_token) => { Ok(session_token) => {
let is_https = state.is_https;
let cookie = if login_request.remember_me.unwrap_or(false) { let cookie = if login_request.remember_me.unwrap_or(false) {
// Persistent cookie for remember_me // Persistent cookie for remember_me
Cookie::build(("session_token", session_token)) Cookie::build(("session_token", session_token))
.http_only(true) .http_only(true)
.secure(true) .secure(is_https)
.same_site(SameSite::Strict) .same_site(SameSite::Strict)
.path("/") .path("/")
.max_age(time::Duration::weeks(4)) .max_age(time::Duration::weeks(4))
@ -46,7 +50,7 @@ pub async fn login_handler(Json(login_request): Json<LoginRequest>) -> impl Into
// Session cookie - NO max_age means it expires when browser closes/refreshes // Session cookie - NO max_age means it expires when browser closes/refreshes
Cookie::build(("session_token", session_token)) Cookie::build(("session_token", session_token))
.http_only(true) .http_only(true)
.secure(true) .secure(is_https)
.same_site(SameSite::Strict) .same_site(SameSite::Strict)
.path("/") .path("/")
.build() .build()

View file

@ -229,6 +229,7 @@ pub async fn serve_web_client(
} }
}); });
let is_https = rustls_config.is_some();
let state = AppState { let state = AppState {
connection_table: connection_table.clone(), connection_table: connection_table.clone(),
config: Arc::new(Mutex::new(config)), config: Arc::new(Mutex::new(config)),
@ -236,6 +237,7 @@ pub async fn serve_web_client(
config_file_path, config_file_path,
session_manager, session_manager,
client_os_api_factory, client_os_api_factory,
is_https,
}; };
tokio::spawn({ tokio::spawn({

View file

@ -174,6 +174,7 @@ pub struct AppState {
pub config_file_path: PathBuf, pub config_file_path: PathBuf,
pub session_manager: Arc<dyn SessionManager>, pub session_manager: Arc<dyn SessionManager>,
pub client_os_api_factory: Arc<dyn ClientOsApiFactory>, pub client_os_api_factory: Arc<dyn ClientOsApiFactory>,
pub is_https: bool,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]