Skip to content

Commit 684a970

Browse files
authored
Unescape HTML entities (mastodon#24019)
1 parent 9dfe2db commit 684a970

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

app/lib/plain_text_formatter.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def to_s
1818
if local?
1919
text
2020
else
21-
strip_tags(insert_newlines).chomp
21+
html_entities.decode(strip_tags(insert_newlines)).chomp
2222
end
2323
end
2424

@@ -27,4 +27,8 @@ def to_s
2727
def insert_newlines
2828
text.gsub(NEWLINE_TAGS_RE) { |match| "#{match}\n" }
2929
end
30+
31+
def html_entities
32+
HTMLEntities.new
33+
end
3034
end

spec/lib/plain_text_formatter_spec.rb

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,71 @@
66
describe '#to_s' do
77
subject { described_class.new(status.text, status.local?).to_s }
88

9-
context 'given a post with local status' do
9+
context 'when status is local' do
1010
let(:status) { Fabricate(:status, text: '<p>a text by a nerd who uses an HTML tag in text</p>', uri: nil) }
1111

1212
it 'returns the raw text' do
1313
expect(subject).to eq '<p>a text by a nerd who uses an HTML tag in text</p>'
1414
end
1515
end
1616

17-
context 'given a post with remote status' do
17+
context 'when status is remote' do
1818
let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') }
19-
let(:status) { Fabricate(:status, account: remote_account, text: '<p>Hello</p><script>alert("Hello")</script>') }
2019

21-
it 'returns tag-stripped text' do
22-
expect(subject).to eq 'Hello'
20+
context 'when text contains inline HTML tags' do
21+
let(:status) { Fabricate(:status, account: remote_account, text: '<b>Lorem</b> <em>ipsum</em>') }
22+
23+
it 'strips the tags' do
24+
expect(subject).to eq 'Lorem ipsum'
25+
end
26+
end
27+
28+
context 'when text contains <p> tags' do
29+
let(:status) { Fabricate(:status, account: remote_account, text: '<p>Lorem</p><p>ipsum</p>') }
30+
31+
it 'inserts a newline' do
32+
expect(subject).to eq "Lorem\nipsum"
33+
end
34+
end
35+
36+
context 'when text contains a single <br> tag' do
37+
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem<br>ipsum') }
38+
39+
it 'inserts a newline' do
40+
expect(subject).to eq "Lorem\nipsum"
41+
end
42+
end
43+
44+
context 'when text contains consecutive <br> tag' do
45+
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem<br><br><br>ipsum') }
46+
47+
it 'inserts a single newline' do
48+
expect(subject).to eq "Lorem\nipsum"
49+
end
50+
end
51+
52+
context 'when text contains HTML entity' do
53+
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem &amp; ipsum &#x2764;') }
54+
55+
it 'unescapes the entity' do
56+
expect(subject).to eq 'Lorem & ipsum ❤'
57+
end
58+
end
59+
60+
context 'when text contains <script> tag' do
61+
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem <script> alert("Booh!") </script>ipsum') }
62+
63+
it 'strips the tag and its contents' do
64+
expect(subject).to eq 'Lorem ipsum'
65+
end
66+
end
67+
68+
context 'when text contains an HTML comment tags' do
69+
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem <!-- Booh! -->ipsum') }
70+
71+
it 'strips the comment' do
72+
expect(subject).to eq 'Lorem ipsum'
73+
end
2374
end
2475
end
2576
end

0 commit comments

Comments
 (0)