mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-03 12:07:21 +00:00
Fixed the app window opening without its session cookie on macOS
This commit is contained in:
4 files changed
+17
-10
No files matched your search
@@ -86,7 +86,7 @@ public sealed class AppAccessMiddleware(RequestDelegate next, AppAccessPolicy po
|
|||||||
context.Response.Cookies.Append(AppAccessPolicy.SESSION_COOKIE_NAME, token, new CookieOptions
|
context.Response.Cookies.Append(AppAccessPolicy.SESSION_COOKIE_NAME, token, new CookieOptions
|
||||||
{
|
{
|
||||||
HttpOnly = true,
|
HttpOnly = true,
|
||||||
SameSite = SameSiteMode.Strict,
|
SameSite = SameSiteMode.Lax,
|
||||||
Path = "/",
|
Path = "/",
|
||||||
IsEssential = true
|
IsEssential = true
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public sealed class AppAccessMiddlewareTests
|
|||||||
Assert.That(response.Headers.Location.ToString(), Is.EqualTo("/"));
|
Assert.That(response.Headers.Location.ToString(), Is.EqualTo("/"));
|
||||||
Assert.That(cookie, Does.StartWith($"{AppAccessPolicy.SESSION_COOKIE_NAME}={UI_TOKEN}"));
|
Assert.That(cookie, Does.StartWith($"{AppAccessPolicy.SESSION_COOKIE_NAME}={UI_TOKEN}"));
|
||||||
Assert.That(cookie, Does.Contain("httponly"));
|
Assert.That(cookie, Does.Contain("httponly"));
|
||||||
Assert.That(cookie, Does.Contain("samesite=strict"));
|
Assert.That(cookie, Does.Contain("samesite=lax"));
|
||||||
Assert.That(cookie, Does.Contain("path=/"));
|
Assert.That(cookie, Does.Contain("path=/"));
|
||||||
Assert.That(cookie, Does.Not.Contain("expires"));
|
Assert.That(cookie, Does.Not.Contain("expires"));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,12 +25,20 @@ const DEV_BOOT_LINK_FILE: &str = "dev-boot-link.txt";
|
|||||||
/// Builds the session cookie of the app window.
|
/// Builds the session cookie of the app window.
|
||||||
///
|
///
|
||||||
/// The cookie is for the app host alone and lives as long as the window: it has no expiry date,
|
/// The cookie is for the app host alone and lives as long as the window: it has no expiry date,
|
||||||
/// scripts cannot read it, and the window never sends it with a request which another site
|
/// and scripts cannot read it. The window never sends it with a request which a page of another
|
||||||
/// started. We parse it from text because the `cookie` crate, whose builder would need its
|
/// site makes, such as a script the page loads or a form it posts.
|
||||||
|
///
|
||||||
|
/// The cookie is `Lax`, not `Strict`. Before the window opens the app, it shows a page of Tauri,
|
||||||
|
/// `tauri://localhost` on macOS, which is another site than the app. WKWebView counts that page
|
||||||
|
/// as the one which opened the app, and it would withhold a `Strict` cookie. A `Lax` cookie goes
|
||||||
|
/// along when a whole page of the app opens. Development builds show the page of the Tauri dev
|
||||||
|
/// server on the app host instead, which hides the difference.
|
||||||
|
///
|
||||||
|
/// We parse the cookie from text because the `cookie` crate, whose builder would need its
|
||||||
/// `SameSite` type, is no direct dependency of ours.
|
/// `SameSite` type, is no direct dependency of ours.
|
||||||
pub fn session_cookie() -> Cookie<'static> {
|
pub fn session_cookie() -> Cookie<'static> {
|
||||||
let token = UI_ACCESS_TOKEN.to_hex_text();
|
let token = UI_ACCESS_TOKEN.to_hex_text();
|
||||||
Cookie::parse(format!("{SESSION_COOKIE_NAME}={token}; Domain={APP_HOST}; Path=/; HttpOnly; SameSite=Strict"))
|
Cookie::parse(format!("{SESSION_COOKIE_NAME}={token}; Domain={APP_HOST}; Path=/; HttpOnly; SameSite=Lax"))
|
||||||
.expect("The session cookie consists of fixed attributes and a hexadecimal token, which always parse.")
|
.expect("The session cookie consists of fixed attributes and a hexadecimal token, which always parse.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +140,7 @@ mod tests {
|
|||||||
let cookie = session_cookie();
|
let cookie = session_cookie();
|
||||||
|
|
||||||
assert_eq!(cookie.http_only(), Some(true));
|
assert_eq!(cookie.http_only(), Some(true));
|
||||||
assert!(cookie.same_site().is_some_and(|same_site| same_site.is_strict()));
|
assert!(cookie.same_site().is_some_and(|same_site| same_site.is_lax()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -708,10 +708,9 @@ pub async fn change_location_to(url: tauri::Url) {
|
|||||||
|
|
||||||
//
|
//
|
||||||
// The window navigates by itself instead of through a script of the page it shows. That page
|
// The window navigates by itself instead of through a script of the page it shows. That page
|
||||||
// comes from Tauri, which is another site than the app, so the app would count as opened by
|
// comes from Tauri, which is another site than the app; app_access::session_cookie explains
|
||||||
// another site, and the window would withhold the session cookie. We take the window out of
|
// why the session cookie goes along all the same. We take the window out of the lock first:
|
||||||
// the lock first: the cookie and the navigation need the main thread, which may wait for this
|
// the cookie and the navigation need the main thread, which may wait for this lock meanwhile.
|
||||||
// lock meanwhile.
|
|
||||||
//
|
//
|
||||||
// Handing over the cookie waits for the main thread. This function serves a request of the
|
// Handing over the cookie waits for the main thread. This function serves a request of the
|
||||||
// runtime API, so the waiting happens outside the async runtime, see runtime/AGENTS.md.
|
// runtime API, so the waiting happens outside the async runtime, see runtime/AGENTS.md.
|
||||||
|
|||||||
Reference in new issue
Block a user