MySQL + Sequelize is working, signup emails working

This commit is contained in:
2021-01-25 07:32:47 +11:00
parent d0b383f5de
commit 9cd57f17fa
19 changed files with 760 additions and 283 deletions
+130 -4
View File
@@ -1,16 +1,142 @@
//libraries
const util = require('util');
const bcrypt = require('bcryptjs');
const sendmail = require('sendmail')({silent: true});
const nodemailer = require('nodemailer');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const { bannedEmails, accounts, pendingSignups } = require('../database/models');
//utilities
const validateEmail = require('../../common/utilities/validate-email.js');
const validateUsername = require('../../common/utilities/validate-username.js');
const sequelize = require('../database');
//api/accounts/signup
const route = (req, res) => {
res.status(200).send("The server has received your information.");
const route = async (req, res) => {
//validate the given details
const validateErr = await validateDetails(req.fields);
if (validateErr) {
return res.status(401).send(validateErr);
}
//generate the password hash
const salt = await bcrypt.genSalt(11);
const hash = await bcrypt.hash(req.fields.password, salt);
//generate the validation field
const verify = Math.floor(Math.random() * 2000000000);
//register signup
const signupErr = await registerPendingSignup(req.fields, hash, verify);
if (signupErr) {
return res.status(500).send(signupErr);
}
//send the validation email
const emailErr = await sendValidationEmail(req.fields.email, verify);
if (emailErr) {
return res.status(500).send(emailErr);
}
//finally
res.status(200).send("Validation email sent!");
return null;
}
const validateDetails = async (fields) => {
//basic formatting
if (!validateEmail(fields.email)) {
return 'invalid email';
}
if (!validateUsername(fields.username)) {
return 'invalid username';
}
//check for existing (banned)
const banned = await bannedEmails.findAll({
where: {
[Op.and]: {
email: fields.email,
expiry: {
[Op.or]: {
[Op.gt]: Sequelize.fn('NOW'),
[Op.eq]: null
}
}
}
}
});
if (banned.length > 0) {
return 'banned email';
}
//check for existing email
const email = await accounts.findOne({
where: {
email: fields.email
}
});
if (email) {
return 'email already exists';
}
//check for existing username
const username = await accounts.findOne({
where: {
username: fields.username
}
});
if (username) {
return 'username already exists';
}
return null;
};
const registerPendingSignup = async (fields, hash, verify) => {
const record = await pendingSignups.upsert({
email: fields.email,
username: fields.username,
hash: hash,
verify: verify
});
return null;
};
const sendValidationEmail = async (email, verify) => {
const addr = `${process.env.WEB_PROTOCOL}://${process.env.WEB_ADDRESS}/api/verify?verify=${verify}`;
const msg = `Hello! Please visit the following address to verify your account: ${addr}`;
//what exactly is a transport?
let transporter = nodemailer.createTransport({
host: process.env.MAIL_SMTP,
port: 465,
secure: true,
auth: {
user: process.env.MAIL_USERNAME,
pass: process.env.MAIL_PASSWORD
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: `signup@${process.env.WEB_ADDRESS}`, //WARNING: google overwrites this
to: email,
subject: 'Email Validation',
text: msg
});
if (info.accepted[0] != email) {
return 'validation email failed';
}
return null;
};
module.exports = route;
+11
View File
@@ -0,0 +1,11 @@
const Sequelize = require('sequelize');
const sequelize = new Sequelize(process.env.DB_DATABASE, process.env.DB_USERNAME, process.env.DB_PASSWORD, {
host: '127.0.0.1',
dialect: 'mariadb',
logging: false
});
sequelize.sync();
module.exports = sequelize;
+36
View File
@@ -0,0 +1,36 @@
const Sequelize = require('sequelize');
const sequelize = require('..');
module.exports = sequelize.define('accounts', {
id: {
type: Sequelize.INTEGER(11),
allowNull: false,
autoIncrement: true,
primaryKey: true,
unique: true
},
privilege: {
type: Sequelize.ENUM,
values: ['administrator', 'moderator', 'alpha', 'beta', 'gamma', 'normal'],
defaultValue: 'normal'
},
email: {
type: 'varchar(320)',
unique: true
},
username: {
type: 'varchar(320)',
unique: true
},
hash: 'varchar(100)', //for passwords
expiry: {
type: 'DATETIME',
allowNull: true,
defaultValue: null
}
});
+25
View File
@@ -0,0 +1,25 @@
const Sequelize = require('sequelize');
const sequelize = require('..');
module.exports = sequelize.define('bannedEmails', {
id: {
type: Sequelize.INTEGER(11),
allowNull: false,
autoIncrement: true,
primaryKey: true,
unique: true
},
email: {
type: 'varchar(320)',
unique: true
},
reason: Sequelize.TEXT,
expiry: {
type: 'DATETIME',
allowNull: true,
defaultValue: null
}
});
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
bannedEmails: require('./banned-emails'),
accounts: require('./accounts'),
pendingSignups: require('./pending-signups')
}
+18
View File
@@ -0,0 +1,18 @@
const Sequelize = require('sequelize');
const sequelize = require('..');
module.exports = sequelize.define('pendingSignups', {
email: {
type: 'varchar(320)',
unique: true
},
username: {
type: 'varchar(320)',
unique: true
},
hash: 'varchar(100)', //for passwords
verify: Sequelize.INTEGER(11)
});
+3
View File
@@ -12,6 +12,9 @@ const formidable = require('express-formidable');
app.use(formidable());
//database connection
const database = require('./database');
//account management
app.use('/api/accounts', require('./accounts'));