Skip to content

Commit c0f7e7d

Browse files
authored
fix: stricter sanitization, fix highlighting code, open urls in new tabs (#886)
* fix: stricter sanitization, fix highlighting code, open urls in new tabs * fix: add norreferrer to links, change function name
1 parent e871f77 commit c0f7e7d

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

src/components/PostView.vue

+41-28
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,43 @@
88
</template>
99

1010
<script lang="ts">
11+
import Vue from 'vue'
12+
import type { PropType } from 'vue'
1113
import DOMPurify from 'dompurify'
1214
import { marked } from 'marked'
13-
import type { PropType } from 'vue'
14-
import Vue from 'vue'
15-
import { transformPostToTemplate } from '../pages/post/readerExtensions'
15+
import { markedRenderer, transformPostToHTML } from '../pages/post/readerExtensions'
1616
import { getPhotoFromIPFS } from '@/backend/getPhoto'
1717
import ImagePopup from '@/components/popups/Image.vue'
1818
19+
const ALLOWED_TAGS = [
20+
`pre`,
21+
`ipfsimage`,
22+
`p`,
23+
`code`,
24+
`ol`,
25+
`li`,
26+
`strong`,
27+
`em`,
28+
`u`,
29+
`del`,
30+
`blockquote`,
31+
`h1`,
32+
`h2`,
33+
`h3`,
34+
`h4`,
35+
`h5`,
36+
`a`,
37+
`span`,
38+
]
39+
40+
const ALLOWED_ATTR = [`cid`, `alt`, `class`, `id`, `href`]
41+
1942
interface IData {
2043
clickedImage: null | string
2144
imageError: null | string
2245
displayImagePopup: boolean
2346
}
2447
25-
function setupSanitization() {
26-
DOMPurify.addHook(`afterSanitizeAttributes`, (node: Element) => {
27-
// set all elements owning target to target=_blank
28-
if (node.getAttribute(`target`)) {
29-
node.setAttribute(`target`, `_blank`)
30-
node.setAttribute(`rel`, `noopener`)
31-
}
32-
})
33-
}
34-
35-
function sanitizeHTML(input: string) {
36-
return DOMPurify.sanitize(input, {
37-
USE_PROFILES: { html: true },
38-
ALLOWED_TAGS: [`pre`],
39-
ADD_ATTR: [`cid`],
40-
ADD_TAGS: [`ipfsimage`],
41-
FORBID_ATTR: [`style`],
42-
FORBID_TAGS: [`style`, `img`],
43-
})
44-
}
45-
4648
export default Vue.extend({
4749
components: {
4850
ImagePopup,
@@ -67,17 +69,28 @@ export default Vue.extend({
6769
computed: {
6870
htmlContent() {
6971
const html = marked.parse(this.content)
70-
const sanitizedHtml = sanitizeHTML(html)
71-
const transformedHtml = transformPostToTemplate(sanitizedHtml, this.postImages)
72-
return transformedHtml
72+
const sanitizedHtml = DOMPurify.sanitize(html, {
73+
ALLOWED_TAGS,
74+
ALLOWED_ATTR,
75+
})
76+
return transformPostToHTML(sanitizedHtml, this.postImages)
7377
},
7478
},
79+
created() {
80+
marked.use({ renderer: markedRenderer })
81+
DOMPurify.addHook(`afterSanitizeAttributes`, (node: Element) => {
82+
// set all elements owning target and all links to target=_blank
83+
if (node.getAttribute(`target`) || node.tagName === `A`) {
84+
node.setAttribute(`target`, `_blank`)
85+
node.setAttribute(`rel`, `noopener noreferrer`)
86+
}
87+
})
88+
},
7589
mounted() {
7690
const images = this.$el.querySelectorAll(`img`)
7791
images.forEach((image) => {
7892
this.lazyLoad(image)
7993
})
80-
setupSanitization()
8194
},
8295
methods: {
8396
openImagePopup(image: HTMLImageElement) {

src/pages/post/readerExtensions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const imgRegexp = (cid: string) =>
2222

2323
const blankImage = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAQAAABeK7cBAAAADUlEQVR42mM8fIaBAQAFegGROSevSQAAAABJRU5ErkJggg==`
2424

25-
export function transformPostToTemplate(body: string, postImages?: Array<string>) {
25+
export function transformPostToHTML(body: string, postImages?: Array<string>) {
2626
if (!postImages) {
2727
return body
2828
}

0 commit comments

Comments
 (0)