Return to the native entry screen after the final website account logs out
Hop-State: A_06FPG94PH3WVGZM2V10TNC0 Hop-Proposal: R_06FPG943E08MTNDQMWHA0E8 Hop-Task: T_06FPG80D8VVAEPFXY3F8WGR Hop-Attempt: AT_06FPG80D8VE7RMJ24BEY3SR
This commit is contained in:
+80
-3
@@ -1,13 +1,15 @@
|
|||||||
use reqwest::{Client, Method, StatusCode, Url};
|
use reqwest::{Client, Method, StatusCode, Url};
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tauri::webview::Cookie;
|
use tauri::webview::{Cookie, PageLoadEvent};
|
||||||
use tauri::{Manager, State, WebviewWindow};
|
use tauri::{Manager, State, WebviewWindow};
|
||||||
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
client: Client,
|
client: Client,
|
||||||
notification_capability_sequence: AtomicU64,
|
notification_capability_sequence: AtomicU64,
|
||||||
|
entry_url: Mutex<Option<Url>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
@@ -247,9 +249,17 @@ async fn has_web_session(webview: WebviewWindow, node_url: String) -> Result<boo
|
|||||||
let cookies = webview
|
let cookies = webview
|
||||||
.cookies_for_url(base)
|
.cookies_for_url(base)
|
||||||
.map_err(|error| format!("Couldn’t restore the web session: {error}"))?;
|
.map_err(|error| format!("Couldn’t restore the web session: {error}"))?;
|
||||||
Ok(cookies
|
Ok(has_synapsis_session(&cookies))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_synapsis_session(cookies: &[Cookie<'_>]) -> bool {
|
||||||
|
cookies
|
||||||
.iter()
|
.iter()
|
||||||
.any(|cookie| cookie.name() == "synapsis_sessions" && !cookie.value().trim().is_empty()))
|
.any(|cookie| cookie.name() == "synapsis_sessions" && !cookie.value().trim().is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_logged_out_explore(url: &Url, cookies: &[Cookie<'_>]) -> bool {
|
||||||
|
url.path().trim_end_matches('/') == "/explore" && !has_synapsis_session(cookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -259,6 +269,19 @@ async fn open_web_app(
|
|||||||
node_url: String,
|
node_url: String,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let base = normalize_node(&node_url)?;
|
let base = normalize_node(&node_url)?;
|
||||||
|
{
|
||||||
|
let mut entry_url = state
|
||||||
|
.entry_url
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| "Couldn’t remember the app entry screen.".to_string())?;
|
||||||
|
if entry_url.is_none() {
|
||||||
|
*entry_url = Some(
|
||||||
|
webview
|
||||||
|
.url()
|
||||||
|
.map_err(|error| format!("Couldn’t read the app entry address: {error}"))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let origin = base.origin().ascii_serialization();
|
let origin = base.origin().ascii_serialization();
|
||||||
let capability_id = state
|
let capability_id = state
|
||||||
.notification_capability_sequence
|
.notification_capability_sequence
|
||||||
@@ -317,6 +340,49 @@ pub fn run() {
|
|||||||
.manage(AppState {
|
.manage(AppState {
|
||||||
client,
|
client,
|
||||||
notification_capability_sequence: AtomicU64::new(0),
|
notification_capability_sequence: AtomicU64::new(0),
|
||||||
|
entry_url: Mutex::new(None),
|
||||||
|
})
|
||||||
|
.on_page_load(|webview, payload| {
|
||||||
|
if payload.event() != PageLoadEvent::Finished
|
||||||
|
|| !matches!(payload.url().scheme(), "http" | "https")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(cookies) = webview.cookies_for_url(payload.url().clone()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if !is_logged_out_explore(payload.url(), &cookies) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = webview.state::<AppState>();
|
||||||
|
let mut entry_url = {
|
||||||
|
let Ok(saved_entry_url) = state.entry_url.lock() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(entry_url) = saved_entry_url.clone() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
entry_url
|
||||||
|
};
|
||||||
|
|
||||||
|
let client = state.client.clone();
|
||||||
|
let node_url = payload.url().clone();
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
if let Ok(base) = normalize_node(node_url.as_str()) {
|
||||||
|
if let Ok(logout_url) = endpoint(&base, "/api/auth/logout") {
|
||||||
|
let _ = client
|
||||||
|
.post(logout_url)
|
||||||
|
.json(&serde_json::json!({}))
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
entry_url.set_query(Some("signedOut=1"));
|
||||||
|
let _ = webview.navigate(entry_url);
|
||||||
})
|
})
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
connect,
|
connect,
|
||||||
@@ -389,4 +455,15 @@ mod tests {
|
|||||||
assert_eq!(value["remote"]["urls"][0], "https://example.com/*");
|
assert_eq!(value["remote"]["urls"][0], "https://example.com/*");
|
||||||
assert_eq!(value["permissions"][0], "notification:default");
|
assert_eq!(value["permissions"][0], "notification:default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_to_entry_only_for_logged_out_explore() {
|
||||||
|
let explore = Url::parse("https://example.com/explore").unwrap();
|
||||||
|
let timeline = Url::parse("https://example.com/").unwrap();
|
||||||
|
let active_cookie = Cookie::new("synapsis_sessions", "active");
|
||||||
|
|
||||||
|
assert!(is_logged_out_explore(&explore, &[]));
|
||||||
|
assert!(!is_logged_out_explore(&timeline, &[]));
|
||||||
|
assert!(!is_logged_out_explore(&explore, &[active_cookie]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,6 +245,15 @@ function App() {
|
|||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const launchParams = new URLSearchParams(window.location.search);
|
||||||
|
if (launchParams.has("signedOut")) {
|
||||||
|
localStorage.removeItem(SAVED_NODE_KEY);
|
||||||
|
window.history.replaceState({}, "", window.location.pathname);
|
||||||
|
setScreen("node");
|
||||||
|
setBootstrapping(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const savedNode = localStorage.getItem(SAVED_NODE_KEY);
|
const savedNode = localStorage.getItem(SAVED_NODE_KEY);
|
||||||
if (!savedNode || !isTauri()) {
|
if (!savedNode || !isTauri()) {
|
||||||
setBootstrapping(false);
|
setBootstrapping(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user