qt-chat-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

keychain.rs (2880B)


      1 //! Credential storage module
      2 //!
      3 //! Uses file-based storage in the user's app data directory.
      4 //! Note: For production, consider using the system keychain with proper code signing.
      5 
      6 use crate::types::KeychainError;
      7 use std::fs;
      8 use std::path::PathBuf;
      9 
     10 /// Get the path to the token file
     11 fn token_file_path() -> Result<PathBuf, KeychainError> {
     12     let home = std::env::var("HOME").map_err(|_| KeychainError::NotFound)?;
     13     let app_dir = PathBuf::from(home).join(".config").join("beegram");
     14     Ok(app_dir.join("auth_token"))
     15 }
     16 
     17 /// Ensure the app config directory exists
     18 fn ensure_config_dir() -> Result<(), KeychainError> {
     19     let path = token_file_path()?;
     20     if let Some(parent) = path.parent() {
     21         fs::create_dir_all(parent).map_err(|e| {
     22             tracing::error!("Failed to create config directory: {:?}", e);
     23             KeychainError::NotFound
     24         })?;
     25     }
     26     Ok(())
     27 }
     28 
     29 /// Save authentication token to file
     30 pub fn save_token(token: &str) -> Result<(), KeychainError> {
     31     ensure_config_dir()?;
     32     let path = token_file_path()?;
     33     tracing::info!("Saving token to {:?}", path);
     34 
     35     fs::write(&path, token).map_err(|e| {
     36         tracing::error!("Failed to save token: {:?}", e);
     37         KeychainError::NotFound
     38     })?;
     39 
     40     // Set file permissions to owner-only (Unix)
     41     #[cfg(unix)]
     42     {
     43         use std::os::unix::fs::PermissionsExt;
     44         let perms = fs::Permissions::from_mode(0o600);
     45         let _ = fs::set_permissions(&path, perms);
     46     }
     47 
     48     tracing::info!("Token saved successfully");
     49     Ok(())
     50 }
     51 
     52 /// Load authentication token from file
     53 pub fn load_token() -> Result<String, KeychainError> {
     54     let path = token_file_path()?;
     55     tracing::info!("Loading token from {:?}", path);
     56 
     57     match fs::read_to_string(&path) {
     58         Ok(token) if !token.is_empty() => {
     59             tracing::info!("Token loaded (length={})", token.len());
     60             Ok(token)
     61         }
     62         Ok(_) => {
     63             tracing::info!("Empty token file");
     64             Err(KeychainError::NotFound)
     65         }
     66         Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
     67             tracing::info!("No token file found");
     68             Err(KeychainError::NotFound)
     69         }
     70         Err(e) => {
     71             tracing::error!("Failed to read token: {:?}", e);
     72             Err(KeychainError::NotFound)
     73         }
     74     }
     75 }
     76 
     77 /// Delete authentication token file
     78 pub fn delete_token() -> Result<(), KeychainError> {
     79     let path = token_file_path()?;
     80     match fs::remove_file(&path) {
     81         Ok(()) => {
     82             tracing::info!("Token deleted");
     83             Ok(())
     84         }
     85         Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
     86             tracing::debug!("No token to delete");
     87             Ok(())
     88         }
     89         Err(e) => {
     90             tracing::warn!("Failed to delete token: {:?}", e);
     91             Err(KeychainError::NotFound)
     92         }
     93     }
     94 }