mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-03 09:49:20 +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
|
@ -1,4 +1,4 @@
|
|||
export function findCommonElement <T> (array1: T[], array2: T[]) {
|
||||
export function findCommonElement<T> (array1: T[], array2: T[]) {
|
||||
for (const a of array1) {
|
||||
for (const b of array2) {
|
||||
if (a === b) return a
|
||||
|
@ -9,13 +9,14 @@ export function findCommonElement <T> (array1: T[], array2: T[]) {
|
|||
}
|
||||
|
||||
// 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 (element === undefined || element === null) return []
|
||||
|
||||
return [ element ]
|
||||
}
|
||||
|
||||
export function unarray <T> (element: T | T[]) {
|
||||
export function unarray<T> (element: T | T[]) {
|
||||
if (Array.isArray(element)) {
|
||||
if (element.length === 0) return undefined
|
||||
|
||||
|
@ -26,24 +27,24 @@ export function unarray <T> (element: T | T[]) {
|
|||
}
|
||||
|
||||
// Avoid conflict with other uniq() functions
|
||||
export function uniqify <T> (elements: T[]) {
|
||||
export function uniqify<T> (elements: T[]) {
|
||||
return Array.from(new Set(elements))
|
||||
}
|
||||
|
||||
// Thanks: https://stackoverflow.com/a/12646864
|
||||
export function shuffle <T> (elements: T[]) {
|
||||
export function shuffle<T> (elements: T[]) {
|
||||
const shuffled = [ ...elements ]
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
export function sortBy <T> (obj: T[], key1: string, key2?: string): T[] {
|
||||
export function sortBy<T> (obj: T[], key1: string, key2?: string): T[] {
|
||||
return obj.sort((a, b) => {
|
||||
const elem1 = key2 ? a[key1][key2] : a[key1]
|
||||
const elem2 = key2 ? b[key1][key2] : b[key1]
|
||||
|
@ -54,7 +55,7 @@ export function sortBy <T> (obj: T[], key1: string, key2?: string): T[] {
|
|||
})
|
||||
}
|
||||
|
||||
export function maxBy <T> (arr: T[], property: keyof T) {
|
||||
export function maxBy<T> (arr: T[], property: keyof T) {
|
||||
let result: T
|
||||
|
||||
for (const obj of arr) {
|
||||
|
@ -64,7 +65,7 @@ export function maxBy <T> (arr: T[], property: keyof T) {
|
|||
return result
|
||||
}
|
||||
|
||||
export function minBy <T> (arr: T[], property: keyof T) {
|
||||
export function minBy<T> (arr: T[], property: keyof T) {
|
||||
let result: T
|
||||
|
||||
for (const obj of arr) {
|
||||
|
|
|
@ -12,46 +12,53 @@ import {
|
|||
} from './objects/index.js'
|
||||
|
||||
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
|
||||
export type ActivityUndoObject =
|
||||
ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate<CacheFileObject | string> | ActivityAnnounce
|
||||
| ActivityFollow
|
||||
| ActivityLike
|
||||
| ActivityDislike
|
||||
| ActivityCreate<CacheFileObject | string>
|
||||
| ActivityAnnounce
|
||||
|
||||
export type ActivityCreateObject =
|
||||
Extract<ActivityObject, VideoObject | CacheFileObject | WatchActionObject | VideoCommentObject | PlaylistObject | string>
|
||||
export type ActivityCreateObject = Extract<
|
||||
ActivityObject,
|
||||
VideoObject | CacheFileObject | WatchActionObject | VideoCommentObject | PlaylistObject | string
|
||||
>
|
||||
|
||||
export type Activity =
|
||||
ActivityCreate<ActivityCreateObject> |
|
||||
ActivityUpdate<ActivityUpdateObject> |
|
||||
ActivityDelete |
|
||||
ActivityFollow |
|
||||
ActivityAccept |
|
||||
ActivityAnnounce |
|
||||
ActivityUndo<ActivityUndoObject> |
|
||||
ActivityLike |
|
||||
ActivityReject |
|
||||
ActivityView |
|
||||
ActivityDislike |
|
||||
ActivityFlag |
|
||||
ActivityApproveReply |
|
||||
ActivityRejectReply
|
||||
| ActivityCreate<ActivityCreateObject>
|
||||
| ActivityUpdate<ActivityUpdateObject>
|
||||
| ActivityDelete
|
||||
| ActivityFollow
|
||||
| ActivityAccept
|
||||
| ActivityAnnounce
|
||||
| ActivityUndo<ActivityUndoObject>
|
||||
| ActivityLike
|
||||
| ActivityReject
|
||||
| ActivityView
|
||||
| ActivityDislike
|
||||
| ActivityFlag
|
||||
| ActivityApproveReply
|
||||
| ActivityRejectReply
|
||||
|
||||
export type ActivityType =
|
||||
'Create' |
|
||||
'Update' |
|
||||
'Delete' |
|
||||
'Follow' |
|
||||
'Accept' |
|
||||
'Announce' |
|
||||
'Undo' |
|
||||
'Like' |
|
||||
'Reject' |
|
||||
'View' |
|
||||
'Dislike' |
|
||||
'Flag' |
|
||||
'ApproveReply' |
|
||||
'RejectReply'
|
||||
| 'Create'
|
||||
| 'Update'
|
||||
| 'Delete'
|
||||
| 'Follow'
|
||||
| 'Accept'
|
||||
| 'Announce'
|
||||
| 'Undo'
|
||||
| 'Like'
|
||||
| 'Reject'
|
||||
| 'View'
|
||||
| 'Dislike'
|
||||
| 'Flag'
|
||||
| 'ApproveReply'
|
||||
| 'RejectReply'
|
||||
|
||||
export interface ActivityAudience {
|
||||
to: string[]
|
||||
|
@ -61,19 +68,19 @@ export interface ActivityAudience {
|
|||
export interface BaseActivity {
|
||||
'@context'?: any[]
|
||||
id: string
|
||||
to?: string[]
|
||||
cc?: string[]
|
||||
to?: string[] | string
|
||||
cc?: string[] | string
|
||||
actor: string | ActivityPubActor
|
||||
type: ActivityType
|
||||
signature?: ActivityPubSignature
|
||||
}
|
||||
|
||||
export interface ActivityCreate <T extends ActivityCreateObject> extends BaseActivity {
|
||||
export interface ActivityCreate<T extends ActivityCreateObject> extends BaseActivity {
|
||||
type: 'Create'
|
||||
object: T
|
||||
}
|
||||
|
||||
export interface ActivityUpdate <T extends ActivityUpdateObject> extends BaseActivity {
|
||||
export interface ActivityUpdate<T extends ActivityUpdateObject> extends BaseActivity {
|
||||
type: 'Update'
|
||||
object: T
|
||||
}
|
||||
|
@ -115,7 +122,7 @@ export interface ActivityAnnounce extends BaseActivity {
|
|||
object: APObjectId
|
||||
}
|
||||
|
||||
export interface ActivityUndo <T extends ActivityUndoObject> extends BaseActivity {
|
||||
export interface ActivityUndo<T extends ActivityUndoObject> extends BaseActivity {
|
||||
type: 'Undo'
|
||||
object: T
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { arrayify } from '@peertube/peertube-core-utils'
|
||||
import { ContextType } from '@peertube/peertube-models'
|
||||
import { ACTIVITY_PUB, REMOTE_SCHEME } from '@server/initializers/constants.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'
|
||||
}
|
||||
|
||||
export function hasAPPublic (toOrCC: string[]) {
|
||||
if (!isArray(toOrCC)) return false
|
||||
|
||||
export function hasAPPublic (toOrCC: string[] | string) {
|
||||
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) {
|
||||
return collection === undefined ||
|
||||
(typeof collection === 'string' && isActivityPubUrlValid(collection)) ||
|
||||
(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 validator from 'validator'
|
||||
import { exists, isArray, isDateValid } from '../misc.js'
|
||||
import { exists, isDateValid } from '../misc.js'
|
||||
import { isActivityPubUrlValid } from './misc.js'
|
||||
import { ActivityTombstoneObject, VideoCommentObject } from '@peertube/peertube-models'
|
||||
|
||||
function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | ActivityTombstoneObject) {
|
||||
if (!comment) return false
|
||||
|
@ -23,7 +23,6 @@ function sanitizeAndCheckVideoCommentObject (comment: VideoCommentObject | Activ
|
|||
isActivityPubUrlValid(comment.inReplyTo) &&
|
||||
isDateValid(comment.published) &&
|
||||
isActivityPubUrlValid(comment.url) &&
|
||||
isArray(comment.to) &&
|
||||
(!exists(comment.replyApproval) || isActivityPubUrlValid(comment.replyApproval)) &&
|
||||
(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 { 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 { checkUrlsSameHost } from '../../url.js'
|
||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
||||
|
||||
export async function fetchRemoteActor (
|
||||
actorUrl: string,
|
||||
|
@ -17,7 +17,7 @@ export async function fetchRemoteActor (
|
|||
logger.debug('Remote actor JSON is not valid.', { actorJSON: body })
|
||||
|
||||
// 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)
|
||||
|
||||
return fetchRemoteActor(body.publicKey.owner, false)
|
||||
|
@ -63,6 +63,6 @@ async function fetchActorTotalItems (url: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function hasPublicKeyOwner (actor: ActivityPubActor) {
|
||||
return isUrlValid(actor?.publicKey?.owner)
|
||||
function hasPublicKeyOwner (actorUrl: string, actor: ActivityPubActor) {
|
||||
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 { resolveThread } from '../video-comments.js'
|
||||
import { canVideoBeFederated, getOrCreateAPVideo } from '../videos/index.js'
|
||||
import { arrayify } from '@peertube/peertube-core-utils'
|
||||
|
||||
async function processCreateActivity (options: APProcessorOptions<ActivityCreate<ActivityCreateObject>>) {
|
||||
const { activity, byActor } = options
|
||||
|
@ -186,5 +187,5 @@ async function processCreatePlaylist (
|
|||
const byAccount = byActor.Account
|
||||
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 {
|
||||
ActivityPubActor,
|
||||
ActivityPubActorType,
|
||||
|
@ -78,7 +79,7 @@ async function processUpdateVideo (activity: ActivityUpdate<VideoObject | string
|
|||
if (created) return
|
||||
|
||||
const updater = new APVideoUpdater(videoObject, video)
|
||||
return updater.update(activity.to)
|
||||
return updater.update(arrayify(activity.to))
|
||||
}
|
||||
|
||||
async function processUpdateCacheFile (
|
||||
|
@ -127,5 +128,5 @@ async function processUpdatePlaylist (
|
|||
const byAccount = byActor.Account
|
||||
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'
|
||||
import { JobQueue } from '../../../job-queue/index.js'
|
||||
import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getOriginVideoAudience } from './audience-utils.js'
|
||||
import { arrayify } from '@peertube/peertube-core-utils'
|
||||
|
||||
async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
|
||||
byActor: MActorLight
|
||||
|
@ -102,8 +103,8 @@ async function forwardActivity (
|
|||
) {
|
||||
logger.info('Forwarding activity %s.', activity.id)
|
||||
|
||||
const to = activity.to || []
|
||||
const cc = activity.cc || []
|
||||
const to = arrayify(activity.to)
|
||||
const cc = arrayify(activity.cc)
|
||||
|
||||
const followersUrls = additionalFollowerUrls
|
||||
for (const dest of to.concat(cc)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue