From e2b7ebd3c4adb0da16c5d8c4a594942c11120f3a Mon Sep 17 00:00:00 2001 From: stephann <3025661+stephannv@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:03:50 -0300 Subject: [PATCH] feat: Add escape_once helper --- spec/blueprint/html/helpers_spec.cr | 30 +++++++++++++++++++++++++++++ spec/blueprint/html/utils_spec.cr | 8 -------- spec/spec_helper.cr | 8 ++++++++ src/blueprint/html/helpers.cr | 14 +++++++++++++- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/spec/blueprint/html/helpers_spec.cr b/spec/blueprint/html/helpers_spec.cr index 95b7d9a..afde4d4 100644 --- a/spec/blueprint/html/helpers_spec.cr +++ b/spec/blueprint/html/helpers_spec.cr @@ -52,4 +52,34 @@ describe "helpers" do page.to_s.should contain expected_html end end + + describe "#escape_once" do + it "escapes HTML without affecting existing escaped entities" do + actual_html = Blueprint::HTML.build do + span escape_once("<< Accept & Checkout") + + div escape_once(MarkdownLink.new("1 < 2 & 3", "example.com")) + end + + expected_html = normalize_html <<-HTML + << Accept & Checkout + +
[1 < 2 & 3](example.com)
+ HTML + + actual_html.to_s.should eq expected_html + end + + it "escapes unsafe content" do + actual_html = Blueprint::HTML.build do + span escape_once("") + end + + expected_html = normalize_html <<-HTML + <script>alert('content')</script> + HTML + + actual_html.to_s.should eq expected_html + end + end end diff --git a/spec/blueprint/html/utils_spec.cr b/spec/blueprint/html/utils_spec.cr index fbde51c..9e3df05 100644 --- a/spec/blueprint/html/utils_spec.cr +++ b/spec/blueprint/html/utils_spec.cr @@ -1,13 +1,5 @@ require "../../spec_helper" -private class MarkdownLink - def initialize(@text : String, @href : String); end - - def to_s - "[#{@text}](#{@href})" - end -end - private class ExamplePage include Blueprint::HTML diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 10276a5..6550fbd 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,6 +1,14 @@ require "spec" require "../src/blueprint/html" +class MarkdownLink + def initialize(@text : String, @href : String); end + + def to_s + "[#{@text}](#{@href})" + end +end + def normalize_html(html : String) : String html.strip.gsub(/\R\s+/, "") end diff --git a/src/blueprint/html/helpers.cr b/src/blueprint/html/helpers.cr index a9f563f..16d8508 100644 --- a/src/blueprint/html/helpers.cr +++ b/src/blueprint/html/helpers.cr @@ -1,8 +1,20 @@ module Blueprint::HTML::Helpers - def safe(value) : SafeValue + HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/ + + HTML_ESCAPE = {"&": "&", ">": ">", "<": "<", %("): """, "'": "'"} + + private def safe(value) : SafeValue Blueprint::SafeValue.new(value) end + private def escape_once(value : String) : SafeValue + safe value.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE) + end + + private def escape_once(value) : SafeValue + escape_once(value.to_s) + end + @[Experimental] macro tokens(**conditions) String.build do |io|