const express = require('express'); const { Level } = require('level'); const { recoverPersonalSignature } = require('@metamask/eth-sig-util'); const objectHash = require('object-hash'); require('dotenv').config(); const app = express(); const port = process.env.PORT || 3000; const dataDir = process.env.DATA_DIR || 'data'; const db = new Level(`${dataDir}/forum`, { valueEncoding: 'json' }); const verifySignature = ({ author, content, signature, embeddedData, }) => { let contentToVerify = content; if (embeddedData && Object.entries(embeddedData).length) { contentToVerify += `\n\n${JSON.stringify(embeddedData, null, 2)}`; } try { const account = recoverPersonalSignature({ data: contentToVerify, signature }); if (account !== author) { console.log('error: author does not match signature'); return false; } } catch (e) { console.log('error: failed to recover signature:', e.message); return false; } return true; }; app.use(express.json()); app.post('/write', async (req, res) => { const { body: { author, content, signature, embeddedData, }, } = req; // Check author signature if (!verifySignature({ author, content, signature, embeddedData, })) { res.status(403).end(); return; } // Compute content hash const data = { author, content, signature, embeddedData, }; const hash = objectHash(data); console.log('write', hash); console.log(data); // Store content db.put(hash, data); // Return hash res.send(hash); }); app.get('/read/:hash', async (req, res) => { const { hash } = req.params; console.log('read', hash); // Fetch content let data; try { data = await db.get(req.params.hash); } catch (e) { console.log('read error:', e.message, hash); res.status(e.status).end(); return; } data.embeddedData = data.embeddedData || undefined; console.log(data); // Verify hash const derivedHash = objectHash(data); if (derivedHash !== hash) { console.log('error: hash mismatch'); res.status(500).end(); return; } // Verify signature if (!verifySignature(data)) { console.log('error: signature verificaition failed'); res.status(500).end(); return; } // Return content res.json(data); }); app.get('*', (req, res) => { console.log(`404 req.path: ${req.path}`); res.status(404).json({ errorCode: 404 }); }); app.listen(port, () => { console.log(`Listening on port ${port}`); });