First working POC
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
use std::sync::Arc;
|
||||
use tauri::State;
|
||||
|
||||
use crate::auth::{AuthManager, SessionVerifier, ServerInfo, AuthResult, Session};
|
||||
|
||||
/// Wrapper for AuthManager to manage in Tauri state
|
||||
pub struct AuthManagerWrapper(pub Arc<AuthManager>);
|
||||
|
||||
/// Wrapper for SessionVerifier to manage in Tauri state
|
||||
pub struct SessionVerifierWrapper(pub Arc<tokio::sync::Mutex<Option<SessionVerifier>>>);
|
||||
|
||||
/// Initialize the auth manager (call on app startup)
|
||||
/// Restores session from storage if available
|
||||
#[tauri::command]
|
||||
pub async fn auth_initialize(
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
database: State<'_, crate::commands::DatabaseWrapper>,
|
||||
credentials: State<'_, crate::commands::CredentialStoreWrapper>,
|
||||
) -> Result<Option<Session>, String> {
|
||||
// First check if we already have a session in memory
|
||||
if let Some(session) = auth_manager.0.get_session().await {
|
||||
return Ok(Some(session));
|
||||
}
|
||||
|
||||
// Try to restore session from storage
|
||||
log::info!("[AuthManager] Restoring session from storage...");
|
||||
|
||||
// Use the existing storage_get_active_session function
|
||||
let active_session = match crate::commands::storage::storage_get_active_session(database, credentials).await {
|
||||
Ok(Some(session)) => session,
|
||||
Ok(None) => {
|
||||
log::info!("[AuthManager] No active session in storage");
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("[AuthManager] Failed to get active session: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Create session object from active session with normalized URL
|
||||
let normalized_url = crate::auth::AuthManager::normalize_url(&active_session.server_url);
|
||||
|
||||
let session = Session {
|
||||
user_id: active_session.user_id,
|
||||
username: active_session.username,
|
||||
server_id: active_session.server_id,
|
||||
server_url: normalized_url,
|
||||
server_name: active_session.server_name,
|
||||
access_token: active_session.access_token,
|
||||
verified: false, // Will be verified in background
|
||||
needs_reauth: false,
|
||||
};
|
||||
|
||||
// Store in AuthManager
|
||||
auth_manager.0.set_session(Some(session.clone())).await;
|
||||
|
||||
log::info!("[AuthManager] Session restored for user: {} with normalized URL: {}", session.username, session.server_url);
|
||||
Ok(Some(session))
|
||||
}
|
||||
|
||||
/// Connect to a Jellyfin server and get server info
|
||||
#[tauri::command]
|
||||
pub async fn auth_connect_to_server(
|
||||
server_url: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<ServerInfo, String> {
|
||||
auth_manager.0.connect_to_server(&server_url).await
|
||||
}
|
||||
|
||||
/// Login with username and password
|
||||
#[tauri::command]
|
||||
pub async fn auth_login(
|
||||
server_url: String,
|
||||
username: String,
|
||||
password: String,
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<AuthResult, String> {
|
||||
let result = auth_manager.0.login(&server_url, &username, &password, &device_id).await?;
|
||||
|
||||
// Create session from auth result with normalized URL
|
||||
let normalized_url = crate::auth::AuthManager::normalize_url(&server_url);
|
||||
|
||||
let session = Session {
|
||||
user_id: result.user.id.clone(),
|
||||
username: result.user.name.clone(),
|
||||
server_id: result.server_id.clone(),
|
||||
server_url: normalized_url,
|
||||
server_name: String::new(), // Will be set by frontend
|
||||
access_token: result.access_token.clone(),
|
||||
verified: true,
|
||||
needs_reauth: false,
|
||||
};
|
||||
|
||||
auth_manager.0.set_session(Some(session)).await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Verify current session
|
||||
#[tauri::command]
|
||||
pub async fn auth_verify_session(
|
||||
server_url: String,
|
||||
user_id: String,
|
||||
access_token: String,
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<bool, String> {
|
||||
match auth_manager.0.verify_session(&server_url, &user_id, &access_token, &device_id).await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => {
|
||||
log::warn!("[AuthCommands] Session verification failed: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Logout (clear session and call Jellyfin logout endpoint)
|
||||
#[tauri::command]
|
||||
pub async fn auth_logout(
|
||||
server_url: String,
|
||||
access_token: String,
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
session_verifier: State<'_, SessionVerifierWrapper>,
|
||||
) -> Result<(), String> {
|
||||
// Stop session verification
|
||||
let mut verifier_guard = session_verifier.0.lock().await;
|
||||
if let Some(verifier) = verifier_guard.take() {
|
||||
verifier.stop();
|
||||
}
|
||||
drop(verifier_guard);
|
||||
|
||||
// Call Jellyfin logout endpoint
|
||||
auth_manager.0.logout(&server_url, &access_token, &device_id).await?;
|
||||
|
||||
// Clear session
|
||||
auth_manager.0.set_session(None).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get current session
|
||||
#[tauri::command]
|
||||
pub async fn auth_get_session(
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<Option<Session>, String> {
|
||||
Ok(auth_manager.0.get_session().await)
|
||||
}
|
||||
|
||||
/// Set current session (for restoration from storage)
|
||||
#[tauri::command]
|
||||
pub async fn auth_set_session(
|
||||
session: Option<Session>,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<(), String> {
|
||||
// Normalize the server URL if session is provided
|
||||
let normalized_session = session.map(|mut s| {
|
||||
s.server_url = crate::auth::AuthManager::normalize_url(&s.server_url);
|
||||
s
|
||||
});
|
||||
|
||||
auth_manager.0.set_session(normalized_session).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start background session verification
|
||||
#[tauri::command]
|
||||
pub async fn auth_start_verification(
|
||||
device_id: String,
|
||||
app_handle: tauri::AppHandle,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
session_verifier: State<'_, SessionVerifierWrapper>,
|
||||
) -> Result<(), String> {
|
||||
let mut verifier_guard = session_verifier.0.lock().await;
|
||||
|
||||
// Stop existing verifier if any
|
||||
if let Some(verifier) = verifier_guard.take() {
|
||||
verifier.stop();
|
||||
}
|
||||
|
||||
// Get AuthManager Arc
|
||||
let manager = auth_manager.0.clone();
|
||||
|
||||
// Create new verifier
|
||||
let mut verifier = SessionVerifier::new(manager, device_id);
|
||||
verifier.set_app_handle(app_handle);
|
||||
verifier.start().await;
|
||||
|
||||
*verifier_guard = Some(verifier);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stop background session verification
|
||||
#[tauri::command]
|
||||
pub async fn auth_stop_verification(
|
||||
session_verifier: State<'_, SessionVerifierWrapper>,
|
||||
) -> Result<(), String> {
|
||||
let mut verifier_guard = session_verifier.0.lock().await;
|
||||
|
||||
if let Some(verifier) = verifier_guard.take() {
|
||||
verifier.stop();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Re-authenticate with password (when session expired)
|
||||
#[tauri::command]
|
||||
pub async fn auth_reauthenticate(
|
||||
password: String,
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<AuthResult, String> {
|
||||
// Get current session to extract server_url and username
|
||||
let session = auth_manager.0.get_session().await
|
||||
.ok_or_else(|| "No active session to re-authenticate".to_string())?;
|
||||
|
||||
// Re-login with stored credentials
|
||||
let result = auth_manager.0.login(&session.server_url, &session.username, &password, &device_id).await?;
|
||||
|
||||
// Update session with new token
|
||||
let updated_session = Session {
|
||||
user_id: result.user.id.clone(),
|
||||
username: result.user.name.clone(),
|
||||
server_id: result.server_id.clone(),
|
||||
server_url: session.server_url,
|
||||
server_name: session.server_name,
|
||||
access_token: result.access_token.clone(),
|
||||
verified: true,
|
||||
needs_reauth: false,
|
||||
};
|
||||
|
||||
auth_manager.0.set_session(Some(updated_session)).await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Reference in New Issue
Block a user