Add liquid tag for Soundcloud (#844)

* Add liquid tag for Soundcloud

Adds a liquid tag for soundcloud links. Currently does not support customizing autplay, display for comments, or color.

* Strip HTML from Soundcloud tag input

We want to prevent potential XSS exploits, so we sanitize all link input

* Add Soundcloud tag documentation to editor guide
This commit is contained in:
dgolant 2018-10-09 13:51:59 -04:00 committed by Ben Halpern
parent 85abcb957d
commit 3a81c82b28
4 changed files with 99 additions and 0 deletions

View file

@ -0,0 +1,46 @@
class SoundcloudTag < LiquidTagBase
def initialize(tag_name, link, tokens)
super
@link = parse_link(link)
@height = 166
end
def render(_context)
# src = build_src
html = <<-HTML
<iframe
width="100%"
height="#{@height}"
scrolling="no"
frameborder="no"
allow="autoplay"
src="https://w.soundcloud.com/player/?url=#{@link}&auto_play=false&color=%23000000&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true">
</iframe>
HTML
finalize_html(html)
end
private
def parse_link(link)
stripped_link = sanitize_link(link)
raise_error unless valid_link?(stripped_link)
stripped_link
end
def sanitize_link(link)
link = ActionController::Base.helpers.strip_tags(link)
link = ActionController::Base.helpers.sanitize(link)
link.tr(" ", "")
end
def valid_link?(link)
link.include?("soundcloud.com")
end
def raise_error
raise StandardError, "Invalid Soundcloud URL"
end
end
Liquid::Template.register_tag("soundcloud", SoundcloudTag)

View file

@ -144,6 +144,10 @@
{% speakerdeck <span style="color: orange;">7e9f8c0fa0c949bd8025457181913fd0</span> %}
</pre>
<h3><strong>Soundcloud Embed</strong></h3>
<p>Just enter the full URL of the Soundcloud track you are trying to embed.</p>
<code>{% soundcloud https://soundcloud.com/user-261265215/dev-to-review-episode-1 %}</code>
<h3><strong>Parsing Liquid Tags as a Code Example</strong></h3>
<p>To parse Liquid tags as code, simply wrap it with a single backtick or triple backticks.</p>
<p><code>`{% mytag %}{{ site.SOMETHING }}{% endmytag %}`</code></p>

View file

@ -0,0 +1,43 @@
require "rails_helper"
require "nokogiri"
RSpec.describe SoundcloudTag, type: :liquid_template do
describe "#link" do
let(:soundcloud_link) { "https://soundcloud.com/user-261265215/dev-to-review-episode-2" }
let(:evil_string) { "<SCRIPT SRC=//xss.rocks/.j>soundcloud.com</SCRIPT>" }
let(:url_segment) { "https://w.soundcloud.com/player/?url" }
def generate_new_liquid(link)
Liquid::Template.register_tag("soundcloud", SoundcloudTag)
Liquid::Template.parse("{% soundcloud #{link} %}")
end
def extract_iframe_src(rendered_iframe)
parsed_iframe = Nokogiri.HTML(rendered_iframe)
iframe_src = parsed_iframe.xpath("//iframe/@src")
CGI::parse(iframe_src[0].value)
end
it "accepts soundcloud link" do
liquid = generate_new_liquid(soundcloud_link)
rendered_soundcloud_iframe = liquid.render
Approvals.verify(rendered_soundcloud_iframe, name: "soundcloud_liquid_tag", format: :html)
end
it "rejects invalid soundcloud link" do
expect do
generate_new_liquid("invalid_soundcloud_link")
end.to raise_error(StandardError)
end
it "strips script input" do
allow(ActionController::Base.helpers).to receive(:strip_tags).and_return(evil_string)
liquid = generate_new_liquid(evil_string)
rendered_soundcloud_iframe = liquid.render
iframe_src = extract_iframe_src(rendered_soundcloud_iframe)
expect(iframe_src[url_segment]).not_to include("<SCRIPT SRC=//xss.rocks/.j>")
end
end
end

View file

@ -0,0 +1,6 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https://soundcloud.com/user-261265215/dev-to-review-episode-2&amp;auto_play=false&amp;color=%23000000&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"> </iframe>
</body>
</html>