Escape single quotes on the buyer-facing buy page
buy_page.rs kept a private html_escape that omitted the `'` escape the canonical api::mod.rs impl has, so operator/product/discount-code text rendered into HTML attributes was under-escaped. Drop the fork, reuse the canonical escaper, and add a unit test covering the single quote.
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
//! buyer-facing surface — easy to deploy, no asset hosting required.
|
//! buyer-facing surface — easy to deploy, no asset hosting required.
|
||||||
|
|
||||||
use crate::api::AppState;
|
use crate::api::AppState;
|
||||||
|
// Reuse the canonical HTML escaper (escapes `'` as well as `&<>"`) instead of a
|
||||||
|
// private copy, so the buyer-facing page can't fall behind on attribute escaping.
|
||||||
|
use crate::api::html_escape;
|
||||||
use crate::db::repo;
|
use crate::db::repo;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, State},
|
||||||
@@ -1533,13 +1536,6 @@ code{{background:#eee;padding:0.1em 0.4em;border-radius:4px;font-family:ui-monos
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn html_escape(s: &str) -> String {
|
|
||||||
s.replace('&', "&")
|
|
||||||
.replace('<', "<")
|
|
||||||
.replace('>', ">")
|
|
||||||
.replace('"', """)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_thousands(n: i64) -> String {
|
fn format_thousands(n: i64) -> String {
|
||||||
// Renders 50000 as "50,000" — visible price legibility for sat amounts.
|
// Renders 50000 as "50,000" — visible price legibility for sat amounts.
|
||||||
let s = n.to_string();
|
let s = n.to_string();
|
||||||
|
|||||||
@@ -1193,3 +1193,22 @@ async fn pubkey(
|
|||||||
"public_key_pem": state.keypair.public_key_pem,
|
"public_key_pem": state.keypair.public_key_pem,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// The canonical escaper must cover the single quote — operator/product/
|
||||||
|
/// discount-code text renders into HTML attributes (incl. single-quoted),
|
||||||
|
/// so omitting `'` is an injection hole. Guards against re-forking a copy
|
||||||
|
/// that drops it (the bug that lived in `buy_page.rs`).
|
||||||
|
#[test]
|
||||||
|
fn html_escape_covers_single_quote_and_friends() {
|
||||||
|
assert_eq!(html_escape("'"), "'");
|
||||||
|
assert_eq!(
|
||||||
|
html_escape(r#"<a href='x' title="y">&</a>"#),
|
||||||
|
"<a href='x' title="y">&</a>"
|
||||||
|
);
|
||||||
|
assert_eq!(html_escape("plain"), "plain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user