mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 02:39:33 +02:00
Support raw strings for AP to/cc
This commit is contained in:
parent
5138e28ff8
commit
8d3bc24c4b
9 changed files with 76 additions and 66 deletions
|
@ -11,6 +11,7 @@ export function findCommonElement <T> (array1: T[], array2: T[]) {
|
||||||
// Avoid conflict with other toArray() functions
|
// Avoid conflict with other toArray() functions
|
||||||
export function arrayify<T> (element: T | T[]) {
|
export function arrayify<T> (element: T | T[]) {
|
||||||
if (Array.isArray(element)) return element
|
if (Array.isArray(element)) return element
|
||||||
|
if (element === undefined || element === null) return []
|
||||||
|
|
||||||
return [ element ]
|
return [ element ]
|
||||||
}
|
}
|
||||||
|
@ -35,9 +36,9 @@ export function shuffle <T> (elements: T[]) {
|
||||||
const shuffled = [ ...elements ]
|
const shuffled = [ ...elements ]
|
||||||
|
|
||||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
const j = Math.floor(Math.random() * (i + 1))
|
||||||
|
|
||||||
[ shuffled[i], shuffled[j] ] = [ shuffled[j], shuffled[i] ]
|
;[ shuffled[i], shuffled[j] ] = [ shuffled[j], shuffled[i] ]
|
||||||
}
|
}
|
||||||
|
|
||||||
return shuffled
|
return shuffled
|
||||||
|
|
|
@ -12,46 +12,53 @@ import {
|
||||||
} from './objects/index.js'
|
} from './objects/index.js'
|
||||||
|
|
||||||
export type ActivityUpdateObject =
|
export type ActivityUpdateObject =
|
||||||
Extract<ActivityObject, VideoObject | CacheFileObject | PlaylistObject | ActivityPubActor | string> | ActivityPubActor
|
| Extract<ActivityObject, VideoObject | CacheFileObject | PlaylistObject | ActivityPubActor | string>
|
||||||
|
| ActivityPubActor
|
||||||
|
|
||||||
// Cannot Extract from Activity because of circular reference
|
// Cannot Extract from Activity because of circular reference
|
||||||
export type ActivityUndoObject =
|
export type ActivityUndoObject =
|
||||||
ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate<CacheFileObject | string> | ActivityAnnounce
|
| ActivityFollow
|
||||||
|
| ActivityLike
|
||||||
|
| ActivityDislike
|
||||||
|
| ActivityCreate<CacheFileObject | string>
|
||||||
|
| ActivityAnnounce
|
||||||
|
|
||||||
export type ActivityCreateObject =
|
export type ActivityCreateObject = Extract<
|
||||||
Extract<ActivityObject, VideoObject | CacheFileObject | WatchActionObject | VideoCommentObject | PlaylistObject | string>
|
ActivityObject,
|
||||||
|
VideoObject | CacheFileObject | WatchActionObject | VideoCommentObject | PlaylistObject | string
|
||||||
|
>
|
||||||
|
|
||||||
export type Activity =
|
export type Activity =
|
||||||
ActivityCreate<ActivityCreateObject> |
|
| ActivityCreate<ActivityCreateObject>
|
||||||
ActivityUpdate<ActivityUpdateObject> |
|
| ActivityUpdate<ActivityUpdateObject>
|
||||||
ActivityDelete |
|
| ActivityDelete
|
||||||
ActivityFollow |
|
| ActivityFollow
|
||||||
ActivityAccept |
|
| ActivityAccept
|
||||||
ActivityAnnounce |
|
| ActivityAnnounce
|
||||||
ActivityUndo<ActivityUndoObject> |
|
| ActivityUndo<ActivityUndoObject>
|
||||||
ActivityLike |
|
| ActivityLike
|
||||||
ActivityReject |
|
| ActivityReject
|
||||||
ActivityView |
|
| ActivityView
|
||||||
ActivityDislike |
|
| ActivityDislike
|
||||||
ActivityFlag |
|
| ActivityFlag
|
||||||
ActivityApproveReply |
|
| ActivityApproveReply
|
||||||
ActivityRejectReply
|
| ActivityRejectReply
|
||||||
|
|
||||||
export type ActivityType =
|
export type ActivityType =
|
||||||
'Create' |
|
| 'Create'
|
||||||
'Update' |
|
| 'Update'
|
||||||
'Delete' |
|
| 'Delete'
|
||||||
'Follow' |
|
| 'Follow'
|
||||||
'Accept' |
|
| 'Accept'
|
||||||
'Announce' |
|
| 'Announce'
|
||||||
'Undo' |
|
| 'Undo'
|
||||||
'Like' |
|
| 'Like'
|
||||||
'Reject' |
|
| 'Reject'
|
||||||
'View' |
|
| 'View'
|
||||||
'Dislike' |
|
| 'Dislike'
|
||||||
'Flag' |
|
| 'Flag'
|
||||||
'ApproveReply' |
|
| 'ApproveReply'
|
||||||
'RejectReply'
|
| 'RejectReply'
|
||||||
|
|
||||||
export interface ActivityAudience {
|
export interface ActivityAudience {
|
||||||
to: string[]
|
to: string[]
|
||||||
|
@ -61,8 +68,8 @@ export interface ActivityAudience {
|
||||||
export interface BaseActivity {
|
export interface BaseActivity {
|
||||||
'@context'?: any[]
|
'@context'?: any[]
|
||||||
id: string
|
id: string
|
||||||
to?: string[]
|
to?: string[] | string
|
||||||
cc?: string[]
|
cc?: string[] | string
|
||||||
actor: string | ActivityPubActor
|
actor: string | ActivityPubActor
|
||||||
type: ActivityType
|
type: ActivityType
|
||||||
signature?: ActivityPubSignature
|
signature?: ActivityPubSignature
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { arrayify } from '@peertube/peertube-core-utils'
|
||||||
import { ContextType } from '@peertube/peertube-models'
|
import { ContextType } from '@peertube/peertube-models'
|
||||||
import { ACTIVITY_PUB, REMOTE_SCHEME } from '@server/initializers/constants.js'
|
import { ACTIVITY_PUB, REMOTE_SCHEME } from '@server/initializers/constants.js'
|
||||||
import { isArray } from './custom-validators/misc.js'
|
import { isArray } from './custom-validators/misc.js'
|
||||||
|
@ -53,12 +54,10 @@ export function getAPPublicValue (): 'https://www.w3.org/ns/activitystreams#Publ
|
||||||
return 'https://www.w3.org/ns/activitystreams#Public'
|
return 'https://www.w3.org/ns/activitystreams#Public'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasAPPublic (toOrCC: string[]) {
|
export function hasAPPublic (toOrCC: string[] | string) {
|
||||||
if (!isArray(toOrCC)) return false
|
|
||||||
|
|
||||||
const publicValue = getAPPublicValue()
|
const publicValue = getAPPublicValue()
|
||||||
|
|
||||||
return toOrCC.some(f => f === 'as:Public' || publicValue)
|
return arrayify(toOrCC).some(f => f === 'as:Public' || publicValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -35,6 +35,7 @@ export function isBaseActivityValid (activity: any, type: string) {
|
||||||
|
|
||||||
export function isUrlCollectionValid (collection: any) {
|
export function isUrlCollectionValid (collection: any) {
|
||||||
return collection === undefined ||
|
return collection === undefined ||
|
||||||
|
(typeof collection === 'string' && isActivityPubUrlValid(collection)) ||
|
||||||
(Array.isArray(collection) && collection.every(t => isActivityPubUrlValid(t)))
|
(Array.isArray(collection) && collection.every(t => isActivityPubUrlValid(t)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { ActivityTombstoneObject, VideoCommentObject } from '@peertube/peertube-models'
|
||||||
import { hasAPPublic } from '@server/helpers/activity-pub-utils.js'
|
import { hasAPPublic } from '@server/helpers/activity-pub-utils.js'
|
||||||
import validator from 'validator'
|
import validator from 'validator'
|
||||||
import { exists, isArray, isDateValid } from '../misc.js'
|
import { exists, isDateValid } from '../misc.js'
|
||||||
import { isActivityPubUrlValid } from './misc.js'
|
import { isActivityPubUrlValid } from './misc.js'
|
||||||
import { ActivityTombstoneObject, VideoCommentObject } from '@peertube/peertube-models'
|
|
||||||
|
|
||||||
function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | ActivityTombstoneObject) {
|
function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | ActivityTombstoneObject) {
|
||||||
if (!comment) return false
|
if (!comment) return false
|
||||||
|
@ -23,7 +23,6 @@ function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | Activ
|
||||||
isActivityPubUrlValid(comment.inReplyTo) &&
|
isActivityPubUrlValid(comment.inReplyTo) &&
|
||||||
isDateValid(comment.published) &&
|
isDateValid(comment.published) &&
|
||||||
isActivityPubUrlValid(comment.url) &&
|
isActivityPubUrlValid(comment.url) &&
|
||||||
isArray(comment.to) &&
|
|
||||||
(!exists(comment.replyApproval) || isActivityPubUrlValid(comment.replyApproval)) &&
|
(!exists(comment.replyApproval) || isActivityPubUrlValid(comment.replyApproval)) &&
|
||||||
(hasAPPublic(comment.to) || hasAPPublic(comment.cc)) // Only accept public comments
|
(hasAPPublic(comment.to) || hasAPPublic(comment.cc)) // Only accept public comments
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { sanitizeAndCheckActorObject } from '@server/helpers/custom-validators/activitypub/actor.js'
|
|
||||||
import { logger } from '@server/helpers/logger.js'
|
|
||||||
import { ActivityPubActor, ActivityPubOrderedCollection } from '@peertube/peertube-models'
|
import { ActivityPubActor, ActivityPubOrderedCollection } from '@peertube/peertube-models'
|
||||||
|
import { sanitizeAndCheckActorObject } from '@server/helpers/custom-validators/activitypub/actor.js'
|
||||||
|
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
||||||
|
import { logger } from '@server/helpers/logger.js'
|
||||||
import { fetchAP } from '../../activity.js'
|
import { fetchAP } from '../../activity.js'
|
||||||
import { checkUrlsSameHost } from '../../url.js'
|
import { checkUrlsSameHost } from '../../url.js'
|
||||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
|
||||||
|
|
||||||
export async function fetchRemoteActor (
|
export async function fetchRemoteActor (
|
||||||
actorUrl: string,
|
actorUrl: string,
|
||||||
|
@ -17,7 +17,7 @@ export async function fetchRemoteActor (
|
||||||
logger.debug('Remote actor JSON is not valid.', { actorJSON: body })
|
logger.debug('Remote actor JSON is not valid.', { actorJSON: body })
|
||||||
|
|
||||||
// Retry with the public key owner
|
// Retry with the public key owner
|
||||||
if (canRefetchPublicKeyOwner && hasPublicKeyOwner(body)) {
|
if (canRefetchPublicKeyOwner && hasPublicKeyOwner(actorUrl, body)) {
|
||||||
logger.debug('Retrying with public key owner ' + body.publicKey.owner)
|
logger.debug('Retrying with public key owner ' + body.publicKey.owner)
|
||||||
|
|
||||||
return fetchRemoteActor(body.publicKey.owner, false)
|
return fetchRemoteActor(body.publicKey.owner, false)
|
||||||
|
@ -63,6 +63,6 @@ async function fetchActorTotalItems (url: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasPublicKeyOwner (actor: ActivityPubActor) {
|
function hasPublicKeyOwner (actorUrl: string, actor: ActivityPubActor) {
|
||||||
return isUrlValid(actor?.publicKey?.owner)
|
return isUrlValid(actor?.publicKey?.owner) && checkUrlsSameHost(actorUrl, actor.publicKey.owner)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { sendReplyApproval } from '../send/send-reply-approval.js'
|
||||||
import { forwardVideoRelatedActivity } from '../send/shared/send-utils.js'
|
import { forwardVideoRelatedActivity } from '../send/shared/send-utils.js'
|
||||||
import { resolveThread } from '../video-comments.js'
|
import { resolveThread } from '../video-comments.js'
|
||||||
import { canVideoBeFederated, getOrCreateAPVideo } from '../videos/index.js'
|
import { canVideoBeFederated, getOrCreateAPVideo } from '../videos/index.js'
|
||||||
|
import { arrayify } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
async function processCreateActivity (options: APProcessorOptions<ActivityCreate<ActivityCreateObject>>) {
|
async function processCreateActivity (options: APProcessorOptions<ActivityCreate<ActivityCreateObject>>) {
|
||||||
const { activity, byActor } = options
|
const { activity, byActor } = options
|
||||||
|
@ -186,5 +187,5 @@ async function processCreatePlaylist (
|
||||||
const byAccount = byActor.Account
|
const byAccount = byActor.Account
|
||||||
if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url)
|
if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url)
|
||||||
|
|
||||||
await createOrUpdateVideoPlaylist({ playlistObject, contextUrl: byActor.url, to: activity.to })
|
await createOrUpdateVideoPlaylist({ playlistObject, contextUrl: byActor.url, to: arrayify(activity.to) })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { arrayify } from '@peertube/peertube-core-utils'
|
||||||
import {
|
import {
|
||||||
ActivityPubActor,
|
ActivityPubActor,
|
||||||
ActivityPubActorType,
|
ActivityPubActorType,
|
||||||
|
@ -78,7 +79,7 @@ async function processUpdateVideo (activity: ActivityUpdate<VideoObject | string
|
||||||
if (created) return
|
if (created) return
|
||||||
|
|
||||||
const updater = new APVideoUpdater(videoObject, video)
|
const updater = new APVideoUpdater(videoObject, video)
|
||||||
return updater.update(activity.to)
|
return updater.update(arrayify(activity.to))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processUpdateCacheFile (
|
async function processUpdateCacheFile (
|
||||||
|
@ -127,5 +128,5 @@ async function processUpdatePlaylist (
|
||||||
const byAccount = byActor.Account
|
const byAccount = byActor.Account
|
||||||
if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url)
|
if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url)
|
||||||
|
|
||||||
await createOrUpdateVideoPlaylist({ playlistObject, contextUrl: byActor.url, to: activity.to })
|
await createOrUpdateVideoPlaylist({ playlistObject, contextUrl: byActor.url, to: arrayify(activity.to) })
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
} from '../../../../types/models/index.js'
|
} from '../../../../types/models/index.js'
|
||||||
import { JobQueue } from '../../../job-queue/index.js'
|
import { JobQueue } from '../../../job-queue/index.js'
|
||||||
import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getOriginVideoAudience } from './audience-utils.js'
|
import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getOriginVideoAudience } from './audience-utils.js'
|
||||||
|
import { arrayify } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
|
async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
|
||||||
byActor: MActorLight
|
byActor: MActorLight
|
||||||
|
@ -102,8 +103,8 @@ async function forwardActivity (
|
||||||
) {
|
) {
|
||||||
logger.info('Forwarding activity %s.', activity.id)
|
logger.info('Forwarding activity %s.', activity.id)
|
||||||
|
|
||||||
const to = activity.to || []
|
const to = arrayify(activity.to)
|
||||||
const cc = activity.cc || []
|
const cc = arrayify(activity.cc)
|
||||||
|
|
||||||
const followersUrls = additionalFollowerUrls
|
const followersUrls = additionalFollowerUrls
|
||||||
for (const dest of to.concat(cc)) {
|
for (const dest of to.concat(cc)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue