159 lines
6.5 KiB
Rust
159 lines
6.5 KiB
Rust
use std::sync::atomic::{AtomicBool, Ordering};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use tauri::{AppHandle, Emitter};
|
|
use serde::Serialize;
|
|
|
|
use super::{AuthManager, User};
|
|
|
|
// Verification interval (5 minutes)
|
|
const VERIFICATION_INTERVAL_MS: u64 = 300000;
|
|
|
|
/// Session verification result event emitted to frontend
|
|
#[derive(Debug, Clone, Serialize)]
|
|
#[serde(rename_all = "camelCase", tag = "type")]
|
|
pub enum SessionVerificationEvent {
|
|
Verified { user: User },
|
|
NeedsReauth { reason: String },
|
|
NetworkError { message: String },
|
|
}
|
|
|
|
/// Background session verifier
|
|
pub struct SessionVerifier {
|
|
auth_manager: Arc<AuthManager>,
|
|
is_running: Arc<AtomicBool>,
|
|
device_id: String,
|
|
app_handle: Option<AppHandle>,
|
|
}
|
|
|
|
impl SessionVerifier {
|
|
/// Create a new session verifier
|
|
pub fn new(auth_manager: Arc<AuthManager>, device_id: String) -> Self {
|
|
Self {
|
|
auth_manager,
|
|
is_running: Arc::new(AtomicBool::new(false)),
|
|
device_id,
|
|
app_handle: None,
|
|
}
|
|
}
|
|
|
|
/// Set the Tauri app handle for event emission
|
|
pub fn set_app_handle(&mut self, app_handle: AppHandle) {
|
|
self.app_handle = Some(app_handle);
|
|
}
|
|
|
|
/// Start periodic session verification
|
|
pub async fn start(&self) {
|
|
if self.is_running.swap(true, Ordering::SeqCst) {
|
|
log::info!("[SessionVerifier] Already running");
|
|
return;
|
|
}
|
|
|
|
log::info!("[SessionVerifier] Starting background verification");
|
|
|
|
let auth_manager = Arc::clone(&self.auth_manager);
|
|
let is_running = Arc::clone(&self.is_running);
|
|
let device_id = self.device_id.clone();
|
|
let app_handle = self.app_handle.clone();
|
|
|
|
tokio::spawn(async move {
|
|
// Initial verification after short delay
|
|
tokio::time::sleep(Duration::from_millis(2000)).await;
|
|
|
|
while is_running.load(Ordering::SeqCst) {
|
|
// Get current session
|
|
let session = auth_manager.get_session().await;
|
|
|
|
if let Some(session) = session {
|
|
log::debug!("[SessionVerifier] Verifying session for: {}", session.username);
|
|
|
|
// Verify the session
|
|
match auth_manager
|
|
.verify_session(
|
|
&session.server_url,
|
|
&session.user_id,
|
|
&session.access_token,
|
|
&device_id,
|
|
)
|
|
.await
|
|
{
|
|
Ok(user) => {
|
|
log::info!("[SessionVerifier] Session verified successfully");
|
|
|
|
// Emit success event
|
|
if let Some(app) = &app_handle {
|
|
let event = SessionVerificationEvent::Verified { user };
|
|
if let Err(e) = app.emit("auth:session-verified", event) {
|
|
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
|
}
|
|
}
|
|
|
|
// Update session as verified
|
|
let mut updated_session = session;
|
|
updated_session.verified = true;
|
|
updated_session.needs_reauth = false;
|
|
auth_manager.set_session(Some(updated_session)).await;
|
|
}
|
|
Err(e) => {
|
|
log::warn!("[SessionVerifier] Verification failed: {}", e);
|
|
|
|
// Classify error
|
|
let is_auth_error = e.contains("401") || e.contains("403");
|
|
let is_network_error = e.contains("network")
|
|
|| e.contains("timeout")
|
|
|| e.contains("connection")
|
|
|| e.contains("DNS");
|
|
|
|
if is_auth_error {
|
|
// Token is invalid - need re-authentication
|
|
log::warn!("[SessionVerifier] Session requires re-authentication");
|
|
|
|
if let Some(app) = &app_handle {
|
|
let event = SessionVerificationEvent::NeedsReauth {
|
|
reason: "Session expired".to_string(),
|
|
};
|
|
if let Err(e) = app.emit("auth:needs-reauth", event) {
|
|
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
|
}
|
|
}
|
|
|
|
// Update session
|
|
let mut updated_session = session;
|
|
updated_session.verified = false;
|
|
updated_session.needs_reauth = true;
|
|
auth_manager.set_session(Some(updated_session)).await;
|
|
} else if is_network_error {
|
|
// Network error - keep using cached session
|
|
log::info!("[SessionVerifier] Network error during verification, keeping cached session");
|
|
|
|
if let Some(app) = &app_handle {
|
|
let event = SessionVerificationEvent::NetworkError {
|
|
message: e.clone(),
|
|
};
|
|
if let Err(e) = app.emit("auth:network-error", event) {
|
|
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
|
}
|
|
}
|
|
} else {
|
|
// Unknown error - log but don't invalidate
|
|
log::error!("[SessionVerifier] Unknown error during verification: {}", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait for next verification
|
|
tokio::time::sleep(Duration::from_millis(VERIFICATION_INTERVAL_MS)).await;
|
|
}
|
|
|
|
log::info!("[SessionVerifier] Stopped");
|
|
});
|
|
}
|
|
|
|
/// Stop periodic verification
|
|
pub fn stop(&self) {
|
|
log::info!("[SessionVerifier] Stopping background verification");
|
|
self.is_running.store(false, Ordering::SeqCst);
|
|
}
|
|
}
|