From dee0b36981f2e11893e1c9ab7d2060c5d4bbd523 Mon Sep 17 00:00:00 2001 From: Arit Amana <32520970+msarit@users.noreply.github.com> Date: Fri, 17 Dec 2021 12:12:54 -0500 Subject: [PATCH] Implement Unified Embed for CodeSandbox URLs (#15808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement embed and write specs * fix slight regex ommision * remove error over invalid options; add specs to cover * account for missing options when using embed keyword * no videos, no ns video_id 🤦🏾‍♀️ --- app/liquid_tags/codesandbox_tag.rb | 45 ++++++++++++------------ spec/liquid_tags/codesandbox_tag_spec.rb | 42 ++++++++++++++-------- spec/liquid_tags/unified_embed_spec.rb | 29 ++++++++++----- 3 files changed, 72 insertions(+), 44 deletions(-) diff --git a/app/liquid_tags/codesandbox_tag.rb b/app/liquid_tags/codesandbox_tag.rb index 0d136fc0a..f2bfd541c 100644 --- a/app/liquid_tags/codesandbox_tag.rb +++ b/app/liquid_tags/codesandbox_tag.rb @@ -1,15 +1,17 @@ class CodesandboxTag < LiquidTagBase PARTIAL = "liquids/codesandbox".freeze + REGISTRY_REGEXP = %r{https?://(?:www|app\.)?(?:codesandbox\.io/embed/)(?[\w-]{,60})(?:\?)?(?\S+)?} OPTIONS_REGEXP = %r{\A(initialpath=([a-zA-Z0-9\-_/.@%])+)\Z| + \A(file=([a-zA-Z0-9\-_/.@%])+)\Z| \A(module=([a-zA-Z0-9\-_/.@%])+)\Z| \A(runonclick=((0|1){1}))\Z| \Aview=(editor|split|preview)\Z}x def initialize(_tag_name, id, _parse_context) super - @id = parse_id(id) - @query = parse_options(id) + input = CGI.unescape_html(strip_tags(id)) + @id, @query = parse_id_or_url_and_options(input) end def render(_context) @@ -24,39 +26,38 @@ class CodesandboxTag < LiquidTagBase private - def parse_id(input) + def parse_id_or_url_and_options(input) + match = pattern_match_for(input, [REGISTRY_REGEXP]) + return [match[:id], parse_options(match[:options]&.split("&"))] if match + id = input.split.first raise StandardError, "CodeSandbox Error: Invalid ID" unless valid_id?(id) - id + [id, parse_options(extract_options(input))] end def valid_id?(id) - id =~ /\A[a-zA-Z0-9\-]{0,60}\Z/ + id =~ /\A[\w-]{,60}\Z/ end - def parse_options(input) + def extract_options(input) _, *options = input.split - - options.map { |option| valid_option(option) }.reject(&:nil?) - - query = options.join("&") - - if query.blank? - query - else - "?#{query}" - end + options end - # Valid options must start with 'initialpath=' or 'module=' and a string of at least 1 length - # composed of letters, numbers, dashes, underscores, forward slashes, @ signs, periods/dots, - # and % symbols. Invalid options will raise an exception - def valid_option(option) - raise StandardError, "CodeSandbox Error: Invalid options" unless (option =~ OPTIONS_REGEXP)&.zero? + def parse_options(options) + return if options.blank? - option + query = options.filter_map { |option| option if valid_option(option) }.join("&") + + query.blank? ? query : "?#{query}" + end + + def valid_option(option) + (option =~ OPTIONS_REGEXP)&.zero? end end Liquid::Template.register_tag("codesandbox", CodesandboxTag) + +UnifiedEmbed.register(CodesandboxTag, regexp: CodesandboxTag::REGISTRY_REGEXP) diff --git a/spec/liquid_tags/codesandbox_tag_spec.rb b/spec/liquid_tags/codesandbox_tag_spec.rb index 5a8b538f7..9a95fb403 100644 --- a/spec/liquid_tags/codesandbox_tag_spec.rb +++ b/spec/liquid_tags/codesandbox_tag_spec.rb @@ -3,6 +3,7 @@ require "rails_helper" RSpec.describe CodesandboxTag, type: :liquid_tag do describe "#id" do let(:valid_id) { "22qaa1wcxr" } + let(:valid_id_with_file) { "68jkdlsaie file=/file.js" } let(:valid_id_with_initialpath) { "68jkdlsaie initialpath=/initial/path/file.js" } let(:valid_id_with_module) { "28qvv1wvxr module=/path/to/module.html" } let(:valid_id_with_view) { "28qvv1wvxr view=editor" } @@ -21,23 +22,17 @@ RSpec.describe CodesandboxTag, type: :liquid_tag do "43lkjfdauf initialpath=/initial-path/file.js module=/path/to/module.html runonclick=1 view=split" end let(:valid_id_with_special_characters) { "68jkfdsasa initialpath=/.@%_- module=-/%@._" } + let(:valid_id_with_valid_and_invalid_options) do + "43lkjfdauf initialpath=/initial-path/file.js fakeoption=/fakeoptionvalue runonclick=1" + end + let(:valid_id_with_only_invalid_options) do + "43lkjfdauf fakeoption1=/fakeoptionvalue fakeoption2=/fakeoptionvalue" + end let(:bad_ids) do [ - "28qvv1wvxr initialpath=((", - "22qaa1wcxr module=", - "22qaa1wcxr runonclick=", - "22qaa1wcxr runonclick=42836", - "68jkdlsaie initialpath=uses-a-(", - "68jkfdsasa initialpath=/uses-a-semi-colon-;", - "43lkjfdauf module= initialpath=", - "89fadksjhe random=/stuff", - "initialpath=/initial/path/file.js", - "view=foobar", - "view=", - "54jfadslkj module=stuff \"onmouseover='alert(\"XSS\")'", - "42fadfdaf;", - "%&*($#@$&=", + Faker::Alphanumeric.alphanumeric(number: 70), + "%^$#@!", ] end @@ -51,6 +46,11 @@ RSpec.describe CodesandboxTag, type: :liquid_tag do expect(liquid.render).to include("