traxxx/src/auth.js

88 lines
2.0 KiB
JavaScript

'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,
};