v0.0.21 - Activity log: show caller identity, role, curve, and actual requested key path
This commit is contained in:
Generated
+1
-1
@@ -2207,7 +2207,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signer"
|
||||
version = "0.0.20"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chacha20poly1305",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "signer"
|
||||
version = "0.0.20"
|
||||
version = "0.0.21"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Attended Nostr signing daemon — Rust port of n_signer"
|
||||
|
||||
+1
-1
@@ -31,4 +31,4 @@ pub mod error;
|
||||
pub use error::SignerError;
|
||||
|
||||
/// Version string (matches C NSIGNER_VERSION).
|
||||
pub const VERSION: &str = "v0.0.20";
|
||||
pub const VERSION: &str = "v0.0.21";
|
||||
|
||||
+6
-2
@@ -241,7 +241,9 @@ fn run_headless(cli: &Cli, listen_mode: ListenMode) -> Result<(), SignerError> {
|
||||
key_store: &mut key_store,
|
||||
alg_key_cache: &mut alg_key_cache,
|
||||
};
|
||||
let _ = server.handle_one(&mut dispatcher);
|
||||
if let Ok(Some(activity)) = server.handle_one(&mut dispatcher) {
|
||||
println!("{}", activity);
|
||||
}
|
||||
server.stop();
|
||||
} else {
|
||||
// Tcp / Http poll loop
|
||||
@@ -253,7 +255,9 @@ fn run_headless(cli: &Cli, listen_mode: ListenMode) -> Result<(), SignerError> {
|
||||
alg_key_cache: &mut alg_key_cache,
|
||||
};
|
||||
match server.handle_one(&mut dispatcher) {
|
||||
Ok(Some(_activity)) => {}
|
||||
Ok(Some(activity)) => {
|
||||
println!("{}", activity);
|
||||
}
|
||||
Ok(None) => {
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
|
||||
+58
-12
@@ -62,6 +62,38 @@ impl CallerIdentity {
|
||||
auth_label: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a rich identity string for the activity log — as much as can be
|
||||
/// identified about the caller.
|
||||
///
|
||||
/// - Unix socket: `uid:<n> gid:<n> pid:<n>`
|
||||
/// - Qrexec: `qubes:<vm>`
|
||||
/// - TCP/HTTP: `tcp:<addr>`
|
||||
/// - Auth envelope verified: `pubkey:<hex> label:<label>` appended.
|
||||
pub fn identity_str(&self) -> String {
|
||||
let mut parts: Vec<String> = Vec::new();
|
||||
match self.kind {
|
||||
ListenMode::Unix => {
|
||||
parts.push(format!("uid:{}", self.uid));
|
||||
if self.gid != 0 {
|
||||
parts.push(format!("gid:{}", self.gid));
|
||||
}
|
||||
if self.pid != 0 {
|
||||
parts.push(format!("pid:{}", self.pid));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
parts.push(self.caller_id.clone());
|
||||
}
|
||||
}
|
||||
if self.auth_present {
|
||||
parts.push(format!("pubkey:{}", self.auth_pubkey_hex));
|
||||
if !self.auth_label.is_empty() {
|
||||
parts.push(format!("label:{}", self.auth_label));
|
||||
}
|
||||
}
|
||||
parts.join(" ")
|
||||
}
|
||||
}
|
||||
|
||||
/// Server context.
|
||||
@@ -294,7 +326,7 @@ impl ServerContext {
|
||||
Err((code, msg)) => {
|
||||
if self.auth_mode == AuthMode::Required {
|
||||
let response = make_auth_error(&request, code, msg);
|
||||
let activity = format!("{} DENIED:{}", caller.caller_id, msg);
|
||||
let activity = format!("{} DENIED:{}", caller.identity_str(), msg);
|
||||
return (response, activity);
|
||||
}
|
||||
// Optional: continue without auth
|
||||
@@ -308,7 +340,7 @@ impl ServerContext {
|
||||
None => {
|
||||
// Malformed request — let the dispatcher produce the error
|
||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
||||
let activity = format!("{} DENIED:malformed", caller.caller_id);
|
||||
let activity = format!("{} DENIED:malformed", caller.identity_str());
|
||||
return (response, activity);
|
||||
}
|
||||
};
|
||||
@@ -316,7 +348,7 @@ impl ServerContext {
|
||||
// get_info is metadata — no key material
|
||||
if method == crate::enforcement::VERB_GET_INFO {
|
||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
||||
let activity = format!("{} {}()", caller.caller_id, method);
|
||||
let activity = format!("{} {}()", caller.identity_str(), method);
|
||||
return (response, activity);
|
||||
}
|
||||
|
||||
@@ -327,9 +359,9 @@ impl ServerContext {
|
||||
// standard derivation path identifies the key material.
|
||||
let (alg_name, path) = extract_algorithm_and_path(request);
|
||||
let activity = match (alg_name, path) {
|
||||
(Some(a), Some(p)) => format!("{} {}({},{} {})", caller.caller_id, method, a, selector_req.index, p),
|
||||
(Some(a), None) => format!("{} {}({})", caller.caller_id, method, a),
|
||||
_ => format!("{} {}()", caller.caller_id, method),
|
||||
(Some(a), Some(p)) => format!("{} {}({},{} {})", caller.identity_str(), method, a, selector_req.index, p),
|
||||
(Some(a), None) => format!("{} {}({})", caller.identity_str(), method, a),
|
||||
_ => format!("{} {}()", caller.identity_str(), method),
|
||||
};
|
||||
return (response, activity);
|
||||
}
|
||||
@@ -337,7 +369,7 @@ impl ServerContext {
|
||||
// OTP verbs
|
||||
if method == crate::enforcement::VERB_ENCRYPT || method == crate::enforcement::VERB_DECRYPT {
|
||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
||||
let activity = format!("{} {}()", caller.caller_id, method);
|
||||
let activity = format!("{} {}()", caller.identity_str(), method);
|
||||
return (response, activity);
|
||||
}
|
||||
|
||||
@@ -349,7 +381,7 @@ impl ServerContext {
|
||||
let response = make_selector_error(&request, e);
|
||||
let activity = format!(
|
||||
"{} {}() DENIED:{}",
|
||||
caller.caller_id,
|
||||
caller.identity_str(),
|
||||
method,
|
||||
e.as_str()
|
||||
);
|
||||
@@ -358,15 +390,29 @@ impl ServerContext {
|
||||
};
|
||||
|
||||
// Role entry from the resolved selector — used for the activity
|
||||
// message (curve + key path).
|
||||
// message (role name, curve, and the concrete key path requested).
|
||||
let role_entry = &dispatcher.role_table.entries[role_index];
|
||||
let role_name = role_entry.name.clone();
|
||||
let curve = role_entry.curve_str.clone();
|
||||
let path = role_entry.display_path();
|
||||
// The actual key path the caller requested/accessed — the concrete
|
||||
// role_path from the request when supplied, otherwise the role's
|
||||
// fixed/derived path. (Not the allowed range.)
|
||||
let actual_path = if selector_req.has_role_path {
|
||||
selector_req.role_path.clone()
|
||||
} else {
|
||||
role_entry.display_path()
|
||||
};
|
||||
|
||||
// ── Dispatch ───────────────────────────────────────────────
|
||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
||||
// Activity format: uid curve path (timestamp is added by the log).
|
||||
let activity = format!("{} {} {}", caller.caller_id, curve, path);
|
||||
// Activity format: uid role curve path (timestamp is added by the log).
|
||||
let activity = format!(
|
||||
"{} {} {} {}",
|
||||
caller.identity_str(),
|
||||
role_name,
|
||||
curve,
|
||||
actual_path
|
||||
);
|
||||
(response, activity)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user