unoffical wafrn mirror
wafrn.net
atproto
social-network
activitypub
1import { SignedRequest } from '../../interfaces/fediverse/signedRequest.js'
2import { Response } from 'express'
3import { getPostAndUserFromPostId } from '../cacheGetters/getPostAndUserFromPostId.js'
4import { getFollowerRemoteIds } from '../cacheGetters/getFollowerRemoteIds.js'
5import { logger } from '../logger.js'
6import { postToJSONLD } from './postToJSONLD.js'
7import { getRemoteActor } from './getRemoteActor.js'
8import { Queue } from 'bullmq'
9import { completeEnvironment } from '../backendOptions.js'
10import { FederatedHost, Follows, User } from '../../models/index.js'
11import { Op } from 'sequelize'
12import { Privacy } from '../../models/post.js'
13
14const processPostViewQueue = new Queue('processRemoteView', {
15 connection: completeEnvironment.bullmqConnection,
16 defaultJobOptions: {
17 removeOnComplete: true,
18 attempts: 3,
19 backoff: {
20 type: 'exponential',
21 delay: 25000
22 },
23 removeOnFail: true
24 }
25})
26
27async function handlePostRequest(req: SignedRequest, res: Response) {
28 if (req.params?.id) {
29 const cachePost = await getPostAndUserFromPostId(req.params.id)
30 const post = cachePost.data
31 if (post) {
32 // we get remote user async-ly
33 const fediData = req.fediData as {
34 fediHost: string
35 remoteUserUrl: string
36 valid: boolean
37 }
38 const user = post.user
39 if (user.isRemoteUser) {
40 // EXTERNAL USER
41 if (post.remotePostId) {
42 res.redirect(post.remotePostId)
43 } else {
44 // bsky post
45 res.sendStatus(404)
46 }
47 return
48 }
49 if (user.banned) {
50 res.sendStatus(410)
51 return
52 }
53 const remoteActor = await getRemoteActor(fediData.remoteUserUrl, cachePost.data.user, false)
54 if (!remoteActor) {
55 logger.debug({
56 message: `remote actor not found`,
57 fedidata: fediData
58 })
59 return res.sendStatus(500)
60 } else {
61 const federatedHost = await remoteActor.getFederatedHost()
62 await processPostViewQueue.add('processPost', {
63 postId: post.id,
64 federatedHostId: federatedHost && federatedHost.publicInbox ? federatedHost.id : '',
65 userId: federatedHost?.publicInbox ? '' : remoteActor.id
66 })
67 }
68 if (post.privacy === Privacy.DirectMessage) {
69 res.sendStatus(403)
70 return
71 }
72 if (post.privacy === Privacy.FollowersOnly) {
73 const followerIds = await getFollowerRemoteIds(user.id)
74 try {
75 if (remoteActor) {
76 const followerServers = (
77 await User.findAll({
78 include: [FederatedHost],
79 where: {
80 id: {
81 [Op.in]: (
82 await Follows.findAll({
83 where: {
84 followedId: user.id
85 }
86 })
87 ).map((elem: any) => elem.followerId)
88 }
89 }
90 })
91 ).map((elem: any) => elem.federatedHostId)
92 if (
93 !(followerIds.includes(remoteActor.remoteId) || followerServers.includes(remoteActor.federatedHostId))
94 ) {
95 res.sendStatus(403)
96 return
97 }
98 } else {
99 res.sendStatus(403)
100 return
101 }
102 } catch (error) {
103 logger.warn({
104 message: 'Error on post',
105 postId: post.id,
106 fediData: req.fediData,
107 user: user.id,
108 error: error
109 })
110 res.sendStatus(500)
111 return
112 }
113 }
114 const response = await postToJSONLD(post.id)
115 if (!response) {
116 return res.sendStatus(404)
117 }
118 res.set({
119 'content-type': 'application/activity+json'
120 })
121 res.send({
122 ...response.object,
123 '@context': response['@context']
124 })
125 } else {
126 res.sendStatus(404)
127 }
128 } else {
129 res.sendStatus(404)
130 }
131 res.end()
132}
133
134export { handlePostRequest }