1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-05 10:49:28 +02:00

Add public links to AP representation

See https://github.com/Chocobozzz/PeerTube/issues/6389
This commit is contained in:
Chocobozzz 2025-02-21 07:52:33 +01:00
parent de5adc09b2
commit e81b6eba74
No known key found for this signature in database
GPG key ID: 583A612D890159BE
17 changed files with 267 additions and 152 deletions

View file

@ -1,10 +1,11 @@
import { unarray } from '@peertube/peertube-core-utils'
import { arrayify } from '@peertube/peertube-core-utils'
import { peertubeTruncate } from '@server/helpers/core-utils.js'
import { ActivityPubActor } from 'packages/models/src/activitypub/activitypub-actor.js'
import validator from 'validator'
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants.js'
import { exists, isArray, isDateValid } from '../misc.js'
import { isHostValid } from '../servers.js'
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc.js'
import { isActivityPubHTMLUrlValid, isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc.js'
export function isActorEndpointsObjectValid (endpointObject: any) {
if (endpointObject?.sharedInbox) {
@ -62,7 +63,7 @@ export function isActorDeleteActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Delete')
}
export function sanitizeAndCheckActorObject (actor: any) {
export function sanitizeAndCheckActorObject (actor: ActivityPubActor) {
if (!isActorTypeValid(actor.type)) return false
normalizeActor(actor)
@ -71,43 +72,16 @@ export function sanitizeAndCheckActorObject (actor: any) {
isActivityPubUrlValid(actor.id) &&
isActivityPubUrlValid(actor.inbox) &&
isActorPreferredUsernameValid(actor.preferredUsername) &&
isActivityPubUrlValid(actor.url) &&
isActorPublicKeyObjectValid(actor.publicKey) &&
isActorEndpointsObjectValid(actor.endpoints) &&
(!actor.outbox || isActivityPubUrlValid(actor.outbox)) &&
(!actor.following || isActivityPubUrlValid(actor.following)) &&
(!actor.followers || isActivityPubUrlValid(actor.followers)) &&
setValidAttributedTo(actor) &&
setValidDescription(actor) &&
// If this is a group (a channel), it should be attributed to an account
// In PeerTube we use this to attach a video channel to a specific account
(actor.type !== 'Group' || actor.attributedTo.length !== 0)
}
export function normalizeActor (actor: any) {
if (!actor) return
if (!actor.url) {
actor.url = actor.id
} else if (isArray(actor.url)) {
actor.url = unarray(actor.url)
} else if (typeof actor.url !== 'string') {
actor.url = actor.url.href || actor.url.url
}
if (!isDateValid(actor.published)) actor.published = undefined
if (actor.summary && typeof actor.summary === 'string') {
actor.summary = peertubeTruncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
actor.summary = null
}
}
}
export function isValidActorHandle (handle: string) {
if (!exists(handle)) return false
@ -121,8 +95,38 @@ export function areValidActorHandles (handles: string[]) {
return isArray(handles) && handles.every(h => isValidActorHandle(h))
}
export function setValidDescription (obj: any) {
if (!obj.summary) obj.summary = null
// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------
return true
function normalizeActor (actor: ActivityPubActor) {
if (!actor) return
setValidUrls(actor)
setValidAttributedTo(actor)
setValidDescription(actor)
if (!isDateValid(actor.published)) actor.published = undefined
if (actor.summary && typeof actor.summary === 'string') {
actor.summary = peertubeTruncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) {
actor.summary = null
}
}
}
function setValidDescription (actor: ActivityPubActor) {
if (!actor.summary) actor.summary = null
}
function setValidUrls (actor: any) {
if (!actor.url) {
actor.url = []
return
}
actor.url = arrayify(actor.url)
.filter(u => isActivityPubHTMLUrlValid(u))
}

View file

@ -1,9 +1,10 @@
import validator from 'validator'
import { CONFIG } from '@server/initializers/config.js'
import { ActivityHtmlUrlObject } from 'packages/models/src/activitypub/index.js'
import validator from 'validator'
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants.js'
import { exists } from '../misc.js'
function isUrlValid (url: string) {
export function isUrlValid (url: string) {
const isURLOptions = {
require_host: true,
require_tld: true,
@ -20,11 +21,11 @@ function isUrlValid (url: string) {
return exists(url) && validator.default.isURL('' + url, isURLOptions)
}
function isActivityPubUrlValid (url: string) {
export function isActivityPubUrlValid (url: string) {
return isUrlValid(url) && validator.default.isLength('' + url, CONSTRAINTS_FIELDS.ACTORS.URL)
}
function isBaseActivityValid (activity: any, type: string) {
export function isBaseActivityValid (activity: any, type: string) {
return activity.type === type &&
isActivityPubUrlValid(activity.id) &&
isObjectValid(activity.actor) &&
@ -32,19 +33,26 @@ function isBaseActivityValid (activity: any, type: string) {
isUrlCollectionValid(activity.cc)
}
function isUrlCollectionValid (collection: any) {
export function isUrlCollectionValid (collection: any) {
return collection === undefined ||
(Array.isArray(collection) && collection.every(t => isActivityPubUrlValid(t)))
}
function isObjectValid (object: any) {
export function isObjectValid (object: any) {
return exists(object) &&
(
isActivityPubUrlValid(object) || isActivityPubUrlValid(object.id)
)
}
function setValidAttributedTo (obj: any) {
export function isActivityPubHTMLUrlValid (url: ActivityHtmlUrlObject) {
return url &&
url.type === 'Link' &&
url.mediaType === 'text/html' &&
isActivityPubUrlValid(url.href)
}
export function setValidAttributedTo (obj: any) {
if (Array.isArray(obj.attributedTo) === false) {
obj.attributedTo = []
return true
@ -58,19 +66,10 @@ function setValidAttributedTo (obj: any) {
return true
}
function isActivityPubVideoDurationValid (value: string) {
export function isActivityPubVideoDurationValid (value: string) {
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
return exists(value) &&
typeof value === 'string' &&
value.startsWith('PT') &&
value.endsWith('S')
}
export {
isUrlValid,
isActivityPubUrlValid,
isBaseActivityValid,
setValidAttributedTo,
isObjectValid,
isActivityPubVideoDurationValid
}