Skip to content

Commit ee51732

Browse files
authored
Merge pull request #1054 from oskarhane/htmlentities
Fix HTML rendering issues on query results
2 parents c0b14fe + f4d47a4 commit ee51732

File tree

10 files changed

+121
-22
lines changed

10 files changed

+121
-22
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@
147147
"dateformat": "^3.0.3",
148148
"deepmerge": "^2.1.1",
149149
"dnd-core": "^2.5.1",
150-
"dompurify": "^2.0.7",
151150
"faker": "^4.1.0",
152151
"file-saver": "^1.3.8",
153152
"firebase": "^5.8.3",
@@ -174,6 +173,7 @@
174173
"redux-observable": "^0.16.0",
175174
"regenerator-runtime": "^0.13.2",
176175
"rxjs": "^5.4.2",
176+
"sanitize-html": "^1.21.1",
177177
"save-as": "^0.1.7",
178178
"semantic-ui-react": "^0.88.0",
179179
"semver": "^5.5.0",

src/browser/components/clickable-urls.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@
1616
*/
1717

1818
import React from 'react'
19-
import { sanitize } from 'dompurify'
19+
import { HTMLEntities } from 'services/santize.utils'
2020

2121
export default function ClickableUrls({ text }) {
2222
return (
2323
<span
2424
dangerouslySetInnerHTML={{
25-
__html: convertUrlsToHrefTags(sanitize(text))
25+
__html: convertUrlsToHrefTags(HTMLEntities(text))
2626
}}
2727
/>
2828
)
2929
}
3030

