use ammonia::Builder; use markdown::{to_html_with_options, Options, CompileOptions, ParseOptions, Constructs}; use std::collections::HashSet; /// Render markdown input into HTML pub fn render_markdown(input: &str) -> String { let options = Options { compile: CompileOptions { allow_any_img_src: false, allow_dangerous_html: true, gfm_task_list_item_checkable: false, gfm_tagfilter: false, ..Default::default() }, parse: ParseOptions { constructs: Constructs { gfm_autolink_literal: true, ..Default::default() }, gfm_strikethrough_single_tilde: false, math_text_single_dollar: false, mdx_expression_parse: None, mdx_esm_parse: None, ..Default::default() }, }; let html = match to_html_with_options(input, &options) { Ok(h) => h, Err(e) => e.to_string(), }; let mut allowed_attributes = HashSet::new(); allowed_attributes.insert("id"); allowed_attributes.insert("class"); allowed_attributes.insert("ref"); allowed_attributes.insert("aria-label"); allowed_attributes.insert("lang"); allowed_attributes.insert("title"); allowed_attributes.insert("align"); allowed_attributes.insert("src"); Builder::default() .generic_attributes(allowed_attributes) .add_tags(&[ "video", "source", "img", "b", "span", "p", "i", "strong", "em", "a", ]) .rm_tags(&["script", "style", "link", "canvas"]) .add_tag_attributes("a", &["href", "target"]) .clean(&html) .to_string() .replace( "src=\"http", "loading=\"lazy\" src=\"/api/v1/util/proxy?url=http", ) .replace("