feat(config): 在加密导出/导入中包含个人访问令牌
This commit is contained in:
@@ -4,6 +4,8 @@ use std::env;
|
||||
const SERVICE_NAME: &str = "quicommit";
|
||||
const ENV_API_KEY: &str = "QUICOMMIT_API_KEY";
|
||||
|
||||
const PAT_SERVICE_PREFIX: &str = "quicommit/pat";
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum KeyringStatus {
|
||||
Available,
|
||||
@@ -83,19 +85,16 @@ impl KeyringManager {
|
||||
}
|
||||
|
||||
pub fn get_api_key(&self, provider: &str) -> Result<Option<String>> {
|
||||
// 优先从环境变量获取
|
||||
if let Ok(key) = env::var(ENV_API_KEY) {
|
||||
if !key.is_empty() {
|
||||
return Ok(Some(key));
|
||||
}
|
||||
}
|
||||
|
||||
// keyring 不可用时直接返回
|
||||
if !self.is_available() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// 从 keyring 获取
|
||||
let entry = keyring::Entry::new(SERVICE_NAME, provider)
|
||||
.context("Failed to create keyring entry")?;
|
||||
|
||||
@@ -124,6 +123,85 @@ impl KeyringManager {
|
||||
self.get_api_key(provider).unwrap_or(None).is_some()
|
||||
}
|
||||
|
||||
fn make_pat_service_name(profile_name: &str) -> String {
|
||||
format!("{}/{}", PAT_SERVICE_PREFIX, profile_name)
|
||||
}
|
||||
|
||||
pub fn store_pat(&self, profile_name: &str, user_email: &str, service: &str, token: &str) -> Result<()> {
|
||||
if !self.is_available() {
|
||||
bail!("Keyring is not available on this system");
|
||||
}
|
||||
|
||||
let keyring_service = Self::make_pat_service_name(profile_name);
|
||||
let keyring_user = format!("{}:{}", user_email, service);
|
||||
|
||||
let entry = keyring::Entry::new(&keyring_service, &keyring_user)
|
||||
.context("Failed to create keyring entry for PAT")?;
|
||||
|
||||
entry.set_password(token)
|
||||
.context("Failed to store PAT in keyring")?;
|
||||
|
||||
eprintln!("[DEBUG] PAT stored in keyring: service={}, user={}", keyring_service, keyring_user);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_pat(&self, profile_name: &str, user_email: &str, service: &str) -> Result<Option<String>> {
|
||||
if !self.is_available() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let keyring_service = Self::make_pat_service_name(profile_name);
|
||||
let keyring_user = format!("{}:{}", user_email, service);
|
||||
|
||||
let entry = keyring::Entry::new(&keyring_service, &keyring_user)
|
||||
.context("Failed to create keyring entry for PAT")?;
|
||||
|
||||
match entry.get_password() {
|
||||
Ok(token) => {
|
||||
eprintln!("[DEBUG] PAT retrieved from keyring: service={}, user={}", keyring_service, keyring_user);
|
||||
Ok(Some(token))
|
||||
}
|
||||
Err(keyring::Error::NoEntry) => {
|
||||
eprintln!("[DEBUG] PAT not found in keyring: service={}, user={}", keyring_service, keyring_user);
|
||||
Ok(None)
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_pat(&self, profile_name: &str, user_email: &str, service: &str) -> Result<()> {
|
||||
if !self.is_available() {
|
||||
bail!("Keyring is not available on this system");
|
||||
}
|
||||
|
||||
let keyring_service = Self::make_pat_service_name(profile_name);
|
||||
let keyring_user = format!("{}:{}", user_email, service);
|
||||
|
||||
let entry = keyring::Entry::new(&keyring_service, &keyring_user)
|
||||
.context("Failed to create keyring entry for PAT")?;
|
||||
|
||||
entry.delete_credential()
|
||||
.context("Failed to delete PAT from keyring")?;
|
||||
|
||||
eprintln!("[DEBUG] PAT deleted from keyring: service={}, user={}", keyring_service, keyring_user);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn has_pat(&self, profile_name: &str, user_email: &str, service: &str) -> bool {
|
||||
self.get_pat(profile_name, user_email, service).unwrap_or(None).is_some()
|
||||
}
|
||||
|
||||
pub fn delete_all_pats_for_profile(&self, profile_name: &str, user_email: &str, services: &[String]) -> Result<()> {
|
||||
for service in services {
|
||||
if let Err(e) = self.delete_pat(profile_name, user_email, service) {
|
||||
eprintln!("[DEBUG] Failed to delete PAT for service '{}': {}", service, e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_status_message(&self) -> String {
|
||||
match self.status {
|
||||
KeyringStatus::Available => {
|
||||
|
||||
Reference in New Issue
Block a user