Skip to content

Commit

Permalink
Merge pull request #1204 from basecamp/dom-purify-1-3
Browse files Browse the repository at this point in the history
Dom purify 1 3
  • Loading branch information
djmb authored Dec 9, 2024
2 parents fc2a4b9 + 6c263d2 commit d0a0fb1
Show file tree
Hide file tree
Showing 18 changed files with 616 additions and 27 deletions.
1 change: 1 addition & 0 deletions .blade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ load_paths:
- test/vendor
- assets
- polyfills
- vendor
- src

logical_paths:
Expand Down
1 change: 1 addition & 0 deletions assets/trix-core.coffee
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#= require trix/banner
#= require trix/index
#= require vendor
1 change: 1 addition & 0 deletions assets/trix.coffee
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#= require trix/banner
#= require polyfills
#= require trix/index
#= require vendor
1 change: 1 addition & 0 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"assets",
"bin",
"polyfills",
"vendor",
"src",
"test",
"*.md",
Expand Down
20 changes: 13 additions & 7 deletions dist/trix-core.js

Large diffs are not rendered by default.

22 changes: 14 additions & 8 deletions dist/trix.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
"url": "https://github.com/basecamp/trix/issues"
},
"homepage": "https://trix-editor.org/",
"dependencies": {
"dompurify": "^3.2.0"
},
"devDependencies": {
"@babel/preset-env": "^7.26.0",
"svgo": "^0.6.1"
}
}
1 change: 1 addition & 0 deletions src/trix/inspector/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#= require ./control_element
#= require_tree ./templates
#= require_tree ./views
#= require_tree ./vendor

Trix.Inspector =
views: []
Expand Down
10 changes: 2 additions & 8 deletions src/trix/models/html_parser.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ class Trix.HTMLParser extends Trix.BasicObject
parse: ->
try
@createHiddenContainer()
html = Trix.HTMLSanitizer.sanitize(@html).getHTML()
@containerElement.innerHTML = html
Trix.HTMLSanitizer.setHTML @containerElement, @html
walker = walkTree(@containerElement, usingFilter: nodeFilter)
@processNode(walker.currentNode) while walker.nextNode()
@translateBlockElementMarginsToNewlines()
Expand Down Expand Up @@ -238,12 +237,7 @@ class Trix.HTMLParser extends Trix.BasicObject

parseTrixDataAttribute = (element, name) ->
try
data = JSON.parse(element.getAttribute("data-trix-#{name}"))

if data.contentType == "text/html" and data.content
data.content = HTMLSanitizer.sanitize(data.content).getHTML()

data
JSON.parse element.getAttribute("data-trix-#{name}")
catch
{}

Expand Down
7 changes: 7 additions & 0 deletions src/trix/models/html_sanitizer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ class Trix.HTMLSanitizer extends Trix.BasicObject
DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ")
DEFAULT_FORBIDDEN_ELEMENTS = "script iframe noscript".split(" ")

@setHTML = (element, html) ->
sanitizer = new this html
sanitizedElement = sanitizer.sanitize()
sanitizedHtml = if sanitizedElement.getHTML? then sanitizedElement.getHTML() else sanitizedElement.outerHTML
element.innerHTML = sanitizedHtml

@sanitize: (html, options) ->
sanitizer = new this html, options
sanitizer.sanitize()
Expand All @@ -19,6 +25,7 @@ class Trix.HTMLSanitizer extends Trix.BasicObject
sanitize: ->
@sanitizeElements()
@normalizeListElementNesting()
DOMPurify.sanitize @body, ADD_ATTR: ["language"], RETURN_DOM: true

getHTML: ->
@body.innerHTML
Expand Down
4 changes: 2 additions & 2 deletions src/trix/views/attachment_view.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Trix.AttachmentView extends Trix.ObjectView
figure.appendChild(innerElement)

if @attachment.hasContent()
innerElement.innerHTML = @attachment.getContent()
Trix.HTMLSanitizer.setHTML innerElement, @attachment.getContent()
else
innerElement.appendChild(node) for node in @createContentNodes()

Expand Down Expand Up @@ -118,5 +118,5 @@ class Trix.AttachmentView extends Trix.ObjectView

