diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-12-26 17:50:54 +0100 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-12-26 17:58:27 +0100 |
commit | dfb5714045e99a09bf3f67890ae3cdeab47058b3 (patch) | |
tree | 5e76e310892ea7e36099312e25023aa154217a28 /pkgs/by-name/ba/back/src/git_bug/format | |
parent | fix(pkgs/back): Use rocket to manage the configuration values (diff) | |
download | nixos-server-dfb5714045e99a09bf3f67890ae3cdeab47058b3.zip |
feat(pkgs/back): Rewrite the `git-bug` interface code
The previous code was more or less reverse engineered, whilst this code is based on the actually git-bug source code. This improves the whole issue and operation handling immensely and also makes the code better maintainable. Furthermore, it also adds support for the operations that had not already used in `vhack.eu/nixos-server.git`.
Diffstat (limited to 'pkgs/by-name/ba/back/src/git_bug/format')
-rw-r--r-- | pkgs/by-name/ba/back/src/git_bug/format/mod.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/pkgs/by-name/ba/back/src/git_bug/format/mod.rs b/pkgs/by-name/ba/back/src/git_bug/format/mod.rs new file mode 100644 index 0000000..4ebf6d4 --- /dev/null +++ b/pkgs/by-name/ba/back/src/git_bug/format/mod.rs @@ -0,0 +1,123 @@ +// 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 chrono::DateTime; +use markdown::to_html; +use serde::Deserialize; +use serde_json::Value; + +#[derive(Debug, Default, Clone)] +/// Markdown content. +pub struct MarkDown { + value: String, +} + +impl Display for MarkDown { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(to_html(&self.value).as_str()) + } +} +impl From<&Value> for MarkDown { + fn from(value: &Value) -> Self { + Self { + value: value.as_str().expect("This will exist").to_owned(), + } + } +} + +/// An UNIX time stamp. +/// +/// These should only ever be used for human-display, because timestamps are unreliably in a +/// distributed system. +/// Because of this reason, there is no `value()` function. +#[derive(Debug, Default, Clone, Copy)] +pub struct TimeStamp { + value: u64, +} +impl From<&Value> for TimeStamp { + fn from(value: &Value) -> Self { + Self { + value: value.as_u64().expect("This must exist"), + } + } +} +impl Display for TimeStamp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let date = + DateTime::from_timestamp(self.value as i64, 0).expect("This timestamp should be vaild"); + + let newdate = date.format("%Y-%m-%d %H:%M:%S"); + f.write_str(newdate.to_string().as_str()) + } +} + +#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)] +/// A string that should be escaped when injected into html content. +pub struct HtmlString { + value: String, +} + +impl From<MarkDown> for HtmlString { + fn from(value: MarkDown) -> Self { + Self { value: value.value } + } +} + +impl From<&Value> for HtmlString { + fn from(value: &Value) -> Self { + Self { + value: value.as_str().expect("This will exist").to_owned(), + } + } +} +impl Display for HtmlString { + 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 +} |