'use strict'; const util = require('util'); const crypto = require('crypto'); const knex = require('./knex'); const { curateUser } = require('./users'); const { HttpError } = require('./errors'); const scrypt = util.promisify(crypto.scrypt); async function verifyPassword(password, storedPassword) { const [salt, hash] = storedPassword.split('/'); const hashedPassword = (await scrypt(password, salt, 64)).toString('hex'); if (hashedPassword === hash) { return true; } throw new HttpError('Username or password incorrect', 401); } async function login(credentials) { const user = await knex('users') .select('users.*', 'users_roles.abilities as role_abilities') .where('username', credentials.username) .orWhere('email', credentials.username) .leftJoin('users_roles', 'users_roles.role', 'users.role') .first(); if (!user) { throw new HttpError('Username or password incorrect', 401); } await verifyPassword(credentials.password, user.password); return curateUser(user); } async function signup(credentials) { if (!credentials.username) { throw new HttpError('Username required', 400); } if (!credentials.email) { throw new HttpError('E-mail required', 400); } if (credentials.password?.length < 3) { throw new HttpError('Password must be 3 characters or longer', 400); } const existingUser = await knex('users') .where('username', credentials.username) .orWhere('email', credentials.email) .first(); if (existingUser) { throw new HttpError('Username or e-mail already in use', 409); } const salt = crypto.randomBytes(16).toString('hex'); const hashedPassword = (await scrypt(credentials.password, salt, 64)).toString('hex'); const storedPassword = `${salt}/${hashedPassword}`; const [user] = await knex('users') .insert({ username: credentials.username, email: credentials.email, password: storedPassword, }) .returning('*'); await knex('stashes').insert({ user_id: user.id, name: 'Favorites', slug: 'favorites', public: false, }); return curateUser(user); } module.exports = { login, signup, };