htmlContainsTagName = (html, tagName) ->
div = makeElement("div")
div.innerHTML = html ? ""
Trix.HTMLSanitizer.setHTML div, html or ""
div.querySelector(tagName)
1 change: 1 addition & 0 deletions test/.blade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ load_paths:
- vendor
- ../assets
- ../polyfills
- ../vendor
- ../src

build:
Expand Down
26 changes: 25 additions & 1 deletion test/src/system/pasting_test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,31 @@ testGroup "Pasting", template: "editor_empty", ->
window.unsanitized = []
pasteData =
"text/plain": "x",
"text/html": "copy<div data-trix-attachment=\"{&quot;contentType&quot;:&quot;text/html&quot;,&quot;content&quot;:&quot;&lt;img src=1 onerror=window.unsanitized.push(1)&gt;HELLO123&quot;}\"></div>me"
"text/html": "copy<div data-trix-attachment=\"{&quot;contentType&quot;:&quot;text/anything&quot;,&quot;content&quot;:&quot;&lt;img src=1 onerror=window.unsanitized.push(1)&gt;HELLO123&quot;}\"></div>me"

pasteContent pasteData, ->
after 20, ->
assert.deepEqual window.unsanitized, []
delete window.unsanitized
done()

test "paste data-trix-attachment encoded mathml", (done) ->
window.unsanitized = []
pasteData =
"text/plain": "x",
"text/html": "copy<div data-trix-attachment=\"{&quot;contentType&quot;:&quot;text/html5&quot;,&quot;content&quot;:&quot;&lt;math&gt;&lt;mtext&gt;&lt;table&gt;&lt;mglyph&gt;&lt;style&gt;&lt;img src=x onerror=alert()&gt;&lt;/style&gt;XSS POC&quot;}\"></div>me"

pasteContent pasteData, ->
after 20, ->
assert.deepEqual window.unsanitized, []
delete window.unsanitized
done()

test "paste data-trix-attachment encoded embed", (done) ->
window.unsanitized = []
pasteData =
"text/plain": "x",
"text/html": "copy<div data-trix-attachment=\"{&quot;contentType&quot;:&quot;text/html5&quot;,&quot;content&quot;:&quot;&lt;embed src='javascript:alert(1)'&gt;XSS POC&quot;}\"></div>me"

pasteContent pasteData, ->
after 20, ->
Expand Down
2 changes: 1 addition & 1 deletion test/src/test_helpers/fixtures/fixtures.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ removeWhitespace = (string) ->
document: new Trix.Document [new Trix.Block text]

"content attachment": do ->
content = """<blockquote class="twitter-tweet" data-cards="hidden"><p>ruby-build 20150413 is out, with definitions for 2.2.2, 2.1.6, and 2.0.0-p645 to address recent security issues: <a href="https://t.co/YEwV6NtRD8">https://t.co/YEwV6NtRD8</a></p>&mdash; Sam Stephenson (@sstephenson) <a href="https://twitter.com/sstephenson/status/587715996783218688">April 13, 2015</a></blockquote>"""
content = """<blockquote class="twitter-tweet"><p>ruby-build 20150413 is out, with definitions for 2.2.2, 2.1.6, and 2.0.0-p645 to address recent security issues: <a href="https://t.co/YEwV6NtRD8">https://t.co/YEwV6NtRD8</a></p>&mdash; Sam Stephenson (@sstephenson) <a href="https://twitter.com/sstephenson/status/587715996783218688">April 13, 2015</a></blockquote>"""
href = "https://twitter.com/sstephenson/status/587715996783218688"
contentType = "embed/twitter"

Expand Down
3 changes: 3 additions & 0 deletions vendor/dompurify-banner/index.coffee.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
###
<%= depend_on_asset("dompurify-banner.txt").to_s.chomp %>
###
4 changes: 4 additions & 0 deletions vendor/dompurify-banner/index.txt.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DOMPurify 3.2.1
Copyright © Cure53 and other contributors
Released under the Apache license 2.0 and Mozilla Public License 2.0
github.com/cure53/DOMPurify/blob/3.2.1/LICENSE
Loading

0 comments on commit d0a0fb1

Please sign in to comment.