From e989126e868acb36fbf0935ece4bf58a5d49208a Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Mon, 25 Mar 2019 22:17:24 -0700 Subject: [PATCH] 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)); + } } });