From 93aa64b15c53359948c78e6ed60b09437e2ababd Mon Sep 17 00:00:00 2001 From: mistakia <1823355+mistakia@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:30:36 -0400 Subject: [PATCH] refactor: cleanup `users` table, remove `users_addresses` table --- api/routes/auth/message.mjs | 9 ++-- api/routes/auth/register.mjs | 52 +++++------------- db/schema.sql | 32 +++++------ test/auth.register.test.mjs | 100 ++++++++++++++--------------------- 4 files changed, 71 insertions(+), 122 deletions(-) diff --git a/api/routes/auth/message.mjs b/api/routes/auth/message.mjs index 6cdb68f2..37385991 100644 --- a/api/routes/auth/message.mjs +++ b/api/routes/auth/message.mjs @@ -113,16 +113,13 @@ router.post('/?', async (req, res) => { } // public_key can be a linked keypair or an existing nano account - - const linked_accounts = await db('user_addresses') - .select('user_addresses.address') - .leftJoin('users', 'users.id', '=', 'user_addresses.user_id') + const linked_accounts = await db('accounts_keys') + .select('account') .where({ public_key }) - const nano_account = tools.publicKeyToAddress(public_key) const all_accounts = [ - ...linked_accounts.map((row) => row.address), + ...linked_accounts.map((row) => row.account), nano_account ] diff --git a/api/routes/auth/register.mjs b/api/routes/auth/register.mjs index 687ab101..a3e168a8 100644 --- a/api/routes/auth/register.mjs +++ b/api/routes/auth/register.mjs @@ -1,6 +1,6 @@ import express from 'express' import nano from 'nanocurrency' -import { tools } from 'nanocurrency-web' +import ed25519 from '@trashman/ed25519-blake2b' const router = express.Router() const USERNAME_RE = /^[A-Za-z][a-zA-Z0-9_]+$/ @@ -8,8 +8,7 @@ const USERNAME_RE = /^[A-Za-z][a-zA-Z0-9_]+$/ router.post('/?', async (req, res) => { const { logger, db } = req.app.locals try { - // public_key is a linked keypair for the given address - const required = ['public_key', 'address', 'signature', 'username'] + const required = ['public_key', 'signature', 'username'] for (const prop of required) { if (!req.body[prop]) { return res.status(400).send({ error: `missing ${prop} param` }) @@ -17,22 +16,16 @@ router.post('/?', async (req, res) => { } const { public_key, signature, username } = req.body - let { address } = req.body if (!nano.checkKey(public_key)) { return res.status(401).send({ error: 'invalid public_key param' }) } - if (!nano.checkAddress(address)) { - return res.status(401).send({ error: 'invalid address param' }) - } - if (!USERNAME_RE.test(username)) { return res.status(401).send({ error: 'invalid username param' }) } - const publicKey = tools.addressToPublicKey(address) - const valid_signature = tools.verify(publicKey, signature, public_key) + const valid_signature = ed25519.verify(signature, public_key, public_key) if (!valid_signature) { return res.status(401).send({ error: 'invalid signature' }) } @@ -44,45 +37,24 @@ router.post('/?', async (req, res) => { return res.status(401).send({ error: 'username exists' }) } - // TODO verify address exists on ledger - - address = address.replace('xrb_', 'nano_') - - const exists = await db('user_addresses').where({ address }) - let user_id = exists.length ? exists[0].user_id : null - - if (!user_id) { - const result = await db('users') - .insert({ - public_key, - username, - last_visit: Math.round(Date.now() / 1000) - }) - .onConflict() - .merge() - user_id = result[0] - } else { - await db('users') - .update({ last_visit: Math.round(Date.now() / 1000), username }) - .where({ id: user_id }) - } - - await db('user_addresses') + const result = await db('users') .insert({ - user_id, - address, - signature + public_key, + username, + signature, + last_visit: Math.round(Date.now() / 1000) }) .onConflict() .merge() + const user_id = result[0] + return res.send({ user_id, - address, - username, - signature + username }) } catch (error) { + console.log(error) logger(error) res.status(500).send('Internal server error') } diff --git a/db/schema.sql b/db/schema.sql index d1b3e5ce..6efa0ea6 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -18,6 +18,21 @@ CREATE TABLE `accounts` ( -- -------------------------------------------------------- +-- +-- Table structure for table `accounts_keys` +-- + +DROP TABLE IF EXISTS `accounts_keys`; + +CREATE TABLE `accounts_keys` ( + `account` char(65) CHARACTER SET utf8 NOT NULL, + `public_key` varchar(255) DEFAULT NULL, + `signature` varchar(255) DEFAULT NULL, + `created_at` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + -- -- Table structure for table `accounts_delegators` -- @@ -618,6 +633,7 @@ CREATE TABLE `users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL, `public_key` varchar(64) NOT NULL, + `signature` varchar(255) NOT NULL, `last_visit` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `public_key` (`public_key`) @@ -625,22 +641,6 @@ CREATE TABLE `users` ( -- -------------------------------------------------------- --- --- Table structure for table `user_addresses` --- - -DROP TABLE IF EXISTS `user_addresses`; - -CREATE TABLE `user_addresses` ( - `user_id` int(11) NOT NULL, - `address` char(65) NOT NULL, - `signature` varchar(255) NOT NULL, - KEY (`user_id`), - UNIQUE KEY `address` (`address`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci; - --- -------------------------------------------------------- - -- -- Table structure for table `voting_weight` -- diff --git a/test/auth.register.test.mjs b/test/auth.register.test.mjs index 4a7a3024..74581cfd 100644 --- a/test/auth.register.test.mjs +++ b/test/auth.register.test.mjs @@ -1,8 +1,7 @@ /* global describe before it */ import chai from 'chai' -import crypto from 'crypto' import chaiHTTP from 'chai-http' -import { tools, wallet } from 'nanocurrency-web' +import ed25519 from '@trashman/ed25519-blake2b' import server from '#api/server.mjs' import knex from '#db' @@ -22,7 +21,6 @@ describe('API /auth/register', () => { .request(server) .post('/api/auth/register') .send({ - address: 'someaddress', signature: 'somesignature', username: 'test_username' }) // missing public_key @@ -30,26 +28,12 @@ describe('API /auth/register', () => { expect(response.body.error).to.include('missing public_key param') }) - it('should return 400 if address field is missing', async () => { - const response = await chai - .request(server) - .post('/api/auth/register') - .send({ - public_key: 'somepub', - signature: 'somesignature', - username: 'test_username' - }) // missing address - expect(response).to.have.status(400) - expect(response.body.error).to.include('missing address param') - }) - it('should return 400 if signature field is missing', async () => { const response = await chai .request(server) .post('/api/auth/register') .send({ public_key: 'somepub', - address: 'someaddress', username: 'test_username' }) // missing signature expect(response).to.have.status(400) @@ -62,7 +46,6 @@ describe('API /auth/register', () => { .post('/api/auth/register') .send({ public_key: 'somepub', - address: 'someaddress', signature: 'somesignature' }) // missing username expect(response).to.have.status(400) @@ -70,15 +53,11 @@ describe('API /auth/register', () => { }) it('should return 401 if pub param is invalid', async () => { - const w = wallet.generate() - const account = w.accounts[0] - const response = await chai .request(server) .post('/api/auth/register') .send({ public_key: 'invalidpub', - address: account.address, signature: 'somesignature', username: 'test_username' }) @@ -86,23 +65,6 @@ describe('API /auth/register', () => { expect(response.body.error).to.equal('invalid public_key param') }) - it('should return 401 if address param is invalid', async () => { - const w = wallet.generate() - const account = w.accounts[0] - - const response = await chai - .request(server) - .post('/api/auth/register') - .send({ - public_key: account.publicKey, - address: 'invalidaddress', - signature: 'somesignature', - username: 'test_username' - }) - expect(response).to.have.status(401) - expect(response.body.error).to.equal('invalid address param') - }) - const invalid_usernames = [ 'contains space', 'constains@character', @@ -116,15 +78,17 @@ describe('API /auth/register', () => { invalid_usernames.forEach((username) => { it(`should return 401 if username param is invalid: ${username}`, async () => { - const w = wallet.generate() - const account = w.accounts[0] + const private_key = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex' + ) + const public_key = ed25519.publicKey(private_key) const response = await chai .request(server) .post('/api/auth/register') .send({ - public_key: account.publicKey, - address: account.address, + public_key: public_key.toString('hex'), signature: 'somesignature', username }) @@ -134,18 +98,19 @@ describe('API /auth/register', () => { }) it('should return 401 if signature is invalid', async () => { - const w = wallet.generate() - const account = w.accounts[0] - - const signature = tools.sign(account.privateKey, 'some message') + const private_key = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex' + ) + const public_key = ed25519.publicKey(private_key) + const signature = ed25519.sign(public_key, private_key, public_key) const response = await chai .request(server) .post('/api/auth/register') .send({ - public_key: account.publicKey, - address: account.address, - signature, + public_key: public_key.toString('hex'), + signature: signature.toString('hex'), username: 'test_username' }) expect(response).to.have.status(401) @@ -153,27 +118,42 @@ describe('API /auth/register', () => { }) it('should return 401 if username already exists', async () => { - const seed = crypto.randomBytes(64).toString('hex') - const accounts = wallet.accounts(seed, 0, 1) - const account_0 = accounts[0] - const account_1 = accounts[1] + const private_key_0 = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex' + ) + const public_key_0 = ed25519.publicKey(private_key_0) + const signature_0 = ed25519.sign( + public_key_0.toString('hex'), + private_key_0, + public_key_0 + ) + + const private_key_1 = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex' + ) + const public_key_1 = ed25519.publicKey(private_key_1) + const signature_1 = ed25519.sign( + public_key_1.toString('hex'), + private_key_1, + public_key_1 + ) await knex('users').insert({ id: 1, username: 'existing_username', - public_key: account_0.publicKey, + public_key: public_key_0.toString('hex'), + signature: signature_0.toString('hex'), last_visit: Math.floor(Date.now() / 1000) }) - const signature = tools.sign(account_1.privateKey, account_1.publicKey) - const response = await chai .request(server) .post('/api/auth/register') .send({ - public_key: account_1.publicKey, - address: account_1.address, - signature, + public_key: public_key_1.toString('hex'), + signature: signature_1.toString('hex'), username: 'existing_username' }) expect(response).to.have.status(401)