diff options
author | Chocobozzz <me@florianbigard.com> | 2023-06-05 16:18:57 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-06-29 10:18:00 +0200 |
commit | 7f7e9d4e904fed9233f84089e3b2ea60ab8740f7 (patch) | |
tree | 7407ae25a483e3e8b43443a6bbdceb067b5db8e5 /server | |
parent | cefe22cf7c5286af1eb0e7a19937e741e2c2f58a (diff) | |
download | PeerTube-7f7e9d4e904fed9233f84089e3b2ea60ab8740f7.tar.gz PeerTube-7f7e9d4e904fed9233f84089e3b2ea60ab8740f7.tar.zst PeerTube-7f7e9d4e904fed9233f84089e3b2ea60ab8740f7.zip |
Handle correctly formatted AP attributedTo
Diffstat (limited to 'server')
4 files changed, 36 insertions, 20 deletions
diff --git a/server/helpers/custom-validators/activitypub/misc.ts b/server/helpers/custom-validators/activitypub/misc.ts index 279ad83dc..7df47cf15 100644 --- a/server/helpers/custom-validators/activitypub/misc.ts +++ b/server/helpers/custom-validators/activitypub/misc.ts | |||
@@ -51,7 +51,8 @@ function setValidAttributedTo (obj: any) { | |||
51 | } | 51 | } |
52 | 52 | ||
53 | obj.attributedTo = obj.attributedTo.filter(a => { | 53 | obj.attributedTo = obj.attributedTo.filter(a => { |
54 | return (a.type === 'Group' || a.type === 'Person') && isActivityPubUrlValid(a.id) | 54 | return isActivityPubUrlValid(a) || |
55 | ((a.type === 'Group' || a.type === 'Person') && isActivityPubUrlValid(a.id)) | ||
55 | }) | 56 | }) |
56 | 57 | ||
57 | return true | 58 | return true |
diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts index e73b7d707..b2be3f5fb 100644 --- a/server/lib/activitypub/actors/get.ts +++ b/server/lib/activitypub/actors/get.ts | |||
@@ -3,8 +3,9 @@ import { logger } from '@server/helpers/logger' | |||
3 | import { JobQueue } from '@server/lib/job-queue' | 3 | import { JobQueue } from '@server/lib/job-queue' |
4 | import { ActorLoadByUrlType, loadActorByUrl } from '@server/lib/model-loaders' | 4 | import { ActorLoadByUrlType, loadActorByUrl } from '@server/lib/model-loaders' |
5 | import { MActor, MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, MActorFullActor } from '@server/types/models' | 5 | import { MActor, MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, MActorFullActor } from '@server/types/models' |
6 | import { ActivityPubActor } from '@shared/models' | 6 | import { arrayify } from '@shared/core-utils' |
7 | import { getAPId } from '../activity' | 7 | import { ActivityPubActor, APObjectId } from '@shared/models' |
8 | import { fetchAPObject, getAPId } from '../activity' | ||
8 | import { checkUrlsSameHost } from '../url' | 9 | import { checkUrlsSameHost } from '../url' |
9 | import { refreshActorIfNeeded } from './refresh' | 10 | import { refreshActorIfNeeded } from './refresh' |
10 | import { APActorCreator, fetchRemoteActor } from './shared' | 11 | import { APActorCreator, fetchRemoteActor } from './shared' |
@@ -40,7 +41,7 @@ async function getOrCreateAPActor ( | |||
40 | const { actorObject } = await fetchRemoteActor(actorUrl) | 41 | const { actorObject } = await fetchRemoteActor(actorUrl) |
41 | if (actorObject === undefined) throw new Error('Cannot fetch remote actor ' + actorUrl) | 42 | if (actorObject === undefined) throw new Error('Cannot fetch remote actor ' + actorUrl) |
42 | 43 | ||
43 | // actorUrl is just an alias/rediraction, so process object id instead | 44 | // actorUrl is just an alias/redirection, so process object id instead |
44 | if (actorObject.id !== actorUrl) return getOrCreateAPActor(actorObject, 'all', recurseIfNeeded, updateCollections) | 45 | if (actorObject.id !== actorUrl) return getOrCreateAPActor(actorObject, 'all', recurseIfNeeded, updateCollections) |
45 | 46 | ||
46 | // Create the attributed to actor | 47 | // Create the attributed to actor |
@@ -68,29 +69,48 @@ async function getOrCreateAPActor ( | |||
68 | return actorRefreshed | 69 | return actorRefreshed |
69 | } | 70 | } |
70 | 71 | ||
71 | function getOrCreateAPOwner (actorObject: ActivityPubActor, actorUrl: string) { | 72 | async function getOrCreateAPOwner (actorObject: ActivityPubActor, actorUrl: string) { |
72 | const accountAttributedTo = actorObject.attributedTo.find(a => a.type === 'Person') | 73 | const accountAttributedTo = await findOwner(actorUrl, actorObject.attributedTo, 'Person') |
73 | if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actorUrl) | 74 | if (!accountAttributedTo) { |
74 | 75 | throw new Error(`Cannot find account attributed to video channel ${actorUrl}`) | |
75 | if (checkUrlsSameHost(accountAttributedTo.id, actorUrl) !== true) { | ||
76 | throw new Error(`Account attributed to ${accountAttributedTo.id} does not have the same host than actor url ${actorUrl}`) | ||
77 | } | 76 | } |
78 | 77 | ||
79 | try { | 78 | try { |
80 | // Don't recurse another time | 79 | // Don't recurse another time |
81 | const recurseIfNeeded = false | 80 | const recurseIfNeeded = false |
82 | return getOrCreateAPActor(accountAttributedTo.id, 'all', recurseIfNeeded) | 81 | return getOrCreateAPActor(accountAttributedTo, 'all', recurseIfNeeded) |
83 | } catch (err) { | 82 | } catch (err) { |
84 | logger.error('Cannot get or create account attributed to video channel ' + actorUrl) | 83 | logger.error('Cannot get or create account attributed to video channel ' + actorUrl) |
85 | throw new Error(err) | 84 | throw new Error(err) |
86 | } | 85 | } |
87 | } | 86 | } |
88 | 87 | ||
88 | async function findOwner (rootUrl: string, attributedTo: APObjectId[] | APObjectId, type: 'Person' | 'Group') { | ||
89 | for (const actorToCheck of arrayify(attributedTo)) { | ||
90 | const actorObject = await fetchAPObject<ActivityPubActor>(getAPId(actorToCheck)) | ||
91 | |||
92 | if (!actorObject) { | ||
93 | logger.warn('Unknown attributed to actor %s for owner %s', actorToCheck, rootUrl) | ||
94 | continue | ||
95 | } | ||
96 | |||
97 | if (checkUrlsSameHost(actorObject.id, rootUrl) !== true) { | ||
98 | logger.warn(`Account attributed to ${actorObject.id} does not have the same host than owner actor url ${rootUrl}`) | ||
99 | continue | ||
100 | } | ||
101 | |||
102 | if (actorObject.type === type) return actorObject | ||
103 | } | ||
104 | |||
105 | return undefined | ||
106 | } | ||
107 | |||
89 | // --------------------------------------------------------------------------- | 108 | // --------------------------------------------------------------------------- |
90 | 109 | ||
91 | export { | 110 | export { |
92 | getOrCreateAPOwner, | 111 | getOrCreateAPOwner, |
93 | getOrCreateAPActor | 112 | getOrCreateAPActor, |
113 | findOwner | ||
94 | } | 114 | } |
95 | 115 | ||
96 | // --------------------------------------------------------------------------- | 116 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/playlists/create-update.ts b/server/lib/activitypub/playlists/create-update.ts index 9339e8ea4..920d3943a 100644 --- a/server/lib/activitypub/playlists/create-update.ts +++ b/server/lib/activitypub/playlists/create-update.ts | |||
@@ -77,7 +77,7 @@ async function setVideoChannel (playlistObject: PlaylistObject, playlistAttribut | |||
77 | throw new Error('Not attributed to for playlist object ' + getAPId(playlistObject)) | 77 | throw new Error('Not attributed to for playlist object ' + getAPId(playlistObject)) |
78 | } | 78 | } |
79 | 79 | ||
80 | const actor = await getOrCreateAPActor(playlistObject.attributedTo[0], 'all') | 80 | const actor = await getOrCreateAPActor(getAPId(playlistObject.attributedTo[0]), 'all') |
81 | 81 | ||
82 | if (!actor.VideoChannel) { | 82 | if (!actor.VideoChannel) { |
83 | logger.warn('Playlist "attributedTo" %s is not a video channel.', playlistObject.id, { playlistObject, ...lTags(playlistObject.id) }) | 83 | logger.warn('Playlist "attributedTo" %s is not a video channel.', playlistObject.id, { playlistObject, ...lTags(playlistObject.id) }) |
diff --git a/server/lib/activitypub/videos/shared/abstract-builder.ts b/server/lib/activitypub/videos/shared/abstract-builder.ts index 7c5c73139..8af67ecac 100644 --- a/server/lib/activitypub/videos/shared/abstract-builder.ts +++ b/server/lib/activitypub/videos/shared/abstract-builder.ts | |||
@@ -18,8 +18,7 @@ import { | |||
18 | MVideoThumbnail | 18 | MVideoThumbnail |
19 | } from '@server/types/models' | 19 | } from '@server/types/models' |
20 | import { ActivityTagObject, ThumbnailType, VideoObject, VideoStreamingPlaylistType } from '@shared/models' | 20 | import { ActivityTagObject, ThumbnailType, VideoObject, VideoStreamingPlaylistType } from '@shared/models' |
21 | import { getOrCreateAPActor } from '../../actors' | 21 | import { findOwner, getOrCreateAPActor } from '../../actors' |
22 | import { checkUrlsSameHost } from '../../url' | ||
23 | import { | 22 | import { |
24 | getCaptionAttributesFromObject, | 23 | getCaptionAttributesFromObject, |
25 | getFileAttributesFromUrl, | 24 | getFileAttributesFromUrl, |
@@ -37,13 +36,9 @@ export abstract class APVideoAbstractBuilder { | |||
37 | protected abstract lTags: LoggerTagsFn | 36 | protected abstract lTags: LoggerTagsFn |
38 | 37 | ||
39 | protected async getOrCreateVideoChannelFromVideoObject () { | 38 | protected async getOrCreateVideoChannelFromVideoObject () { |
40 | const channel = this.videoObject.attributedTo.find(a => a.type === 'Group') | 39 | const channel = await findOwner(this.videoObject.id, this.videoObject.attributedTo, 'Group') |
41 | if (!channel) throw new Error('Cannot find associated video channel to video ' + this.videoObject.url) | 40 | if (!channel) throw new Error('Cannot find associated video channel to video ' + this.videoObject.url) |
42 | 41 | ||
43 | if (checkUrlsSameHost(channel.id, this.videoObject.id) !== true) { | ||
44 | throw new Error(`Video channel url ${channel.id} does not have the same host than video object id ${this.videoObject.id}`) | ||
45 | } | ||
46 | |||
47 | return getOrCreateAPActor(channel.id, 'all') | 42 | return getOrCreateAPActor(channel.id, 'all') |
48 | } | 43 | } |
49 | 44 | ||