qiita-markdown 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of qiita-markdown might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 142f1f300d42442f62e84b3ffe54321caa229b2b
4
- data.tar.gz: 8029e1417074df1acc82af5cfd075efebe87c959
3
+ metadata.gz: 83c8da2e7dd55be72fce627ec6b14cb23362346e
4
+ data.tar.gz: 5752e8dae6fbbd5c9f9f94dc3e4a4320b9d222fa
5
5
  SHA512:
6
- metadata.gz: db7ea2bc3c6e992848e569c695dddb5923d8aeba7f289eb845c6feea58b7150152317df655540350db6967d0871b93ebaa6e7fc82c475742b6ad95f98c779cb1
7
- data.tar.gz: c98d93c9fd42393475a09560131d125eafe6d5f43ac429b333a2b2dfecfacf4c9fb8035c5a1cc3234c1209417591ba86aaac409501750a5c1b1c013198904b23
6
+ metadata.gz: 885e5a8cc2397dfedbe970b5f85e8dc952275986912149c3a24a1068b32b1c0922b7d1fb9a19db93133410d130ccbe4cda3d45218dc15bbc9b43baf5070cf0bb
7
+ data.tar.gz: f2a6c4b200eb88f247c16a4d87b4807a083042050e862a58fb7392bfbb25428f7a710ba3c1d1bf67fff0c02f1a1ff2e9fc443107f4f2a987e7147d4b5a965ab1
data/.travis.yml CHANGED
@@ -7,8 +7,6 @@ before_install:
7
7
  - gem update bundler
8
8
  language: ruby
9
9
  rvm:
10
- - 2.0
11
- - 2.1
12
10
  - 2.2
13
11
  - 2.3
14
12
  - 2.4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 0.19.0
4
+
5
+ - Drop 2.0 and 2.1 from support Ruby versions
6
+ - Rename `Sanitize` as `FinalSanitizer`
7
+ - Add `:strict` context for stricter sanitization
8
+
3
9
  ## 0.18.0
4
10
 
5
11
  - Extract heading decoration logic from Greenmat renderer to `Toc` filter
@@ -11,16 +11,17 @@ require "qiita/markdown/filters/checkbox"
11
11
  require "qiita/markdown/filters/code"
12
12
  require "qiita/markdown/filters/emoji"
13
13
  require "qiita/markdown/filters/external_link"
14
+ require "qiita/markdown/filters/final_sanitizer"
14
15
  require "qiita/markdown/filters/footnote"
15
16
  require "qiita/markdown/filters/greenmat"
16
17
  require "qiita/markdown/filters/group_mention"
17
18
  require "qiita/markdown/filters/image_link"
18
19
  require "qiita/markdown/filters/mention"
19
- require "qiita/markdown/filters/sanitize"
20
20
  require "qiita/markdown/filters/simplify"
21
21
  require "qiita/markdown/filters/syntax_highlight"
22
22
  require "qiita/markdown/filters/toc"
23
23
  require "qiita/markdown/filters/truncate"
24
+ require "qiita/markdown/filters/user_input_sanitizer"
24
25
  require "qiita/markdown/greenmat/heading_rendering"
25
26
  require "qiita/markdown/greenmat/html_renderer"
26
27
  require "qiita/markdown/greenmat/html_toc_renderer"
@@ -3,7 +3,13 @@ module Qiita
3
3
  module Filters
4
4
  # Sanitizes undesirable elements by whitelist-based rule.
5
5
  # You can pass optional :rule and :script context.
6
- class Sanitize < HTML::Pipeline::Filter
6
+ #
7
+ # Since this filter is applied at the end of html-pipeline, it's rules
8
+ # are intentionally weakened to allow elements and attributes which are
9
+ # generated by other filters.
10
+ #
11
+ # @see Qiita::Markdown::Filters::UserInputSanitizerr
12
+ class FinalSanitizer < HTML::Pipeline::Filter
7
13
  # Wraps a node env to transform invalid node.
8
14
  class TransformableNode
9
15
  def self.call(*args)
@@ -4,7 +4,7 @@ module Qiita
4
4
  # A filter for simplifying document structure by removing complex markups
5
5
  # (mainly block elements) and complex contents.
6
6
  #
7
- # The logic of this filter is similar to the `Sanitize` filter, but this
7
+ # The logic of this filter is similar to the `FinalSanitizer` filter, but this
8
8
  # does not use the `sanitize` gem internally for the following reasons:
9
9
  #
10
10
  # * Each filter should do only its own responsibility, and this filter is
@@ -12,7 +12,7 @@ module Qiita
12
12
  #
13
13
  # * The `sanitize` gem automatically adds extra transformers even if we
14
14
  # want to clean up only some elements, and they would be run in the
15
- # `Sanitize` filter later.
15
+ # `FinalSanitizer` filter later.
16
16
  # https://github.com/rgrove/sanitize/blob/v3.1.2/lib/sanitize.rb#L77-L100
17
17
  class Simplify < HTML::Pipeline::Filter
18
18
  SIMPLE_ELEMENTS = %w[a b code em i ins q s samp span strike strong sub sup var]
@@ -0,0 +1,102 @@
1
+ module Qiita
2
+ module Markdown
3
+ module Filters
4
+ # Sanitizes user input if :strict context is given.
5
+ class UserInputSanitizer < HTML::Pipeline::Filter
6
+ class AttributeFilter
7
+ FILTERS = {
8
+ "a" => {
9
+ "class" => %w[autolink],
10
+ "rel" => %w[footnote url],
11
+ "rev" => %w[footnote],
12
+ },
13
+ "sup" => {
14
+ "id" => /\Afnref\d+\z/,
15
+ },
16
+ "li" => {
17
+ "id" => /\Afn\d+\z/,
18
+ },
19
+ }.freeze
20
+
21
+ DELIMITER = " ".freeze
22
+
23
+ def self.call(*args)
24
+ new(*args).transform
25
+ end
26
+
27
+ def initialize(env)
28
+ @env = env
29
+ end
30
+
31
+ def transform
32
+ return unless FILTERS.key?(name)
33
+ FILTERS[name].each_pair do |attr, pattern|
34
+ filter_attribute(attr, pattern) if node.attributes.key?(attr)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def filter_attribute(attr, pattern)
41
+ node[attr] = node[attr].split(DELIMITER).select do |value|
42
+ pattern.is_a?(Array) ? pattern.include?(value) : (pattern =~ value)
43
+ end.join(DELIMITER)
44
+ end
45
+
46
+ def name
47
+ @env[:node_name]
48
+ end
49
+
50
+ def node
51
+ @env[:node]
52
+ end
53
+ end
54
+
55
+ RULE = {
56
+ elements: %w[
57
+ a b blockquote br code dd del details div dl dt em font h1 h2 h3 h4 h5 h6
58
+ hr i img input ins kbd li ol p pre q rp rt ruby s samp strike strong sub
59
+ summary sup table tbody td tfoot th thead tr ul var
60
+ ],
61
+ attributes: {
62
+ "a" => %w[class href rel title],
63
+ "blockquote" => %w[cite],
64
+ "code" => %w[data-metadata],
65
+ "div" => %w[class],
66
+ "font" => %w[color],
67
+ "h1" => %w[id],
68
+ "h2" => %w[id],
69
+ "h3" => %w[id],
70
+ "h4" => %w[id],
71
+ "h5" => %w[id],
72
+ "h6" => %w[id],
73
+ "img" => %w[alt height src title width],
74
+ "ins" => %w[cite datetime],
75
+ "li" => %w[id],
76
+ "q" => %w[cite],
77
+ "sup" => %w[id],
78
+ "td" => %w[colspan rowspan style],
79
+ "th" => %w[colspan rowspan style],
80
+ },
81
+ protocols: {
82
+ "a" => { "href" => ["http", "https", "mailto", :relative] },
83
+ "blockquote" => { "cite" => ["http", "https", :relative] },
84
+ "q" => { "cite" => ["http", "https", :relative] },
85
+ },
86
+ css: {
87
+ properties: %w[text-align],
88
+ },
89
+ remove_contents: %w[
90
+ script
91
+ ],
92
+ transformers: AttributeFilter,
93
+ }.freeze
94
+
95
+ def call
96
+ ::Sanitize.clean_node!(doc, RULE) if context[:strict]
97
+ doc
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -10,6 +10,7 @@ module Qiita
10
10
  def self.default_filters
11
11
  [
12
12
  Filters::Greenmat,
13
+ Filters::UserInputSanitizer,
13
14
  Filters::ImageLink,
14
15
  Filters::Footnote,
15
16
  Filters::Code,
@@ -20,7 +21,7 @@ module Qiita
20
21
  Filters::Mention,
21
22
  Filters::GroupMention,
22
23
  Filters::ExternalLink,
23
- Filters::Sanitize,
24
+ Filters::FinalSanitizer,
24
25
  ]
25
26
  end
26
27
  end
@@ -16,11 +16,12 @@ module Qiita
16
16
  def self.default_filters
17
17
  [
18
18
  Filters::Greenmat,
19
+ Filters::UserInputSanitizer,
19
20
  Filters::Simplify,
20
21
  Filters::Emoji,
21
22
  Filters::Mention,
22
23
  Filters::ExternalLink,
23
- Filters::Sanitize,
24
+ Filters::FinalSanitizer,
24
25
  Filters::Truncate,
25
26
  ]
26
27
  end
@@ -1,5 +1,5 @@
1
1
  module Qiita
2
2
  module Markdown
3
- VERSION = "0.18.0"
3
+ VERSION = "0.19.0"
4
4
  end
5
5
  end
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.required_ruby_version = ">= 2.0.0"
19
+ spec.required_ruby_version = ">= 2.2.0"
20
20
 
21
21
  spec.add_dependency "gemoji"
22
22
  spec.add_dependency "github-linguist", "~> 4.0"
@@ -18,1025 +18,1164 @@ describe Qiita::Markdown::Processor do
18
18
  described_class.new(context).call(markdown)
19
19
  end
20
20
 
21
- context "with valid condition" do
22
- let(:markdown) do
23
- <<-EOS.strip_heredoc
24
- example
25
- EOS
26
- end
21
+ shared_examples_for "basic markdown syntax" do
22
+ context "with valid condition" do
23
+ let(:markdown) do
24
+ <<-EOS.strip_heredoc
25
+ example
26
+ EOS
27
+ end
27
28
 
28
- it "returns a Hash with HTML output and other metadata" do
29
- expect(result[:codes]).to be_an Array
30
- expect(result[:mentioned_usernames]).to be_an Array
31
- expect(result[:output]).to be_a Nokogiri::HTML::DocumentFragment
29
+ it "returns a Hash with HTML output and other metadata" do
30
+ expect(result[:codes]).to be_an Array
31
+ expect(result[:mentioned_usernames]).to be_an Array
32
+ expect(result[:output]).to be_a Nokogiri::HTML::DocumentFragment
33
+ end
32
34
  end
33
- end
34
35
 
35
- context "with HTML-characters" do
36
- let(:markdown) do
37
- "<>&"
38
- end
36
+ context "with HTML-characters" do
37
+ let(:markdown) do
38
+ "<>&"
39
+ end
39
40
 
40
- it "sanitizes them" do
41
- should eq <<-EOS.strip_heredoc
42
- <p>&lt;&gt;&amp;</p>
43
- EOS
41
+ it "sanitizes them" do
42
+ should eq <<-EOS.strip_heredoc
43
+ <p>&lt;&gt;&amp;</p>
44
+ EOS
45
+ end
44
46
  end
45
- end
46
47
 
47
- context "with email address" do
48
- let(:markdown) do
49
- "test@example.com"
50
- end
48
+ context "with email address" do
49
+ let(:markdown) do
50
+ "test@example.com"
51
+ end
51
52
 
52
- it "replaces with mailto link" do
53
- should eq <<-EOS.strip_heredoc
54
- <p><a href="mailto:test@example.com" class="autolink">test@example.com</a></p>
55
- EOS
53
+ it "replaces with mailto link" do
54
+ should eq <<-EOS.strip_heredoc
55
+ <p><a href="mailto:test@example.com" class="autolink">test@example.com</a></p>
56
+ EOS
57
+ end
56
58
  end
57
- end
58
59
 
59
- context "with headings" do
60
- let(:markdown) do
61
- <<-EOS.strip_heredoc
62
- # a
63
- ## a
64
- ### a
65
- ### a
66
- EOS
67
- end
60
+ context "with headings" do
61
+ let(:markdown) do
62
+ <<-EOS.strip_heredoc
63
+ # a
64
+ ## a
65
+ ### a
66
+ ### a
67
+ EOS
68
+ end
68
69
 
69
- it "adds ID for ToC" do
70
- should eq <<-EOS.strip_heredoc
70
+ it "adds ID for ToC" do
71
+ should eq <<-EOS.strip_heredoc
71
72
 
72
- <h1>
73
- <span id="a" class="fragment"></span><a href="#a"><i class="fa fa-link"></i></a>a</h1>
73
+ <h1>
74
+ <span id="a" class="fragment"></span><a href="#a"><i class="fa fa-link"></i></a>a</h1>
74
75
 
75
- <h2>
76
- <span id="a-1" class="fragment"></span><a href="#a-1"><i class="fa fa-link"></i></a>a</h2>
76
+ <h2>
77
+ <span id="a-1" class="fragment"></span><a href="#a-1"><i class="fa fa-link"></i></a>a</h2>
77
78
 
78
- <h3>
79
- <span id="a-2" class="fragment"></span><a href="#a-2"><i class="fa fa-link"></i></a>a</h3>
79
+ <h3>
80
+ <span id="a-2" class="fragment"></span><a href="#a-2"><i class="fa fa-link"></i></a>a</h3>
80
81
 
81
- <h3>
82
- <span id="a-3" class="fragment"></span><a href="#a-3"><i class="fa fa-link"></i></a>a</h3>
83
- EOS
82
+ <h3>
83
+ <span id="a-3" class="fragment"></span><a href="#a-3"><i class="fa fa-link"></i></a>a</h3>
84
+ EOS
85
+ end
84
86
  end
85
- end
86
87
 
87
- context "with heading whose title includes special HTML characters" do
88
- let(:markdown) do
89
- <<-EOS.strip_heredoc
90
- # <b>R&amp;B</b>
91
- EOS
92
- end
88
+ context "with heading whose title includes special HTML characters" do
89
+ let(:markdown) do
90
+ <<-EOS.strip_heredoc
91
+ # <b>R&amp;B</b>
92
+ EOS
93
+ end
93
94
 
94
- it "generates fragment identifier by sanitizing the special characters in the title" do
95
- should eq <<-EOS.strip_heredoc
95
+ it "generates fragment identifier by sanitizing the special characters in the title" do
96
+ should eq <<-EOS.strip_heredoc
96
97
 
97
- <h1>
98
- <span id="rb" class="fragment"></span><a href="#rb"><i class="fa fa-link"></i></a><b>R&amp;B</b>
99
- </h1>
100
- EOS
98
+ <h1>
99
+ <span id="rb" class="fragment"></span><a href="#rb"><i class="fa fa-link"></i></a><b>R&amp;B</b>
100
+ </h1>
101
+ EOS
102
+ end
101
103
  end
102
- end
103
104
 
104
- context "with manually inputted heading HTML tags without id attribute" do
105
- let(:markdown) do
106
- <<-EOS.strip_heredoc
107
- <h1>foo</h1>
108
- EOS
109
- end
105
+ context "with manually inputted heading HTML tags without id attribute" do
106
+ let(:markdown) do
107
+ <<-EOS.strip_heredoc
108
+ <h1>foo</h1>
109
+ EOS
110
+ end
110
111
 
111
- it "does nothing" do
112
- should eq <<-EOS.strip_heredoc
113
- <h1>foo</h1>
114
- EOS
112
+ it "does nothing" do
113
+ should eq <<-EOS.strip_heredoc
114
+ <h1>foo</h1>
115
+ EOS
116
+ end
115
117
  end
116
- end
117
118
 
118
- context "with code" do
119
- let(:markdown) do
120
- <<-EOS.strip_heredoc
121
- ```foo.rb
122
- puts 'hello world'
123
- ```
124
- EOS
125
- end
119
+ context "with code" do
120
+ let(:markdown) do
121
+ <<-EOS.strip_heredoc
122
+ ```foo.rb
123
+ puts 'hello world'
124
+ ```
125
+ EOS
126
+ end
126
127
 
127
- it "returns detected codes" do
128
- expect(result[:codes]).to eq [
129
- {
130
- code: "puts 'hello world'\n",
131
- filename: "foo.rb",
132
- language: "ruby",
133
- },
134
- ]
128
+ it "returns detected codes" do
129
+ expect(result[:codes]).to eq [
130
+ {
131
+ code: "puts 'hello world'\n",
132
+ filename: "foo.rb",
133
+ language: "ruby",
134
+ },
135
+ ]
136
+ end
135
137
  end
136
- end
137
138
 
138
- context "with code & filename" do
139
- let(:markdown) do
140
- <<-EOS.strip_heredoc
141
- ```example.rb
142
- 1
143
- ```
144
- EOS
145
- end
139
+ context "with code & filename" do
140
+ let(:markdown) do
141
+ <<-EOS.strip_heredoc
142
+ ```example.rb
143
+ 1
144
+ ```
145
+ EOS
146
+ end
146
147
 
147
- it "returns code-frame, code-lang, and highlighted pre element" do
148
- should eq <<-EOS.strip_heredoc
149
- <div class="code-frame" data-lang="ruby">
150
- <div class="code-lang"><span class="bold">example.rb</span></div>
151
- <div class="highlight"><pre><span></span><span class="mi">1</span>
152
- </pre></div>
153
- </div>
154
- EOS
148
+ it "returns code-frame, code-lang, and highlighted pre element" do
149
+ should eq <<-EOS.strip_heredoc
150
+ <div class="code-frame" data-lang="ruby">
151
+ <div class="code-lang"><span class="bold">example.rb</span></div>
152
+ <div class="highlight"><pre><span></span><span class="mi">1</span>
153
+ </pre></div>
154
+ </div>
155
+ EOS
156
+ end
155
157
  end
156
- end
157
158
 
158
- context "with code & filename with .php" do
159
- let(:markdown) do
160
- <<-EOS.strip_heredoc
161
- ```example.php
162
- 1
163
- ```
164
- EOS
165
- end
159
+ context "with code & filename with .php" do
160
+ let(:markdown) do
161
+ <<-EOS.strip_heredoc
162
+ ```example.php
163
+ 1
164
+ ```
165
+ EOS
166
+ end
166
167
 
167
- it "returns PHP code-frame" do
168
- should eq <<-EOS.strip_heredoc
169
- <div class="code-frame" data-lang="php">
170
- <div class="code-lang"><span class="bold">example.php</span></div>
171
- <div class="highlight"><pre><span></span><span class="mi">1</span>
172
- </pre></div>
173
- </div>
174
- EOS
168
+ it "returns PHP code-frame" do
169
+ should eq <<-EOS.strip_heredoc
170
+ <div class="code-frame" data-lang="php">
171
+ <div class="code-lang"><span class="bold">example.php</span></div>
172
+ <div class="highlight"><pre><span></span><span class="mi">1</span>
173
+ </pre></div>
174
+ </div>
175
+ EOS
176
+ end
175
177
  end
176
- end
177
178
 
178
- context "with malicious script in filename" do
179
- let(:markdown) do
180
- <<-EOS.strip_heredoc
181
- ```js:test<script>alert(1)</script>
182
- 1
183
- ```
184
- EOS
185
- end
179
+ context "with code & no filename" do
180
+ let(:markdown) do
181
+ <<-EOS.strip_heredoc
182
+ ```ruby
183
+ 1
184
+ ```
185
+ EOS
186
+ end
186
187
 
187
- it "sanitizes script element" do
188
- should eq <<-EOS.strip_heredoc
189
- <div class="code-frame" data-lang="js">
190
- <div class="code-lang"><span class="bold">test</span></div>
191
- <div class="highlight"><pre><span></span><span class="mi">1</span>
192
- </pre></div>
193
- </div>
194
- EOS
188
+ it "returns code-frame and highlighted pre element" do
189
+ should eq <<-EOS.strip_heredoc
190
+ <div class="code-frame" data-lang="ruby"><div class="highlight"><pre><span></span><span class="mi">1</span>
191
+ </pre></div></div>
192
+ EOS
193
+ end
195
194
  end
196
- end
197
195
 
198
- context "with code & no filename" do
199
- let(:markdown) do
200
- <<-EOS.strip_heredoc
201
- ```ruby
202
- 1
203
- ```
204
- EOS
205
- end
196
+ context "with undefined but aliased language" do
197
+ let(:markdown) do
198
+ <<-EOS.strip_heredoc
199
+ ```zsh
200
+ true
201
+ ```
202
+ EOS
203
+ end
206
204
 
207
- it "returns code-frame and highlighted pre element" do
208
- should eq <<-EOS.strip_heredoc
209
- <div class="code-frame" data-lang="ruby"><div class="highlight"><pre><span></span><span class="mi">1</span>
210
- </pre></div></div>
211
- EOS
205
+ it "returns aliased language name" do
206
+ expect(result[:codes]).to eq [
207
+ {
208
+ code: "true\n",
209
+ filename: nil,
210
+ language: "bash",
211
+ },
212
+ ]
213
+ end
212
214
  end
213
- end
214
215
 
215
- context "with undefined but aliased language" do
216
- let(:markdown) do
217
- <<-EOS.strip_heredoc
218
- ```zsh
219
- true
220
- ```
221
- EOS
222
- end
216
+ context "with code with leading and trailing newlines" do
217
+ let(:markdown) do
218
+ <<-EOS.strip_heredoc
219
+ ```
223
220
 
224
- it "returns aliased language name" do
225
- expect(result[:codes]).to eq [
226
- {
227
- code: "true\n",
228
- filename: nil,
229
- language: "bash",
230
- },
231
- ]
232
- end
233
- end
221
+ foo
234
222
 
235
- context "with code with leading and trailing newlines" do
236
- let(:markdown) do
237
- <<-EOS.strip_heredoc
238
- ```
223
+ ```
224
+ EOS
225
+ end
239
226
 
240
- foo
227
+ it "does not strip the newlines" do
228
+ should eq <<-EOS.strip_heredoc
229
+ <div class="code-frame" data-lang="text"><div class="highlight"><pre><span></span>
230
+ foo
241
231
 
242
- ```
243
- EOS
232
+ </pre></div></div>
233
+ EOS
234
+ end
244
235
  end
245
236
 
246
- it "does not strip the newlines" do
247
- should eq <<-EOS.strip_heredoc
248
- <div class="code-frame" data-lang="text"><div class="highlight"><pre><span></span>
249
- foo
237
+ context "with mention" do
238
+ let(:markdown) do
239
+ "@alice"
240
+ end
250
241
 
251
- </pre></div></div>
252
- EOS
242
+ it "replaces mention with link" do
243
+ should include(<<-EOS.strip_heredoc.rstrip)
244
+ <a href="/alice" class="user-mention js-hovercard" title="alice" data-hovercard-target-type="user" data-hovercard-target-name="alice">@alice</a>
245
+ EOS
246
+ end
253
247
  end
254
- end
255
248
 
256
- context "with script element" do
257
- let(:markdown) do
258
- <<-EOS.strip_heredoc
259
- <script>alert(1)</script>
260
- EOS
261
- end
249
+ context "with mention to short name user" do
250
+ let(:markdown) do
251
+ "@al"
252
+ end
262
253
 
263
- it "removes script element" do
264
- should eq "\n"
254
+ it "replaces mention with link" do
255
+ should include(<<-EOS.strip_heredoc.rstrip)
256
+ <a href="/al" class="user-mention js-hovercard" title="al" data-hovercard-target-type="user" data-hovercard-target-name="al">@al</a>
257
+ EOS
258
+ end
265
259
  end
266
- end
267
260
 
268
- context "with script context" do
269
- before do
270
- context[:script] = true
271
- end
261
+ context "with mentions in complex patterns" do
262
+ let(:markdown) do
263
+ <<-EOS.strip_heredoc
264
+ @alice
265
+
266
+ ```
267
+ @bob
268
+ ```
269
+
270
+ @charlie/@dave
271
+ @ell_en
272
+ @fran-k
273
+ @Isaac
274
+ @justin
275
+ @justin
276
+ @mallory@github
277
+ @#{'o' * 33}
278
+ @o
279
+ @o-
280
+ @-o
281
+ @o_
282
+ @_o
283
+ EOS
284
+ end
272
285
 
273
- let(:markdown) do
274
- <<-EOS.strip_heredoc
275
- <p><script>alert(1)</script></p>
276
- EOS
286
+ it "extracts mentions correctly" do
287
+ expect(result[:mentioned_usernames]).to eq %w[
288
+ alice
289
+ dave
290
+ ell_en
291
+ fran-k
292
+ Isaac
293
+ justin
294
+ mallory@github
295
+ o_
296
+ _o
297
+ ]
298
+ end
277
299
  end
278
300
 
279
- it "allows script element" do
280
- should eq markdown
281
- end
282
- end
301
+ context "with mention-like filename on code block" do
302
+ let(:markdown) do
303
+ <<-EOS.strip_heredoc
304
+ ```ruby:@alice
305
+ 1
306
+ ```
307
+ EOS
308
+ end
283
309
 
284
- context "with allowed attributes" do
285
- before do
286
- context[:script] = true
310
+ it "does not treat it as mention" do
311
+ should include(<<-EOS.strip_heredoc.rstrip)
312
+ <div class="code-frame" data-lang="ruby">
313
+ <div class="code-lang"><span class="bold">@alice</span></div>
314
+ <div class="highlight"><pre><span></span><span class="mi">1</span>
315
+ </pre></div>
316
+ </div>
317
+ EOS
318
+ end
287
319
  end
288
320
 
289
- let(:markdown) do
290
- <<-EOS.strip_heredoc
291
- <p><script async data-a="b" type="text/javascript">alert(1)</script></p>
292
- EOS
293
- end
321
+ context "with mention in blockquote" do
322
+ let(:markdown) do
323
+ "> @alice"
324
+ end
294
325
 
295
- it "allows data-attributes" do
296
- should eq markdown
326
+ it "does not replace mention with link" do
327
+ should include(<<-EOS.strip_heredoc.rstrip)
328
+ <blockquote>
329
+ <p>@alice</p>
330
+ </blockquote>
331
+ EOS
332
+ end
297
333
  end
298
- end
299
334
 
300
- context "with iframe" do
301
- before do
302
- context[:script] = true
303
- end
335
+ context "with mention to user whose name starts and ends with underscore" do
336
+ let(:markdown) do
337
+ "@_alice_"
338
+ end
304
339
 
305
- let(:markdown) do
306
- <<-EOS.strip_heredoc
307
- <iframe width="1" height="2" src="//example.com" frameborder="0" allowfullscreen></iframe>
308
- EOS
340
+ it "does not emphasize the name" do
341
+ should include(<<-EOS.strip_heredoc.rstrip)
342
+ <a href="/_alice_" class="user-mention js-hovercard" title="_alice_" data-hovercard-target-type="user" data-hovercard-target-name="_alice_">@_alice_</a>
343
+ EOS
344
+ end
309
345
  end
310
346
 
311
- it "allows iframe with some attributes" do
312
- should eq markdown
313
- end
314
- end
347
+ context "with allowed_usernames context" do
348
+ before do
349
+ context[:allowed_usernames] = ["alice"]
350
+ end
315
351
 
316
- context "with mention" do
317
- let(:markdown) do
318
- "@alice"
319
- end
352
+ let(:markdown) do
353
+ <<-EOS.strip_heredoc
354
+ @alice
355
+ @bob
356
+ EOS
357
+ end
320
358
 
321
- it "replaces mention with link" do
322
- should include(<<-EOS.strip_heredoc.rstrip)
323
- <a href="/alice" class="user-mention js-hovercard" title="alice" data-hovercard-target-type="user" data-hovercard-target-name="alice">@alice</a>
324
- EOS
359
+ it "limits mentions to allowed usernames" do
360
+ expect(result[:mentioned_usernames]).to eq ["alice"]
361
+ end
325
362
  end
326
- end
327
363
 
328
- context "with mention to short name user" do
329
- let(:markdown) do
330
- "@al"
331
- end
364
+ context "with @all and allowed_usernames context" do
365
+ before do
366
+ context[:allowed_usernames] = ["alice", "bob"]
367
+ end
368
+
369
+ let(:markdown) do
370
+ "@all"
371
+ end
332
372
 
333
- it "replaces mention with link" do
334
- should include(<<-EOS.strip_heredoc.rstrip)
335
- <a href="/al" class="user-mention js-hovercard" title="al" data-hovercard-target-type="user" data-hovercard-target-name="al">@al</a>
336
- EOS
373
+ it "links it and reports all allowed users as mentioned user names" do
374
+ should include(<<-EOS.strip_heredoc.rstrip)
375
+ <a href="/" class="user-mention" title="all">@all</a>
376
+ EOS
377
+ expect(result[:mentioned_usernames]).to eq context[:allowed_usernames]
378
+ end
337
379
  end
338
- end
339
380
 
340
- context "with mentions in complex patterns" do
341
- let(:markdown) do
342
- <<-EOS.strip_heredoc
343
- @alice
381
+ context "with @all and @alice" do
382
+ before do
383
+ context[:allowed_usernames] = ["alice", "bob"]
384
+ end
344
385
 
345
- ```
346
- @bob
347
- ```
348
-
349
- @charlie/@dave
350
- @ell_en
351
- @fran-k
352
- @Isaac
353
- @justin
354
- @justin
355
- @mallory@github
356
- @#{'o' * 33}
357
- @o
358
- @o-
359
- @-o
360
- @o_
361
- @_o
362
- EOS
363
- end
364
-
365
- it "extracts mentions correctly" do
366
- expect(result[:mentioned_usernames]).to eq %w[
367
- alice
368
- dave
369
- ell_en
370
- fran-k
371
- Isaac
372
- justin
373
- mallory@github
374
- o_
375
- _o
376
- ]
377
- end
378
- end
386
+ let(:markdown) do
387
+ "@all @alice"
388
+ end
379
389
 
380
- context "with mention-like filename on code block" do
381
- let(:markdown) do
382
- <<-EOS.strip_heredoc
383
- ```ruby:@alice
384
- 1
385
- ```
386
- EOS
390
+ it "does not duplicate mentioned user names" do
391
+ expect(result[:mentioned_usernames]).to eq context[:allowed_usernames]
392
+ end
387
393
  end
388
394
 
389
- it "does not treat it as mention" do
390
- should include(<<-EOS.strip_heredoc.rstrip)
391
- <div class="code-frame" data-lang="ruby">
392
- <div class="code-lang"><span class="bold">@alice</span></div>
393
- <div class="highlight"><pre><span></span><span class="mi">1</span>
394
- </pre></div>
395
- </div>
396
- EOS
397
- end
398
- end
395
+ context "with @all and no allowed_usernames context" do
396
+ let(:markdown) do
397
+ "@all"
398
+ end
399
399
 
400
- context "with mention in blockquote" do
401
- let(:markdown) do
402
- "> @alice"
400
+ it "does not repond to @all" do
401
+ should eq "<p>@all</p>\n"
402
+ expect(result[:mentioned_usernames]).to eq []
403
+ end
403
404
  end
404
405
 
405
- it "does not replace mention with link" do
406
- should include(<<-EOS.strip_heredoc.rstrip)
407
- <blockquote>
408
- <p>@alice</p>
409
- </blockquote>
410
- EOS
411
- end
412
- end
406
+ context "with group mention without group_memberion_url_generator" do
407
+ let(:markdown) do
408
+ "@alice/bob"
409
+ end
413
410
 
414
- context "with mention to user whose name starts and ends with underscore" do
415
- let(:markdown) do
416
- "@_alice_"
411
+ it "does not replace it" do
412
+ is_expected.to eq <<-EOS.strip_heredoc
413
+ <p>@alice/bob</p>
414
+ EOS
415
+ end
417
416
  end
418
417
 
419
- it "does not emphasize the name" do
420
- should include(<<-EOS.strip_heredoc.rstrip)
421
- <a href="/_alice_" class="user-mention js-hovercard" title="_alice_" data-hovercard-target-type="user" data-hovercard-target-name="_alice_">@_alice_</a>
422
- EOS
423
- end
424
- end
418
+ context "with group mention" do
419
+ let(:context) do
420
+ super().merge(group_mention_url_generator: lambda do |group|
421
+ "https://#{group[:team_url_name]}.example.com/groups/#{group[:group_url_name]}"
422
+ end)
423
+ end
425
424
 
426
- context "with allowed_usernames context" do
427
- before do
428
- context[:allowed_usernames] = ["alice"]
429
- end
425
+ let(:markdown) do
426
+ "@alice/bob"
427
+ end
430
428
 
431
- let(:markdown) do
432
- <<-EOS.strip_heredoc
433
- @alice
434
- @bob
435
- EOS
429
+ it "replaces it with preferred link and updates :mentioned_groups" do
430
+ is_expected.to eq <<-EOS.strip_heredoc
431
+ <p><a href="https://alice.example.com/groups/bob" rel="nofollow noopener" target="_blank">@alice/bob</a></p>
432
+ EOS
433
+ expect(result[:mentioned_groups]).to eq [{
434
+ group_url_name: "bob",
435
+ team_url_name: "alice",
436
+ }]
437
+ end
436
438
  end
437
439
 
438
- it "limits mentions to allowed usernames" do
439
- expect(result[:mentioned_usernames]).to eq ["alice"]
440
- end
441
- end
440
+ context "with group mention following another text" do
441
+ let(:context) do
442
+ super().merge(group_mention_url_generator: lambda do |group|
443
+ "https://#{group[:team_url_name]}.example.com/groups/#{group[:group_url_name]}"
444
+ end)
445
+ end
442
446
 
443
- context "with @all and allowed_usernames context" do
444
- before do
445
- context[:allowed_usernames] = ["alice", "bob"]
446
- end
447
+ let(:markdown) do
448
+ "FYI @alice/bob"
449
+ end
447
450
 
448
- let(:markdown) do
449
- "@all"
451
+ it "preserves space after preceding text" do
452
+ is_expected.to start_with("<p>FYI <a ")
453
+ end
450
454
  end
451
455
 
452
- it "links it and reports all allowed users as mentioned user names" do
453
- should include(<<-EOS.strip_heredoc.rstrip)
454
- <a href="/" class="user-mention" title="all">@all</a>
455
- EOS
456
- expect(result[:mentioned_usernames]).to eq context[:allowed_usernames]
457
- end
458
- end
456
+ context "with normal link" do
457
+ let(:markdown) do
458
+ "[](/example)"
459
+ end
459
460
 
460
- context "with @all and @alice" do
461
- before do
462
- context[:allowed_usernames] = ["alice", "bob"]
461
+ it "creates link for that" do
462
+ should eq <<-EOS.strip_heredoc
463
+ <p><a href="/example"></a></p>
464
+ EOS
465
+ end
463
466
  end
464
467
 
465
- let(:markdown) do
466
- "@all @alice"
467
- end
468
+ context "with anchor link" do
469
+ let(:markdown) do
470
+ "[](#example)"
471
+ end
468
472
 
469
- it "does not duplicate mentioned user names" do
470
- expect(result[:mentioned_usernames]).to eq context[:allowed_usernames]
473
+ it "creates link for that" do
474
+ should eq <<-EOS.strip_heredoc
475
+ <p><a href="#example"></a></p>
476
+ EOS
477
+ end
471
478
  end
472
- end
473
479
 
474
- context "with @all and no allowed_usernames context" do
475
- let(:markdown) do
476
- "@all"
477
- end
480
+ context "with link with title" do
481
+ let(:markdown) do
482
+ '[](/example "Title")'
483
+ end
478
484
 
479
- it "does not repond to @all" do
480
- should eq "<p>@all</p>\n"
481
- expect(result[:mentioned_usernames]).to eq []
485
+ it "creates link for that with the title" do
486
+ should eq <<-EOS.strip_heredoc
487
+ <p><a href="/example" title="Title"></a></p>
488
+ EOS
489
+ end
482
490
  end
483
- end
484
491
 
485
- context "with group mention without group_memberion_url_generator" do
486
- let(:markdown) do
487
- "@alice/bob"
488
- end
492
+ context "with raw URL" do
493
+ let(:markdown) do
494
+ "http://example.com/search?q=日本語"
495
+ end
489
496
 
490
- it "does not replace it" do
491
- is_expected.to eq <<-EOS.strip_heredoc
492
- <p>@alice/bob</p>
493
- EOS
497
+ it "creates link for that with .autolink class" do
498
+ should eq(
499
+ '<p><a href="http://example.com/search?q=%E6%97%A5%E6%9C%AC%E8%AA%9E" class="autolink">' \
500
+ "http://example.com/search?q=日本語</a></p>\n"
501
+ )
502
+ end
494
503
  end
495
- end
496
504
 
497
- context "with group mention" do
498
- let(:context) do
499
- super().merge(group_mention_url_generator: lambda do |group|
500
- "https://#{group[:team_url_name]}.example.com/groups/#{group[:group_url_name]}"
501
- end)
502
- end
505
+ context "with javascript: link" do
506
+ let(:markdown) do
507
+ "[](javascript:alert(1))"
508
+ end
503
509
 
504
- let(:markdown) do
505
- "@alice/bob"
510
+ it "removes that link by creating empty a element" do
511
+ should eq <<-EOS.strip_heredoc
512
+ <p><a></a></p>
513
+ EOS
514
+ end
506
515
  end
507
516
 
508
- it "replaces it with preferred link and updates :mentioned_groups" do
509
- is_expected.to eq <<-EOS.strip_heredoc
510
- <p><a href="https://alice.example.com/groups/bob" rel="nofollow noopener" target="_blank">@alice/bob</a></p>
511
- EOS
512
- expect(result[:mentioned_groups]).to eq [{
513
- group_url_name: "bob",
514
- team_url_name: "alice",
515
- }]
516
- end
517
- end
517
+ context "with emoji" do
518
+ let(:markdown) do
519
+ ":+1:"
520
+ end
518
521
 
519
- context "with group mention following another text" do
520
- let(:context) do
521
- super().merge(group_mention_url_generator: lambda do |group|
522
- "https://#{group[:team_url_name]}.example.com/groups/#{group[:group_url_name]}"
523
- end)
522
+ it "replaces it with img element" do
523
+ should include("img")
524
+ end
524
525
  end
525
526
 
526
- let(:markdown) do
527
- "FYI @alice/bob"
528
- end
527
+ context "with emoji in pre or code element" do
528
+ let(:markdown) do
529
+ <<-EOS.strip_heredoc
530
+ ```
531
+ :+1:
532
+ ```
533
+ EOS
534
+ end
529
535
 
530
- it "preserves space after preceding text" do
531
- is_expected.to start_with("<p>FYI <a ")
536
+ it "does not replace it" do
537
+ should_not include("img")
538
+ end
532
539
  end
533
- end
534
540
 
535
- context "with normal link" do
536
- let(:markdown) do
537
- "[](/example)"
538
- end
541
+ context "with image notation" do
542
+ let(:markdown) do
543
+ "![a](http://example.com/b.png)"
544
+ end
539
545
 
540
- it "creates link for that" do
541
- should eq <<-EOS.strip_heredoc
542
- <p><a href="/example"></a></p>
543
- EOS
546
+ it "wraps it in a element" do
547
+ should eq %(<p><a href="http://example.com/b.png" target="_blank">) +
548
+ %(<img src="http://example.com/b.png" alt="a"></a></p>\n)
549
+ end
544
550
  end
545
- end
546
551
 
547
- context "with anchor link" do
548
- let(:markdown) do
549
- "[](#example)"
550
- end
552
+ context "with image notation with title" do
553
+ let(:markdown) do
554
+ '![a](http://example.com/b.png "Title")'
555
+ end
551
556
 
552
- it "creates link for that" do
553
- should eq <<-EOS.strip_heredoc
554
- <p><a href="#example"></a></p>
555
- EOS
557
+ it "generates <img> tag with the title" do
558
+ should eq %(<p><a href="http://example.com/b.png" target="_blank">) +
559
+ %(<img src="http://example.com/b.png" alt="a" title="Title"></a></p>\n)
560
+ end
556
561
  end
557
- end
558
562
 
559
- context "with raw URL" do
560
- let(:markdown) do
561
- "http://example.com/search?q=日本語"
562
- end
563
+ context "with <img> tag with width and height attribute (for Retina image)" do
564
+ let(:markdown) do
565
+ '<img width="80" height="48" alt="a" src="http://example.com/b.png">'
566
+ end
563
567
 
564
- it "creates link for that with .autolink class" do
565
- should eq(
566
- '<p><a href="http://example.com/search?q=%E6%97%A5%E6%9C%AC%E8%AA%9E" class="autolink">' \
567
- "http://example.com/search?q=日本語</a></p>\n"
568
- )
568
+ it "wraps it in a element while keeping the width attribute" do
569
+ should eq %(<p><a href="http://example.com/b.png" target="_blank">) +
570
+ %(<img width="80" height="48" alt="a" src="http://example.com/b.png"></a></p>\n)
571
+ end
569
572
  end
570
- end
571
573
 
572
- context "with javascript: link" do
573
- let(:markdown) do
574
- "[](javascript:alert(1))"
575
- end
574
+ context "with colon-only label" do
575
+ let(:markdown) do
576
+ <<-EOS.strip_heredoc
577
+ ```:
578
+ 1
579
+ ```
580
+ EOS
581
+ end
576
582
 
577
- it "removes that link by creating empty a element" do
578
- should eq <<-EOS.strip_heredoc
579
- <p><a></a></p>
580
- EOS
583
+ it "does not replace it" do
584
+ expect(result[:codes]).to eq [
585
+ {
586
+ code: "1\n",
587
+ filename: nil,
588
+ language: nil,
589
+ },
590
+ ]
591
+ end
581
592
  end
582
- end
583
593
 
584
- context "with emoji" do
585
- let(:markdown) do
586
- ":+1:"
587
- end
594
+ context "with font element with color attribute" do
595
+ let(:markdown) do
596
+ %[<font color="red">test</font>]
597
+ end
588
598
 
589
- it "replaces it with img element" do
590
- should include("img")
599
+ it "allows font element with color attribute" do
600
+ should eq <<-EOS.strip_heredoc
601
+ <p>#{markdown}</p>
602
+ EOS
603
+ end
591
604
  end
592
- end
593
605
 
594
- context "with emoji in pre or code element" do
595
- let(:markdown) do
596
- <<-EOS.strip_heredoc
597
- ```
598
- :+1:
599
- ```
600
- EOS
601
- end
606
+ context "with task list" do
607
+ let(:markdown) do
608
+ <<-EOS.strip_heredoc
609
+ - [ ] a
610
+ - [x] b
611
+ EOS
612
+ end
602
613
 
603
- it "does not replace it" do
604
- should_not include("img")
614
+ it "inserts checkbox" do
615
+ should eq <<-EOS.strip_heredoc
616
+ <ul>
617
+ <li class="task-list-item">
618
+ <input type="checkbox" class="task-list-item-checkbox" disabled>a</li>
619
+ <li class="task-list-item">
620
+ <input type="checkbox" class="task-list-item-checkbox" checked disabled>b</li>
621
+ </ul>
622
+ EOS
623
+ end
605
624
  end
606
- end
607
625
 
608
- context "with image notation" do
609
- let(:markdown) do
610
- "![a](http://example.com/b.png)"
611
- end
626
+ context "with nested task list" do
627
+ let(:markdown) do
628
+ <<-EOS.strip_heredoc
629
+ - [ ] a
630
+ - [ ] b
631
+ EOS
632
+ end
612
633
 
613
- it "wraps it in a element" do
614
- should eq '<p><a href="http://example.com/b.png" target="_blank">' +
615
- %(<img src="http://example.com/b.png" alt="a"></a></p>\n)
634
+ it "inserts checkbox" do
635
+ should eq <<-EOS.strip_heredoc
636
+ <ul>
637
+ <li class="task-list-item">
638
+ <input type="checkbox" class="task-list-item-checkbox" disabled>a
639
+
640
+ <ul>
641
+ <li class="task-list-item">
642
+ <input type="checkbox" class="task-list-item-checkbox" disabled>b</li>
643
+ </ul>
644
+ </li>
645
+ </ul>
646
+ EOS
647
+ end
616
648
  end
617
- end
618
649
 
619
- context "with colon-only label" do
620
- let(:markdown) do
621
- <<-EOS.strip_heredoc
622
- ```:
623
- 1
624
- ```
625
- EOS
626
- end
650
+ context "with task list in code block" do
651
+ let(:markdown) do
652
+ <<-EOS.strip_heredoc
653
+ ```
654
+ - [ ] a
655
+ - [x] b
656
+ ```
657
+ EOS
658
+ end
627
659
 
628
- it "does not replace it" do
629
- expect(result[:codes]).to eq [
630
- {
631
- code: "1\n",
632
- filename: nil,
633
- language: nil,
634
- },
635
- ]
660
+ it "does not replace checkbox" do
661
+ should eq <<-EOS.strip_heredoc
662
+ <div class="code-frame" data-lang="text"><div class="highlight"><pre><span></span>- [ ] a
663
+ - [x] b
664
+ </pre></div></div>
665
+ EOS
666
+ end
636
667
  end
637
- end
638
668
 
