From 900b5aa4e5830c5e00e1878670a9e51994d62806 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Sat, 23 Mar 2024 15:26:27 -0500 Subject: [PATCH] Add hash and signature verification on API read from leveldb --- backend/index.js | 54 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/backend/index.js b/backend/index.js index 978289b..739ecc7 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,10 +1,7 @@ const express = require('express'); const { Level } = require('level'); const { recoverPersonalSignature } = require('@metamask/eth-sig-util'); -// const { ecrecover, fromRpcSig, pubToAddress } = require('@ethereumjs/util'); -// const { Keccak } = require('sha3'); const objectHash = require('object-hash'); -// const { createHash } = require('node:crypto'); require('dotenv').config(); @@ -14,39 +11,47 @@ const dataDir = process.env.DATA_DIR || 'data'; const db = new Level(`${dataDir}/forum`, { valueEncoding: 'json' }); -// const keccak = Keccak(256); +const verifySignature = ({ author, content, signature }) => { + try { + const account = recoverPersonalSignature({ data: content, 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 } } = req; // Check author signature - try { - const account = recoverPersonalSignature({ data: content, signature }); - if (account !== author) { - console.log('error: author does not match signature'); - res.status(403).end(); - return; - } - } catch (e) { - console.log('error: failed to recover signature:', e.message); - res.status(400).end(); + if (!verifySignature({ author, content, signature })) { + res.status(403).end(); return; } + // Compute content hash const data = { author, content, signature }; const hash = objectHash(data); - console.log('write', hash); + // Store content db.put(hash, data); + // Return hash res.send(hash); }); app.get('/read/:hash', async (req, res) => { - // Fetch content const { hash } = req.params; + console.log('read', hash); + + // Fetch content let data; try { data = await db.get(req.params.hash); @@ -55,7 +60,22 @@ app.get('/read/:hash', async (req, res) => { res.status(e.status).end(); return; } - console.log('read', hash); + + // 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); });