Fix review findings: direction-bind the gossip handshake proof, whitespace-tokenize log redaction, show ranked STATS to viewers, single-pass render, code-before-message email templating
This commit is contained in:
parent
829a3916fd
commit
621bba00f2
5 changed files with 92 additions and 46 deletions
|
|
@ -24,13 +24,17 @@ fn brand_mark(brand: &str, accent: &str, logo: &str) -> String {
|
|||
}
|
||||
|
||||
fn render(brand: &str, accent: &str, logo: &str, title: &str, message: &str, code: &str, note: &str) -> String {
|
||||
// `message` carries the account name (attacker-influenceable). Substitute every
|
||||
// OTHER slot first and `{{message}}` LAST, so a message that literally contains
|
||||
// `{{code}}`/`{{note}}` (an account named that) is inserted verbatim rather than
|
||||
// splicing in the real code.
|
||||
BASE.replace("{{brand_mark}}", &brand_mark(brand, accent, logo))
|
||||
.replace("{{brand}}", &escape(brand))
|
||||
.replace("{{accent}}", &escape(accent))
|
||||
.replace("{{title}}", &escape(title))
|
||||
.replace("{{message}}", &escape(message))
|
||||
.replace("{{code}}", &escape(code))
|
||||
.replace("{{note}}", &escape(note))
|
||||
.replace("{{message}}", &escape(message))
|
||||
}
|
||||
|
||||
pub fn reset(brand: &str, accent: &str, logo: &str, account: &str, code: &str, lang: &str) -> Mail {
|
||||
|
|
|
|||
|
|
@ -497,13 +497,29 @@ pub fn render(lang: &str, msgid: &str, args: &[(&str, String)]) -> String {
|
|||
.and_then(|m| m.get(msgid))
|
||||
.map(String::as_str)
|
||||
.unwrap_or(msgid);
|
||||
if args.is_empty() {
|
||||
if args.is_empty() || !template.contains('{') {
|
||||
return template.to_string();
|
||||
}
|
||||
let mut out = template.to_string();
|
||||
for (name, val) in args {
|
||||
out = out.replace(&format!("{{{name}}}"), val);
|
||||
// Single left-to-right pass: a substituted value is copied to the output and
|
||||
// never re-scanned, so a value that itself contains `{name}` (e.g. a nick like
|
||||
// "{game}") can't trigger a second substitution. An unknown `{x}` (no matching
|
||||
// arg, e.g. the literal `{ON|OFF}`) is left verbatim, as before.
|
||||
let mut out = String::with_capacity(template.len() + 16);
|
||||
let mut rest = template;
|
||||
while let Some(open) = rest.find('{') {
|
||||
out.push_str(&rest[..open]);
|
||||
let Some(rel_close) = rest[open..].find('}') else {
|
||||
break; // unbalanced '{' — emit the remainder verbatim below
|
||||
};
|
||||
let close = open + rel_close;
|
||||
let name = &rest[open + 1..close];
|
||||
match args.iter().find(|(n, _)| *n == name) {
|
||||
Some((_, val)) => out.push_str(val),
|
||||
None => out.push_str(&rest[open..=close]),
|
||||
}
|
||||
rest = &rest[close + 1..];
|
||||
}
|
||||
out.push_str(rest);
|
||||
out
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue