Skip to content

Commit

Permalink
fix: escape curly braces in <code> tags (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
leandrocp authored Jan 11, 2025
1 parent 6d529cd commit 2afb828
Show file tree
Hide file tree
Showing 9 changed files with 895 additions and 55 deletions.
1 change: 1 addition & 0 deletions examples/heex.exs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ markdown = """
```heex
<%= @hello %>
{ @hello }
```
Elixir was created by José Valim.
Expand Down
1 change: 1 addition & 0 deletions examples/live_view.exs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ defmodule DemoLive do
```heex
<%= @hello %>
{ @hello }
```
Elixir was created by José Valim.
Expand Down
35 changes: 35 additions & 0 deletions lib/mdex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -602,4 +602,39 @@ defmodule MDEx do

defp maybe_trim({:ok, result}), do: {:ok, String.trim(result)}
defp maybe_trim(error), do: error

@doc """
Utility function to sanitize and escape HTML.
## Examples
iex> MDEx.safe_html("<script>console.log('attack')</script>")
""
iex> MDEx.safe_html("<h1>{'Example:'}</h1><code>{:ok, 'MDEx'}</code>")
"&lt;h1&gt;{&#x27;Example:&#x27;}&lt;&#x2f;h1&gt;&lt;code&gt;&lbrace;:ok, &#x27;MDEx&#x27;&rbrace;&lt;&#x2f;code&gt;"
iex> MDEx.safe_html("<h1>{'Example:'}</h1><code>{:ok, 'MDEx'}</code>", escape: [content: false])
"<h1>{'Example:'}</h1><code>&lbrace;:ok, 'MDEx'&rbrace;</code>"
## Options
- `:sanitize` - clean HTML using these rules https://docs.rs/ammonia/latest/ammonia/fn.clean.html. Defaults to `true`.
- `:escape` - which entities should be escaped. Defaults to `[:content, :curly_braces_in_code]`.
- `:content` - escape common chars like `<`, `>`, `&`, and others in the HTML content;
- `:curly_braces_in_code` - escape `{` and `}` only inside `<code>` tags, particularly useful for compiling HTML in LiveView;
"""
def safe_html(unsafe_html, opts \\ []) when is_binary(unsafe_html) and is_list(opts) do
sanitize = opt(opts, [:sanitize], true)
escape_content = opt(opts, [:escape, :content], true)
escape_curly_braces_in_code = opt(opts, [:escape, :curly_braces_in_code], true)
Native.safe_html(unsafe_html, sanitize, escape_content, escape_curly_braces_in_code)
end

defp opt(opts, keys, default) do
case get_in(opts, keys) do
nil -> default
val -> val
end
end
end
2 changes: 2 additions & 0 deletions lib/mdex/native.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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_content, _escape_curly_braces_in_code), do: :erlang.nif_error(:nif_not_loaded)

# markdown
# - to document (parse)
# - to html
Expand Down
Loading

0 comments on commit 2afb828

Please sign in to comment.