mirror of
https://github.com/dariusk/rss-to-activitypub.git
synced 2024-05-19 09:59:18 +03:00
34b46ed9fc
As of the `v2.0.0` release of this project, only users who are authenticated with a particular OAuth server can _create_ feeds. Any federated user can still read the feeds. I implemented this because running this service in the open invited thousands of spammers to create feeds and overwhelm the service. With this new model, you can run this as an added bonus for people in a community like a Mastodon server, and as the person running it you are taking on only the moderation burden of the users you are already responsible for on your federated server.
107 lines
3.8 KiB
JavaScript
107 lines
3.8 KiB
JavaScript
'use strict';
|
|
const express = require('express'),
|
|
crypto = require('crypto'),
|
|
request = require('request'),
|
|
fs = require('fs'),
|
|
router = express.Router();
|
|
|
|
function signAndSend(message, name, domain, req, res, targetDomain) {
|
|
// get the URI of the actor object and append 'inbox' to it
|
|
let inbox = message.object.actor+'/inbox';
|
|
let inboxFragment = inbox.replace('https://'+targetDomain,'');
|
|
// get the private key
|
|
let db = req.app.get('db');
|
|
let result = db.prepare('select privkey from accounts where name = ?').get(`${name}@${domain}`);
|
|
if (result === undefined) {
|
|
return res.status(404).send(`No record found for ${name}.`);
|
|
}
|
|
else {
|
|
// digest
|
|
const digest = crypto.createHash('sha256').update(JSON.stringify(message)).digest('base64');
|
|
|
|
let privkey = result.privkey;
|
|
const signer = crypto.createSign('sha256');
|
|
let d = new Date();
|
|
let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}\ndigest: SHA-256=${digest}`;
|
|
signer.update(stringToSign);
|
|
signer.end();
|
|
const signature = signer.sign(privkey);
|
|
const signature_b64 = signature.toString('base64');
|
|
const algorithm = 'rsa-sha256';
|
|
let header = `keyId="https://${domain}/u/${name}",algorithm="${algorithm}",headers="(request-target) host date digest",signature="${signature_b64}"`;
|
|
request({
|
|
url: inbox,
|
|
headers: {
|
|
'Host': targetDomain,
|
|
'Date': d.toUTCString(),
|
|
'Signature': header,
|
|
'Digest': `SHA-256=${digest}`,
|
|
'Content-Type': 'application/activity+json',
|
|
'Accept': 'application/activity+json'
|
|
},
|
|
method: 'POST',
|
|
json: true,
|
|
body: message
|
|
}, function (error, response, body){
|
|
});
|
|
res.json('done');
|
|
}
|
|
}
|
|
|
|
function sendAcceptMessage(thebody, name, domain, req, res, targetDomain) {
|
|
const guid = crypto.randomBytes(16).toString('hex');
|
|
let message = {
|
|
'@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
|
|
'id': `https://${domain}/${guid}`,
|
|
'type': 'Accept',
|
|
'actor': `https://${domain}/u/${name}`,
|
|
'object': thebody,
|
|
};
|
|
signAndSend(message, name, domain, req, res, targetDomain);
|
|
}
|
|
|
|
router.post('/', function (req, res) {
|
|
// pass in a name for an account, if the account doesn't exist, create it!
|
|
let domain = req.app.get('domain');
|
|
if (req.body.actor === undefined) {
|
|
return res.status(400).send(`No actor specified.`);
|
|
}
|
|
const myURL = new URL(req.body.actor);
|
|
let targetDomain = myURL.hostname;
|
|
fs.appendFile('./inbox.log', JSON.stringify(req.body)+'\r\n', function (err) {
|
|
if (err) {
|
|
return console.log(err);
|
|
}
|
|
});
|
|
// TODO: add "Undo" follow event
|
|
if (typeof req.body.object === 'string' && req.body.type === 'Follow') {
|
|
let name = req.body.object.replace(`https://${domain}/u/`,'');
|
|
sendAcceptMessage(req.body, name, domain, req, res, targetDomain);
|
|
// Add the user to the DB of accounts that follow the account
|
|
let db = req.app.get('db');
|
|
// get the followers JSON for the user
|
|
let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`);
|
|
if (result === undefined) {
|
|
console.log(`No record found for ${name}.`);
|
|
}
|
|
else {
|
|
// update followers
|
|
let followers = result.followers;
|
|
if (followers) {
|
|
followers = JSON.parse(followers);
|
|
followers.push(req.body.actor);
|
|
// unique items
|
|
followers = [...new Set(followers)];
|
|
}
|
|
else {
|
|
followers = [req.body.actor];
|
|
}
|
|
let followersText = JSON.stringify(followers);
|
|
// update into DB
|
|
db.prepare('update accounts set followers = ? where name = ?').run(followersText, `${name}@${domain}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|