639
- context "with font element with color attribute" do
640
- let(:markdown) do
641
- %[<font color="red">test</font>]
642
- end
669
+ context "with empty line between task list" do
670
+ let(:markdown) do
671
+ <<-EOS.strip_heredoc
672
+ - [ ] a
643
673
 
644
- it "allows font element with color attribute" do
645
- should eq <<-EOS.strip_heredoc
646
- <p>#{markdown}</p>
647
- EOS
648
- end
649
- end
674
+ - [x] b
675
+ EOS
676
+ end
650
677
 
651
- context "with task list" do
652
- let(:markdown) do
653
- <<-EOS.strip_heredoc
654
- - [ ] a
655
- - [x] b
656
- EOS
678
+ it "inserts checkbox" do
679
+ should eq <<-EOS.strip_heredoc
680
+ <ul>
681
+ <li class="task-list-item"><p><input type="checkbox" class="task-list-item-checkbox" disabled>a</p></li>
682
+ <li class="task-list-item"><p><input type="checkbox" class="task-list-item-checkbox" checked disabled>b</p></li>
683
+ </ul>
684
+ EOS
685
+ end
657
686
  end
658
687
 
659
- it "inserts checkbox" do
660
- should eq <<-EOS.strip_heredoc
661
- <ul>
662
- <li class="task-list-item">
663
- <input type="checkbox" class="task-list-item-checkbox" disabled>a</li>
664
- <li class="task-list-item">
665
- <input type="checkbox" class="task-list-item-checkbox" checked disabled>b</li>
666
- </ul>
667
- EOS
668
- end
669
- end
688
+ context "with empty list" do
689
+ let(:markdown) do
690
+ "- \n"
691
+ end
670
692
 
671
- context "with nested task list" do
672
- let(:markdown) do
673
- <<-EOS.strip_heredoc
674
- - [ ] a
675
- - [ ] b
676
- EOS
693
+ it "inserts checkbox" do
694
+ should eq <<-EOS.strip_heredoc
695
+ <ul>
696
+ <li>
697
+ </ul>
698
+ EOS
699
+ end
677
700
  end
678
701
 
679
- it "inserts checkbox" do
680
- should eq <<-EOS.strip_heredoc
681
- <ul>
682
- <li class="task-list-item">
683
- <input type="checkbox" class="task-list-item-checkbox" disabled>a
702
+ context "with text-aligned table" do
703
+ let(:markdown) do
704
+ <<-EOS.strip_heredoc
705
+ | a | b | c |
706
+ |:---|---:|:---:|
707
+ | a | b | c |
708
+ EOS
709
+ end
684
710
 
685
- <ul>
686
- <li class="task-list-item">
687
- <input type="checkbox" class="task-list-item-checkbox" disabled>b</li>
688
- </ul>
689
- </li>
690
- </ul>
691
- EOS
711
+ it "creates table element with text-align style" do
712
+ should eq <<-EOS.strip_heredoc
713
+ <table>
714
+ <thead>
715
+ <tr>
716
+ <th style="text-align: left">a</th>
717
+ <th style="text-align: right">b</th>
718
+ <th style="text-align: center">c</th>
719
+ </tr>
720
+ </thead>
721
+ <tbody>
722
+ <tr>
723
+ <td style="text-align: left">a</td>
724
+ <td style="text-align: right">b</td>
725
+ <td style="text-align: center">c</td>
726
+ </tr>
727
+ </tbody>
728
+ </table>
729
+ EOS
730
+ end
692
731
  end
693
- end
694
732
 
695
- context "with task list in code block" do
696
- let(:markdown) do
697
- <<-EOS.strip_heredoc
698
- ```
699
- - [ ] a
700
- - [x] b
701
- ```
702
- EOS
703
- end
733
+ context "with footenotes syntax" do
734
+ let(:markdown) do
735
+ <<-EOS.strip_heredoc
736
+ [^1]
737
+ [^1]: test
738
+ EOS
739
+ end
704
740
 
705
- it "does not replace checkbox" do
706
- should eq <<-EOS.strip_heredoc
707
- <div class="code-frame" data-lang="text"><div class="highlight"><pre><span></span>- [ ] a
708
- - [x] b
709
- </pre></div></div>
710
- EOS
711
- end
712
- end
741
+ it "generates footnotes elements" do
742
+ should eq <<-EOS.strip_heredoc
743
+ <p><sup id="fnref1"><a href="#fn1" rel="footnote" title="test">1</a></sup></p>
713
744
 
714
- context "with empty line between task list" do
715
- let(:markdown) do
716
- <<-EOS.strip_heredoc
717
- - [ ] a
745
+ <div class="footnotes">
746
+ <hr>
747
+ <ol>
718
748
 
719
- - [x] b
720
- EOS
721
- end
749
+ <li id="fn1">
750
+ <p>test <a href="#fnref1">↩</a></p>
751
+ </li>
722
752
 
723
- it "inserts checkbox" do
724
- should eq <<-EOS.strip_heredoc
725
- <ul>
726
- <li class="task-list-item"><p><input type="checkbox" class="task-list-item-checkbox" disabled>a</p></li>
727
- <li class="task-list-item"><p><input type="checkbox" class="task-list-item-checkbox" checked disabled>b</p></li>
728
- </ul>
729
- EOS
753
+ </ol>
754
+ </div>
755
+ EOS
756
+ end
730
757
  end
731
- end
732
758
 
