You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
3.2 KiB
JavaScript

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
})