Fix breaking schema.org with special chars

This commit is contained in:
Chocobozzz
2026-06-12 15:46:43 +02:00
parent 0292ee6ce7
commit 797445268b
3 changed files with 60 additions and 16 deletions
+11
View File
@@ -85,3 +85,14 @@ export function escapeAttribute (value: string) {
return String(value).replace(/"/g, '"')
}
export function escapeHtmlJSONStr (jsonStr: string) {
if (!jsonStr) return ''
return jsonStr
.replace(/</g, '\\u003c')
.replace(/>/g, '\\u003e')
.replace(/&/g, '\\u0026')
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
}
+47 -14
View File
@@ -268,18 +268,6 @@ describe('Test <head> HTML tags', function () {
})
})
describe('Escaping', function () {
it('Should correctly escape values', async function () {
await servers[0].users.updateMe({ description: '<strong>"super description"</strong>' })
const res = await makeGetRequest({ url: servers[0].url, path: '/a/root', accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 })
const text = res.text
expect(text).to.contain(`<meta property="twitter:description" content="&quot;super description&quot;" />`)
expect(text).to.contain(`<meta property="og:description" content="&quot;super description&quot;" />`)
})
})
describe('Mastodon link', function () {
async function check (path: string, href: string, exist = true) {
const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 })
@@ -373,11 +361,18 @@ describe('Test <head> HTML tags', function () {
for (const id of playlistIds) {
await commonPageTest(path + id)
const res = await makeGetRequest({ url: servers[0].url, path: path + id, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 })
const res = await makeGetRequest({
url: servers[0].url,
path: path + id,
accept: 'text/html',
expectedStatus: HttpStatusCode.OK_200
})
const text = res.text
const feedUrl = `${servers[0].url}/feeds/podcast/videos.xml?playlistId=${playlist.id}`
expect(text).to.contain(`<link rel="alternate" type="application/rss+xml" title="${playlistName} - Podcast feed" href="${feedUrl}" />`)
expect(text).to.contain(
`<link rel="alternate" type="application/rss+xml" title="${playlistName} - Podcast feed" href="${feedUrl}" />`
)
}
}
})
@@ -395,6 +390,44 @@ describe('Test <head> HTML tags', function () {
})
})
describe('Escaping', function () {
it('Should correctly escape values', async function () {
{
await servers[0].users.updateMe({ description: '<strong>"super description"</strong>' })
const res = await makeGetRequest({
url: servers[0].url,
path: '/a/root',
accept: 'text/html',
expectedStatus: HttpStatusCode.OK_200
})
const text = res.text
expect(text).to.contain(`<meta property="twitter:description" content="&quot;super description&quot;" />`)
expect(text).to.contain(`<meta property="og:description" content="&quot;super description&quot;" />`)
}
{
await servers[0].channels.update({
channelName: 'root_channel',
attributes: {
displayName: '</strong>toto'
}
})
const res = await makeGetRequest({
url: servers[0].url,
path: '/w/' + videoIds[0],
accept: 'text/html',
expectedStatus: HttpStatusCode.OK_200
})
const text = res.text
expect(text).to.contain('\\u003c/strong\\u003etoto')
}
})
})
after(async function () {
await cleanupTests(servers)
})
+2 -2
View File
@@ -1,4 +1,4 @@
import { escapeAttribute, escapeHTML } from '@peertube/peertube-core-utils'
import { escapeAttribute, escapeHTML, escapeHtmlJSONStr } from '@peertube/peertube-core-utils'
import { mdToPlainText } from '@server/helpers/markdown.js'
import { getActivityStreamDuration } from '@server/lib/activitypub/activity.js'
import { ServerConfigManager } from '@server/lib/server-config-manager.js'
@@ -188,7 +188,7 @@ export class TagsHtml {
const schemaTags = await this.generateSchemaTagsOptions(tagsValues, context)
if (schemaTags) {
tagsStr += `<script type="application/ld+json">${JSON.stringify(schemaTags)}</script>`
tagsStr += `<script type="application/ld+json">${escapeHtmlJSONStr(JSON.stringify(schemaTags))}</script>`
}
// Rel Me