diff --git a/lib/auth-tokens.js b/lib/auth-tokens.js new file mode 100644 index 00000000..830b679b --- /dev/null +++ b/lib/auth-tokens.js @@ -0,0 +1,14 @@ +const crypto = require('crypto') + +const constants = require('./constants') + +function createAuthToken (userID, type) { + const token = crypto.randomBytes(32).toString('hex') + const sql = `INSERT INTO auth_tokens (token, type, user_id) VALUES ($1, $2, $3) ON CONFLICT (user_id, type) DO UPDATE SET token=$1, expire=now() + interval '${constants.AUTH_TOKEN_EXPIRATION_TIME}' RETURNING *` + + return db.one(sql, [token, type, userID]) +} + +module.exports = { + createAuthToken +} diff --git a/lib/constants.js b/lib/constants.js index 3c2f4267..bfef792b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -3,4 +3,13 @@ const anonymousCustomer = { name: 'anonymous' } -module.exports = {anonymousCustomer} +const AUTHENTICATOR_ISSUER_ENTITY = 'Lamassu' +const AUTH_TOKEN_EXPIRATION_TIME = '30 minutes' +const REGISTRATION_TOKEN_EXPIRATION_TIME = '30 minutes' + +module.exports = { + anonymousCustomer, + AUTHENTICATOR_ISSUER_ENTITY, + AUTH_TOKEN_EXPIRATION_TIME, + REGISTRATION_TOKEN_EXPIRATION_TIME +} diff --git a/lib/new-admin/graphql/modules/authentication.js b/lib/new-admin/graphql/modules/authentication.js index 3e1ebccb..798e6aa1 100644 --- a/lib/new-admin/graphql/modules/authentication.js +++ b/lib/new-admin/graphql/modules/authentication.js @@ -1,6 +1,8 @@ const otplib = require('otplib') const argon2 = require('argon2') +const constants = require('../../../constants') +const authTokens = require('../../../auth-tokens') const loginHelper = require('../../services/login') const T = require('../../../time') const users = require('../../../users') @@ -76,7 +78,7 @@ const get2FASecret = (username, password) => { return authenticateUser(username, password) .then(user => { const secret = otplib.authenticator.generateSecret() - const otpauth = otplib.authenticator.keyuri(user.username, 'Lamassu', secret) + const otpauth = otplib.authenticator.keyuri(user.username, constants.AUTHENTICATOR_ISSUER_ENTITY, secret) return Promise.all([users.saveTemp2FASecret(user.id, secret), secret, otpauth]) }) .then(([_, secret, otpauth]) => { @@ -125,7 +127,7 @@ const validateReset2FALink = token => { }) .then(user => { const secret = otplib.authenticator.generateSecret() - const otpauth = otplib.authenticator.keyuri(user.username, 'Lamassu', secret) + const otpauth = otplib.authenticator.keyuri(user.username, constants.AUTHENTICATOR_ISSUER_ENTITY, secret) return Promise.all([users.saveTemp2FASecret(user.id, secret), user, secret, otpauth]) }) .then(([_, user, secret, otpauth]) => { @@ -185,12 +187,12 @@ const disableUser = (code, id, context) => { } const createResetPasswordToken = (code, userID, context) => { - const action = () => users.createAuthToken(userID, 'reset_password') + const action = () => authTokens.createAuthToken(userID, 'reset_password') return executeProtectedAction(code, userID, context, action) } const createReset2FAToken = (code, userID, context) => { - const action = () => users.createAuthToken(userID, 'reset_twofa') + const action = () => authTokens.createAuthToken(userID, 'reset_twofa') return executeProtectedAction(code, userID, context, action) } diff --git a/lib/users.js b/lib/users.js index ef0b3aa6..b11a0bf3 100644 --- a/lib/users.js +++ b/lib/users.js @@ -4,6 +4,7 @@ const crypto = require('crypto') const argon2 = require('argon2') const uuid = require('uuid') +const constants = require('./constants') const db = require('./db') /** @@ -97,13 +98,6 @@ function reset2FASecret (token, id, secret) { }) } -function createAuthToken (userID, type) { - const token = crypto.randomBytes(32).toString('hex') - const sql = `INSERT INTO auth_tokens (token, type, user_id) VALUES ($1, $2, $3) ON CONFLICT (user_id, type) DO UPDATE SET token=$1, expire=now() + interval '30 minutes' RETURNING *` - - return db.one(sql, [token, type, userID]) -} - function updatePassword (token, id, password) { return validateAuthToken(token, 'reset_password').then(res => { if (!res.success) throw new Error('Failed to verify password reset token') @@ -121,7 +115,7 @@ function updatePassword (token, id, password) { function createUserRegistrationToken (username, role) { const token = crypto.randomBytes(32).toString('hex') const sql = `INSERT INTO user_register_tokens (token, username, role) VALUES ($1, $2, $3) ON CONFLICT (username) - DO UPDATE SET token=$1, expire=now() + interval '30 minutes' RETURNING *` + DO UPDATE SET token=$1, expire=now() + interval '${constants.REGISTRATION_TOKEN_EXPIRATION_TIME}' RETURNING *` return db.one(sql, [token, username, role]) } @@ -176,7 +170,6 @@ module.exports = { save2FASecret, reset2FASecret, validateAuthToken, - createAuthToken, createUserRegistrationToken, validateUserRegistrationToken, register, diff --git a/migrations/1618843631500-users.js b/migrations/1618843631500-users.js index 509a4cdd..37b4902d 100644 --- a/migrations/1618843631500-users.js +++ b/migrations/1618843631500-users.js @@ -1,4 +1,5 @@ var db = require('./db') +const constants = require('../lib/constants') exports.up = function (next) { var sql = [ @@ -27,14 +28,14 @@ exports.up = function (next) { token TEXT NOT NULL PRIMARY KEY, type auth_token_type NOT NULL, user_id UUID REFERENCES users(id) ON DELETE CASCADE, - expire TIMESTAMPTZ NOT NULL DEFAULT now() + interval '30 minutes', + expire TIMESTAMPTZ NOT NULL DEFAULT now() + interval '${constants.AUTH_TOKEN_EXPIRATION_TIME}', CONSTRAINT unique_userid_type UNIQUE (user_id, type) )`, `CREATE TABLE user_register_tokens ( token TEXT NOT NULL PRIMARY KEY, username TEXT NOT NULL UNIQUE, role role DEFAULT 'user', - expire TIMESTAMPTZ NOT NULL DEFAULT now() + interval '30 minutes' + expire TIMESTAMPTZ NOT NULL DEFAULT now() + interval '${constants.REGISTRATION_TOKEN_EXPIRATION_TIME}' )`, // migrate values from customers which reference user_tokens for data persistence `ALTER TABLE customers ADD COLUMN sms_override_by_old TEXT`,