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]]
|
[[package]]
|
||||||
name = "signer"
|
name = "signer"
|
||||||
version = "0.0.20"
|
version = "0.0.21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "signer"
|
name = "signer"
|
||||||
version = "0.0.20"
|
version = "0.0.21"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "Attended Nostr signing daemon — Rust port of n_signer"
|
description = "Attended Nostr signing daemon — Rust port of n_signer"
|
||||||
|
|||||||
+1
-1
@@ -31,4 +31,4 @@ pub mod error;
|
|||||||
pub use error::SignerError;
|
pub use error::SignerError;
|
||||||
|
|
||||||
/// Version string (matches C NSIGNER_VERSION).
|
/// 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,
|
key_store: &mut key_store,
|
||||||
alg_key_cache: &mut alg_key_cache,
|
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();
|
server.stop();
|
||||||
} else {
|
} else {
|
||||||
// Tcp / Http poll loop
|
// 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,
|
alg_key_cache: &mut alg_key_cache,
|
||||||
};
|
};
|
||||||
match server.handle_one(&mut dispatcher) {
|
match server.handle_one(&mut dispatcher) {
|
||||||
Ok(Some(_activity)) => {}
|
Ok(Some(activity)) => {
|
||||||
|
println!("{}", activity);
|
||||||
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-12
@@ -62,6 +62,38 @@ impl CallerIdentity {
|
|||||||
auth_label: String::new(),
|
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.
|
/// Server context.
|
||||||
@@ -294,7 +326,7 @@ impl ServerContext {
|
|||||||
Err((code, msg)) => {
|
Err((code, msg)) => {
|
||||||
if self.auth_mode == AuthMode::Required {
|
if self.auth_mode == AuthMode::Required {
|
||||||
let response = make_auth_error(&request, code, msg);
|
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);
|
return (response, activity);
|
||||||
}
|
}
|
||||||
// Optional: continue without auth
|
// Optional: continue without auth
|
||||||
@@ -308,7 +340,7 @@ impl ServerContext {
|
|||||||
None => {
|
None => {
|
||||||
// Malformed request — let the dispatcher produce the error
|
// Malformed request — let the dispatcher produce the error
|
||||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
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);
|
return (response, activity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -316,7 +348,7 @@ impl ServerContext {
|
|||||||
// get_info is metadata — no key material
|
// get_info is metadata — no key material
|
||||||
if method == crate::enforcement::VERB_GET_INFO {
|
if method == crate::enforcement::VERB_GET_INFO {
|
||||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
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);
|
return (response, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,9 +359,9 @@ impl ServerContext {
|
|||||||
// standard derivation path identifies the key material.
|
// standard derivation path identifies the key material.
|
||||||
let (alg_name, path) = extract_algorithm_and_path(request);
|
let (alg_name, path) = extract_algorithm_and_path(request);
|
||||||
let activity = match (alg_name, path) {
|
let activity = match (alg_name, path) {
|
||||||
(Some(a), Some(p)) => format!("{} {}({},{} {})", caller.caller_id, method, a, selector_req.index, p),
|
(Some(a), Some(p)) => format!("{} {}({},{} {})", caller.identity_str(), method, a, selector_req.index, p),
|
||||||
(Some(a), None) => format!("{} {}({})", caller.caller_id, method, a),
|
(Some(a), None) => format!("{} {}({})", caller.identity_str(), method, a),
|
||||||
_ => format!("{} {}()", caller.caller_id, method),
|
_ => format!("{} {}()", caller.identity_str(), method),
|
||||||
};
|
};
|
||||||
return (response, activity);
|
return (response, activity);
|
||||||
}
|
}
|
||||||
@@ -337,7 +369,7 @@ impl ServerContext {
|
|||||||
// OTP verbs
|
// OTP verbs
|
||||||
if method == crate::enforcement::VERB_ENCRYPT || method == crate::enforcement::VERB_DECRYPT {
|
if method == crate::enforcement::VERB_ENCRYPT || method == crate::enforcement::VERB_DECRYPT {
|
||||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
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);
|
return (response, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +381,7 @@ impl ServerContext {
|
|||||||
let response = make_selector_error(&request, e);
|
let response = make_selector_error(&request, e);
|
||||||
let activity = format!(
|
let activity = format!(
|
||||||
"{} {}() DENIED:{}",
|
"{} {}() DENIED:{}",
|
||||||
caller.caller_id,
|
caller.identity_str(),
|
||||||
method,
|
method,
|
||||||
e.as_str()
|
e.as_str()
|
||||||
);
|
);
|
||||||
@@ -358,15 +390,29 @@ impl ServerContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Role entry from the resolved selector — used for the activity
|
// 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_entry = &dispatcher.role_table.entries[role_index];
|
||||||
|
let role_name = role_entry.name.clone();
|
||||||
let curve = role_entry.curve_str.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 ───────────────────────────────────────────────
|
// ── Dispatch ───────────────────────────────────────────────
|
||||||
let response = crate::dispatcher::handle_request(dispatcher, request);
|
let response = crate::dispatcher::handle_request(dispatcher, request);
|
||||||
// Activity format: uid curve path (timestamp is added by the log).
|
// Activity format: uid role curve path (timestamp is added by the log).
|
||||||
let activity = format!("{} {} {}", caller.caller_id, curve, path);
|
let activity = format!(
|
||||||
|
"{} {} {} {}",
|
||||||
|
caller.identity_str(),
|
||||||
|
role_name,
|
||||||
|
curve,
|
||||||
|
actual_path
|
||||||
|
);
|
||||||
(response, activity)
|
(response, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user