From dadd959f232a7dbdf7694303109d33257c7a2a20 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Sat, 15 Sep 2018 12:19:12 -0700 Subject: [PATCH 1/7] Make GUIDs of Create and Note objects different Per #1. --- routes/api.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/routes/api.js b/routes/api.js index d7a38f0..43ddb2f 100644 --- a/routes/api.js +++ b/routes/api.js @@ -63,18 +63,19 @@ function signAndSend(message, name, domain, req, res, targetDomain, inbox) { } function createMessage(text, name, domain) { - const guid = crypto.randomBytes(16).toString('hex'); + const guidCreate = crypto.randomBytes(16).toString('hex'); + const guidNote = crypto.randomBytes(16).toString('hex'); let d = new Date(); return { '@context': 'https://www.w3.org/ns/activitystreams', - 'id': `https://${domain}/${guid}`, + 'id': `https://${domain}/${guidCreate}`, 'type': 'Create', 'actor': `https://${domain}/u/${name}`, 'object': { - 'id': `https://${domain}/${guid}`, + 'id': `https://${domain}/${guidNote}`, 'type': 'Note', 'published': d.toISOString(), 'attributedTo': `https://${domain}/u/${name}`, From 62f0fa88dd03f69e027331a10d57cdf3aa5871a8 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 24 Sep 2018 20:10:39 -0700 Subject: [PATCH 2/7] Store messages and allow retrieval via the message URI Addresses #1. --- index.js | 3 +++ routes/api.js | 41 +++++++++++++++++++++++++++++------------ routes/index.js | 1 + routes/message.js | 23 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 routes/message.js diff --git a/index.js b/index.js index 6f6b133..b5ea5ff 100644 --- a/index.js +++ b/index.js @@ -28,6 +28,8 @@ try { // if there is no `accounts` table in the DB, create an empty table db.run('CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, privkey TEXT, pubkey TEXT, webfinger TEXT, actor TEXT, apikey TEXT, followers TEXT, messages TEXT)'); +// if there is no `messages` table in the DB, create an empty table +db.run('CREATE TABLE IF NOT EXISTS messages (guid TEXT PRIMARY KEY, message TEXT)'); app.set('db', db); app.set('domain', DOMAIN); @@ -65,6 +67,7 @@ app.use('/api/admin', cors({ credentials: true, origin: true }), basicUserAuth, app.use('/admin', express.static('public/admin')); app.use('/.well-known/webfinger', cors(), routes.webfinger); app.use('/u', cors(), routes.user); +app.use('/m', cors(), routes.message); app.use('/api/inbox', cors(), routes.inbox); http.createServer(app).listen(app.get('port'), function(){ diff --git a/routes/api.js b/routes/api.js index 43ddb2f..80fa486 100644 --- a/routes/api.js +++ b/routes/api.js @@ -6,6 +6,7 @@ const express = require('express'), router.post('/sendMessage', function (req, res) { let db = req.app.get('db'); + console.log('DB',db); let domain = req.app.get('domain'); let acct = req.body.acct; let apikey = req.body.apikey; @@ -62,31 +63,47 @@ function signAndSend(message, name, domain, req, res, targetDomain, inbox) { }); } -function createMessage(text, name, domain) { +function createMessage(text, name, domain, req, res) { const guidCreate = crypto.randomBytes(16).toString('hex'); const guidNote = crypto.randomBytes(16).toString('hex'); + let db = req.app.get('db'); let d = new Date(); - return { + let noteMessage = { + 'id': `https://${domain}/m/${guidNote}`, + 'type': 'Note', + 'published': d.toISOString(), + 'attributedTo': `https://${domain}/u/${name}`, + 'content': text, + 'to': 'https://www.w3.org/ns/activitystreams#Public' + }; + + let createMessage = { '@context': 'https://www.w3.org/ns/activitystreams', - 'id': `https://${domain}/${guidCreate}`, + 'id': `https://${domain}/m/${guidCreate}`, 'type': 'Create', 'actor': `https://${domain}/u/${name}`, - 'object': { - 'id': `https://${domain}/${guidNote}`, - 'type': 'Note', - 'published': d.toISOString(), - 'attributedTo': `https://${domain}/u/${name}`, - 'content': text, - 'to': 'https://www.w3.org/ns/activitystreams#Public' - } + 'object': noteMessage }; + + db.run('insert or replace into messages(guid, message) values($guid, $message)', { + $guid: guidCreate, + $message: JSON.stringify(createMessage), + }, (err, accounts) => { + }); + db.run('insert or replace into messages(guid, message) values($guid, $message)', { + $guid: guidNote, + $message: JSON.stringify(noteMessage), + }, (err, accounts) => { + }); + + return createMessage; } function sendCreateMessage(text, name, domain, req, res) { - let message = createMessage(text, name, domain); + let message = createMessage(text, name, domain, req, res); let db = req.app.get('db'); db.get('select followers from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { diff --git a/routes/index.js b/routes/index.js index 2b97780..afd9141 100644 --- a/routes/index.js +++ b/routes/index.js @@ -4,6 +4,7 @@ module.exports = { api: require('./api'), admin: require('./admin'), user: require('./user'), + message: require('./message'), inbox: require('./inbox'), webfinger: require('./webfinger'), }; diff --git a/routes/message.js b/routes/message.js new file mode 100644 index 0000000..3b819ac --- /dev/null +++ b/routes/message.js @@ -0,0 +1,23 @@ +'use strict'; +const express = require('express'), + router = express.Router(); + +router.get('/:guid', function (req, res) { + let guid = req.params.guid; + if (!guid) { + return res.status(400).send('Bad request.'); + } + else { + let db = req.app.get('db'); + db.get('select message from messages where guid = $guid', {$guid: guid}, (err, result) => { + if (result === undefined) { + return res.status(404).send(`No record found for ${guid}.`); + } + else { + res.json(JSON.parse(result.message)); + } + }); + } +}); + +module.exports = router; From 24a4ad52c04b4ba6bb17ed12ed8a4f23a0535e65 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 25 Mar 2019 21:08:40 -0700 Subject: [PATCH 3/7] Make it so config.json is not checked in --- .gitignore | 1 + README.md | 6 +++++- config-template.json | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 config-template.json diff --git a/.gitignore b/.gitignore index 4913e17..8d3e807 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ package-lock.json *.db +config.json diff --git a/README.md b/README.md index 6ed1d15..3dbf993 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ Clone the repository, then `cd` into its root directory. Install dependencies: `npm i` +Copy `config-template.json` to `config.json`. + +`cp config-template.json config.json` + Update your `config.json` file: ```js @@ -45,7 +49,7 @@ Enter "test" in the "Create Account" section and hit the "Create Account" button ## Local testing -You can use a service like [ngrok](https://ngrok.com/) to test things out before you deploy on a real server. All you need to do is install ngrok and run `ngrok http 3000` (or whatever port you're using if you changed it). Then go to your `config.json` and update the `DOMAIN` field to whatever `abcdef.ngrok.io` domain that ngrok gives you and restart your server. +You can use a service like [ngrok](https://ngrok.com/) to test things out before you deploy on a real server. All you need to do is install ngrok and run `ngrok http 3000` (or whatever port you're using if you changed it). Then go to your `config.json` and update the `DOMAIN` field to whatever `abcdef.ngrok.io` domain that ngrok gives you and restart your server. *For local testing you do not need to specify `PRIVKEY_PATH` or `CERT_PARTH`.* ## Admin Page diff --git a/config-template.json b/config-template.json new file mode 100644 index 0000000..a1c50a4 --- /dev/null +++ b/config-template.json @@ -0,0 +1,8 @@ +{ + "USER": "", + "PASS": "", + "DOMAIN": "", + "PORT": "3000", + "PRIVKEY_PATH": "", + "CERT_PATH": "" +} From 489a228b68004cdc4afa94faf911ea33c47c0c50 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 25 Mar 2019 21:10:55 -0700 Subject: [PATCH 4/7] Delete config.json --- config.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 config.json diff --git a/config.json b/config.json deleted file mode 100644 index a1c50a4..0000000 --- a/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "USER": "", - "PASS": "", - "DOMAIN": "", - "PORT": "3000", - "PRIVKEY_PATH": "", - "CERT_PATH": "" -} From e2ab4dd51e3a66a8ac75afc29f7bc792806dfd80 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 25 Mar 2019 21:26:17 -0700 Subject: [PATCH 5/7] Adding a Followers object to the Actor See https://github.com/dariusk/rss-to-activitypub/issues/11 for more information on why this fix is needed. --- routes/admin.js | 1 + routes/inbox.js | 7 +++++-- routes/user.js | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/routes/admin.js b/routes/admin.js index bec6d5e..57d93c6 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -15,6 +15,7 @@ function createActor(name, domain, pubkey) { 'type': 'Person', 'preferredUsername': `${name}`, 'inbox': `https://${domain}/api/inbox`, + 'followers': `https://${domain}/u/${name}/followers`, 'publicKey': { 'id': `https://${domain}/u/${name}#main-key`, diff --git a/routes/inbox.js b/routes/inbox.js index e8f39a7..ee210c0 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -5,6 +5,9 @@ const express = require('express'), 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'); db.get('select privkey from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { @@ -15,14 +18,14 @@ function signAndSend(message, name, domain, req, res, targetDomain) { let privkey = result.privkey; const signer = crypto.createSign('sha256'); let d = new Date(); - let stringToSign = `(request-target): post /inbox\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; + let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; signer.update(stringToSign); signer.end(); const signature = signer.sign(privkey); const signature_b64 = signature.toString('base64'); let header = `keyId="https://${domain}/u/${name}",headers="(request-target) host date",signature="${signature_b64}"`; request({ - url: `https://${targetDomain}/inbox`, + url: inbox, headers: { 'Host': targetDomain, 'Date': d.toUTCString(), diff --git a/routes/user.js b/routes/user.js index 062e931..f86a2ba 100644 --- a/routes/user.js +++ b/routes/user.js @@ -10,16 +10,53 @@ router.get('/:name', function (req, res) { else { let db = req.app.get('db'); let domain = req.app.get('domain'); + let username = name; name = `${name}@${domain}`; db.get('select actor from accounts where name = $name', {$name: name}, (err, result) => { if (result === undefined) { return res.status(404).send(`No record found for ${name}.`); } else { - res.json(JSON.parse(result.actor)); + let tempActor = JSON.parse(result.actor); + // Added this followers URI for Pleroma compatibility, see https://github.com/dariusk/rss-to-activitypub/issues/11#issuecomment-471390881 + // New Actors should have this followers URI but in case of migration from an old version this will add it in on the fly + if (tempActor.followers === undefined) { + tempActor.followers = `https://${domain}/u/${username}/followers`; + } + res.json(tempActor); } }); } }); +router.get('/:name/followers', function (req, res) { + let name = req.params.name; + if (!name) { + return res.status(400).send('Bad request.'); + } + else { + let db = req.app.get('db'); + let domain = req.app.get('domain'); + let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`); + let followers = JSON.parse(result.followers); + if (!followers) { + followers = []; + } + let followersCollection = { + "type":"OrderedCollection", + "totalItems":followers.length, + "id":`https://${domain}/u/${name}/followers`, + "first": { + "type":"OrderedCollectionPage", + "totalItems":followers.length, + "partOf":`https://${domain}/u/${name}/followers`, + "orderedItems": followers, + "id":`https://${domain}/u/${name}/followers?page=1` + }, + "@context":["https://www.w3.org/ns/activitystreams"] + }; + res.json(followersCollection); + } +}); + module.exports = router; From e989126e868acb36fbf0935ece4bf58a5d49208a Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 25 Mar 2019 22:17:24 -0700 Subject: [PATCH 6/7] Migrate to better-sqlite3 --- index.js | 8 +-- package.json | 4 +- routes/admin.js | 15 ++--- routes/api.js | 130 ++++++++++++++++++++------------------------ routes/inbox.js | 110 +++++++++++++++++++------------------ routes/user.js | 30 +++++----- routes/webfinger.js | 15 +++-- 7 files changed, 148 insertions(+), 164 deletions(-) diff --git a/index.js b/index.js index b5ea5ff..e4b9140 100644 --- a/index.js +++ b/index.js @@ -2,8 +2,8 @@ const config = require('./config.json'); const { USER, PASS, DOMAIN, PRIVKEY_PATH, CERT_PATH, PORT } = config; const express = require('express'); const app = express(); -const sqlite3 = require('sqlite3').verbose(); -const db = new sqlite3.Database('bot-node.db'); +const Database = require('better-sqlite3'); +const db = new Database('bot-node.db'); const fs = require('fs'); const routes = require('./routes'), bodyParser = require('body-parser'), @@ -27,9 +27,9 @@ try { } // if there is no `accounts` table in the DB, create an empty table -db.run('CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, privkey TEXT, pubkey TEXT, webfinger TEXT, actor TEXT, apikey TEXT, followers TEXT, messages TEXT)'); +db.prepare('CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, privkey TEXT, pubkey TEXT, webfinger TEXT, actor TEXT, apikey TEXT, followers TEXT, messages TEXT)').run(); // if there is no `messages` table in the DB, create an empty table -db.run('CREATE TABLE IF NOT EXISTS messages (guid TEXT PRIMARY KEY, message TEXT)'); +db.prepare('CREATE TABLE IF NOT EXISTS messages (guid TEXT PRIMARY KEY, message TEXT)').run(); app.set('db', db); app.set('domain', DOMAIN); diff --git a/package.json b/package.json index 791a1cb..89b33d2 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "description": "", "main": "index.js", "dependencies": { + "better-sqlite3": "^5.4.0", "body-parser": "^1.18.3", "cors": "^2.8.4", "express": "^4.16.3", "express-basic-auth": "^1.1.5", "generate-rsa-keypair": "^0.1.2", - "request": "^2.87.0", - "sqlite3": "^4.0.2" + "request": "^2.87.0" }, "engines": { "node": ">=10.10.0" diff --git a/routes/admin.js b/routes/admin.js index 57d93c6..0398389 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -52,16 +52,13 @@ router.post('/create', function (req, res) { let actorRecord = createActor(account, domain, pair.public); let webfingerRecord = createWebfinger(account, domain); const apikey = crypto.randomBytes(16).toString('hex'); - db.run('insert or replace into accounts(name, actor, apikey, pubkey, privkey, webfinger) values($name, $actor, $apikey, $pubkey, $privkey, $webfinger)', { - $name: `${account}@${domain}`, - $apikey: apikey, - $pubkey: pair.public, - $privkey: pair.private, - $actor: JSON.stringify(actorRecord), - $webfinger: JSON.stringify(webfingerRecord) - }, (err, accounts) => { + try { + db.prepare('insert or replace into accounts(name, actor, apikey, pubkey, privkey, webfinger) values(?, ?, ?, ?, ?, ?)').run(`${account}@${domain}`, JSON.stringify(actorRecord), apikey, pair.public, pair.private, JSON.stringify(webfingerRecord)); res.status(200).json({msg: 'ok', apikey}); - }); + } + catch(e) { + res.status(200).json({error: e}); + } }); module.exports = router; diff --git a/routes/api.js b/routes/api.js index 80fa486..b9a48c4 100644 --- a/routes/api.js +++ b/routes/api.js @@ -6,61 +6,58 @@ const express = require('express'), router.post('/sendMessage', function (req, res) { let db = req.app.get('db'); - console.log('DB',db); let domain = req.app.get('domain'); let acct = req.body.acct; let apikey = req.body.apikey; let message = req.body.message; // check to see if your API key matches - db.get('select apikey from accounts where name = $name', {$name: `${acct}@${domain}`}, (err, result) => { - if (result.apikey === apikey) { - sendCreateMessage(message, acct, domain, req, res); - } - else { - res.status(403).json({msg: 'wrong api key'}); - } - }); + let result = db.prepare('select apikey from accounts where name = ?').get(`${acct}@${domain}`); + if (result.apikey === apikey) { + sendCreateMessage(message, acct, domain, req, res); + } + else { + res.status(403).json({msg: 'wrong api key'}); + } }); function signAndSend(message, name, domain, req, res, targetDomain, inbox) { // get the private key let db = req.app.get('db'); let inboxFragment = inbox.replace('https://'+targetDomain,''); - db.get('select privkey from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { - if (result === undefined) { - console.log(`No record found for ${name}.`); - } - else { - let privkey = result.privkey; - const signer = crypto.createSign('sha256'); - let d = new Date(); - let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; - signer.update(stringToSign); - signer.end(); - const signature = signer.sign(privkey); - const signature_b64 = signature.toString('base64'); - let header = `keyId="https://${domain}/u/${name}",headers="(request-target) host date",signature="${signature_b64}"`; - request({ - url: inbox, - headers: { - 'Host': targetDomain, - 'Date': d.toUTCString(), - 'Signature': header - }, - method: 'POST', - json: true, - body: message - }, function (error, response){ - console.log(`Sent message to an inbox at ${targetDomain}!`); - if (error) { - console.log('Error:', error, response); - } - else { - console.log('Response Status Code:', response.statusCode); - } - }); - } - }); + let result = db.prepare('select privkey from accounts where name = ?').get(`${name}@${domain}`); + if (result === undefined) { + console.log(`No record found for ${name}.`); + } + else { + let privkey = result.privkey; + const signer = crypto.createSign('sha256'); + let d = new Date(); + let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; + signer.update(stringToSign); + signer.end(); + const signature = signer.sign(privkey); + const signature_b64 = signature.toString('base64'); + let header = `keyId="https://${domain}/u/${name}",headers="(request-target) host date",signature="${signature_b64}"`; + request({ + url: inbox, + headers: { + 'Host': targetDomain, + 'Date': d.toUTCString(), + 'Signature': header + }, + method: 'POST', + json: true, + body: message + }, function (error, response){ + console.log(`Sent message to an inbox at ${targetDomain}!`); + if (error) { + console.log('Error:', error, response); + } + else { + console.log('Response Status Code:', response.statusCode); + } + }); + } } function createMessage(text, name, domain, req, res) { @@ -88,16 +85,8 @@ function createMessage(text, name, domain, req, res) { 'object': noteMessage }; - db.run('insert or replace into messages(guid, message) values($guid, $message)', { - $guid: guidCreate, - $message: JSON.stringify(createMessage), - }, (err, accounts) => { - }); - db.run('insert or replace into messages(guid, message) values($guid, $message)', { - $guid: guidNote, - $message: JSON.stringify(noteMessage), - }, (err, accounts) => { - }); + db.prepare('insert or replace into messages(guid, message) values(?, ?)').run( guidCreate, JSON.stringify(createMessage)); + db.prepare('insert or replace into messages(guid, message) values(?, ?)').run( guidNote, JSON.stringify(noteMessage)); return createMessage; } @@ -106,24 +95,23 @@ function sendCreateMessage(text, name, domain, req, res) { let message = createMessage(text, name, domain, req, res); let db = req.app.get('db'); - db.get('select followers from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { - let followers = JSON.parse(result.followers); - console.log(followers); - console.log('type',typeof followers); - if (followers === null) { - console.log('aaaa'); - res.status(400).json({msg: `No followers for account ${name}@${domain}`}); + let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`); + let followers = JSON.parse(result.followers); + console.log(followers); + console.log('type',typeof followers); + if (followers === null) { + console.log('aaaa'); + res.status(400).json({msg: `No followers for account ${name}@${domain}`}); + } + else { + for (let follower of followers) { + let inbox = follower+'/inbox'; + let myURL = new URL(follower); + let targetDomain = myURL.hostname; + signAndSend(message, name, domain, req, res, targetDomain, inbox); } - else { - for (let follower of followers) { - let inbox = follower+'/inbox'; - let myURL = new URL(follower); - let targetDomain = myURL.hostname; - signAndSend(message, name, domain, req, res, targetDomain, inbox); - } - res.status(200).json({msg: 'ok'}); - } - }); + res.status(200).json({msg: 'ok'}); + } } module.exports = router; diff --git a/routes/inbox.js b/routes/inbox.js index ee210c0..359931a 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -10,41 +10,40 @@ function signAndSend(message, name, domain, req, res, targetDomain) { let inboxFragment = inbox.replace('https://'+targetDomain,''); // get the private key let db = req.app.get('db'); - db.get('select privkey from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { - if (result === undefined) { - return res.status(404).send(`No record found for ${name}.`); - } - else { - let privkey = result.privkey; - const signer = crypto.createSign('sha256'); - let d = new Date(); - let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; - signer.update(stringToSign); - signer.end(); - const signature = signer.sign(privkey); - const signature_b64 = signature.toString('base64'); - let header = `keyId="https://${domain}/u/${name}",headers="(request-target) host date",signature="${signature_b64}"`; - request({ - url: inbox, - headers: { - 'Host': targetDomain, - 'Date': d.toUTCString(), - 'Signature': header - }, - method: 'POST', - json: true, - body: message - }, function (error, response){ - if (error) { - console.log('Error:', error, response.body); - } - else { - console.log('Response:', response.body); - } - }); - return res.status(200); - } - }); + let result = db.prepare('select privkey from accounts where name = ?').get(name); + if (result === undefined) { + return res.status(404).send(`No record found for ${name}.`); + } + else { + let privkey = result.privkey; + const signer = crypto.createSign('sha256'); + let d = new Date(); + let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}`; + signer.update(stringToSign); + signer.end(); + const signature = signer.sign(privkey); + const signature_b64 = signature.toString('base64'); + let header = `keyId="https://${domain}/u/${name}",headers="(request-target) host date",signature="${signature_b64}"`; + request({ + url: inbox, + headers: { + 'Host': targetDomain, + 'Date': d.toUTCString(), + 'Signature': header + }, + method: 'POST', + json: true, + body: message + }, function (error, response){ + if (error) { + console.log('Error:', error, response.body); + } + else { + console.log('Response:', response.body); + } + }); + return res.status(200); + } } function sendAcceptMessage(thebody, name, domain, req, res, targetDomain) { @@ -79,28 +78,31 @@ router.post('/', function (req, res) { // 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 - db.get('select followers from accounts where name = $name', {$name: `${name}@${domain}`}, (err, result) => { - if (result === undefined) { - console.log(`No record found for ${name}.`); + 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 = parseJSON(result.followers); + if (followers) { + followers.push(req.body.actor); + // unique items + followers = [...new Set(followers)]; } else { - // update followers - let followers = parseJSON(result.followers); - if (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.run('update accounts set followers=$followers where name = $name', {$name: `${name}@${domain}`, $followers: followersText}, (err, result) => { - console.log('updated followers!', err, result); - }); + followers = [req.body.actor]; } - }); + let followersText = JSON.stringify(followers); + try { + // update into DB + let newFollowers = db.prepare('update accounts set followers=? where name = ?').run(followersText, `${name}@${domain}`); + console.log('updated followers!', newFollowers); + } + catch(e) { + console.log('error', e); + } + } } }); diff --git a/routes/user.js b/routes/user.js index f86a2ba..65d627b 100644 --- a/routes/user.js +++ b/routes/user.js @@ -12,20 +12,19 @@ router.get('/:name', function (req, res) { let domain = req.app.get('domain'); let username = name; name = `${name}@${domain}`; - db.get('select actor from accounts where name = $name', {$name: name}, (err, result) => { - if (result === undefined) { - return res.status(404).send(`No record found for ${name}.`); + let result = db.prepare('select actor from accounts where name = ?').get(name); + if (result === undefined) { + return res.status(404).send(`No record found for ${name}.`); + } + else { + let tempActor = JSON.parse(result.actor); + // Added this followers URI for Pleroma compatibility, see https://github.com/dariusk/rss-to-activitypub/issues/11#issuecomment-471390881 + // New Actors should have this followers URI but in case of migration from an old version this will add it in on the fly + if (tempActor.followers === undefined) { + tempActor.followers = `https://${domain}/u/${username}/followers`; } - else { - let tempActor = JSON.parse(result.actor); - // Added this followers URI for Pleroma compatibility, see https://github.com/dariusk/rss-to-activitypub/issues/11#issuecomment-471390881 - // New Actors should have this followers URI but in case of migration from an old version this will add it in on the fly - if (tempActor.followers === undefined) { - tempActor.followers = `https://${domain}/u/${username}/followers`; - } - res.json(tempActor); - } - }); + res.json(tempActor); + } } }); @@ -38,10 +37,9 @@ router.get('/:name/followers', function (req, res) { let db = req.app.get('db'); let domain = req.app.get('domain'); let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`); + console.log(result); + result.followers = result.followers || '[]'; let followers = JSON.parse(result.followers); - if (!followers) { - followers = []; - } let followersCollection = { "type":"OrderedCollection", "totalItems":followers.length, diff --git a/routes/webfinger.js b/routes/webfinger.js index 9cc67dd..c743d84 100644 --- a/routes/webfinger.js +++ b/routes/webfinger.js @@ -10,14 +10,13 @@ router.get('/', function (req, res) { else { let name = resource.replace('acct:',''); let db = req.app.get('db'); - db.get('select webfinger from accounts where name = $name', {$name: name}, (err, result) => { - if (result === undefined) { - return res.status(404).send(`No record found for ${name}.`); - } - else { - res.json(JSON.parse(result.webfinger)); - } - }); + let result = db.prepare('select webfinger from accounts where name = ?').get(name); + if (result === undefined) { + return res.status(404).send(`No record found for ${name}.`); + } + else { + res.json(JSON.parse(result.webfinger)); + } } }); From 49ce1635474ea331521d9d39215d72bfe3643084 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Tue, 26 Mar 2019 00:01:34 -0700 Subject: [PATCH 7/7] Fixing remaining better-sqlite bugs, fixing pleroma messagin --- routes/api.js | 8 +++++--- routes/inbox.js | 2 +- routes/message.js | 15 +++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/routes/api.js b/routes/api.js index b9a48c4..d80a474 100644 --- a/routes/api.js +++ b/routes/api.js @@ -60,7 +60,7 @@ function signAndSend(message, name, domain, req, res, targetDomain, inbox) { } } -function createMessage(text, name, domain, req, res) { +function createMessage(text, name, domain, req, res, follower) { const guidCreate = crypto.randomBytes(16).toString('hex'); const guidNote = crypto.randomBytes(16).toString('hex'); let db = req.app.get('db'); @@ -72,7 +72,7 @@ function createMessage(text, name, domain, req, res) { 'published': d.toISOString(), 'attributedTo': `https://${domain}/u/${name}`, 'content': text, - 'to': 'https://www.w3.org/ns/activitystreams#Public' + 'to': ['https://www.w3.org/ns/activitystreams#Public'], }; let createMessage = { @@ -81,6 +81,8 @@ function createMessage(text, name, domain, req, res) { 'id': `https://${domain}/m/${guidCreate}`, 'type': 'Create', 'actor': `https://${domain}/u/${name}`, + 'to': ['https://www.w3.org/ns/activitystreams#Public'], + 'cc': [follower], 'object': noteMessage }; @@ -92,7 +94,6 @@ function createMessage(text, name, domain, req, res) { } function sendCreateMessage(text, name, domain, req, res) { - let message = createMessage(text, name, domain, req, res); let db = req.app.get('db'); let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`); @@ -108,6 +109,7 @@ function sendCreateMessage(text, name, domain, req, res) { let inbox = follower+'/inbox'; let myURL = new URL(follower); let targetDomain = myURL.hostname; + let message = createMessage(text, name, domain, req, res, follower); signAndSend(message, name, domain, req, res, targetDomain, inbox); } res.status(200).json({msg: 'ok'}); diff --git a/routes/inbox.js b/routes/inbox.js index 359931a..424f1ee 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -10,7 +10,7 @@ function signAndSend(message, name, domain, req, res, targetDomain) { 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); + 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}.`); } diff --git a/routes/message.js b/routes/message.js index 3b819ac..f002277 100644 --- a/routes/message.js +++ b/routes/message.js @@ -9,14 +9,13 @@ router.get('/:guid', function (req, res) { } else { let db = req.app.get('db'); - db.get('select message from messages where guid = $guid', {$guid: guid}, (err, result) => { - if (result === undefined) { - return res.status(404).send(`No record found for ${guid}.`); - } - else { - res.json(JSON.parse(result.message)); - } - }); + let result = db.prepare('select message from messages where guid = ?').get(guid); + if (result === undefined) { + return res.status(404).send(`No record found for ${guid}.`); + } + else { + res.json(JSON.parse(result.message)); + } } });