9a99bca466
- lib.rs nur noch Prozessrollen-Dispatch + Panic-Tracer - KWin-Script als KDE-Pendant zur GNOME-Extension (Popup ans Zeiger- Rechteck), wird von deb/rpm mit ausgeliefert - SNI-Tray auf ksni (pure Rust), appindicator-Depends entfallen
66 lines
2.4 KiB
Rust
66 lines
2.4 KiB
Rust
//! Credential-Ablage der Pools. Der ApikeyStore abstrahiert den nativen
|
|
//! Secret-Store (macOS-Keychain / Secret Service / Credential Manager) —
|
|
//! die Implementierungen liegen in platform/.
|
|
|
|
use sha2::{Digest, Sha256};
|
|
|
|
use crate::domain::paths::Paths;
|
|
|
|
/// Service-Name der Einträge; Account ist die Pool-ID. Unter Linux legt die
|
|
/// keyring-Crate die Attribute service/username an — der apiKeyHelper liest
|
|
/// mit denselben Attributen über secret-tool.
|
|
pub(crate) const APIKEY_SERVICE: &str = "ai-control-apikey";
|
|
|
|
/// Fehler-Sentinel an die UI: Store nicht verfügbar und Datei-Ablage (noch)
|
|
/// nicht erlaubt — die UI fragt dann nach und wiederholt mit allow_file.
|
|
pub(crate) const KEYCHAIN_UNAVAILABLE: &str = "keychain-unavailable";
|
|
|
|
/// Ablage der API-Keys im nativen Secret-Store. Die Key-Datei im Pool-Ordner
|
|
/// bleibt Fallback, wenn der Store beim Schreiben nicht verfügbar ist.
|
|
pub(crate) trait ApikeyStore {
|
|
fn set(&self, pool: &str, key: &str) -> Result<(), String>;
|
|
fn has(&self, pool: &str) -> Result<bool, String>;
|
|
fn delete(&self, pool: &str) -> Result<(), String>;
|
|
}
|
|
|
|
/// Keychain-Service-Name des OAuth-Pools: claude legt pro CLAUDE_CONFIG_DIR
|
|
/// einen suffixierten Eintrag an, Suffix = erste 8 Hex-Zeichen von SHA-256
|
|
/// über den Pool-Pfad.
|
|
pub(crate) fn keychain_service(paths: &Paths, pool: &str) -> String {
|
|
let hash = Sha256::digest(paths.pool_dir(pool).to_string_lossy().as_bytes());
|
|
let hex: String = hash.iter().map(|b| format!("{b:02x}")).collect();
|
|
format!("Claude Code-credentials-{}", &hex[..8])
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::path::PathBuf;
|
|
|
|
/// Referenzwert vom echten System: privateDefault → 096c4ef9
|
|
/// (verifiziert 2026-07-03 gegen den von claude angelegten Eintrag).
|
|
#[test]
|
|
fn keychain_service_suffix() {
|
|
let p = Paths { home: PathBuf::from("/Users/marcus.hinz") };
|
|
assert_eq!(
|
|
keychain_service(&p, "privateDefault"),
|
|
"Claude Code-credentials-096c4ef9"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn apikey_helper_kette_referenz() {
|
|
let dir = PathBuf::from("/pools/abc");
|
|
let cmd = crate::platform::apikey_helper_command(&dir, "abc");
|
|
assert!(cmd.ends_with("|| cat '/pools/abc/apikey'"));
|
|
#[cfg(target_os = "macos")]
|
|
assert!(cmd.starts_with(
|
|
"security find-generic-password -w -s ai-control-apikey -a abc 2>/dev/null"
|
|
));
|
|
#[cfg(target_os = "linux")]
|
|
assert!(cmd.starts_with(
|
|
"secret-tool lookup service ai-control-apikey username abc 2>/dev/null"
|
|
));
|
|
}
|
|
}
|