2
1

activitypub-follow.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import * as Bull from 'bull'
  2. import { logger } from '../../../helpers/logger'
  3. import { REMOTE_SCHEME, WEBSERVER } from '../../../initializers/constants'
  4. import { sendFollow } from '../../activitypub/send'
  5. import { sanitizeHost } from '../../../helpers/core-utils'
  6. import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger'
  7. import { getOrCreateActorAndServerAndModel } from '../../activitypub/actor'
  8. import { retryTransactionWrapper } from '../../../helpers/database-utils'
  9. import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
  10. import { ActorModel } from '../../../models/activitypub/actor'
  11. import { Notifier } from '../../notifier'
  12. import { sequelizeTypescript } from '../../../initializers/database'
  13. export type ActivitypubFollowPayload = {
  14. followerActorId: number
  15. name: string
  16. host: string
  17. }
  18. async function processActivityPubFollow (job: Bull.Job) {
  19. const payload = job.data as ActivitypubFollowPayload
  20. const host = payload.host
  21. logger.info('Processing ActivityPub follow in job %d.', job.id)
  22. let targetActor: ActorModel
  23. if (!host || host === WEBSERVER.HOST) {
  24. targetActor = await ActorModel.loadLocalByName(payload.name)
  25. } else {
  26. const sanitizedHost = sanitizeHost(host, REMOTE_SCHEME.HTTP)
  27. const actorUrl = await loadActorUrlOrGetFromWebfinger(payload.name + '@' + sanitizedHost)
  28. targetActor = await getOrCreateActorAndServerAndModel(actorUrl)
  29. }
  30. const fromActor = await ActorModel.load(payload.followerActorId)
  31. return retryTransactionWrapper(follow, fromActor, targetActor)
  32. }
  33. // ---------------------------------------------------------------------------
  34. export {
  35. processActivityPubFollow
  36. }
  37. // ---------------------------------------------------------------------------
  38. async function follow (fromActor: ActorModel, targetActor: ActorModel) {
  39. if (fromActor.id === targetActor.id) {
  40. throw new Error('Follower is the same than target actor.')
  41. }
  42. // Same server, direct accept
  43. const state = !fromActor.serverId && !targetActor.serverId ? 'accepted' : 'pending'
  44. const actorFollow = await sequelizeTypescript.transaction(async t => {
  45. const [ actorFollow ] = await ActorFollowModel.findOrCreate({
  46. where: {
  47. actorId: fromActor.id,
  48. targetActorId: targetActor.id
  49. },
  50. defaults: {
  51. state,
  52. actorId: fromActor.id,
  53. targetActorId: targetActor.id
  54. },
  55. transaction: t
  56. })
  57. actorFollow.ActorFollowing = targetActor
  58. actorFollow.ActorFollower = fromActor
  59. // Send a notification to remote server if our follow is not already accepted
  60. if (actorFollow.state !== 'accepted') await sendFollow(actorFollow)
  61. return actorFollow
  62. })
  63. if (actorFollow.state === 'accepted') Notifier.Instance.notifyOfNewUserFollow(actorFollow)
  64. }