sign out
This commit is contained in:
11
src-tauri/Cargo.lock
generated
11
src-tauri/Cargo.lock
generated
@@ -1162,6 +1162,7 @@ dependencies = [
|
|||||||
"tauri-plugin-global-shortcut",
|
"tauri-plugin-global-shortcut",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
"tauri-plugin-positioner",
|
"tauri-plugin-positioner",
|
||||||
|
"tauri-plugin-process",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@@ -4492,6 +4493,16 @@ dependencies = [
|
|||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-process"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a"
|
||||||
|
dependencies = [
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.9.1"
|
version = "2.9.1"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ serde_json = "1"
|
|||||||
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||||
tauri-plugin-global-shortcut = "2"
|
tauri-plugin-global-shortcut = "2"
|
||||||
tauri-plugin-positioner = "2"
|
tauri-plugin-positioner = "2"
|
||||||
|
tauri-plugin-process = "2"
|
||||||
reqwest = { version = "0.12.23", features = ["json", "native-tls", "blocking"] }
|
reqwest = { version = "0.12.23", features = ["json", "native-tls", "blocking"] }
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
ts-rs = "11.0.1"
|
ts-rs = "11.0.1"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"dialog:default",
|
"dialog:default",
|
||||||
"core:event:allow-listen",
|
"core:event:allow-listen",
|
||||||
"core:event:allow-unlisten",
|
"core:event:allow-unlisten",
|
||||||
"core:window:allow-close"
|
"core:window:allow-close",
|
||||||
|
"process:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,6 +330,20 @@ fn quit_app() -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn restart_app() -> Result<(), String> {
|
||||||
|
let app_handle = get_app_handle();
|
||||||
|
app_handle.restart();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn logout_and_restart() -> Result<(), String> {
|
||||||
|
crate::services::auth::logout_and_restart()
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn start_auth_flow() -> Result<(), String> {
|
fn start_auth_flow() -> Result<(), String> {
|
||||||
// Cancel any in-flight auth listener/state before starting a new one
|
// Cancel any in-flight auth listener/state before starting a new one
|
||||||
@@ -352,6 +366,7 @@ pub fn run() {
|
|||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_positioner::init())
|
.plugin(tauri_plugin_positioner::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.plugin(tauri_plugin_process::init())
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
start_cursor_tracking,
|
start_cursor_tracking,
|
||||||
get_app_data,
|
get_app_data,
|
||||||
@@ -373,8 +388,10 @@ pub fn run() {
|
|||||||
remove_active_doll,
|
remove_active_doll,
|
||||||
recolor_gif_base64,
|
recolor_gif_base64,
|
||||||
quit_app,
|
quit_app,
|
||||||
|
restart_app,
|
||||||
open_doll_editor_window,
|
open_doll_editor_window,
|
||||||
start_auth_flow
|
start_auth_flow,
|
||||||
|
logout_and_restart
|
||||||
])
|
])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
APP_HANDLE
|
APP_HANDLE
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod dolls;
|
pub mod dolls;
|
||||||
pub mod friends;
|
pub mod friends;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
pub mod session;
|
||||||
|
|||||||
49
src-tauri/src/remotes/session.rs
Normal file
49
src-tauri/src/remotes/session.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use reqwest::Error;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use crate::services::auth::with_auth;
|
||||||
|
use crate::{lock_r, state::FDOLL};
|
||||||
|
|
||||||
|
pub struct SessionRemote {
|
||||||
|
pub base_url: String,
|
||||||
|
pub client: reqwest::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionRemote {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let guard = lock_r!(FDOLL);
|
||||||
|
Self {
|
||||||
|
base_url: guard
|
||||||
|
.app_config
|
||||||
|
.api_base_url
|
||||||
|
.as_ref()
|
||||||
|
.expect("App configuration error")
|
||||||
|
.clone(),
|
||||||
|
client: guard
|
||||||
|
.clients
|
||||||
|
.as_ref()
|
||||||
|
.expect("App configuration error")
|
||||||
|
.http_client
|
||||||
|
.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn logout(
|
||||||
|
&self,
|
||||||
|
refresh_token: &str,
|
||||||
|
session_state: Option<&str>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let url = format!("{}/users/logout", self.base_url);
|
||||||
|
let body = json!({
|
||||||
|
"refreshToken": refresh_token,
|
||||||
|
"sessionState": session_state,
|
||||||
|
});
|
||||||
|
let resp = with_auth(self.client.post(url))
|
||||||
|
.await
|
||||||
|
.json(&body)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
resp.error_for_status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -388,6 +388,47 @@ pub fn logout() -> Result<(), OAuthError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience helper to perform logout side effects before app restart.
|
||||||
|
pub async fn logout_and_restart() -> Result<(), OAuthError> {
|
||||||
|
// capture tokens and base_url before clearing for backend revocation
|
||||||
|
let (refresh_token, session_state, base_url) = {
|
||||||
|
let guard = lock_r!(FDOLL);
|
||||||
|
(
|
||||||
|
guard.auth_pass.as_ref().map(|p| p.refresh_token.clone()),
|
||||||
|
guard
|
||||||
|
.auth_pass
|
||||||
|
.as_ref()
|
||||||
|
.map(|p| p.session_state.clone()),
|
||||||
|
guard
|
||||||
|
.app_config
|
||||||
|
.api_base_url
|
||||||
|
.as_ref()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
logout()?;
|
||||||
|
|
||||||
|
if !base_url.is_empty() {
|
||||||
|
if let Some(refresh_token) = refresh_token.as_deref() {
|
||||||
|
let session_remote = crate::remotes::session::SessionRemote::new();
|
||||||
|
if let Err(err) = session_remote
|
||||||
|
.logout(refresh_token, session_state.as_deref())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
warn!("Failed to revoke session on server: {}", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("No refresh token available to revoke on server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let app_handle = get_app_handle();
|
||||||
|
app_handle.restart();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper to add authentication header to a request builder if tokens are available.
|
/// Helper to add authentication header to a request builder if tokens are available.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
|||||||
@@ -2,11 +2,27 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { appData } from "../../../events/app-data";
|
import { appData } from "../../../events/app-data";
|
||||||
import Power from "../../../assets/icons/power.svelte";
|
import Power from "../../../assets/icons/power.svelte";
|
||||||
|
|
||||||
|
let signingOut = false;
|
||||||
|
|
||||||
|
async function handleSignOut() {
|
||||||
|
if (signingOut) return;
|
||||||
|
signingOut = true;
|
||||||
|
try {
|
||||||
|
await invoke("logout_and_restart");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to sign out", error);
|
||||||
|
signingOut = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="size-full flex flex-col justify-between">
|
<div class="size-full flex flex-col justify-between">
|
||||||
<div>
|
<div class="flex flex-col gap-2">
|
||||||
<p>{$appData?.user?.name}'s preferences</p>
|
<p>{$appData?.user?.name}'s preferences</p>
|
||||||
|
<button class="btn" class:btn-disabled={signingOut} onclick={handleSignOut}>
|
||||||
|
{signingOut ? "Signing out..." : "Sign out"}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex flex-row justify-between">
|
<div class="w-full flex flex-row justify-between">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user