3131
// credits to https://www.regextester.com/96504
32-
const URL_REGEX = /(([a-zA-Z]+):\/\/)(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()[\]{};:'".,<>?«»]))?/gi
32+
const URL_REGEX = /(([a-zA-Z]+):\/\/)(?:(?:[^\s()<>"]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()[\]{};:'".,<>?«»]))?/gi
3333

3434
/**
3535
* Finds all urls in a string and wraps them in <a target="_blank" />

src/browser/components/clickable-urls.test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
*
1616
*/
1717

18+
import React from 'react'
19+
import { sanitizeQueryResult } from 'services/santize.utils'
1820
import { convertUrlsToHrefTags } from './clickable-urls'
21+
import { render } from '@testing-library/react'
22+
import ClickableUrls from './clickable-urls'
1923

2024
describe('clickable-urls', () => {
2125
describe('convertUrlsToHrefTags', () => {
@@ -86,4 +90,25 @@ describe('clickable-urls', () => {
8690
expect(convertUrlsToHrefTags(textBlock)).toBe(expectedTextBlock)
8791
})
8892
})
93+
describe('ClickableUrls', () => {
94+
it('renders escaped HTML except for generated tags', () => {
95+
const text = `Hello, my <strong>name</strong> is <a href="http://twitter.com/neo4j" onClick="alert(1)">Neo4j</a>.`
96+
97+
const { container } = render(<ClickableUrls text={text} />)
98+
expect(container).toMatchInlineSnapshot(`
99+
<div>
100+
<span>
101+
Hello, my &lt;strong&gt;name&lt;/strong&gt; is &lt;a href="
102+
<a
103+
href="http://twitter.com/neo4j"
104+
target="_blank"
105+
>
106+
http://twitter.com/neo4j
107+
</a>
108+
" onclick="alert(1)"&gt;Neo4j&lt;/a&gt;.
109+
</span>
110+
</div>
111+
`)
112+
})
113+
})
89114
})

src/browser/modules/Stream/CypherFrame/TableView.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import React, { Component } from 'react'
2222
import { v4 } from 'uuid'
2323
import neo4j from 'neo4j-driver'
24-
import { sanitize } from 'dompurify'
24+
import { HTMLEntities } from 'services/santize.utils'
2525

2626
import {
2727
StyledStatsBar,
@@ -69,7 +69,7 @@ export const renderObject = entry => {
6969
<StyledJsonPre
7070
dangerouslySetInnerHTML={{
7171
__html: convertUrlsToHrefTags(
72-
sanitize(stringifyMod(entry, stringModifier, true))
72+
HTMLEntities(stringifyMod(entry, stringModifier, true))
7373
)
7474
}}
7575
/>

src/browser/modules/Stream/CypherFrame/TableView.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ describe('TableViews', () => {
4646
// Then
4747
expect(container).toMatchSnapshot()
4848
})
49-
test('does not display bodyMessage if rows', () => {
49+
test('does not display bodyMessage if rows, and escapes HTML', () => {
5050
// Given
5151
const sps = jest.fn()
52+
const value = 'String with HTML <strong>in</strong> it'
5253
const result = {
53-
records: [{ keys: ['x'], _fields: ['y'], get: () => 'y' }],
54+
records: [{ keys: ['x'], _fields: [value], get: () => value }],
5455
summary: {
5556
resultAvailableAfter: neo4j.int(5),
5657
resultConsumedAfter: neo4j.int(5)

src/browser/modules/Stream/CypherFrame/VisualizationView.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const mockEmptyResult = {
2727
records: []
2828
}
2929
const node = new neo4j.types.Node('1', ['Person'], {
30-
prop1: 'prop1'
30+
prop1: '<b>String</b> with HTML <strong>in</strong> it'
3131
})
3232
const mockResult = {
3333
records: [{ keys: ['0'], __fields: [node], get: key => node }]
@@ -37,7 +37,7 @@ test('Visualization renders', () => {
3737
const { container } = render(<Visualization result={mockEmptyResult} />)
3838
expect(container).toMatchSnapshot()
3939
})
40-
test('Visualization renders with result', () => {
40+
test('Visualization renders with result and escapes any HTML', () => {
4141
const { container } = render(
4242
<Visualization updateStyle={() => {}} autoComplete result={mockResult} />
4343
)

src/browser/modules/Stream/CypherFrame/__snapshots__/TableView.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ exports[`TableViews TableView displays bodyMessage if no rows 1`] = `
4040
</div>
4141
`;
4242

43-
exports[`TableViews TableView does not display bodyMessage if rows 1`] = `
43+
exports[`TableViews TableView does not display bodyMessage if rows, and escapes HTML 1`] = `
4444
<div>
4545
<div
4646
class="styled__PaddedDiv-sc-1dtvgs1-1 styled__PaddedTableViewDiv-sc-1dtvgs1-2 clXnC"
@@ -65,7 +65,7 @@ exports[`TableViews TableView does not display bodyMessage if rows 1`] = `
6565
class="DataTables__StyledTd-bf850j-3 lfnTDs table-properties"
6666
>
6767
<span>
68-
"y"
68+
"String with HTML &lt;strong&gt;in&lt;/strong&gt; it"
6969
</span>
7070
</td>
7171
</tr>

src/browser/modules/Stream/CypherFrame/__snapshots__/VisualizationView.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`Visualization renders 1`] = `<div />`;
44

5-
exports[`Visualization renders with result 1`] = `
5+
exports[`Visualization renders with result and escapes any HTML 1`] = `
66
<div>
77
<div
88
class="VisualizationViewstyled__StyledVisContainer-sc-1b47q51-0 dFbJTz"
@@ -122,7 +122,7 @@ exports[`Visualization renders with result 1`] = `
122122
text-anchor="middle"
123123
y="5"
124124
>
125-
pro
125+
&lt;b&gt;
126126
</text>
127127
</g>
128128
</g>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2002-2020 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
* This file is part of Neo4j.
5+
* Neo4j is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
import sanitizeHTML from 'sanitize-html'
18+
export const PRINT_ENTITIES = {
19+
allowedTags: [],
20+
allowedAttributes: { '*': ['*'] },
21+
disallowedTagsMode: 'escape'
22+
}
23+
24+
export const sanitize = config => str => sanitizeHTML(str, config)
25+
export const HTMLEntities = sanitize(PRINT_ENTITIES)

yarn.lock

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2299,7 +2299,7 @@ array-union@^1.0.1:
22992299
dependencies:
23002300
array-uniq "^1.0.1"
23012301

2302-
array-uniq@^1.0.1:
2302+
array-uniq@^1.0.1, array-uniq@^1.0.2:
23032303
version "1.0.3"
23042304
resolved "https://neo.jfrog.io/neo/api/npm/npm/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
23052305
integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
@@ -4240,11 +4240,6 @@ domhandler@^2.3.0:
42404240
dependencies:
42414241
domelementtype "1"
42424242

4243-
dompurify@^2.0.7:
4244-
version "2.0.7"
4245-
resolved "https://neo.jfrog.io/neo/api/npm/npm/dompurify/-/dompurify-2.0.7.tgz#f8266ad38fe1602fb5b3222f31eedbf5c16c4fd5"
4246-
integrity sha1-+CZq04/hYC+1syIvMe7b9cFsT9U=
4247-
42484243
42494244
version "1.5.1"
42504245
resolved "https://neo.jfrog.io/neo/api/npm/npm/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
@@ -5837,7 +5832,7 @@ html-webpack-plugin@^3.2.0:
58375832
toposort "^1.0.0"
58385833
util.promisify "1.0.0"
58395834

5840-
htmlparser2@^3.3.0:
5835+
htmlparser2@^3.10.0, htmlparser2@^3.3.0:
58415836
version "3.10.1"
58425837
resolved "https://neo.jfrog.io/neo/api/npm/npm/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
58435838
integrity sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=
@@ -7407,11 +7402,26 @@ lodash.clone@^4.5.0:
74077402
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6"
74087403
integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=
74097404

7405+
lodash.clonedeep@^4.5.0:
7406+
version "4.5.0"
7407+
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
7408+
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
7409+
7410+
lodash.escaperegexp@^4.1.2:
7411+
version "4.1.2"
7412+
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
7413+
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
7414+
74107415
lodash.isplainobject@^4.0.6:
74117416
version "4.0.6"
74127417
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
74137418
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
74147419

7420+
lodash.isstring@^4.0.1:
7421+
version "4.0.1"
7422+
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
7423+
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
7424+
74157425
lodash.memoize@^4.1.2:
74167426
version "4.1.2"
74177427
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -7422,6 +7432,11 @@ lodash.merge@^4.6.0:
74227432
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
74237433
integrity sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=
74247434

7435+
lodash.mergewith@^4.6.1:
7436+
version "4.6.2"
7437+
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
7438+
integrity sha1-YXEh+JrFX1kEfHrsHM1mVMZZD1U=
7439+
74257440
lodash.once@^4.1.1:
74267441
version "4.1.1"
74277442
resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
@@ -9237,6 +9252,15 @@ postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.
92379252
source-map "^0.6.1"
92389253
supports-color "^6.1.0"
92399254

9255+
postcss@^7.0.5:
9256+
version "7.0.26"
9257+
resolved "https://neo.jfrog.io/neo/api/npm/npm/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587"
9258+
integrity sha1-XtYVz8qzW6m7uCQUpPqI6hBClYc=
9259+
dependencies:
9260+
chalk "^2.4.2"
9261+
source-map "^0.6.1"
9262+
supports-color "^6.1.0"
9263+
92409264
precss@^2.0.0:
92419265
version "2.0.0"
92429266
resolved "https://neo.jfrog.io/neo/api/npm/npm/precss/-/precss-2.0.0.tgz#7f567e3318e06d44c8fdbf9e58452e8358bf4b71"
@@ -10340,6 +10364,22 @@ sane@^4.0.3:
1034010364
minimist "^1.1.1"
1034110365
walker "~1.0.5"
1034210366

10367+
sanitize-html@^1.21.1:
10368+
version "1.21.1"
10369+
resolved "https://neo.jfrog.io/neo/api/npm/npm/sanitize-html/-/sanitize-html-1.21.1.tgz#1647d15c0c672901aa41eac1b86d0c38146d30ce"
10370+
integrity sha1-FkfRXAxnKQGqQerBuG0MOBRtMM4=
10371+
dependencies:
10372+
chalk "^2.4.1"
10373+
htmlparser2 "^3.10.0"
10374+
lodash.clonedeep "^4.5.0"
10375+
lodash.escaperegexp "^4.1.2"
10376+
lodash.isplainobject "^4.0.6"
10377+
lodash.isstring "^4.0.1"
10378+
lodash.mergewith "^4.6.1"
10379+
postcss "^7.0.5"
10380+
srcset "^1.0.0"
10381+
xtend "^4.0.1"
10382+
1034310383
save-as@^0.1.7:
1034410384
version "0.1.8"
1034510385
resolved "https://neo.jfrog.io/neo/api/npm/npm/save-as/-/save-as-0.1.8.tgz#765f947b7878bab233e1952bbc9120e1c3f041be"
@@ -10781,6 +10821,14 @@ sprintf-js@~1.0.2:
1078110821
resolved "https://neo.jfrog.io/neo/api/npm/npm/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
1078210822
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
1078310823

10824+
srcset@^1.0.0:
10825+
version "1.0.0"
10826+
resolved "https://neo.jfrog.io/neo/api/npm/npm/srcset/-/srcset-1.0.0.tgz#a5669de12b42f3b1d5e83ed03c71046fc48f41ef"
10827+
integrity sha1-pWad4StC87HV6D7QPHEEb8SPQe8=
10828+
dependencies:
10829+
array-uniq "^1.0.2"
10830+
number-is-nan "^1.0.0"
10831+
1078410832
sshpk@^1.7.0:
1078510833
version "1.16.1"
1078610834
resolved "https://neo.jfrog.io/neo/api/npm/npm/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
@@ -12066,7 +12114,7 @@ [email protected]:
1206612114
resolved "https://neo.jfrog.io/neo/api/npm/npm/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
1206712115
integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=
1206812116

12069-
xtend@^4.0.0, xtend@~4.0.1:
12117+
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
1207012118
version "4.0.2"
1207112119
resolved "https://neo.jfrog.io/neo/api/npm/npm/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
1207212120
integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=

0 commit comments

Comments
 (0)