commit: 6175a153ed4e5eb30fd4b5d5f6b3fff34a81a89c
parent 045a222183ac47b48e14e1639e7107aa0bffb015
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date: Sat, 26 Nov 2022 22:17:18 +0000
Merge branch 'shout-float-fix' into 'develop'
Fix HTML exploit of the day (shout-float in rich media)
See merge request pleroma/pleroma-fe!1689
Diffstat:
3 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx
@@ -150,6 +150,7 @@ export default {
if (Array.isArray(item)) {
const [opener, children, closer] = item
const Tag = getTagName(opener)
+ const fullAttrs = getAttrs(opener, () => true)
const attrs = getAttrs(opener)
const previouslyMentions = currentMentions !== null
/* During grouping of mentions we trim all the empty text elements
@@ -171,7 +172,7 @@ export default {
return ['', [mentionsLinePadding, renderImage(opener)], '']
case 'a': // replace mentions with MentionLink
if (!this.handleLinks) break
- if (attrs['class'] && attrs['class'].includes('mention')) {
+ if (fullAttrs.class && fullAttrs.class.includes('mention')) {
// Handling mentions here
return renderMention(attrs, children)
} else {
@@ -179,7 +180,7 @@ export default {
break
}
case 'span':
- if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) {
+ if (this.handleLinks && fullAttrs.class && fullAttrs.class.includes('h-card')) {
return ['', children.map(processItem), '']
}
}
@@ -213,13 +214,14 @@ export default {
const [opener, children] = item
const Tag = opener === '' ? '' : getTagName(opener)
switch (Tag) {
- case 'a': // replace mentions with MentionLink
+ case 'a': { // replace mentions with MentionLink
if (!this.handleLinks) break
- const attrs = getAttrs(opener)
+ const fullAttrs = getAttrs(opener, () => true)
+ const attrs = getAttrs(opener, () => true)
// should only be this
if (
- (attrs['class'] && attrs['class'].includes('hashtag')) || // Pleroma style
- (attrs['rel'] === 'tag') // Mastodon style
+ (fullAttrs.class && fullAttrs.class.includes('hashtag')) || // Pleroma style
+ (fullAttrs.rel === 'tag') // Mastodon style
) {
return renderHashtag(attrs, children, encounteredTextReverse)
} else {
@@ -230,6 +232,7 @@ export default {
{ newChildren }
</a>
}
+ }
case '':
return [...children].reverse().map(processItemReverse).reverse()
}
diff --git a/src/services/html_converter/utility.service.js b/src/services/html_converter/utility.service.js
@@ -16,7 +16,7 @@ export const getTagName = (tag) => {
* @return {Object} - map of attributes key = attribute name, value = attribute value
* attributes without values represented as boolean true
*/
-export const getAttrs = tag => {
+export const getAttrs = (tag, filter) => {
const innertag = tag
.substring(1, tag.length - 1)
.replace(new RegExp('^' + getTagName(tag)), '')
@@ -28,7 +28,15 @@ export const getAttrs = tag => {
if (!v) return [k, true]
return [k, v.substring(1, v.length - 1)]
})
- return Object.fromEntries(attrs)
+ const defaultFilter = ([k, v]) => {
+ const attrKey = k.toLowerCase()
+ if (attrKey === 'style') return false
+ if (attrKey === 'class') {
+ return v === 'greentext' || v === 'cyantext'
+ }
+ return true
+ }
+ return Object.fromEntries(attrs.filter(filter || defaultFilter))
}
/**
diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js
@@ -19,9 +19,11 @@ const global = {
}
}
-const makeMention = (who) => {
+const makeMention = (who, noClass) => {
attentions.push({ statusnet_profile_url: `https://fake.tld/@${who}` })
- return `<span class="h-card"><a class="u-url mention" href="https://fake.tld/@${who}">@<span>${who}</span></a></span>`
+ return noClass
+ ? `<span><a href="https://fake.tld/@${who}">@<span>${who}</span></a></span>`
+ : `<span class="h-card"><a class="u-url mention" href="https://fake.tld/@${who}">@<span>${who}</span></a></span>`
}
const p = (...data) => `<p>${data.join('')}</p>`
const compwrap = (...data) => `<span class="RichContent">${data.join('')}</span>`
@@ -142,6 +144,17 @@ describe('RichContent', () => {
makeMention('Josh'), makeMention('Jeremy')
].join('')
].join('\n')
+ const strippedHtml = [
+ [
+ makeMention('Jack', true),
+ 'let\'s meet up with ',
+ makeMention('Janet', true)
+ ].join(''),
+ [
+ makeMention('John', true),
+ makeMention('Josh', true), makeMention('Jeremy', true)
+ ].join('')
+ ].join('\n')
const wrapper = shallowMount(RichContent, {
global,
@@ -154,7 +167,7 @@ describe('RichContent', () => {
}
})
- expect(wrapper.html()).to.eql(compwrap(html))
+ expect(wrapper.html()).to.eql(compwrap(strippedHtml))
})
it('Adds greentext and cyantext to the post', () => {
@@ -412,7 +425,7 @@ describe('RichContent', () => {
'Testing'
].join('')
const expected = [
- '<span class="poast-style">',
+ '<span>',
'<span class="MentionsLine">',
'<span class="MentionLink mention-link">',
'<a href="lol" class="original" target="_blank">',