From c18126d50e574cab4c5e1859e18c432f1fad3e42 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Thu, 9 Jan 2025 17:56:09 -0500 Subject: [PATCH] expose safe_html --- lib/mdex.ex | 5 +++++ lib/mdex/native.ex | 2 ++ native/comrak_nif/src/lib.rs | 32 +++++++++++++++++++++++++------- test/mdex_test.exs | 14 ++++++++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/mdex.ex b/lib/mdex.ex index 3238511..311ab5e 100644 --- a/lib/mdex.ex +++ b/lib/mdex.ex @@ -602,4 +602,9 @@ defmodule MDEx do defp maybe_trim({:ok, result}), do: {:ok, String.trim(result)} defp maybe_trim(error), do: error + + # TODO: spec/docs + def safe_html(unsafe_html, sanitize, escape_tags, escape_curly_braces_in_code) do + Native.safe_html(unsafe_html, sanitize, escape_tags, escape_curly_braces_in_code) + end end diff --git a/lib/mdex/native.ex b/lib/mdex/native.ex index d748935..d0bb414 100644 --- a/lib/mdex/native.ex +++ b/lib/mdex/native.ex @@ -56,6 +56,8 @@ defmodule MDEx.Native do mode: mode, force_build: System.get_env("MDEX_BUILD") in ["1", "true"] + def safe_html(_unsafe_html, _sanitize, _escape_tags, _escape_curly_braces_in_code), do: :erlang.nif_error(:nif_not_loaded) + # markdown # - to document (parse) # - to html diff --git a/native/comrak_nif/src/lib.rs b/native/comrak_nif/src/lib.rs index 3b46a7f..c25608e 100644 --- a/native/comrak_nif/src/lib.rs +++ b/native/comrak_nif/src/lib.rs @@ -17,6 +17,7 @@ use types::{atoms::ok, document::*, options::*}; rustler::init!( "Elixir.MDEx.Native", [ + safe_html, parse_document, markdown_to_html, markdown_to_html_with_options, @@ -50,7 +51,7 @@ fn markdown_to_html<'a>(env: Env<'a>, md: &str) -> NifResult> { let mut plugins = ComrakPlugins::default(); plugins.render.codefence_syntax_highlighter = Some(&inkjet_adapter); let unsafe_html = comrak::markdown_to_html_with_plugins(md, &Options::default(), &plugins); - let html = sanitize( + let html = do_safe_html( unsafe_html, ExFeaturesOptions::default().sanitize, false, @@ -83,12 +84,12 @@ fn markdown_to_html_with_options<'a>( let mut plugins = ComrakPlugins::default(); plugins.render.codefence_syntax_highlighter = Some(&inkjet_adapter); let unsafe_html = comrak::markdown_to_html_with_plugins(md, &comrak_options, &plugins); - let html = sanitize(unsafe_html, options.features.sanitize, false, true); + let html = do_safe_html(unsafe_html, options.features.sanitize, false, true); Ok((ok(), html).encode(env)) } None => { let unsafe_html = comrak::markdown_to_html(md, &comrak_options); - let html = sanitize(unsafe_html, options.features.sanitize, false, true); + let html = do_safe_html(unsafe_html, options.features.sanitize, false, true); Ok((ok(), html).encode(env)) } } @@ -232,7 +233,7 @@ fn document_to_html(env: Env<'_>, ex_document: ExDocument) -> NifResult let options = Options::default(); comrak::format_html_with_plugins(comrak_ast, &options, &mut buffer, &plugins).unwrap(); let unsafe_html = String::from_utf8(buffer).unwrap(); - let html = sanitize( + let html = do_safe_html( unsafe_html, ExFeaturesOptions::default().sanitize, false, @@ -273,14 +274,14 @@ fn document_to_html_with_options( comrak::format_html_with_plugins(comrak_ast, &comrak_options, &mut buffer, &plugins) .unwrap(); let unsafe_html = String::from_utf8(buffer).unwrap(); - let html = sanitize(unsafe_html, options.features.sanitize, false, true); + let html = do_safe_html(unsafe_html, options.features.sanitize, false, true); Ok((ok(), html).encode(env)) } None => { let mut buffer = vec![]; comrak::format_commonmark(comrak_ast, &comrak_options, &mut buffer).unwrap(); let unsafe_html = String::from_utf8(buffer).unwrap(); - let html = sanitize(unsafe_html, options.features.sanitize, false, true); + let html = do_safe_html(unsafe_html, options.features.sanitize, false, true); Ok((ok(), html).encode(env)) } } @@ -352,8 +353,25 @@ fn document_to_xml_with_options( } } +#[rustler::nif(schedule = "DirtyCpu")] +pub fn safe_html( + env: Env<'_>, + unsafe_html: String, + sanitize: bool, + escape_tags: bool, + escape_curly_braces_in_code: bool, +) -> NifResult> { + Ok(do_safe_html( + unsafe_html, + sanitize, + escape_tags, + escape_curly_braces_in_code, + ) + .encode(env)) +} + // https://github.com/p-jackson/entities/blob/1d166204433c2ee7931251a5494f94c7e35be9d6/src/entities.rs -fn sanitize( +fn do_safe_html( unsafe_html: String, sanitize: bool, escape_tags: bool, diff --git a/test/mdex_test.exs b/test/mdex_test.exs index 79312e5..bec7761 100644 --- a/test/mdex_test.exs +++ b/test/mdex_test.exs @@ -216,6 +216,20 @@ defmodule MDExTest do end end + describe "safe html" do + test "sanitize" do + assert MDEx.safe_html("tag", true, false, false) == "tag" + end + + test "escape tags" do + assert MDEx.safe_html("tag", false, true, false) == "<span>tag</span>" + end + + test "escape curly braces in code tags" do + assert MDEx.safe_html("

{test}

{:foo}", false, false, true) == "

{test}

{:foo}" + end + end + describe "to_commonmark" do test "document to commonmark with default options" do assert MDEx.to_commonmark!(%Document{nodes: [%Heading{nodes: [%Text{literal: "Test"}]}]}) == "# Test"