2021-03-13 03:26:24 +00:00
|
|
|
'use strict';
|
|
|
|
|
2021-03-16 03:12:05 +00:00
|
|
|
const config = require('config');
|
2021-03-13 03:26:24 +00:00
|
|
|
const util = require('util');
|
|
|
|
const crypto = require('crypto');
|
|
|
|
|
|
|
|
const knex = require('./knex');
|
2021-03-15 02:30:47 +00:00
|
|
|
const { curateUser, fetchUser } = require('./users');
|
2021-03-13 03:26:24 +00:00
|
|
|
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) {
|
2021-06-27 22:05:24 +00:00
|
|
|
if (!config.auth.login) {
|
2021-03-16 03:12:05 +00:00
|
|
|
throw new HttpError('Authentication is disabled', 405);
|
|
|
|
}
|
|
|
|
|
2023-06-08 01:57:50 +00:00
|
|
|
const user = await fetchUser(credentials.username.trim(), true);
|
2021-03-13 03:26:24 +00:00
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
throw new HttpError('Username or password incorrect', 401);
|
|
|
|
}
|
|
|
|
|
|
|
|
await verifyPassword(credentials.password, user.password);
|
|
|
|
|
2022-04-03 22:23:37 +00:00
|
|
|
await knex('users')
|
|
|
|
.update('last_login', 'NOW()')
|
|
|
|
.where('id', user.id);
|
|
|
|
|
2021-03-13 03:26:24 +00:00
|
|
|
return curateUser(user);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function signup(credentials) {
|
2021-06-27 22:05:24 +00:00
|
|
|
if (!config.auth.signup) {
|
2021-03-16 03:12:05 +00:00
|
|
|
throw new HttpError('Authentication is disabled', 405);
|
|
|
|
}
|
|
|
|
|
2023-06-08 01:57:50 +00:00
|
|
|
const curatedUsername = credentials.username.trim();
|
|
|
|
|
|
|
|
if (!curatedUsername) {
|
2021-03-13 03:26:24 +00:00
|
|
|
throw new HttpError('Username required', 400);
|
|
|
|
}
|
|
|
|
|
2023-06-08 01:57:50 +00:00
|
|
|
if (curatedUsername.length < config.auth.usernameLength[0]) {
|
|
|
|
throw new HttpError('Username is too short', 400);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (curatedUsername.length > config.auth.usernameLength[1]) {
|
|
|
|
throw new HttpError('Username is too long', 400);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!config.auth.usernamePattern.test(curatedUsername)) {
|
|
|
|
throw new HttpError('Username contains invalid characters', 400);
|
|
|
|
}
|
|
|
|
|
2021-03-13 03:26:24 +00:00
|
|
|
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')
|
2023-06-08 01:57:50 +00:00
|
|
|
.where('username', curatedUsername)
|
2021-03-13 03:26:24 +00:00
|
|
|
.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}`;
|
|
|
|
|
2023-11-30 02:12:47 +00:00
|
|
|
const [{ id: userId }] = await knex('users')
|
2021-03-13 03:26:24 +00:00
|
|
|
.insert({
|
2023-06-08 01:57:50 +00:00
|
|
|
username: curatedUsername,
|
2021-03-13 03:26:24 +00:00
|
|
|
email: credentials.email,
|
|
|
|
password: storedPassword,
|
|
|
|
})
|
2021-03-15 02:30:47 +00:00
|
|
|
.returning('id');
|
2021-03-13 03:26:24 +00:00
|
|
|
|
2021-03-14 03:54:43 +00:00
|
|
|
await knex('stashes').insert({
|
2021-03-17 04:11:17 +00:00
|
|
|
user_id: userId,
|
2021-03-14 03:54:43 +00:00
|
|
|
name: 'Favorites',
|
|
|
|
slug: 'favorites',
|
|
|
|
public: false,
|
2021-03-21 02:23:58 +00:00
|
|
|
primary: true,
|
2021-03-14 03:54:43 +00:00
|
|
|
});
|
|
|
|
|
2021-03-17 04:11:17 +00:00
|
|
|
return fetchUser(userId);
|
2021-03-13 03:26:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
login,
|
|
|
|
signup,
|
|
|
|
};
|