kopia lustrzana https://github.com/cloudflare/wildebeest
ignore invalid user mentions
rodzic
08a5bc4fa4
commit
5e77067324
|
@ -1,4 +1,6 @@
|
|||
import { parseHandle } from 'wildebeest/backend/src/utils/parse'
|
||||
import type { Actor } from 'wildebeest/backend/src/activitypub/actors'
|
||||
import { urlToHandle } from 'wildebeest/backend/src/utils/handle'
|
||||
|
||||
function tag(name: string, content: string, attrs: Record<string, string> = {}): string {
|
||||
let htmlAttrs = ''
|
||||
|
@ -13,18 +15,24 @@ const linkRegex = /(^|\s|\b)(https?:\/\/[-\w@:%._+~#=]{2,256}\.[a-z]{2,6}\b(?:[-
|
|||
const mentionedEmailRegex = /(^|\s|\b|\W)@(\w+(?:[.-]?\w+)+@\w+(?:[.-]?\w+)+(?:\.\w{2,63})+)(\b|\s|$)/g
|
||||
|
||||
/// Transform a text status into a HTML status; enriching it with links / mentions.
|
||||
export function enrichStatus(status: string): string {
|
||||
export function enrichStatus(status: string, mentions: Array<Actor>): string {
|
||||
const enrichedStatus = status
|
||||
.replace(
|
||||
linkRegex,
|
||||
(_, matchPrefix: string, link: string, matchSuffix: string) =>
|
||||
`${matchPrefix}${getLinkAnchor(link)}${matchSuffix}`
|
||||
)
|
||||
.replace(
|
||||
mentionedEmailRegex,
|
||||
(_, matchPrefix: string, email: string, matchSuffix: string) =>
|
||||
`${matchPrefix}${getMentionSpan(email)}${matchSuffix}`
|
||||
)
|
||||
.replace(mentionedEmailRegex, (_, matchPrefix: string, email: string, matchSuffix: string) => {
|
||||
// ensure that the match is part of the mentions array
|
||||
for (let i = 0, len = mentions.length; i < len; i++) {
|
||||
if (email === urlToHandle(mentions[i].id)) {
|
||||
return `${matchPrefix}${getMentionSpan(email)}${matchSuffix}`
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise the match isn't valid and we don't add HTML
|
||||
return `${matchPrefix}${email}${matchSuffix}`
|
||||
})
|
||||
|
||||
return tag('p', enrichedStatus)
|
||||
}
|
||||
|
|
|
@ -21,20 +21,21 @@ export async function queryAcct(domain: string, acct: string): Promise<Actor | n
|
|||
|
||||
export async function queryAcctLink(domain: string, acct: string): Promise<URL | null> {
|
||||
const params = new URLSearchParams({ resource: `acct:${acct}` })
|
||||
let res
|
||||
let data: WebFingerResponse
|
||||
try {
|
||||
const url = new URL('/.well-known/webfinger?' + params, 'https://' + domain)
|
||||
console.log('query', url.href)
|
||||
res = await fetch(url, { headers })
|
||||
const res = await fetch(url, { headers })
|
||||
if (!res.ok) {
|
||||
throw new Error(`WebFinger API returned: ${res.status}`)
|
||||
}
|
||||
|
||||
data = await res.json<WebFingerResponse>()
|
||||
} catch (err) {
|
||||
console.warn('failed to query WebFinger:', err)
|
||||
return null
|
||||
}
|
||||
|
||||
const data = await res.json<WebFingerResponse>()
|
||||
for (let i = 0, len = data.links.length; i < len; i++) {
|
||||
const link = data.links[i]
|
||||
if (link.rel === 'self' && link.type === 'application/activity+json') {
|
||||
|
|
|
@ -167,7 +167,7 @@ describe('Mastodon APIs', () => {
|
|||
})
|
||||
|
||||
describe('Microformats', () => {
|
||||
test('convert mentions to HTML', () => {
|
||||
test('convert mentions to HTML', async () => {
|
||||
const mentionsToTest = [
|
||||
{
|
||||
mention: '@sven2@example.com',
|
||||
|
@ -195,18 +195,34 @@ describe('Mastodon APIs', () => {
|
|||
'<span class="h-card"><a href="https://123456.test.testey.abcdef/@testey" class="u-url mention">@<span>testey</span></a></span>',
|
||||
},
|
||||
]
|
||||
mentionsToTest.forEach(({ mention, expectedMentionSpan }) => {
|
||||
assert.equal(enrichStatus(`hey ${mention} hi`), `<p>hey ${expectedMentionSpan} hi</p>`)
|
||||
assert.equal(enrichStatus(`${mention} hi`), `<p>${expectedMentionSpan} hi</p>`)
|
||||
assert.equal(enrichStatus(`${mention}\n\thein`), `<p>${expectedMentionSpan}\n\thein</p>`)
|
||||
assert.equal(enrichStatus(`hey ${mention}`), `<p>hey ${expectedMentionSpan}</p>`)
|
||||
assert.equal(enrichStatus(`${mention}`), `<p>${expectedMentionSpan}</p>`)
|
||||
assert.equal(enrichStatus(`@!@£${mention}!!!`), `<p>@!@£${expectedMentionSpan}!!!</p>`)
|
||||
})
|
||||
|
||||
for (let i = 0, len = mentionsToTest.length; i < len; i++) {
|
||||
const { mention, expectedMentionSpan } = mentionsToTest[i]
|
||||
|
||||
// List of mentioned actors, only the `id` is required so we can hack together an Actor
|
||||
const mentions: any = [
|
||||
{ id: new URL('https://example.com/sven2') },
|
||||
{ id: new URL('https://example.eng.com/test') },
|
||||
{ id: new URL('https://example.eng.co.uk/test.a.b.c-d') },
|
||||
{ id: new URL('https://123456.abcdef/testey') },
|
||||
{ id: new URL('https://123456.test.testey.abcdef/testey') },
|
||||
]
|
||||
|
||||
assert.equal(enrichStatus(`hey ${mention} hi`, mentions), `<p>hey ${expectedMentionSpan} hi</p>`)
|
||||
assert.equal(enrichStatus(`${mention} hi`, mentions), `<p>${expectedMentionSpan} hi</p>`)
|
||||
assert.equal(enrichStatus(`${mention}\n\thein`, mentions), `<p>${expectedMentionSpan}\n\thein</p>`)
|
||||
assert.equal(enrichStatus(`hey ${mention}`, mentions), `<p>hey ${expectedMentionSpan}</p>`)
|
||||
assert.equal(enrichStatus(`${mention}`, mentions), `<p>${expectedMentionSpan}</p>`)
|
||||
assert.equal(enrichStatus(`@!@£${mention}!!!`, mentions), `<p>@!@£${expectedMentionSpan}!!!</p>`)
|
||||
}
|
||||
})
|
||||
|
||||
test('handle invalid mention', () => {
|
||||
assert.equal(enrichStatus('hey @#-...@example.com'), '<p>hey @#-...@example.com</p>')
|
||||
assert.equal(enrichStatus('hey @#-...@example.com', []), '<p>hey @#-...@example.com</p>')
|
||||
})
|
||||
|
||||
test('mention to invalid user', () => {
|
||||
assert.equal(enrichStatus('hey test@example.com', []), '<p>hey test@example.com</p>')
|
||||
})
|
||||
|
||||
test('convert links to HTML', () => {
|
||||
|
@ -222,11 +238,11 @@ describe('Mastodon APIs', () => {
|
|||
linksToTest.forEach((link) => {
|
||||
const url = new URL(link)
|
||||
const urlDisplayText = `${url.hostname}${url.pathname}`
|
||||
assert.equal(enrichStatus(`hey ${link} hi`), `<p>hey <a href="${link}">${urlDisplayText}</a> hi</p>`)
|
||||
assert.equal(enrichStatus(`${link} hi`), `<p><a href="${link}">${urlDisplayText}</a> hi</p>`)
|
||||
assert.equal(enrichStatus(`hey ${link}`), `<p>hey <a href="${link}">${urlDisplayText}</a></p>`)
|
||||
assert.equal(enrichStatus(`${link}`), `<p><a href="${link}">${urlDisplayText}</a></p>`)
|
||||
assert.equal(enrichStatus(`@!@£${link}!!!`), `<p>@!@£<a href="${link}">${urlDisplayText}</a>!!!</p>`)
|
||||
assert.equal(enrichStatus(`hey ${link} hi`, []), `<p>hey <a href="${link}">${urlDisplayText}</a> hi</p>`)
|
||||
assert.equal(enrichStatus(`${link} hi`, []), `<p><a href="${link}">${urlDisplayText}</a> hi</p>`)
|
||||
assert.equal(enrichStatus(`hey ${link}`, []), `<p>hey <a href="${link}">${urlDisplayText}</a></p>`)
|
||||
assert.equal(enrichStatus(`${link}`, []), `<p><a href="${link}">${urlDisplayText}</a></p>`)
|
||||
assert.equal(enrichStatus(`@!@£${link}!!!`, []), `<p>@!@£<a href="${link}">${urlDisplayText}</a>!!!</p>`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -457,6 +457,11 @@ describe('Mastodon APIs', () => {
|
|||
})
|
||||
)
|
||||
}
|
||||
if (
|
||||
input.toString() === 'https://cloudflare.com/.well-known/webfinger?resource=acct%3Ano-json%40cloudflare.com'
|
||||
) {
|
||||
return new Response('not json', { status: 200 })
|
||||
}
|
||||
|
||||
if (input.toString() === 'https://instance.horse/users/sven') {
|
||||
return new Response(
|
||||
|
@ -496,7 +501,7 @@ describe('Mastodon APIs', () => {
|
|||
}
|
||||
|
||||
{
|
||||
const mentions = await getMentions('unknown@actor.com', domain)
|
||||
const mentions = await getMentions('no-json@actor.com', domain)
|
||||
assert.equal(mentions.length, 0)
|
||||
}
|
||||
|
||||
|
@ -524,6 +529,11 @@ describe('Mastodon APIs', () => {
|
|||
assert.equal(mentions.length, 1)
|
||||
assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/sven')
|
||||
}
|
||||
|
||||
{
|
||||
const mentions = await getMentions('<p>@unknown</p>', domain)
|
||||
assert.equal(mentions.length, 0)
|
||||
}
|
||||
})
|
||||
|
||||
test('get status count likes', async () => {
|
||||
|
|
|
@ -107,12 +107,12 @@ export async function handleRequest(
|
|||
|
||||
const hashtags = getHashtags(body.status)
|
||||
|
||||
const content = enrichStatus(body.status)
|
||||
const mentions = await getMentions(body.status, domain)
|
||||
if (mentions.length > 0) {
|
||||
extraProperties.tag = mentions.map(newMention)
|
||||
}
|
||||
|
||||
const content = enrichStatus(body.status, mentions)
|
||||
const note = await createStatus(domain, db, connectedActor, content, mediaAttachments, extraProperties)
|
||||
|
||||
if (hashtags.length > 0) {
|
||||
|
|
Ładowanie…
Reference in New Issue