Skip to content

Commit e4df711

Browse files
committed
Merge remote-tracking branch 'origin/cells-haml-love' into prepare_0.7.4_release
2 parents e01cffb + 5c61571 commit e4df711

File tree

17 files changed

+241
-10
lines changed

17 files changed

+241
-10
lines changed

app/concepts/matestack/ui/core/app/app.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Matestack::Ui::Core::App
22
class App < Trailblazer::Cell
33

4-
include ::Cell::Haml
4+
include Matestack::Ui::Core::Cell
55
include Matestack::Ui::Core::ApplicationHelper
66
include Matestack::Ui::Core::ToCell
77

app/concepts/matestack/ui/core/component/dynamic.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module Matestack::Ui::Core::Component
22
class Dynamic < Trailblazer::Cell
3-
4-
include ::Cell::Haml
3+
include Matestack::Ui::Core::Cell
54
include Matestack::Ui::Core::ApplicationHelper
65
include Matestack::Ui::Core::ToCell
76
include Matestack::Ui::Core::HasViewContext

app/concepts/matestack/ui/core/page/page.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Matestack::Ui::Core::Page
22
class Page < Trailblazer::Cell
33

44
include ActionView::Helpers::TranslationHelper
5-
include ::Cell::Haml
5+
include Matestack::Ui::Core::Cell
66
include Matestack::Ui::Core::ApplicationHelper
77
include Matestack::Ui::Core::ToCell
88
include Matestack::Ui::Core::HasViewContext
@@ -94,7 +94,7 @@ def show(component_key=nil, only_page=false)
9494
begin
9595
render_child_component component_key
9696
rescue => e
97-
raise "Component '#{component_key}' could not be resolved."
97+
raise "Component '#{component_key}' could not be resolved, because of #{e},\n#{e.backtrace.join("\n")}"
9898
end
9999
end
100100
end

app/concepts/matestack/ui/core/plain/plain.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Matestack::Ui::Core::Plain
22
class Plain < Matestack::Ui::Core::Component::Static
33

44
def show
5-
@argument
5+
html_escape @argument
66
end
77

88
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Matestack::Ui::Core::Rawhtml
2+
class Rawhtml < Matestack::Ui::Core::Component::Static
3+
def show
4+
@argument
5+
end
6+
end
7+
end

docs/components/plain.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Show [specs](/spec/usage/components/plain_spec.rb)
44

5-
This element simply renders the value of a variable (or simple a string) wherever you want it.
5+
This element simply renders the value of a variable (or simple a string) wherever you want it **escaping HTML tags** (`<` becomes `&lt;` etc.).
66

77
## Parameters
88

docs/components/rawhtml.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# matestack core component: Rawhtml
2+
3+
Show [specs](/spec/usage/components/rawhtml_spec.rb)
4+
5+
This element simply renders the value of a variable (or simple a string) wherever you want it **without escaping HTML**.
6+
7+
Only use this if you are sure that you have full control over the input to this function/no malicious code can find its way inside.
8+
9+
## Parameters
10+
11+
This component expects one parameter.
12+
13+
## Example 1
14+
15+
Rendering some HTML.
16+
17+
```ruby
18+
19+
def response
20+
components {
21+
rawhtml <<~HTML
22+
<h1>Hello World</h1>
23+
<script>alert('Really Hello!')</script>
24+
HTML
25+
}
26+
end
27+
28+
```
29+
30+
returns
31+
32+
```html
33+
<h1>Hello World</h1>
34+
<script>alert('Really Hello!')</script>
35+
```

lib/matestack/ui/core.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'cell/rails'
55
require 'cell/haml'
66

7+
require "matestack/ui/core/cell"
78
require "matestack/ui/core/engine"
89

910
module Matestack

lib/matestack/ui/core/cell.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module Matestack
2+
module Ui
3+
module Core
4+
# Custom Cell options/handling based on a Cell from the cells gem.
5+
#
6+
# Needed to redefine some options and gives us more control over
7+
# the cells.
8+
module Cell
9+
include ::Cell::Haml
10+
11+
# based on https://github.com/trailblazer/cells-haml/blob/master/lib/cell/haml.rb
12+
# be aware that as of February 2020 this differs from the released version though.
13+
def template_options_for(_options)
14+
# Note, cells uses Hash#delete which mutates the hash,
15+
# hence we can't use a constant here as on the first
16+
# invocation it'd lose it's suffix key
17+
{
18+
template_class: ::Tilt::HamlTemplate,
19+
escape_html: true,
20+
escape_attrs: true,
21+
suffix: "haml"
22+
}
23+
end
24+
25+
def html_escape(string)
26+
ERB::Util.html_escape(string)
27+
end
28+
end
29+
end
30+
end
31+
end
32+
33+
# Matestack::Ui::Core::Cell = ::Cell::Haml

spec/spec_helper.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
require 'rspec/retry'
4242
require "rspec/wait"
4343

44-
4544
RSpec.configure do |config|
4645
# repeat flaky tests
4746
# show retry status in spec process

spec/support/xss.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module XSS
2+
EVIL_SCRIPT = "<script>alert('hello');</script>"
3+
ESCAPED_EVIL_SCRIPT = "&lt;script&gt;alert('hello');&lt;/script&gt;"
4+
end

spec/usage/base/component_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ def response
345345
after_content = element.text
346346

347347
expect(before_content).not_to eq(after_content)
348-
349348
end
350349

