fix: redact user-controlled log fields

This commit is contained in:
2026-09-25 01:49:31 +08:00
parent 9d40f3bc50
commit 50299bacbb
5 changed files with 25 additions and 13 deletions
+3 -3
View File
@@ -34,7 +34,7 @@ impl Config {
fn parse_u64(name: &str, default: u64) -> u64 {
match env::var(name) {
Ok(v) => v.parse::<u64>().unwrap_or_else(|_| {
log::warn!("invalid {name}={v:?}; using default {default}");
log::warn!("invalid {name}; using default {default}");
default
}),
Err(_) => default,
@@ -46,7 +46,7 @@ impl Config {
fn parse_opt<T: std::str::FromStr>(name: &str) -> Option<T> {
env::var(name).ok().and_then(|s| {
s.parse::<T>().ok().or_else(|| {
log::warn!("invalid {name}={s:?}");
log::warn!("invalid {name}");
None
})
})
@@ -68,7 +68,7 @@ impl Config {
})
.collect();
if !bad.is_empty() {
log::warn!("BOT_ADMIN: ignoring non-numeric ids: {bad:?}");
log::warn!("BOT_ADMIN: ignoring {} non-numeric id(s)", bad.len());
}
ids
})
+9 -2
View File
@@ -202,14 +202,21 @@ async fn handle_callback(
}
})
.await;
log::info!("template '{name}' applied to prompt {prompt_message_id}");
log::info!(
"template '{}' applied to prompt {prompt_message_id}",
super::log_escape(name)
);
}
// Nothing was applied, so nothing is recorded either: the
// prompt keeps rendering through whatever it used before, and
// the toast says why (a silently "successful" press left the
// caption unchanged).
super::EditOutcome::Failed(reason) => {
log::error!("template '{name}' could not be applied: {reason}");
log::error!(
"template '{}' could not be applied: {}",
super::log_escape(name),
super::log_escape(&reason)
);
answer = Some(format!("Could not apply the template: {reason}"));
}
}
+1 -1
View File
@@ -155,7 +155,7 @@ async fn answer_inline_query(
// The query is user input: `debug` keeps only its normalized key, the
// text itself is `trace` (same split as the message handler).
log::debug!("inline query [key={}]", log_key(&query.query));
log::trace!("inline query: {}", query.query);
log::trace!("inline query: {}", super::log_escape(&query.query));
let Some(key) = x_media::site::cache_key(&query.query) else {
answer(ctx.sender, query.id, Vec::new()).await?;
return Ok(true);
+5 -4
View File
@@ -222,14 +222,15 @@ pub(crate) async fn handle_message(
.text()
.map(|t| {
let end = t.floor_char_boundary(120.min(t.len()));
&t[..end]
log_escape(&t[..end])
})
.unwrap_or("<no text>");
.unwrap_or_else(|| std::borrow::Cow::Borrowed("<no text>"));
// Per-request detail: who and where at `debug`; the message text itself is
// user data and only ever appears at `trace`, so a `debug` log can be
// shared without leaking what people pasted.
log::debug!(
"message from {sender} in {} (private={is_private})",
"message from {} in {} (private={is_private})",
log_escape(&sender),
message.chat.id
);
log::trace!("message text: {text_preview}");
@@ -249,7 +250,7 @@ pub(crate) async fn handle_message(
log::debug!(
"command from {}: {}",
message.chat.id,
text.split_whitespace().next().unwrap_or("<empty>")
log_escape(text.split_whitespace().next().unwrap_or("<empty>"))
);
log::trace!("command text: {text_preview}");
execute_command(ctx, bot, &message, command).await?;
+7 -3
View File
@@ -609,7 +609,7 @@ async fn url_media_inner(
}
log::debug!("fetching [key={}]", log_key(url));
log::trace!("fetching {url}");
log::trace!("fetching {}", super::log_escape(url));
// One fetch per post at a time: a concurrent duplicate of this link waits
// for *this* fetch instead of running its own.
let outcome = match x_media::site::cache_key(url) {
@@ -624,11 +624,15 @@ async fn url_media_inner(
// The URL itself is user data, so only `trace` names the link;
// `debug` just records that the message was looked at.
log::debug!("no site pattern matches the link; ignoring");
log::trace!("no site pattern matches {url}");
log::trace!("no site pattern matches {}", super::log_escape(url));
}
// Retries exhausted: notify the user (Rust-only requirement 3).
Err(e) => {
log::error!("fetch [key={}]: {e}", log_key(url));
log::error!(
"fetch [key={}]: {}",
log_key(url),
super::log_escape(&e.to_string())
);
let _ = reply(ctx.sender, chat_id, reply_to, fetch_error_message(e)).await;
}
Ok(Some(fetched)) => {