import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
-import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor'
+import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils'
import { logger } from '../../helpers/logger'
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
import { doRequest, downloadImage } from '../../helpers/requests'
import { getUrlFromWebfinger } from '../../helpers/webfinger'
-import { AVATARS_SIZE, CONFIG, MIMETYPES, sequelizeTypescript } from '../../initializers'
+import { AVATARS_SIZE, MIMETYPES, WEBSERVER } from '../../initializers/constants'
import { AccountModel } from '../../models/account/account'
import { ActorModel } from '../../models/activitypub/actor'
import { AvatarModel } from '../../models/avatar/avatar'
import { JobQueue } from '../job-queue'
import { getServerActor } from '../../helpers/utils'
import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor'
+import { CONFIG } from '../../initializers/config'
+import { sequelizeTypescript } from '../../initializers/database'
// Set account keys, this could be long so process after the account creation and do not block the client
function setAsyncActorKeys (actor: ActorModel) {
return actor.save()
})
.catch(err => {
- logger.error('Cannot set public/private keys of actor %d.', actor.uuid, { err })
+ logger.error('Cannot set public/private keys of actor %d.', actor.url, { err })
return actor
})
}
) {
const actorUrl = getAPId(activityActor)
let created = false
+ let accountPlaylistsUrl: string
let actor = await fetchActorByUrl(actorUrl, fetchType)
// Orphan actor (not associated to an account of channel) so recreate it
try {
// Don't recurse another time
- ownerActor = await getOrCreateActorAndServerAndModel(accountAttributedTo.id, 'all', false)
+ const recurseIfNeeded = false
+ ownerActor = await getOrCreateActorAndServerAndModel(accountAttributedTo.id, 'all', recurseIfNeeded)
} catch (err) {
logger.error('Cannot get or create account attributed to video channel ' + actor.url)
throw new Error(err)
actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor)
created = true
+ accountPlaylistsUrl = result.playlists
}
if (actor.Account) actor.Account.Actor = actor
await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
}
+ // We created a new account: fetch the playlists
+ if (created === true && actor.Account && accountPlaylistsUrl) {
+ const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' }
+ await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
+ }
+
return actorRefreshed
}
followingCount: 0,
inboxUrl: url + '/inbox',
outboxUrl: url + '/outbox',
- sharedInboxUrl: CONFIG.WEBSERVER.URL + '/inbox',
+ sharedInboxUrl: WEBSERVER.URL + '/inbox',
followersUrl: url + '/followers',
followingUrl: url + '/following'
})
const followersCount = await fetchActorTotalItems(attributes.followers)
const followingCount = await fetchActorTotalItems(attributes.following)
- actorInstance.set('type', attributes.type)
- actorInstance.set('uuid', attributes.uuid)
- actorInstance.set('preferredUsername', attributes.preferredUsername)
- actorInstance.set('url', attributes.id)
- actorInstance.set('publicKey', attributes.publicKey.publicKeyPem)
- actorInstance.set('followersCount', followersCount)
- actorInstance.set('followingCount', followingCount)
- actorInstance.set('inboxUrl', attributes.inbox)
- actorInstance.set('outboxUrl', attributes.outbox)
- actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox)
- actorInstance.set('followersUrl', attributes.followers)
- actorInstance.set('followingUrl', attributes.following)
+ actorInstance.type = attributes.type
+ actorInstance.preferredUsername = attributes.preferredUsername
+ actorInstance.url = attributes.id
+ actorInstance.publicKey = attributes.publicKey.publicKeyPem
+ actorInstance.followersCount = followersCount
+ actorInstance.followingCount = followingCount
+ actorInstance.inboxUrl = attributes.inbox
+ actorInstance.outboxUrl = attributes.outbox
+ actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox
+ actorInstance.followersUrl = attributes.followers
+ actorInstance.followingUrl = attributes.following
}
async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) {
return undefined
}
-async function addFetchOutboxJob (actor: ActorModel) {
+async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) {
// Don't fetch ourselves
const serverActor = await getServerActor()
if (serverActor.id === actor.id) {
await actor.save({ transaction: t })
if (actor.Account) {
- actor.Account.set('name', result.name)
- actor.Account.set('description', result.summary)
+ actor.Account.name = result.name
+ actor.Account.description = result.summary
await actor.Account.save({ transaction: t })
} else if (actor.VideoChannel) {
- actor.VideoChannel.set('name', result.name)
- actor.VideoChannel.set('description', result.summary)
- actor.VideoChannel.set('support', result.support)
+ actor.VideoChannel.name = result.name
+ actor.VideoChannel.description = result.summary
+ actor.VideoChannel.support = result.support
await actor.VideoChannel.save({ transaction: t })
}
return { refreshed: true, actor }
})
} catch (err) {
- logger.warn('Cannot refresh actor.', { err })
+ logger.warn('Cannot refresh actor %s.', actor.url, { err })
return { actor, refreshed: false }
}
}
actorCreated.VideoChannel.Account = ownerActor.Account
}
+ actorCreated.Server = server
+
return actorCreated
}
}
name: string
summary: string
support?: string
+ playlists?: string
avatarName?: string
attributedTo: ActivityPubAttributedTo[]
}
logger.info('Fetching remote actor %s.', actorUrl)
const requestResult = await doRequest<ActivityPubActor>(options)
- normalizeActor(requestResult.body)
-
const actorJSON = requestResult.body
- if (isActorObjectValid(actorJSON) === false) {
+
+ if (sanitizeAndCheckActorObject(actorJSON) === false) {
logger.debug('Remote actor JSON is not valid.', { actorJSON })
return { result: undefined, statusCode: requestResult.response.statusCode }
}
if (checkUrlsSameHost(actorJSON.id, actorUrl) !== true) {
- throw new Error('Actor url ' + actorUrl + ' has not the same host than its AP id ' + actorJSON.id)
+ logger.warn('Actor url %s has not the same host than its AP id %s', actorUrl, actorJSON.id)
+ return { result: undefined, statusCode: requestResult.response.statusCode }
}
const followersCount = await fetchActorTotalItems(actorJSON.followers)
const actor = new ActorModel({
type: actorJSON.type,
- uuid: actorJSON.uuid,
preferredUsername: actorJSON.preferredUsername,
url: actorJSON.id,
publicKey: actorJSON.publicKey.publicKeyPem,
avatarName,
summary: actorJSON.summary,
support: actorJSON.support,
+ playlists: actorJSON.playlists,
attributedTo: actorJSON.attributedTo
}
}