aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r--server/lib/activitypub/actor.ts80
-rw-r--r--server/lib/activitypub/process/process-update.ts45
2 files changed, 86 insertions, 39 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index b6ba2cc22..0882ab843 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -7,10 +7,11 @@ import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/a
7import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' 7import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
8import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' 8import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor'
9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
10import { retryTransactionWrapper } from '../../helpers/database-utils' 10import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils'
11import { logger } from '../../helpers/logger' 11import { logger } from '../../helpers/logger'
12import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' 12import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
13import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' 13import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
14import { getUrlFromWebfinger } from '../../helpers/webfinger'
14import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' 15import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers'
15import { AccountModel } from '../../models/account/account' 16import { AccountModel } from '../../models/account/account'
16import { ActorModel } from '../../models/activitypub/actor' 17import { ActorModel } from '../../models/activitypub/actor'
@@ -63,7 +64,7 @@ async function getOrCreateActorAndServerAndModel (actorUrl: string, recurseIfNee
63 actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) 64 actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options)
64 } 65 }
65 66
66 return actor 67 return refreshActorIfNeeded(actor)
67} 68}
68 69
69function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { 70function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) {
@@ -84,6 +85,45 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU
84 }) 85 })
85} 86}
86 87
88async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) {
89 const followersCount = await fetchActorTotalItems(attributes.followers)
90 const followingCount = await fetchActorTotalItems(attributes.following)
91
92 actorInstance.set('type', attributes.type)
93 actorInstance.set('uuid', attributes.uuid)
94 actorInstance.set('preferredUsername', attributes.preferredUsername)
95 actorInstance.set('url', attributes.id)
96 actorInstance.set('publicKey', attributes.publicKey.publicKeyPem)
97 actorInstance.set('followersCount', followersCount)
98 actorInstance.set('followingCount', followingCount)
99 actorInstance.set('inboxUrl', attributes.inbox)
100 actorInstance.set('outboxUrl', attributes.outbox)
101 actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox)
102 actorInstance.set('followersUrl', attributes.followers)
103 actorInstance.set('followingUrl', attributes.following)
104}
105
106async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) {
107 if (avatarName !== undefined) {
108 if (actorInstance.avatarId) {
109 try {
110 await actorInstance.Avatar.destroy({ transaction: t })
111 } catch (err) {
112 logger.error('Cannot remove old avatar of actor %s.', actorInstance.url, err)
113 }
114 }
115
116 const avatar = await AvatarModel.create({
117 filename: avatarName
118 }, { transaction: t })
119
120 actorInstance.set('avatarId', avatar.id)
121 actorInstance.Avatar = avatar
122 }
123
124 return actorInstance
125}
126
87async function fetchActorTotalItems (url: string) { 127async function fetchActorTotalItems (url: string) {
88 const options = { 128 const options = {
89 uri: url, 129 uri: url,
@@ -129,7 +169,9 @@ export {
129 buildActorInstance, 169 buildActorInstance,
130 setAsyncActorKeys, 170 setAsyncActorKeys,
131 fetchActorTotalItems, 171 fetchActorTotalItems,
132 fetchAvatarIfExists 172 fetchAvatarIfExists,
173 updateActorInstance,
174 updateActorAvatarInstance
133} 175}
134 176
135// --------------------------------------------------------------------------- 177// ---------------------------------------------------------------------------
@@ -263,3 +305,35 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu
263 305
264 return videoChannel.save({ transaction: t }) 306 return videoChannel.save({ transaction: t })
265} 307}
308
309async function refreshActorIfNeeded (actor: ActorModel) {
310 if (!actor.isOutdated()) return actor
311
312 const actorUrl = await getUrlFromWebfinger(actor.preferredUsername, actor.getHost())
313 const result = await fetchRemoteActor(actorUrl)
314 if (result === undefined) throw new Error('Cannot fetch remote actor in refresh actor.')
315
316 return sequelizeTypescript.transaction(async t => {
317 updateInstanceWithAnother(actor, result.actor)
318
319 if (result.avatarName !== undefined) {
320 await updateActorAvatarInstance(actor, result.avatarName, t)
321 }
322
323 await actor.save({ transaction: t })
324
325 if (actor.Account) {
326 await actor.save({ transaction: t })
327
328 actor.Account.set('name', result.name)
329 await actor.Account.save({ transaction: t })
330 } else if (actor.VideoChannel) {
331 await actor.save({ transaction: t })
332
333 actor.VideoChannel.set('name', result.name)
334 await actor.VideoChannel.save({ transaction: t })
335 }
336
337 return actor
338 })
339}
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts
index 05ea7d272..2c094f7ca 100644
--- a/server/lib/activitypub/process/process-update.ts
+++ b/server/lib/activitypub/process/process-update.ts
@@ -8,11 +8,10 @@ import { resetSequelizeInstance } from '../../../helpers/utils'
8import { sequelizeTypescript } from '../../../initializers' 8import { sequelizeTypescript } from '../../../initializers'
9import { AccountModel } from '../../../models/account/account' 9import { AccountModel } from '../../../models/account/account'
10import { ActorModel } from '../../../models/activitypub/actor' 10import { ActorModel } from '../../../models/activitypub/actor'
11import { AvatarModel } from '../../../models/avatar/avatar'
12import { TagModel } from '../../../models/video/tag' 11import { TagModel } from '../../../models/video/tag'
13import { VideoModel } from '../../../models/video/video' 12import { VideoModel } from '../../../models/video/video'
14import { VideoFileModel } from '../../../models/video/video-file' 13import { VideoFileModel } from '../../../models/video/video-file'
15import { fetchActorTotalItems, fetchAvatarIfExists, getOrCreateActorAndServerAndModel } from '../actor' 14import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
16import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' 15import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc'
17 16
18async function processUpdateActivity (activity: ActivityUpdate) { 17async function processUpdateActivity (activity: ActivityUpdate) {
@@ -124,7 +123,6 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate)
124 const accountAttributesToUpdate = activity.object as ActivityPubActor 123 const accountAttributesToUpdate = activity.object as ActivityPubActor
125 124
126 logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid) 125 logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid)
127 let actorInstance: ActorModel
128 let accountInstance: AccountModel 126 let accountInstance: AccountModel
129 let actorFieldsSave: object 127 let actorFieldsSave: object
130 let accountFieldsSave: object 128 let accountFieldsSave: object
@@ -134,39 +132,14 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate)
134 132
135 try { 133 try {
136 await sequelizeTypescript.transaction(async t => { 134 await sequelizeTypescript.transaction(async t => {
137 actorInstance = await ActorModel.loadByUrl(accountAttributesToUpdate.id, t) 135 actorFieldsSave = actor.toJSON()
138 if (!actorInstance) throw new Error('Actor ' + accountAttributesToUpdate.id + ' not found.') 136 accountInstance = actor.Account
139 137 accountFieldsSave = actor.Account.toJSON()
140 actorFieldsSave = actorInstance.toJSON()
141 accountInstance = actorInstance.Account
142 accountFieldsSave = actorInstance.Account.toJSON()
143
144 const followersCount = await fetchActorTotalItems(accountAttributesToUpdate.followers)
145 const followingCount = await fetchActorTotalItems(accountAttributesToUpdate.following)
146
147 actorInstance.set('type', accountAttributesToUpdate.type)
148 actorInstance.set('uuid', accountAttributesToUpdate.uuid)
149 actorInstance.set('preferredUsername', accountAttributesToUpdate.preferredUsername)
150 actorInstance.set('url', accountAttributesToUpdate.id)
151 actorInstance.set('publicKey', accountAttributesToUpdate.publicKey.publicKeyPem)
152 actorInstance.set('followersCount', followersCount)
153 actorInstance.set('followingCount', followingCount)
154 actorInstance.set('inboxUrl', accountAttributesToUpdate.inbox)
155 actorInstance.set('outboxUrl', accountAttributesToUpdate.outbox)
156 actorInstance.set('sharedInboxUrl', accountAttributesToUpdate.endpoints.sharedInbox)
157 actorInstance.set('followersUrl', accountAttributesToUpdate.followers)
158 actorInstance.set('followingUrl', accountAttributesToUpdate.following)
159 138
160 if (avatarName !== undefined) { 139 await updateActorInstance(actor, accountAttributesToUpdate)
161 if (actorInstance.avatarId) {
162 await actorInstance.Avatar.destroy({ transaction: t })
163 }
164
165 const avatar = await AvatarModel.create({
166 filename: avatarName
167 }, { transaction: t })
168 140
169 actor.set('avatarId', avatar.id) 141 if (avatarName !== undefined) {
142 await updateActorAvatarInstance(actor, avatarName, t)
170 } 143 }
171 144
172 await actor.save({ transaction: t }) 145 await actor.save({ transaction: t })
@@ -177,8 +150,8 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate)
177 150
178 logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid) 151 logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid)
179 } catch (err) { 152 } catch (err) {
180 if (actorInstance !== undefined && actorFieldsSave !== undefined) { 153 if (actor !== undefined && actorFieldsSave !== undefined) {
181 resetSequelizeInstance(actorInstance, actorFieldsSave) 154 resetSequelizeInstance(actor, actorFieldsSave)
182 } 155 }
183 156
184 if (accountInstance !== undefined && accountFieldsSave !== undefined) { 157 if (accountInstance !== undefined && accountFieldsSave !== undefined) {