-
Notifications
You must be signed in to change notification settings - Fork 42
/
sendNote.ts
120 lines (98 loc) · 4.01 KB
/
sendNote.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import type { VercelRequest, VercelResponse } from '@vercel/node';
import { AP } from 'activitypub-core-types';
import admin from 'firebase-admin';
import { OrderedCollection } from 'activitypub-core-types/lib/activitypub/index.js';
import { sendSignedRequest } from '../../lib/activitypub/utils/sendSignedRequest.js';
import { fetchActorInformation } from '../../lib/activitypub/utils/fetchActorInformation.js';
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n')
})
});
}
const db = admin.firestore();
/*
Sends the latest not that hasn't yet been sent.
*/
export default async function (req: VercelRequest, res: VercelResponse) {
const { body, query, method, url, headers } = req;
if (
headers.authorization !== `Bearer ${process.env.CRON_SECRET}`
) {
return res.status(401).end("Unauthorized");
}
const configCollection = db.collection('config');
const configRef = configCollection.doc("config");
const config = await configRef.get();
if (config.exists == false) {
// Config doesn't exist, make something
configRef.set({
"lastId": ""
});
}
const configData = config.data();
let lastId = "";
if (configData != undefined) {
lastId = configData.lastId;
}
// Get my outbox because it contains all my notes.
const outboxResponse = await fetch('https://paul.kinlan.me/outbox');
const outbox = <OrderedCollection>(await outboxResponse.json());
const followersCollection = db.collection('followers');
const followersQuerySnapshot = await followersCollection.get();
let lastSuccessfulSentId = "";
for (const followerDoc of followersQuerySnapshot.docs) {
const follower = followerDoc.data();
try {
const actorUrl = (typeof follower.actor == "string") ? follower.actor : follower.actor.id;
console.log(`Fetching actor information for ${actorUrl}`)
const actorInformation = await fetchActorInformation(actorUrl);
if (actorInformation == undefined) {
// We can't send to this actor, so skip the actor. We should log it.
continue;
}
if (actorInformation.inbox == undefined) {
console.log(
`Actor ${actorUrl} doesn't have an inbox, so we can't send to them. ${actorInformation}`
);
}
const actorInbox = new URL(actorInformation.inbox.toString());
for (const iteIdx in (<AP.EntityReference[]>outbox.orderedItems)) {
// We have to break somewhere... do it after the first.
const item = (<AP.EntityReference[]>outbox.orderedItems)[iteIdx];
console.log(`Checking ID ${item.id}, ${lastId}`);
if (item.id == `${lastId}`) {
lastSuccessfulSentId = item.id;
// We've already posted this, don't try and send it again.
console.log(`${item.id} has already been posted - don't attempt`)
break;
}
if (item.object != undefined) {
// We might not need this.
item.object.published = (new Date()).toISOString();
}
// Item will be an entity, i.e, { Create { Note } }
try {
console.log(`Sending to ${actorInbox}`);
const response = await sendSignedRequest(actorInbox, <AP.Activity> item);
console.log(`Send result: ${actorInbox}`, response.status, response.statusText, await response.text());
// It's not been sent.
lastSuccessfulSentId = item.id; // we shouldn't really set this every time.
} catch (sendSignedError) {
console.log("Error sending signed request", sendSignedError)
}
break; // At some point we might want to post more than one post, so remove this.
}
} catch (ex) {
console.log("Error", ex);
}
}
configRef.set({
"lastId": lastSuccessfulSentId
});
res.status(200).end("ok");
};