macOS: API-Key nicht mehr ueber die Kommandozeile an security

add-generic-password bekam den Key als -w-Argument; damit stand er fuer die
Dauer des Aufrufs in der Prozessliste und war per ps fuer jeden Nutzer des
Rechners lesbar. Jetzt kommt -w ohne Wert, security liest das Secret ueber
stdin (zweimal, Eingabe und Bestaetigung). Die Eingabeaufforderungen landen
auf stderr und werden aus der Fehlermeldung geschnitten.
This commit is contained in:
marcusH
2026-07-20 22:17:21 +02:00
parent e15e128fd3
commit 92f34cb64d
+24 -5
View File
@@ -1,8 +1,9 @@
//! macOS: Aktivierung/Fokus über AppKit (objc2), Dock-Icons pro
//! Terminal-Prozess, Keychain über das security-CLI, nativer Tray.
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::process::{Command, Stdio};
use crate::domain::credentials::{ApikeyStore, APIKEY_SERVICE};
use crate::domain::paths::Paths;
@@ -98,14 +99,32 @@ pub(crate) struct KeychainStore;
impl ApikeyStore for KeychainStore {
fn set(&self, pool: &str, key: &str) -> Result<(), String> {
let out = Command::new("security")
.args(["add-generic-password", "-U", "-s", APIKEY_SERVICE, "-a", pool, "-w", key])
.output()
// -w ohne Wert: security liest das Secret über stdin, zweimal (Eingabe und
// Bestätigung). Als Argument übergeben stünde der Key für die Dauer des
// Aufrufs in der Prozessliste und wäre für jeden `ps` lesbar.
let mut child = Command::new("security")
.args(["add-generic-password", "-U", "-s", APIKEY_SERVICE, "-a", pool, "-w"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| e.to_string())?;
child
.stdin
.take()
.ok_or("security: kein stdin")?
.write_all(format!("{key}\n{key}\n").as_bytes())
.map_err(|e| e.to_string())?;
let out = child.wait_with_output().map_err(|e| e.to_string())?;
if out.status.success() {
Ok(())
} else {
Err(String::from_utf8_lossy(&out.stderr).into_owned())
// Die Eingabeaufforderungen landen auf stderr und stehen sonst vor der
// eigentlichen Fehlermeldung.
let err = String::from_utf8_lossy(&out.stderr)
.replace("password data for new item: ", "")
.replace("retype password for new item: ", "");
Err(err.trim().to_string())
}
}