Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions src-tauri/src/core/github/auth/keychain.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
use std::sync::{Mutex, OnceLock};

use crate::core::errors::{AppError, AppResult};

use crate::core::github::constants::{KEYCHAIN_SERVICE, KEYCHAIN_USER};
use crate::core::github::types::GithubErrorCode;

use super::session::cancel_github_login;

static TOKEN_CACHE: OnceLock<Mutex<Option<String>>> = OnceLock::new();

fn token_cache() -> &'static Mutex<Option<String>> {
TOKEN_CACHE.get_or_init(|| Mutex::new(None))
}

fn cache_token(token: Option<String>) -> AppResult<()> {
let mut cache = token_cache()
.lock()
.map_err(|_error| AppError::unknown("GitHub token cache lock failed"))?;
*cache = token;
Ok(())
}

fn cached_token() -> AppResult<Option<String>> {
token_cache()
.lock()
.map(|cache| cache.clone())
.map_err(|_error| AppError::unknown("GitHub token cache lock failed"))
}

fn token_entry() -> AppResult<keyring::Entry> {
keyring::Entry::new(KEYCHAIN_SERVICE, KEYCHAIN_USER)
.map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed"))
Expand All @@ -13,12 +36,20 @@ fn token_entry() -> AppResult<keyring::Entry> {
pub fn save_token(token: &str) -> AppResult<()> {
token_entry()?
.set_password(token)
.map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed"))
.map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed"))?;
cache_token(Some(token.to_string()))
}

pub fn read_token() -> AppResult<Option<String>> {
if let Some(token) = cached_token()? {
return Ok(Some(token));
}

match token_entry()?.get_password() {
Ok(token) => Ok(Some(token)),
Ok(token) => {
cache_token(Some(token.clone()))?;
Ok(Some(token))
}
Err(keyring::Error::NoEntry) => Ok(None),
Err(_error) => Err(AppError::new(
GithubErrorCode::KeychainFailed,
Expand All @@ -30,7 +61,7 @@ pub fn read_token() -> AppResult<Option<String>> {
pub fn delete_token() -> AppResult<()> {
cancel_github_login();
match token_entry()?.delete_credential() {
Ok(()) | Err(keyring::Error::NoEntry) => Ok(()),
Ok(()) | Err(keyring::Error::NoEntry) => cache_token(None),
Err(_error) => Err(AppError::new(
GithubErrorCode::KeychainFailed,
"Keychain access failed",
Expand Down
Loading