313 lines
6.2 KiB
JavaScript
313 lines
6.2 KiB
JavaScript
const UsersDBApi = require('../db/api/users');
|
|
const ValidationError = require('./notifications/errors/validation');
|
|
const ForbiddenError = require('./notifications/errors/forbidden');
|
|
const bcrypt = require('bcrypt');
|
|
const EmailAddressVerificationEmail = require('./email/list/addressVerification');
|
|
const InvitationEmail = require("./email/list/invitation");
|
|
const PasswordResetEmail = require('./email/list/passwordReset');
|
|
const EmailSender = require('./email');
|
|
const config = require('../config');
|
|
const helpers = require('../helpers');
|
|
|
|
class Auth {
|
|
static async signup(email, password, options = {}, host) {
|
|
const user = await UsersDBApi.findBy({email});
|
|
|
|
const hashedPassword = await bcrypt.hash(
|
|
password,
|
|
config.bcrypt.saltRounds,
|
|
);
|
|
|
|
if (user) {
|
|
if (user.authenticationUid) {
|
|
throw new ValidationError(
|
|
'auth.emailAlreadyInUse',
|
|
);
|
|
}
|
|
|
|
if (user.disabled) {
|
|
throw new ValidationError(
|
|
'auth.userDisabled',
|
|
);
|
|
}
|
|
|
|
await UsersDBApi.updatePassword(
|
|
user.id,
|
|
hashedPassword,
|
|
options,
|
|
);
|
|
|
|
if (EmailSender.isConfigured) {
|
|
await this.sendEmailAddressVerificationEmail(
|
|
user.email,
|
|
host,
|
|
);
|
|
}
|
|
|
|
const data = {
|
|
user: {
|
|
id: user.id,
|
|
email: user.email
|
|
}
|
|
};
|
|
|
|
return helpers.jwtSign(data);
|
|
}
|
|
|
|
const newUser = await UsersDBApi.createFromAuth(
|
|
{
|
|
firstName: email.split('@')[0],
|
|
password: hashedPassword,
|
|
email: email,
|
|
|
|
},
|
|
options,
|
|
);
|
|
|
|
if (EmailSender.isConfigured) {
|
|
await this.sendEmailAddressVerificationEmail(
|
|
newUser.email,
|
|
host,
|
|
);
|
|
}
|
|
|
|
const data = {
|
|
user: {
|
|
id: newUser.id,
|
|
email: newUser.email
|
|
}
|
|
};
|
|
|
|
return helpers.jwtSign(data);
|
|
}
|
|
|
|
static async signin(email, password, options = {}) {
|
|
const user = await UsersDBApi.findBy({email});
|
|
|
|
if (!user) {
|
|
throw new ValidationError(
|
|
'auth.userNotFound',
|
|
);
|
|
}
|
|
|
|
if (user.disabled) {
|
|
throw new ValidationError(
|
|
'auth.userDisabled',
|
|
);
|
|
}
|
|
|
|
if (!user.password) {
|
|
throw new ValidationError(
|
|
'auth.wrongPassword',
|
|
);
|
|
}
|
|
|
|
if (!EmailSender.isConfigured) {
|
|
user.emailVerified = true;
|
|
}
|
|
|
|
if (!user.emailVerified) {
|
|
throw new ValidationError(
|
|
'auth.userNotVerified',
|
|
);
|
|
}
|
|
|
|
const passwordsMatch = await bcrypt.compare(
|
|
password,
|
|
user.password,
|
|
);
|
|
|
|
if (!passwordsMatch) {
|
|
throw new ValidationError(
|
|
'auth.wrongPassword',
|
|
);
|
|
}
|
|
|
|
const data = {
|
|
user: {
|
|
id: user.id,
|
|
email: user.email
|
|
}
|
|
};
|
|
|
|
return helpers.jwtSign(data);
|
|
}
|
|
|
|
static async sendEmailAddressVerificationEmail(
|
|
email,
|
|
host,
|
|
) {
|
|
|
|
|
|
let link;
|
|
try {
|
|
const token = await UsersDBApi.generateEmailVerificationToken(
|
|
email,
|
|
);
|
|
link = `${host}/verify-email?token=${token}`;
|
|
} catch (error) {
|
|
console.error(error);
|
|
throw new ValidationError(
|
|
'auth.emailAddressVerificationEmail.error',
|
|
);
|
|
}
|
|
|
|
const emailAddressVerificationEmail = new EmailAddressVerificationEmail(
|
|
email,
|
|
link,
|
|
);
|
|
|
|
return new EmailSender(
|
|
emailAddressVerificationEmail,
|
|
).send();
|
|
}
|
|
|
|
static async sendPasswordResetEmail(email, type = 'register', host) {
|
|
|
|
|
|
let link;
|
|
|
|
try {
|
|
const token = await UsersDBApi.generatePasswordResetToken(
|
|
email,
|
|
);
|
|
link = `${host}/password-reset?token=${token}`;
|
|
} catch (error) {
|
|
console.error(error);
|
|
throw new ValidationError(
|
|
'auth.passwordReset.error',
|
|
);
|
|
}
|
|
|
|
let passwordResetEmail;
|
|
if (type === 'register') {
|
|
passwordResetEmail = new PasswordResetEmail(
|
|
email,
|
|
link,
|
|
);
|
|
}
|
|
if (type === 'invitation') {
|
|
passwordResetEmail = new InvitationEmail(
|
|
email,
|
|
link,
|
|
);
|
|
}
|
|
|
|
return new EmailSender(passwordResetEmail).send();
|
|
}
|
|
|
|
static async verifyEmail(token, options = {}) {
|
|
const user = await UsersDBApi.findByEmailVerificationToken(
|
|
token,
|
|
options,
|
|
);
|
|
|
|
if (!user) {
|
|
throw new ValidationError(
|
|
'auth.emailAddressVerificationEmail.invalidToken',
|
|
);
|
|
}
|
|
|
|
return UsersDBApi.markEmailVerified(
|
|
user.id,
|
|
options,
|
|
);
|
|
}
|
|
|
|
static async passwordUpdate(currentPassword, newPassword, options) {
|
|
const currentUser = options.currentUser || null;
|
|
if (!currentUser) {
|
|
throw new ForbiddenError();
|
|
}
|
|
|
|
const currentPasswordMatch = await bcrypt.compare(
|
|
currentPassword,
|
|
currentUser.password,
|
|
);
|
|
|
|
if (!currentPasswordMatch) {
|
|
throw new ValidationError(
|
|
'auth.wrongPassword'
|
|
)
|
|
}
|
|
|
|
const newPasswordMatch = await bcrypt.compare(
|
|
newPassword,
|
|
currentUser.password,
|
|
);
|
|
|
|
if (newPasswordMatch) {
|
|
throw new ValidationError(
|
|
'auth.passwordUpdate.samePassword'
|
|
)
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(
|
|
newPassword,
|
|
config.bcrypt.saltRounds,
|
|
);
|
|
|
|
return UsersDBApi.updatePassword(
|
|
currentUser.id,
|
|
hashedPassword,
|
|
options,
|
|
);
|
|
}
|
|
|
|
static async passwordReset(
|
|
token,
|
|
password,
|
|
options = {},
|
|
) {
|
|
const user = await UsersDBApi.findByPasswordResetToken(
|
|
token,
|
|
options,
|
|
);
|
|
|
|
if (!user) {
|
|
throw new ValidationError(
|
|
'auth.passwordReset.invalidToken',
|
|
);
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(
|
|
password,
|
|
config.bcrypt.saltRounds,
|
|
);
|
|
|
|
return UsersDBApi.updatePassword(
|
|
user.id,
|
|
hashedPassword,
|
|
options,
|
|
);
|
|
}
|
|
|
|
static async updateProfile(data, currentUser) {
|
|
let transaction = await db.sequelize.transaction();
|
|
|
|
try {
|
|
await UsersDBApi.findBy(
|
|
{id: currentUser.id},
|
|
{transaction},
|
|
);
|
|
|
|
await UsersDBApi.update(
|
|
currentUser.id,
|
|
data,
|
|
{
|
|
currentUser,
|
|
transaction
|
|
},
|
|
);
|
|
|
|
|
|
await transaction.commit();
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Auth;
|