From b56865915c0c51e3dfd1b683cd8e5ceec062922e Mon Sep 17 00:00:00 2001 From: Andrew Bone Date: Thu, 17 Jan 2019 20:44:01 +0000 Subject: [PATCH] Jsfiddle LiquidTag (#1509) * Create jsfiddle_tag.rb Add liquid tag for jsfiddle * Create jsfiddle_tag-spec.rb Add liquid tag for jsfiddle * Update _editor_guide_text.html.erb Add liquid tag for jsfiddle * Updates for rubocop * Edit boilerplate Change some of the boiler plate code. * rubocop compliance * Fixed name Fixed file name * Fixed boiler plate Changed codepen to jsfiddle * Update guide text Change the Guide Text to be jsfiddle specific. Co-Authored-By: Link2Twenty * Fixed typo in spec Co-Authored-By: Link2Twenty * Update Valid Link * Update jsfiddle_tag.rb * Add Approved html * Remove double slash * Revert change * Fix XSS error * Remove extra line * Remove extra slash * Remove extra slash * Make DRY * rubocop compliance * Change test logic * Revert test to Approvals * Fix HTML approved --- app/liquid_tags/jsfiddle_tag.rb | 55 +++++++++++++++++++ app/views/pages/_editor_guide_text.html.erb | 11 ++++ spec/liquid_tags/jsfiddle_tag_spec.rb | 50 +++++++++++++++++ .../jsfiddle_liquid_tag.approved.html | 6 ++ 4 files changed, 122 insertions(+) create mode 100644 app/liquid_tags/jsfiddle_tag.rb create mode 100644 spec/liquid_tags/jsfiddle_tag_spec.rb create mode 100644 spec/support/fixtures/approvals/jsfiddle_liquid_tag.approved.html diff --git a/app/liquid_tags/jsfiddle_tag.rb b/app/liquid_tags/jsfiddle_tag.rb new file mode 100644 index 000000000..95deb5a06 --- /dev/null +++ b/app/liquid_tags/jsfiddle_tag.rb @@ -0,0 +1,55 @@ +class JSFiddleTag < LiquidTagBase + def initialize(tag_name, link, tokens) + super + @link = parse_link(link) + @build_options = parse_options(link) + @height = 600 + end + + def render(_context) + html = <<-HTML + + HTML + finalize_html(html) + end + + private + + def valid_option(option) + option.match(/^(js|html|css|result|,)*\z/) + end + + def parse_options(input) + stripped_link = ActionController::Base.helpers.strip_tags(input) + _, *options = stripped_link.split(" ") + + # Validation + validated_options = options.map { |o| valid_option(o) }.reject { |e| e == nil } + raise StandardError, "Invalid Options" unless options.empty? || !validated_options.empty? + + validated_options.length.zero? ? "" : validated_options.join(",").concat("/") + end + + def parse_link(link) + stripped_link = ActionController::Base.helpers.strip_tags(link) + the_link = stripped_link.split(" ").first + raise StandardError, "Invalid JSFiddle URL" unless valid_link?(the_link) + + the_link + end + + def valid_link?(link) + link_no_space = link.delete(" ") + (link_no_space =~ /^(http|https):\/\/(jsfiddle\.net)\/[a-zA-Z0-9\-\/]*\z/).zero? + end +end + +Liquid::Template.register_tag("jsfiddle", JSFiddleTag) diff --git a/app/views/pages/_editor_guide_text.html.erb b/app/views/pages/_editor_guide_text.html.erb index b543c8c7a..396e6cf2b 100644 --- a/app/views/pages/_editor_guide_text.html.erb +++ b/app/views/pages/_editor_guide_text.html.erb @@ -148,6 +148,17 @@

CodeSandbox Embed

All you need is the ID of the Sandbox:

{% codesandbox ppxnl191zx %} + +

JSFiddle Embed

+

All you need is the full JSFiddle link, ending in the fiddle ID code, as follows:

+ {% jsfiddle https://jsfiddle.net/link2twenty/v2kx9jcd %} + +
+
Custom tabs
+
+ You can add a custom tab order to you JSFiddle embed tag. Defaults to js,html,css,result
+ {% jsfiddle https://jsfiddle.net/webdevem/Q8KVC result,html,css %} +

repl.it Embed

All you need is the URL after the domain name:

diff --git a/spec/liquid_tags/jsfiddle_tag_spec.rb b/spec/liquid_tags/jsfiddle_tag_spec.rb new file mode 100644 index 000000000..738310376 --- /dev/null +++ b/spec/liquid_tags/jsfiddle_tag_spec.rb @@ -0,0 +1,50 @@ +require "rails_helper" + +RSpec.describe JSFiddleTag, type: :liquid_template do + describe "#link" do + let(:jsfiddle_link) { "http://jsfiddle.net/link2twenty/v2kx9jcd" } + let(:jsfiddle_link_with_custom_tabs) { "http://jsfiddle.net/link2twenty/v2kx9jcd result,html,css" } + + xss_links = %w( + //evil.com/?jsfiddle.net + https://jsfiddle.net.evil.com + https://jsfiddle.net/some_username/pen/" onload='alert("xss")' + ) + + def generate_new_liquid(link) + Liquid::Template.register_tag("jsfiddle", JSFiddleTag) + Liquid::Template.parse("{% jsfiddle #{link} %}") + end + + it "accepts jsfiddle link" do + liquid = generate_new_liquid(jsfiddle_link) + rendered_jsfiddle_iframe = liquid.render + Approvals.verify(rendered_jsfiddle_iframe, name: "jsfiddle_liquid_tag", format: :html) + end + + it "accepts jsfiddle link with a / at the end" do + jsfiddle_link = "http://jsfiddle.net/link2twenty/v2kx9jcd/" + expect do + generate_new_liquid(jsfiddle_link) + end.not_to raise_error + end + + it "rejects invalid jsfiddle link" do + expect do + generate_new_liquid("invalid_jsfiddle_link") + end.to raise_error(StandardError) + end + + it "accepts jsfiddle link with a custom-tab parameter" do + expect do + generate_new_liquid(jsfiddle_link_with_custom_tabs) + end.not_to raise_error + end + + it "rejects XSS attempts" do + xss_links.each do |link| + expect { generate_new_liquid(link) }.to raise_error(StandardError) + end + end + end +end diff --git a/spec/support/fixtures/approvals/jsfiddle_liquid_tag.approved.html b/spec/support/fixtures/approvals/jsfiddle_liquid_tag.approved.html new file mode 100644 index 000000000..41a4c105b --- /dev/null +++ b/spec/support/fixtures/approvals/jsfiddle_liquid_tag.approved.html @@ -0,0 +1,6 @@ + + + + + +