diff options
author | Chocobozzz <me@florianbigard.com> | 2018-01-04 14:04:02 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-01-04 14:04:02 +0100 |
commit | a5625b416797fa20f7cccead6201f3faf9427080 (patch) | |
tree | 089ad8155f924385d5f528c96cbcec1b52f56c72 /server/lib/activitypub | |
parent | 4cb6d4578893db310297d7e118ce2fb7ecb952a3 (diff) | |
download | PeerTube-a5625b416797fa20f7cccead6201f3faf9427080.tar.gz PeerTube-a5625b416797fa20f7cccead6201f3faf9427080.tar.zst PeerTube-a5625b416797fa20f7cccead6201f3faf9427080.zip |
Refresh remote accounts
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r-- | server/lib/activitypub/actor.ts | 80 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 45 |
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 | |||
7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
10 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
11 | import { logger } from '../../helpers/logger' | 11 | import { logger } from '../../helpers/logger' |
12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
14 | import { getUrlFromWebfinger } from '../../helpers/webfinger' | ||
14 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' | 15 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' |
15 | import { AccountModel } from '../../models/account/account' | 16 | import { AccountModel } from '../../models/account/account' |
16 | import { ActorModel } from '../../models/activitypub/actor' | 17 | import { 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 | ||
69 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { | 70 | function 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 | ||
88 | async 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 | |||
106 | async 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 | |||
87 | async function fetchActorTotalItems (url: string) { | 127 | async 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 | |||
309 | async 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' | |||
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import { AccountModel } from '../../../models/account/account' | 9 | import { AccountModel } from '../../../models/account/account' |
10 | import { ActorModel } from '../../../models/activitypub/actor' | 10 | import { ActorModel } from '../../../models/activitypub/actor' |
11 | import { AvatarModel } from '../../../models/avatar/avatar' | ||
12 | import { TagModel } from '../../../models/video/tag' | 11 | import { TagModel } from '../../../models/video/tag' |
13 | import { VideoModel } from '../../../models/video/video' | 12 | import { VideoModel } from '../../../models/video/video' |
14 | import { VideoFileModel } from '../../../models/video/video-file' | 13 | import { VideoFileModel } from '../../../models/video/video-file' |
15 | import { fetchActorTotalItems, fetchAvatarIfExists, getOrCreateActorAndServerAndModel } from '../actor' | 14 | import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor' |
16 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' | 15 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' |
17 | 16 | ||
18 | async function processUpdateActivity (activity: ActivityUpdate) { | 17 | async 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) { |