Skip to main content

lib_humus/
util.rs

1// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! This module provides helper functions.
6
7/// Escapes values for use in HTML attributes following the [OWASP recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#output-encoding-rules-summary)
8///
9/// This function is inspired by how tera version 1 does its string escapes, i.e. `tera::escape_html`.
10pub fn escape_html_attribute(text: &str) -> String {
11	let mut output = String::with_capacity(text.len() * 2);
12	for c in text.chars() {
13		match c {
14			'a'..='z' | 'A'..='Z' | '0'..='9' => output.push(c),
15			_ => output.push_str(&format!("&#x{:x};", c as u32)),
16		}
17	}
18	output
19}
20
21/// Escapes values for use in HTML following the [OWASP recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#output-encoding-rules-summary)
22///
23/// This function is inspired by how tera version 1 does its string escapes, i.e. `tera::escape_html`.
24pub fn escape_html(text: &str) -> String {
25	let mut output = String::with_capacity(text.len() * 2);
26	for c in text.chars() {
27		match c {
28			'&' => output.push_str("&amp;"),
29			'<' => output.push_str("&lt;"),
30			'>' => output.push_str("&gt;"),
31			'"' => output.push_str("&quot;"),
32			'\'' => output.push_str("&#x27;"),
33			_ => output.push(c),
34		}
35	}
36	output
37}
38
39#[cfg(test)]
40mod tests {
41	use super::*;
42
43	#[test]
44	fn test_escape_html_attribute() {
45		assert_eq!(
46			"ABZabz0123456789",
47			escape_html_attribute("ABZabz0123456789")
48		);
49		assert_eq!("K&#xe4;se", escape_html_attribute("Käse"));
50		assert_eq!(
51			"&#x3c;script&#x3e;alert&#x28;1&#x29;&#x3c;&#x2f;script&#x3e;",
52			escape_html_attribute("<script>alert(1)</script>")
53		);
54		assert_eq!(
55			"test&#x22;&#x3e;foo&#x3c;span&#x20;bar&#x3d;&#x22;",
56			escape_html_attribute("test\">foo<span bar=\"")
57		);
58		assert_eq!(
59			"I&#x27;ve&#x20;got&#x20;a&#x20;quote&#x21;",
60			escape_html_attribute("I've got a quote!")
61		);
62	}
63}