Skip to content

Commit

Permalink
Support actors with array url field
Browse files Browse the repository at this point in the history
  • Loading branch information
Chocobozzz committed Aug 20, 2024
1 parent 1870626 commit a86252b
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 36 deletions.
10 changes: 10 additions & 0 deletions packages/core-utils/src/common/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ export function arrayify <T> (element: T | T[]) {
return [ element ]
}

export function unarray <T> (element: T | T[]) {
if (Array.isArray(element)) {
if (element.length === 0) return undefined

return element[0]
}

return element
}

// Avoid conflict with other uniq() functions
export function uniqify <T> (elements: T[]) {
return Array.from(new Set(elements))
Expand Down
57 changes: 21 additions & 36 deletions server/core/helpers/custom-validators/activitypub/actor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { unarray } from '@peertube/peertube-core-utils'
import { peertubeTruncate } from '@server/helpers/core-utils.js'
import validator from 'validator'
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants.js'
import { exists, isArray, isDateValid } from '../misc.js'
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc.js'
import { isHostValid } from '../servers.js'
import { peertubeTruncate } from '@server/helpers/core-utils.js'
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc.js'

function isActorEndpointsObjectValid (endpointObject: any) {
export function isActorEndpointsObjectValid (endpointObject: any) {
if (endpointObject?.sharedInbox) {
return isActivityPubUrlValid(endpointObject.sharedInbox)
}
Expand All @@ -14,32 +15,33 @@ function isActorEndpointsObjectValid (endpointObject: any) {
return true
}

function isActorPublicKeyObjectValid (publicKeyObject: any) {
export function isActorPublicKeyObjectValid (publicKeyObject: any) {
return isActivityPubUrlValid(publicKeyObject.id) &&
isActivityPubUrlValid(publicKeyObject.owner) &&
isActorPublicKeyValid(publicKeyObject.publicKeyPem)
}

const actorTypes = new Set([ 'Person', 'Application', 'Group', 'Service', 'Organization' ])
function isActorTypeValid (type: string) {
export function isActorTypeValid (type: string) {
return actorTypes.has(type)
}

function isActorPublicKeyValid (publicKey: string) {
export function isActorPublicKeyValid (publicKey: string) {
return exists(publicKey) &&
typeof publicKey === 'string' &&
publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
publicKey.includes('-----END PUBLIC KEY-----') &&
validator.default.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
}

const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]'
export const actorNameAlphabet = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]'

const actorNameRegExp = new RegExp(`^${actorNameAlphabet}+$`)
function isActorPreferredUsernameValid (preferredUsername: string) {
export function isActorPreferredUsernameValid (preferredUsername: string) {
return exists(preferredUsername) && validator.default.matches(preferredUsername, actorNameRegExp)
}

function isActorPrivateKeyValid (privateKey: string) {
export function isActorPrivateKeyValid (privateKey: string) {
return exists(privateKey) &&
typeof privateKey === 'string' &&
(privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') || privateKey.startsWith('-----BEGIN PRIVATE KEY-----')) &&
Expand All @@ -48,19 +50,19 @@ function isActorPrivateKeyValid (privateKey: string) {
validator.default.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
}

function isActorFollowingCountValid (value: string) {
export function isActorFollowingCountValid (value: string) {
return exists(value) && validator.default.isInt('' + value, { min: 0 })
}

function isActorFollowersCountValid (value: string) {
export function isActorFollowersCountValid (value: string) {
return exists(value) && validator.default.isInt('' + value, { min: 0 })
}

function isActorDeleteActivityValid (activity: any) {
export function isActorDeleteActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Delete')
}

function sanitizeAndCheckActorObject (actor: any) {
export function sanitizeAndCheckActorObject (actor: any) {
if (!isActorTypeValid(actor.type)) return false

normalizeActor(actor)
Expand All @@ -84,11 +86,13 @@ function sanitizeAndCheckActorObject (actor: any) {
(actor.type !== 'Group' || actor.attributedTo.length !== 0)
}

function normalizeActor (actor: any) {
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
}
Expand All @@ -104,7 +108,7 @@ function normalizeActor (actor: any) {
}
}

function isValidActorHandle (handle: string) {
export function isValidActorHandle (handle: string) {
if (!exists(handle)) return false

const parts = handle.split('@')
Expand All @@ -113,31 +117,12 @@ function isValidActorHandle (handle: string) {
return isHostValid(parts[1])
}

function areValidActorHandles (handles: string[]) {
export function areValidActorHandles (handles: string[]) {
return isArray(handles) && handles.every(h => isValidActorHandle(h))
}

function setValidDescription (obj: any) {
export function setValidDescription (obj: any) {
if (!obj.summary) obj.summary = null

return true
}

// ---------------------------------------------------------------------------

export {
normalizeActor,
actorNameAlphabet,
areValidActorHandles,
isActorEndpointsObjectValid,
isActorPublicKeyObjectValid,
isActorTypeValid,
isActorPublicKeyValid,
isActorPreferredUsernameValid,
isActorPrivateKeyValid,
isActorFollowingCountValid,
isActorFollowersCountValid,
isActorDeleteActivityValid,
sanitizeAndCheckActorObject,
isValidActorHandle
}

0 comments on commit a86252b

Please sign in to comment.