const pg = require('../pg') const joinjs = require('join-js').default; const debug = require('debug')('sos:db:user') const mappings = require('../mappings') const dbUtil = require('../util') const uuid = require('uuid') const bcrypt = require('bcrypt') const session = require('./session') const user = module.exports = {} const saltRounds = parseInt(process.env.PW_SALTROUNDS, 10) || 10 user.findById = async (user_uuid) => { const query = { text: 'select * from "user" where user_uuid = $1', values: [ user_uuid ] } debug(query); const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'userMap', 'user_')[0]; } user.findByEmail = async (email) => { const query = { text: 'select * from "user" where user_email = $1', values: [ email ] } debug(query); const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'userMap', 'user_')[0] } user.register = async (email, password) => { const hash = await bcrypt.hash(password, saltRounds) const query = { text: 'select * from sos.register_user($1, $2)', values: [ email, hash ] } debug(query); const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'userMap', 'user_')[0]; } user.login = async (email, password) => { const _user = await user.findByEmail(email) if(!_user){ // Avoid early exit timing difference await bcrypt.hash(password, saltRounds) return null } const passwordCorrect = await bcrypt.compare(password, _user.password_hash) if(!passwordCorrect) return null return _user } user.getOpenEmailLinks = (user_uuid) => dbUtil.executeFunction({ name: 'get_open_email_links_for_user', params: [ user_uuid ], returnType: 'emailLink', tablePrefix: 'email_link_', single: false }) user.createLoginLink = async (user_uuid) => { const linkCode = uuid.v4() const hash = await bcrypt.hash(linkCode, saltRounds) const link_record = await dbUtil.executeFunction({ name: 'create_login_link', params: [ user_uuid, '2 hours', hash ], returnType: 'emailLink', tablePrefix: 'email_link_', single: true }) return `${process.env.EXTERNAL_URL}/api/email/confirm/${link_record.uuid}?key=${linkCode}` } user.verifyLoginLink = async (link_uuid, key) => { const link_record = await dbUtil.executeQuery({ query: { text: 'select * from sos.email_link where email_link_uuid = $1', values: [link_uuid] }, returnType: 'emailLink', tablePrefix: 'email_link_', single: true }) if(!link_record){ // Avoid early exit timing difference await bcrypt.hash(key, saltRounds) return null } const valid = await bcrypt.compare(key, link_record.login_hash) if(!valid) return null return link_record } user.markLoginLinkUsed = link_uuid => dbUtil.executeFunction({ name: 'set_link_used', params: [link_uuid], returnType: 'emailLink', tablePrefix: 'email_link_', single: true }) user.markEmailVerified = user_uuid => dbUtil.executeFunction({ name: 'set_user_email_verified', params: [user_uuid], returnType: 'user', single: true })