diff options
Diffstat (limited to 'pkgs/by-name/ba/back/src/issues/format/mod.rs')
-rw-r--r-- | pkgs/by-name/ba/back/src/issues/format/mod.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/pkgs/by-name/ba/back/src/issues/format/mod.rs b/pkgs/by-name/ba/back/src/issues/format/mod.rs new file mode 100644 index 0000000..f78d3b3 --- /dev/null +++ b/pkgs/by-name/ba/back/src/issues/format/mod.rs @@ -0,0 +1,88 @@ +// Back - An extremely simple git issue tracking system. Inspired by tvix's +// panettone +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This file is part of Back. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/agpl.txt>. + +use std::fmt::Display; + +use markdown::to_html; + +#[derive(Debug, Default, Clone)] +pub struct Markdown { + value: String, +} + +impl From<String> for Markdown { + fn from(value: String) -> Self { + Self { value } + } +} +impl Display for Markdown { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(to_html(&self.value).as_str()) + } +} + +#[derive(Debug, Default)] +pub struct BackString { + value: String, +} + +impl From<Markdown> for BackString { + fn from(value: Markdown) -> Self { + Self { value: value.value } + } +} + +impl From<String> for BackString { + fn from(value: String) -> Self { + Self { value } + } +} +impl Display for BackString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(escape_html(&self.value).as_str()) + } +} + +// From `tera::escape_html` +/// Escape HTML following [OWASP](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) +/// +/// Escape the following characters with HTML entity encoding to prevent switching +/// into any execution context, such as script, style, or event handlers. Using +/// hex entities is recommended in the spec. In addition to the 5 characters +/// significant in XML (&, <, >, ", '), the forward slash is included as it helps +/// to end an HTML entity. +/// +/// ```text +/// & --> & +/// < --> < +/// > --> > +/// " --> " +/// ' --> ' ' is not recommended +/// / --> / forward slash is included as it helps end an HTML entity +/// ``` +#[inline] +pub fn escape_html(input: &str) -> String { + let mut output = String::with_capacity(input.len() * 2); + for c in input.chars() { + match c { + '&' => output.push_str("&"), + '<' => output.push_str("<"), + '>' => output.push_str(">"), + '"' => output.push_str("""), + '\'' => output.push_str("'"), + '/' => output.push_str("/"), + _ => output.push(c), + } + } + + // Not using shrink_to_fit() on purpose + output +} |