351350
it "components can render dynamic content with vue.js involved if inherit from 'Matestack::Ui::DynamicComponent'" do

spec/usage/base/xss_spec.rb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
describe "XSS behavior", type: :feature, js: true do
2+
3+
describe "injection in heading as an example" do
4+
it "escapes the evil script" do
5+
class ExamplePage < Matestack::Ui::Page
6+
def response
7+
components {
8+
heading text: XSS::EVIL_SCRIPT
9+
}
10+
end
11+
end
12+
13+
visit "/example"
14+
15+
static_output = page.html
16+
expect(static_output).to include("<h1>\n#{XSS::ESCAPED_EVIL_SCRIPT}\n</h1>")
17+
end
18+
19+
it "does not escape when we specifically say #html_safe" do
20+
class ExamplePage < Matestack::Ui::Page
21+
def response
22+
components {
23+
heading text: XSS::EVIL_SCRIPT.html_safe
24+
}
25+
end
26+
end
27+
28+
# gotta accept our injected alert
29+
accept_alert do
30+
visit "/example"
31+
end
32+
33+
# for reasons beyond me Chrome seems to remove our injected script tag,
34+
# but since we accepted an alert to get here this test should be fine
35+
end
36+
37+
# note that `heading do "string" end` doesn't work and you
38+
# should rather use `heading do plain "string" end`
39+
# Why the hell is this tested then?
40+
# Well if that behavior changed I'd like to have a reminder
41+
# here to catch it. Call me overly cautious.
42+
it "escaping won't be broken in block form (if it worked)" do
43+
class ExamplePage < Matestack::Ui::Page
44+
def response
45+
components {
46+
heading do
47+
XSS::EVIL_SCRIPT
48+
end
49+
}
50+
end
51+
end
52+
53+
visit "/example"
54+
55+
static_output = page.html
56+
expect(static_output).not_to include("alert(")
57+
end
58+
59+
it "escapes the evil when injecting into attributes" do
60+
class ExamplePage < Matestack::Ui::Page
61+
62+
def response
63+
components {
64+
heading text: "Be Safe!", id: "something-\">#{XSS::EVIL_SCRIPT}"
65+
}
66+
end
67+
68+
end
69+
70+
visit "/example"
71+
72+
expect(page.html).to include("id=\"something-&quot;><script>alert('hello');</script>")
73+
end
74+
end
75+
end

spec/usage/components/absolute_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,26 @@ def response
2828
expect(stripped(static_output)).to include(stripped(expected_static_output))
2929
end
3030

31+
describe "XSSing" do
32+
it "escaping" do
33+
class ExamplePage < Matestack::Ui::Page
34+
35+
def response
36+
components {
37+
absolute top: 50, left: '50px;">' + XSS::EVIL_SCRIPT, right: 50, bottom: 100, z: 3 do
38+
plain 'I am absolute content'
39+
end
40+
}
41+
end
42+
43+
end
44+
45+
visit '/example'
46+
47+
static_output = page.html
48+
49+
expect(static_output).not_to include("alert")
50+
end
51+
end
52+
3153
end

spec/usage/components/plain_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,36 @@ def response
2626
expect(stripped(static_output)).to include(stripped(expected_static_output))
2727
end
2828

29+
describe "XSSing" do
30+
it "doesn't allow script injection" do
31+
class ExamplePage < Matestack::Ui::Page
32+
def response
33+
components {
34+
plain XSS::EVIL_SCRIPT
35+
}
36+
end
37+
end
38+
39+
visit "/example"
40+
41+
expect(page.html).to include(XSS::ESCAPED_EVIL_SCRIPT)
42+
end
43+
44+
it "allows injection when you say #html_safe" do
45+
class ExamplePage < Matestack::Ui::Page
46+
def response
47+
components {
48+
plain XSS::EVIL_SCRIPT.html_safe
49+
}
50+
end
51+
end
52+
53+
# gotta accept our injected alert
54+
accept_alert do
55+
visit "/example"
56+
end
57+
58+
# the script tag seems removed afterwards so we can't check against it here
59+
end
60+
end
2961
end

spec/usage/components/rawhtml_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
describe "Raw Html Component", type: :feature, js: true do
2+
3+
it "allows the insertion of pure HTML: Example 1" do
4+
5+
class ExamplePage < Matestack::Ui::Page
6+
def response
7+
components {
8+
rawhtml <<~HTML
9+
<h1>Hello World</h1>
10+
<script>alert('Really Hello!')</script>
11+
HTML
12+
}
13+
end
14+
end
15+
16+
accept_alert do
17+
visit "/example"
18+
end
19+
20+
static_output = page.html
21+
22+
expect(static_output).to include("<h1>Hello World</h1>")
23+
end
24+
25+
end

spec/usage/components/youtube_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def response
2525
static_output = page.html
2626

2727
expect(page).to have_selector("iframe[src='https://www.youtube.com/embed/OY5AeGhgK7I'][class='iframe']")
28-
expect(page).to have_selector("iframe[src='https://www.youtube.com/embed/OY5AeGhgK7I?controls=0&start=30']")
28+
expect(page).to have_selector("iframe[src='https://www.youtube.com/embed/OY5AeGhgK7I?controls=0&amp;start=30']")
2929
expect(page).to have_selector("iframe[src='https://www.youtube-nocookie.com/embed/OY5AeGhgK7I?start=30']")
3030

3131
end

0 commit comments

Comments
 (0)