From 9b28c6a3f1014773bf8e686329b0b66678e991ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Sat, 12 Jun 2021 19:32:57 +0100 Subject: [PATCH 1/6] feat: create db table and store operator id --- lib/coinatmradar/coinatmradar.js | 13 ++--- lib/middlewares/operatorId.js | 39 ++++--------- lib/operator.js | 8 +++ .../1623413776161-create-operator-ids.js | 55 +++++++++++++++++++ 4 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 lib/operator.js create mode 100644 migrations/1623413776161-create-operator-ids.js diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index be4eec28..55fbf5c6 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -1,17 +1,16 @@ const axios = require('axios') const _ = require('lodash/fp') -const hkdf = require('futoin-hkdf') const pify = require('pify') const fs = pify(require('fs')) const db = require('../db') -const mnemonicHelpers = require('../mnemonic-helpers') const configManager = require('../new-config-manager') const complianceTriggers = require('../compliance-triggers') const options = require('../options') const logger = require('../logger') const plugins = require('../plugins') +const { getOperatorId } = require('../operator') const TIMEOUT = 10000 const MAX_CONTENT_LENGTH = 2000 @@ -133,10 +132,10 @@ function sendRadar (data) { function mapRecord (rates, settings) { const timestamp = new Date().toISOString() - return Promise.all([getMachines(rates, settings), fs.readFile(options.mnemonicPath, 'utf8')]) - .then(([machines, mnemonic]) => { + return Promise.all([getMachines(rates, settings), getOperatorId()]) + .then(([machines, operatorId]) => { return { - operatorId: computeOperatorId(mnemonicHelpers.toEntropyBuffer(mnemonic)), + operatorId: operatorId, operator: { name: null, phone: null, @@ -157,7 +156,3 @@ function update (rates, settings) { .then(sendRadar) .catch(err => logger.error(`Failure to update CoinATMRadar`, err)) } - -function computeOperatorId (masterSeed) { - return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') -} diff --git a/lib/middlewares/operatorId.js b/lib/middlewares/operatorId.js index 0dceb527..04548aaf 100644 --- a/lib/middlewares/operatorId.js +++ b/lib/middlewares/operatorId.js @@ -1,34 +1,15 @@ -const pify = require('pify') -const fs = pify(require('fs')) -const hkdf = require('futoin-hkdf') - -const state = require('./state') -const mnemonicHelpers = require('../mnemonic-helpers') -const options = require('../options') -const logger = require('../logger') - -function computeOperatorId (masterSeed) { - return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') -} - -function getMnemonic () { - if (state.mnemonic) return Promise.resolve(state.mnemonic) - return fs.readFile(options.mnemonicPath, 'utf8').then(mnemonic => { - state.mnemonic = mnemonic - return mnemonic - }) -} +const { getOperatorId } = require('../operator') function findOperatorId (req, res, next) { - return getMnemonic().then(mnemonic => { - return computeOperatorId(mnemonicHelpers.toEntropyBuffer(mnemonic)) - }).then(id => { - res.locals.operatorId = id - return next() - }).catch(e => { - logger.error('Error while computing operator id\n' + e) - next(e) - }) + return getOperatorId() + .then(({ id }) => { + res.locals.operatorId = id + return next() + }) + .catch(e => { + console.error('Error while computing operator id\n' + e) + next(e) + }) } module.exports = findOperatorId diff --git a/lib/operator.js b/lib/operator.js new file mode 100644 index 00000000..a39eaeed --- /dev/null +++ b/lib/operator.js @@ -0,0 +1,8 @@ +const db = require('./db') + +function getOperatorId () { + const sql = `SELECT id FROM operator_ids WHERE description = 'mnemonic'` + return db.oneOrNone(sql) +} + +module.exports = { getOperatorId } diff --git a/migrations/1623413776161-create-operator-ids.js b/migrations/1623413776161-create-operator-ids.js new file mode 100644 index 00000000..d48fcb1e --- /dev/null +++ b/migrations/1623413776161-create-operator-ids.js @@ -0,0 +1,55 @@ +var db = require('./db') +const pify = require('pify') +const fs = pify(require('fs')) +const hkdf = require('futoin-hkdf') + +const state = require('../lib/middlewares/state') +const mnemonicHelpers = require('../lib/mnemonic-helpers') +const options = require('../lib/options') + +function computeOperatorId (masterSeed) { + return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') +} + +function getMnemonic () { + if (state.mnemonic) return Promise.resolve(state.mnemonic) + return fs.readFile(options.mnemonicPath, 'utf8').then(mnemonic => { + state.mnemonic = mnemonic + return mnemonic + }) +} + +function generateOperatorId () { + return getMnemonic().then(mnemonic => { + return computeOperatorId(mnemonicHelpers.toEntropyBuffer(mnemonic)) + }).then(id => { + return id + }).catch(e => { + console.error('Error while computing operator id\n' + e) + throw e + }) +} + +exports.up = function (next) { + const sql = + [ + `CREATE TABLE operator_ids ( + id TEXT PRIMARY KEY, + description TEXT NOT NULL)` + ] + generateOperatorId() + .then(operatorId => { + const sql2 = `INSERT INTO operator_ids (id, description) VALUES ('${operatorId}','mnemonic' )` + sql.push(sql2) + db.multi(sql, next) + .then(() => next()) + }) + .catch(e => { + db.multi(sql, next) + .then(() => next()) + }) +} + +exports.down = function (next) { + next() +} From 8884c75ffd41aa2366b9bc54b73197d8aff6ef19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 16 Jun 2021 11:40:14 +0100 Subject: [PATCH 2/6] fix: store operator id for each service --- lib/coinatmradar/coinatmradar.js | 2 +- lib/middlewares/operatorId.js | 2 +- lib/operator.js | 4 ++-- migrations/1623413776161-create-operator-ids.js | 15 ++++++++++----- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index 55fbf5c6..64660f4e 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -132,7 +132,7 @@ function sendRadar (data) { function mapRecord (rates, settings) { const timestamp = new Date().toISOString() - return Promise.all([getMachines(rates, settings), getOperatorId()]) + return Promise.all([getMachines(rates, settings), getOperatorId('coinatmradar')]) .then(([machines, operatorId]) => { return { operatorId: operatorId, diff --git a/lib/middlewares/operatorId.js b/lib/middlewares/operatorId.js index 04548aaf..663b7527 100644 --- a/lib/middlewares/operatorId.js +++ b/lib/middlewares/operatorId.js @@ -1,7 +1,7 @@ const { getOperatorId } = require('../operator') function findOperatorId (req, res, next) { - return getOperatorId() + return getOperatorId('middleware') .then(({ id }) => { res.locals.operatorId = id return next() diff --git a/lib/operator.js b/lib/operator.js index a39eaeed..52e64217 100644 --- a/lib/operator.js +++ b/lib/operator.js @@ -1,7 +1,7 @@ const db = require('./db') -function getOperatorId () { - const sql = `SELECT id FROM operator_ids WHERE description = 'mnemonic'` +function getOperatorId (service) { + const sql = `SELECT operator_id FROM operator_ids WHERE service = '${service}'` return db.oneOrNone(sql) } diff --git a/migrations/1623413776161-create-operator-ids.js b/migrations/1623413776161-create-operator-ids.js index d48fcb1e..b7f27830 100644 --- a/migrations/1623413776161-create-operator-ids.js +++ b/migrations/1623413776161-create-operator-ids.js @@ -34,14 +34,19 @@ exports.up = function (next) { const sql = [ `CREATE TABLE operator_ids ( - id TEXT PRIMARY KEY, - description TEXT NOT NULL)` + id serial PRIMARY KEY, + operator_id TEXT NOT NULL, + service TEXT NOT NULL + )` ] generateOperatorId() .then(operatorId => { - const sql2 = `INSERT INTO operator_ids (id, description) VALUES ('${operatorId}','mnemonic' )` - sql.push(sql2) - db.multi(sql, next) + const sql2 = [ + `INSERT INTO operator_ids (operator_id, service) VALUES ('${operatorId}','middleware')`, + `INSERT INTO operator_ids (operator_id, service) VALUES ('${operatorId}','coinatmradar')`, + `INSERT INTO operator_ids (operator_id, service) VALUES ('${operatorId}','authentication')` + ] + db.multi(sql.concat(sql2), next) .then(() => next()) }) .catch(e => { From bca6e153569353fbf75beed0d53c0907db2f9038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Sat, 20 Nov 2021 20:20:16 +0000 Subject: [PATCH 3/6] feat: fetch from db auth secret --- lib/new-admin/middlewares/session.js | 49 ++++++++++++---------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/lib/new-admin/middlewares/session.js b/lib/new-admin/middlewares/session.js index fbdf4465..ff9093d4 100644 --- a/lib/new-admin/middlewares/session.js +++ b/lib/new-admin/middlewares/session.js @@ -1,41 +1,32 @@ -const fs = require('fs') const express = require('express') const router = express.Router() -const hkdf = require('futoin-hkdf') const session = require('express-session') const PgSession = require('connect-pg-simple')(session) -const mnemonicHelpers = require('../../mnemonic-helpers') const db = require('../../db') const options = require('../../options') const { USER_SESSIONS_TABLE_NAME } = require('../../constants') - -const getSecret = () => { - const mnemonic = fs.readFileSync(options.mnemonicPath, 'utf8') - return hkdf( - mnemonicHelpers.toEntropyBuffer(mnemonic), - 16, - { info: 'operator-id' } - ).toString('hex') -} +const { getOperatorId } = require('../../operator') const hostname = options.hostname -router.use('*', session({ - store: new PgSession({ - pgPromise: db, - tableName: USER_SESSIONS_TABLE_NAME - }), - name: 'lamassu_sid', - secret: getSecret(), - resave: false, - saveUninitialized: false, - cookie: { - httpOnly: true, - secure: true, - domain: hostname, - sameSite: true, - maxAge: 60 * 10 * 1000 // 10 minutes - } -})) +router.use('*', async () => { + return getOperatorId('authentication').then(secret => session({ + store: new PgSession({ + pgPromise: db, + tableName: USER_SESSIONS_TABLE_NAME + }), + name: 'lamassu_sid', + secret: secret, + resave: false, + saveUninitialized: false, + cookie: { + httpOnly: true, + secure: true, + domain: hostname, + sameSite: true, + maxAge: 60 * 10 * 1000 // 10 minutes + } + })) +}) module.exports = router From 3c38dacdc7177bd9813c23f3d65394848124fe93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 22 Nov 2021 11:31:56 +0000 Subject: [PATCH 4/6] fix: variable operator id variable name --- lib/middlewares/operatorId.js | 4 ++-- lib/new-admin/middlewares/session.js | 4 ++-- lib/operator.js | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/middlewares/operatorId.js b/lib/middlewares/operatorId.js index 663b7527..eeb7d6ac 100644 --- a/lib/middlewares/operatorId.js +++ b/lib/middlewares/operatorId.js @@ -2,8 +2,8 @@ const { getOperatorId } = require('../operator') function findOperatorId (req, res, next) { return getOperatorId('middleware') - .then(({ id }) => { - res.locals.operatorId = id + .then(({ operatorId }) => { + res.locals.operatorId = operatorId return next() }) .catch(e => { diff --git a/lib/new-admin/middlewares/session.js b/lib/new-admin/middlewares/session.js index ff9093d4..7167a277 100644 --- a/lib/new-admin/middlewares/session.js +++ b/lib/new-admin/middlewares/session.js @@ -10,13 +10,13 @@ const { getOperatorId } = require('../../operator') const hostname = options.hostname router.use('*', async () => { - return getOperatorId('authentication').then(secret => session({ + return getOperatorId('authentication').then(({ operatorId }) => session({ store: new PgSession({ pgPromise: db, tableName: USER_SESSIONS_TABLE_NAME }), name: 'lamassu_sid', - secret: secret, + secret: operatorId, resave: false, saveUninitialized: false, cookie: { diff --git a/lib/operator.js b/lib/operator.js index 52e64217..63cbb768 100644 --- a/lib/operator.js +++ b/lib/operator.js @@ -1,8 +1,10 @@ const db = require('./db') +const _ = require('lodash/fp') function getOperatorId (service) { const sql = `SELECT operator_id FROM operator_ids WHERE service = '${service}'` return db.oneOrNone(sql) + .then(_.mapKeys(_.camelCase)) } module.exports = { getOperatorId } From 87c3bbceeea03e448db20f2ce7caaebe9f11a8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 22 Nov 2021 20:25:02 +0000 Subject: [PATCH 5/6] fix: async function arguments --- lib/new-admin/middlewares/session.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/middlewares/session.js b/lib/new-admin/middlewares/session.js index 7167a277..2b40d1cd 100644 --- a/lib/new-admin/middlewares/session.js +++ b/lib/new-admin/middlewares/session.js @@ -9,7 +9,7 @@ const { getOperatorId } = require('../../operator') const hostname = options.hostname -router.use('*', async () => { +router.use('*', async (req, res, next) => { return getOperatorId('authentication').then(({ operatorId }) => session({ store: new PgSession({ pgPromise: db, @@ -26,7 +26,7 @@ router.use('*', async () => { sameSite: true, maxAge: 60 * 10 * 1000 // 10 minutes } - })) + })(req, res, next)) }) module.exports = router From 5432f3df1ce89c49b36162a49eb8253935a14f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 22 Nov 2021 20:28:09 +0000 Subject: [PATCH 6/6] refactor: remove unneeded return statement --- lib/new-admin/middlewares/session.js | 37 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/new-admin/middlewares/session.js b/lib/new-admin/middlewares/session.js index 2b40d1cd..41fc31a0 100644 --- a/lib/new-admin/middlewares/session.js +++ b/lib/new-admin/middlewares/session.js @@ -9,24 +9,23 @@ const { getOperatorId } = require('../../operator') const hostname = options.hostname -router.use('*', async (req, res, next) => { - return getOperatorId('authentication').then(({ operatorId }) => session({ - store: new PgSession({ - pgPromise: db, - tableName: USER_SESSIONS_TABLE_NAME - }), - name: 'lamassu_sid', - secret: operatorId, - resave: false, - saveUninitialized: false, - cookie: { - httpOnly: true, - secure: true, - domain: hostname, - sameSite: true, - maxAge: 60 * 10 * 1000 // 10 minutes - } - })(req, res, next)) -}) +router.use('*', async (req, res, next) => getOperatorId('authentication').then(({ operatorId }) => session({ + store: new PgSession({ + pgPromise: db, + tableName: USER_SESSIONS_TABLE_NAME + }), + name: 'lamassu_sid', + secret: operatorId, + resave: false, + saveUninitialized: false, + cookie: { + httpOnly: true, + secure: true, + domain: hostname, + sameSite: true, + maxAge: 60 * 10 * 1000 // 10 minutes + } +})(req, res, next)) +) module.exports = router