733
- context "with empty list" do
734
- let(:markdown) do
735
- "- \n"
736
- end
759
+ context "with manually written link inside of <sup> tag" do
760
+ let(:markdown) do
761
+ <<-EOS.strip_heredoc
762
+ <sup>[Example](http://example.com/)</sup>
763
+ EOS
764
+ end
737
765
 
738
- it "inserts checkbox" do
739
- should eq <<-EOS.strip_heredoc
740
- <ul>
741
- <li>
742
- </ul>
743
- EOS
766
+ it "does not confuse the structure with automatically generated footnote reference" do
767
+ should eq <<-EOS.strip_heredoc
768
+ <p><sup><a href="http://example.com/">Example</a></sup></p>
769
+ EOS
770
+ end
744
771
  end
745
- end
746
772
 
747
- context "with text-aligned table" do
748
- let(:markdown) do
749
- <<-EOS.strip_heredoc
750
- | a | b | c |
751
- |:---|---:|:---:|
752
- | a | b | c |
753
- EOS
754
- end
755
-
756
- it "creates table element with text-align style" do
757
- should eq <<-EOS.strip_heredoc
758
- <table>
759
- <thead>
760
- <tr>
761
- <th style="text-align: left">a</th>
762
- <th style="text-align: right">b</th>
763
- <th style="text-align: center">c</th>
764
- </tr>
765
- </thead>
766
- <tbody>
767
- <tr>
768
- <td style="text-align: left">a</td>
769
- <td style="text-align: right">b</td>
770
- <td style="text-align: center">c</td>
771
- </tr>
772
- </tbody>
773
- </table>
774
- EOS
773
+ context "with manually written <a> tag with strange href inside of <sup> tag" do
774
+ let(:markdown) do
775
+ <<-EOS.strip_heredoc
776
+ <sup><a href="#foo.1">Link</a></sup>
777
+ EOS
778
+ end
779
+
780
+ it "does not confuse the structure with automatically generated footnote reference" do
781
+ should eq <<-EOS.strip_heredoc
782
+ <p><sup><a href="#foo.1">Link</a></sup></p>
783
+ EOS
784
+ end
775
785
  end
776
- end
777
786
 
778
- context "with footenotes syntax" do
779
- let(:markdown) do
780
- <<-EOS.strip_heredoc
781
- [^1]
782
- [^1]: test
783
- EOS
787
+ context "with markdown: { footnotes: false } context" do
788
+ before do
789
+ context[:markdown] = { footnotes: false }
790
+ end
791
+
792
+ let(:markdown) do
793
+ <<-EOS.strip_heredoc
794
+ [^1]
795
+ [^1]: test
796
+ EOS
797
+ end
798
+
799
+ it "does not generate footnote elements" do
800
+ should eq <<-EOS.strip_heredoc
801
+ <p><a href="test">^1</a></p>
802
+ EOS
803
+ end
784
804
  end
785
805
 
786
- it "generates footnotes elements" do
787
- should eq <<-EOS.strip_heredoc
788
- <p><sup id="fnref1"><a href="#fn1" rel="footnote" title="test">1</a></sup></p>
806
+ context "with emoji_names and emoji_url_generator context" do
807
+ before do
808
+ context[:emoji_names] = %w(foo o)
789
809
 
790
- <div class="footnotes">
791
- <hr>
792
- <ol>
810
+ context[:emoji_url_generator] = proc do |emoji_name|
811
+ "https://example.com/foo.png" if emoji_name == "foo"
812
+ end
813
+ end
793
814
 
794
- <li id="fn1">
795
- <p>test <a href="#fnref1">↩</a></p>
796
- </li>
815
+ let(:markdown) do
816
+ <<-EOS.strip_heredoc
817
+ :foo: :o: :x:
818
+ EOS
819
+ end
797
820
 
798
- </ol>
799
- </div>
800
- EOS
801
- end
802
- end
821
+ it "replaces only the specified emoji names with img elements with custom URL" do
822
+ should include(
823
+ '<img class="emoji" title=":foo:" alt=":foo:" src="https://example.com/foo.png"',
824
+ '<img class="emoji" title=":o:" alt=":o:" src="/images/emoji/unicode/2b55.png"'
825
+ )
803
826
 
804
- context "with manually written link inside of <sup> tag" do
805
- let(:markdown) do
806
- <<-EOS.strip_heredoc
807
- <sup>[Example](http://example.com/)</sup>
808
- EOS
827
+ should_not include(
828
+ '<img class="emoji" title=":x:" alt=":x:"'
829
+ )
830
+ end
809
831
  end
810
832
 
811
- it "does not confuse the structure with automatically generated footnote reference" do
812
- should eq <<-EOS.strip_heredoc
813
- <p><sup><a href="http://example.com/">Example</a></sup></p>
814
- EOS
815
- end
816
- end
833
+ context "with internal URL" do
834
+ let(:markdown) do
835
+ "http://qiita.com/?a=b"
836
+ end
817
837
 
818
- context "with manually written <a> tag with strange href inside of <sup> tag" do
819
- let(:markdown) do
820
- <<-EOS.strip_heredoc
821
- <sup><a href="#foo.1">Link</a></sup>
822
- EOS
823
- end
838
+ let(:context) do
839
+ { hostname: "qiita.com" }
840
+ end
824
841
 
825
- it "does not confuse the structure with automatically generated footnote reference" do
826
- should eq <<-EOS.strip_heredoc
827
- <p><sup><a href="#foo.1">Link</a></sup></p>
828
- EOS
842
+ it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
843
+ should eq(
844
+ '<p><a href="http://qiita.com/?a=b" class="autolink">' \
845
+ "http://qiita.com/?a=b</a></p>\n"
846
+ )
847
+ end
829
848
  end
830
- end
831
849
 
832
- context "with markdown: { footnotes: false } context" do
833
- before do
834
- context[:markdown] = { footnotes: false }
835
- end
850
+ context "with external URL" do
851
+ let(:markdown) do
852
+ "http://external.com/?a=b"
853
+ end
836
854
 
837
- let(:markdown) do
838
- <<-EOS.strip_heredoc
839
- [^1]
840
- [^1]: test
841
- EOS
842
- end
855
+ let(:context) do
856
+ { hostname: "qiita.com" }
857
+ end
843
858
 
844
- it "does not generate footnote elements" do
845
- should eq <<-EOS.strip_heredoc
846
- <p><a href="test">^1</a></p>
847
- EOS
859
+ it "creates link which has rel='nofollow noopener' and target='_blank'" do
860
+ should eq(
861
+ '<p><a href="http://external.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
862
+ "http://external.com/?a=b</a></p>\n"
863
+ )
864
+ end
848
865
  end
849
- end
850
866
 
851
- context "with data-attributes" do
852
- let(:markdown) do
853
- <<-EOS.strip_heredoc
854
- <div data-a="b"></div>
855
- EOS
856
- end
867
+ context "with internal anchor tag" do
868
+ let(:markdown) do
869
+ '<a href="http://qiita.com/?a=b">foobar</a>'
870
+ end
857
871
 
858
- it "sanitizes data-attributes" do
859
- should eq <<-EOS.strip_heredoc
860
- <div></div>
861
- EOS
862
- end
863
- end
872
+ let(:context) do
873
+ { hostname: "qiita.com" }
874
+ end
864
875
 
865
- context "with data-attributes and :script option" do
866
- before do
867
- context[:script] = true
876
+ it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
877
+ should eq(
878
+ "<p><a href=\"http://qiita.com/?a=b\">foobar</a></p>\n"
879
+ )
880
+ end
868
881
  end
869
882
 
870
- let(:markdown) do
871
- <<-EOS.strip_heredoc
872
- <div data-a="b"></div>
873
- EOS
874
- end
883
+ context "with external anchor tag" do
884
+ let(:markdown) do
885
+ '<a href="http://external.com/?a=b">foobar</a>'
886
+ end
887
+
888
+ let(:context) do
889
+ { hostname: "qiita.com" }
890
+ end
875
891
 
876
- it "does not sanitize data-attributes" do
877
- should eq <<-EOS.strip_heredoc
878
- <div data-a="b"></div>
879
- EOS
892
+ it "creates link which has rel='nofollow noopener' and target='_blank'" do
893
+ should eq(
894
+ "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
895
+ )
896
+ end
880
897
  end
881
- end
882
898
 
883
- context "with emoji_names and emoji_url_generator context" do
884
- before do
885
- context[:emoji_names] = %w(foo o)
899
+ context "with external URL which ends with the hostname parameter" do
900
+ let(:markdown) do
901
+ "http://qqqqqqiita.com/?a=b"
902
+ end
886
903
 
887
- context[:emoji_url_generator] = proc do |emoji_name|
888
- "https://example.com/foo.png" if emoji_name == "foo"
904
+ let(:context) do
905
+ { hostname: "qiita.com" }
889
906
  end
890
- end
891
907
 
892
- let(:markdown) do
893
- <<-EOS.strip_heredoc
894
- :foo: :o: :x:
895
- EOS
908
+ it "creates link which has rel='nofollow noopener' and target='_blank'" do
909
+ should eq(
910
+ '<p><a href="http://qqqqqqiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
911
+ "http://qqqqqqiita.com/?a=b</a></p>\n"
912
+ )
913
+ end
896
914
  end
897
915
 
898
- it "replaces only the specified emoji names with img elements with custom URL" do
899
- should include(
900
- '<img class="emoji" title=":foo:" alt=":foo:" src="https://example.com/foo.png"',
901
- '<img class="emoji" title=":o:" alt=":o:" src="/images/emoji/unicode/2b55.png"'
902
- )
916
+ context "with external anchor tag which ends with the hostname parameter" do
917
+ let(:markdown) do
918
+ '<a href="http://qqqqqqiita.com/?a=b">foobar</a>'
919
+ end
903
920
 
904
- should_not include(
905
- '<img class="emoji" title=":x:" alt=":x:"'
906
- )
907
- end
908
- end
921
+ let(:context) do
922
+ { hostname: "qiita.com" }
923
+ end
909
924
 
910
- context "with internal URL" do
911
- let(:markdown) do
912
- "http://qiita.com/?a=b"
925
+ it "creates link which has rel='nofollow noopener' and target='_blank'" do
926
+ should eq(
927
+ "<p><a href=\"http://qqqqqqiita.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
928
+ )
929
+ end
913
930
  end
914
931
 
915
- let(:context) do
916
- { hostname: "qiita.com" }
917
- end
932
+ context "with sub-domain URL of hostname parameter" do
933
+ let(:markdown) do
934
+ "http://sub.qiita.com/?a=b"
935
+ end
918
936
 
919
- it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
920
- should eq(
921
- '<p><a href="http://qiita.com/?a=b" class="autolink">' \
922
- "http://qiita.com/?a=b</a></p>\n"
923
- )
924
- end
925
- end
937
+ let(:context) do
938
+ { hostname: "qiita.com" }
939
+ end
926
940
 
927
- context "with external URL" do
928
- let(:markdown) do
929
- "http://external.com/?a=b"
941
+ it "creates link which has rel='nofollow noopener' and target='_blank'" do
942
+ should eq(
943
+ '<p><a href="http://sub.qiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
944
+ "http://sub.qiita.com/?a=b</a></p>\n"
945
+ )
946
+ end
930
947
  end
931
948
 
932
- let(:context) do
933
- { hostname: "qiita.com" }
934
- end
949
+ context "with external anchor tag which has rel attribute" do
950
+ let(:markdown) do
951
+ '<a href="http://external.com/?a=b" rel="url">foobar</a>'
952
+ end
935
953
 
936
- it "creates link which has rel='nofollow noopener' and target='_blank'" do
937
- should eq(
938
- '<p><a href="http://external.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
939
- "http://external.com/?a=b</a></p>\n"
940
- )
941
- end
942
- end
954
+ let(:context) do
955
+ { hostname: "qiita.com" }
956
+ end
943
957
 
944
- context "with internal anchor tag" do
945
- let(:markdown) do
946
- '<a href="http://qiita.com/?a=b">foobar</a>'
958
+ it "creates link which has rel='nofollow noopener' and target='_blank', and rel value is overwritten" do
959
+ should eq(
960
+ "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
961
+ )
962
+ end
947
963
  end
948
964
 
949
- let(:context) do
950
- { hostname: "qiita.com" }
951
- end
965
+ context "with blockquote syntax" do
966
+ let(:markdown) do
967
+ "> foo"
968
+ end
952
969
 
953
- it "creates link which does not have rel='nofollow noopener' and target='_blank'" do
954
- should eq(
955
- "<p><a href=\"http://qiita.com/?a=b\">foobar</a></p>\n"
956
- )
970
+ it "does not confuse it with HTML tag angle brackets" do
971
+ should eq "<blockquote>\n<p>foo</p>\n</blockquote>\n"
972
+ end
957
973
  end
958
974
  end
959
975
 
960
- context "with external anchor tag" do
961
- let(:markdown) do
962
- '<a href="http://external.com/?a=b">foobar</a>'
963
- end
976
+ shared_examples_for "script element" do |allowed:|
977
+ context "with script element" do
978
+ let(:markdown) do
979
+ <<-EOS.strip_heredoc
980
+ <script>alert(1)</script>
981
+ EOS
982
+ end
964
983
 
965
- let(:context) do
966
- { hostname: "qiita.com" }
984
+ if allowed
985
+ it "allows script element" do
986
+ should eq markdown
987
+ end
988
+
989
+ context "and allowed attributes" do
990
+ let(:markdown) do
991
+ <<-EOS.strip_heredoc
992
+ <p><script async data-a="b" type="text/javascript">alert(1)</script></p>
993
+ EOS
994
+ end
995
+
996
+ it "allows data-attributes" do
997
+ should eq markdown
998
+ end
999
+ end
1000
+ else
1001
+ it "removes script element" do
1002
+ should eq "\n"
1003
+ end
1004
+ end
967
1005
  end
1006
+ end
968
1007
 
969
- it "creates link which has rel='nofollow noopener' and target='_blank'" do
970
- should eq(
971
- "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
972
- )
1008
+ shared_examples_for "malicious script in filename" do |allowed:|
1009
+ context "with malicious script in filename" do
1010
+ let(:markdown) do
1011
+ <<-EOS.strip_heredoc
1012
+ ```js:test<script>alert(1)</script>
1013
+ 1
1014
+ ```
1015
+ EOS
1016
+ end
1017
+
1018
+ if allowed
1019
+ it "does not sanitize script element" do
1020
+ should eq <<-EOS.strip_heredoc
1021
+ <div class="code-frame" data-lang="js">
1022
+ <div class="code-lang"><span class="bold">test<script>alert(1)</script></span></div>
1023
+ <div class="highlight"><pre><span></span><span class="mi">1</span>
1024
+ </pre></div>
1025
+ </div>
1026
+ EOS
1027
+ end
1028
+ else
1029
+ it "sanitizes script element" do
1030
+ should eq <<-EOS.strip_heredoc
1031
+ <div class="code-frame" data-lang="js">
1032
+ <div class="code-lang"><span class="bold">test</span></div>
1033
+ <div class="highlight"><pre><span></span><span class="mi">1</span>
1034
+ </pre></div>
1035
+ </div>
1036
+ EOS
1037
+ end
1038
+ end
973
1039
  end
974
1040
  end
975
1041
 
976
- context "with external URL which ends with the hostname parameter" do
977
- let(:markdown) do
978
- "http://qqqqqqiita.com/?a=b"
979
- end
1042
+ shared_examples_for "iframe element" do |allowed:|
1043
+ context "with iframe" do
1044
+ let(:markdown) do
1045
+ <<-EOS.strip_heredoc
1046
+ <iframe width="1" height="2" src="//example.com" frameborder="0" allowfullscreen></iframe>
1047
+ EOS
1048
+ end
980
1049
 
981
- let(:context) do
982
- { hostname: "qiita.com" }
1050
+ if allowed
1051
+ it "allows iframe with some attributes" do
1052
+ should eq markdown
1053
+ end
1054
+ else
1055
+ it "sanitizes iframe element" do
1056
+ should eq "\n"
1057
+ end
1058
+ end
983
1059
  end
1060
+ end
1061
+
1062
+ shared_examples_for "data-attributes" do |allowed:|
1063
+ context "with data-attributes" do
1064
+ let(:markdown) do
1065
+ <<-EOS.strip_heredoc
1066
+ <div data-a="b"></div>
1067
+ EOS
1068
+ end
984
1069
 
985
- it "creates link which has rel='nofollow noopener' and target='_blank'" do
986
- should eq(
987
- '<p><a href="http://qqqqqqiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
988
- "http://qqqqqqiita.com/?a=b</a></p>\n"
989
- )
1070
+ if allowed
1071
+ it "does not sanitize data-attributes" do
1072
+ should eq <<-EOS.strip_heredoc
1073
+ <div data-a="b"></div>
1074
+ EOS
1075
+ end
1076
+ else
1077
+ it "sanitizes data-attributes" do
1078
+ should eq <<-EOS.strip_heredoc
1079
+ <div></div>
1080
+ EOS
1081
+ end
1082
+ end
990
1083
  end
991
1084
  end
992
1085
 
993
- context "with external anchor tag which ends with the hostname parameter" do
994
- let(:markdown) do
995
- '<a href="http://qqqqqqiita.com/?a=b">foobar</a>'
996
- end
1086
+ shared_examples_for "class attribute" do |allowed:|
1087
+ context "with class attribute for general tags" do
1088
+ let(:markdown) do
1089
+ '<i class="fa fa-user"></i>user'
1090
+ end
997
1091
 
998
- let(:context) do
999
- { hostname: "qiita.com" }
1092
+ if allowed
1093
+ it "does not sanitize the attribute" do
1094
+ should eq "<p><i class=\"fa fa-user\"></i>user</p>\n"
1095
+ end
1096
+ else
1097
+ it "sanitizes the attribute" do
1098
+ should eq "<p><i></i>user</p>\n"
1099
+ end
1100
+ end
1000
1101
  end
1001
1102
 
1002
- it "creates link which has rel='nofollow noopener' and target='_blank'" do
1003
- should eq(
1004
- "<p><a href=\"http://qqqqqqiita.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
1005
- )
1103
+ context "with class attribute for <a> tag" do
1104
+ let(:markdown) do
1105
+ <<-EOS.strip_heredoc
1106
+ <a href="foo" class="malicious-class">foo</a>
1107
+ http://qiita.com/
1108
+ EOS
1109
+ end
1110
+
1111
+ if allowed
1112
+ it "does not sanitize the classes" do
1113
+ should eq <<-EOS.strip_heredoc
1114
+ <p><a href="foo" class="malicious-class">foo</a><br>
1115
+ <a href="http://qiita.com/" class="autolink" rel="nofollow noopener" target="_blank">http://qiita.com/</a></p>
1116
+ EOS
1117
+ end
1118
+ else
1119
+ it "sanitizes classes except `autolink`" do
1120
+ should eq <<-EOS.strip_heredoc
1121
+ <p><a href="foo" class="">foo</a><br>
1122
+ <a href="http://qiita.com/" class="autolink" rel="nofollow noopener" target="_blank">http://qiita.com/</a></p>
1123
+ EOS
1124
+ end
1125
+ end
1006
1126
  end
1007
1127
  end
1008
1128
 
1009
- context "with sub-domain URL of hostname parameter" do
1010
- let(:markdown) do
1011
- "http://sub.qiita.com/?a=b"
1129
+ context "without script and strict context" do
1130
+ let(:context) do
1131
+ super().merge(script: false, strict: false)
1012
1132
  end
1013
1133
 
1134
+ include_examples "basic markdown syntax"
1135
+ include_examples "script element", allowed: false
1136
+ include_examples "malicious script in filename", allowed: false
1137
+ include_examples "iframe element", allowed: false
1138
+ include_examples "data-attributes", allowed: false
1139
+ include_examples "class attribute", allowed: true
1140
+ end
1141
+
1142
+ context "with script context" do
1014
1143
  let(:context) do
1015
- { hostname: "qiita.com" }
1144
+ super().merge(script: true, strict: false)
1016
1145
  end
1017
1146
 
1018
- it "creates link which has rel='nofollow noopener' and target='_blank'" do
1019
- should eq(
1020
- '<p><a href="http://sub.qiita.com/?a=b" class="autolink" rel="nofollow noopener" target="_blank">' \
1021
- "http://sub.qiita.com/?a=b</a></p>\n"
1022
- )
1023
- end
1147
+ include_examples "basic markdown syntax"
1148
+ include_examples "script element", allowed: true
1149
+ include_examples "malicious script in filename", allowed: true
1150
+ include_examples "iframe element", allowed: true
1151
+ include_examples "data-attributes", allowed: true
1152
+ include_examples "class attribute", allowed: true
1024
1153
  end
1025
1154
 
1026
- context "with external anchor tag which has rel attribute" do
1027
- let(:markdown) do
1028
- '<a href="http://external.com/?a=b" rel="url">foobar</a>'
1155
+ context "with strict context" do
1156
+ let(:context) do
1157
+ super().merge(script: false, strict: true)
1029
1158
  end
1030
1159
 
1160
+ include_examples "basic markdown syntax"
1161
+ include_examples "script element", allowed: false
1162
+ include_examples "malicious script in filename", allowed: false
1163
+ include_examples "iframe element", allowed: false
1164
+ include_examples "data-attributes", allowed: false
1165
+ include_examples "class attribute", allowed: false
1166
+ end
1167
+
1168
+ context "with script and strict context" do
1031
1169
  let(:context) do
1032
- { hostname: "qiita.com" }
1170
+ super().merge(script: true, strict: true)
1033
1171
  end
1034
1172
 
1035
- it "creates link which has rel='nofollow noopener' and target='_blank', and rel value is overwritten" do
1036
- should eq(
1037
- "<p><a href=\"http://external.com/?a=b\" rel=\"nofollow noopener\" target=\"_blank\">foobar</a></p>\n"
1038
- )
1039
- end
1173
+ include_examples "basic markdown syntax"
1174
+ include_examples "script element", allowed: false
1175
+ include_examples "malicious script in filename", allowed: true
1176
+ include_examples "iframe element", allowed: false
1177
+ include_examples "data-attributes", allowed: false
1178
+ include_examples "class attribute", allowed: false
1040
1179
  end
1041
1180
  end
1042
1181
  end