Skip to content
Permalink
Browse files
feat: adds email verification
  • Loading branch information
MantasMikal committed Feb 5, 2021
1 parent 1137d9e commit 625a9cbf890dcb147f8c860ff4ad320410a0034d
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 7 deletions.
@@ -3,7 +3,7 @@
"name": "WebAuthn UX Test API - Dev Mode",
"port": 4000,
"mode": "development",
"siteUrl": "https://localhost:3000",
"siteUrl": "https://localhost:3000/",
"protocol": "http",
"serverUrl": "localhost"
}
@@ -3,7 +3,7 @@
"name": "WebAuthn UX Test API - Prod Mode",
"mode": "production",
"protocol": "https",
"siteUrl": "https://web-authn.studio",
"serverUrl": "api.web-authn.studio"
"siteUrl": "https://fido2.app",
"serverUrl": "api.fido2.app"
}
}
@@ -0,0 +1,7 @@
export const accountVerificationTemplate = (url) => ({
subject: `🎉 Successfully created a new account on Fakebook`,
bodyHtml: `
<h1>Thanks for helping me with the study 😎</h1>
<a href="${url}">Verify your account by clicking here </a>
`
});
@@ -0,0 +1,46 @@
/**
* Mailer service to handle email sending
* @module service/mailer
*/

import nodemailer from "nodemailer";

/**
* Sends an email
* @param {Array} recipients email addresses of recipients
* @param {String} subject email subject
* @param {String} bodyHtml email body
* @returns {Object} status of the email
*/
const mailTo = async (recipients, { subject, bodyHtml }) => {
const transporter = nodemailer.createTransport({
host: "mail.privateemail.com",
port: 465,
auth: {
user: process.env.MAILER_USER,
pass: process.env.MAILER_PASSWORD,
},
});
const data = {
from: process.env.MAILER_USER,
to: recipients,
subject: subject,
html: bodyHtml,
};
return await sendEmail(transporter, data);
};

/**
* Wrapper for sending emails that returns a promise
* @param {Object} transporter Nodemailer transporter object
* @param {Object} data data to be send
*/
const sendEmail = async (transporter, data) =>
new Promise((resolve, reject) => {
transporter.sendMail(data, (err, info) => {
if (err) reject(err);
resolve(info);
});
});

export default mailTo;
@@ -0,0 +1,22 @@
import mongoose from "../helpers/db.js";

const AccountVerificationCode = mongoose.model(
"AccountVerificationCode",
new mongoose.Schema({
email: {
type: String,
required: true,
},
code: {
type: String,
required: true,
},
dateCreated: {
type: Date,
default: Date.now(),
expires: 600,
},
})
);

export default AccountVerificationCode;
@@ -34,6 +34,10 @@ const User = mongoose.model(
},
userAgent: {
type: Object
},
status: {
type: String,
default: 'pending'
}
})
);

Some generated files are not rendered by default. Learn more.

@@ -37,6 +37,7 @@
"glob": "^7.1.6",
"helmet": "^4.4.1",
"mongoose": "^5.11.12",
"nodemailer": "^6.4.17",
"nodemon": "^2.0.7",
"xss-clean": "^0.1.1"
},
@@ -6,6 +6,9 @@ import bcrypt from "bcrypt";
import cfg from "config";
import User from "../models/user.js";
import { verifyPassword } from "../helpers/utils.js";
import { accountVerificationTemplate } from "../helpers/emailTemplates.js";
import mailTo from "../helpers/mailer.js";
import AccountVerificationCode from "../models/accountVerificationCode.js";

const mode = process.env.NODE_ENV || "dev";
const config = cfg.get(mode);
@@ -81,6 +84,7 @@ router.post("/register", async (req, res) => {
req.session.publicKey = regResult.authnrData.get("credentialPublicKeyPem");
req.session.prevCounter = regResult.authnrData.get("counter");
const hash = bcrypt.hashSync(password, 10);

const user = await User.create({
id: req.session.userHandle,
credentialId: base64RawId,
@@ -91,10 +95,22 @@ router.post("/register", async (req, res) => {
regDuration: regDuration,
userAgent: userAgent,
});

user.save();
console.log("Created new account for: ", email);

const secretVerificationCode = crypto.randomBytes(32).toString("hex")
const verificationCode = await AccountVerificationCode.create({
email: user.email,
code: secretVerificationCode,
});

verificationCode.save();
console.log("Created new account for: ", email);
await mailTo(
[email],
accountVerificationTemplate(
`${config.siteUrl}verification/verify-account/${user.email}/${secretVerificationCode}`
)
);
res.json({ status: "ok" });
} catch (e) {
console.log("error", e);
@@ -125,7 +141,6 @@ router.post("/authenticate", async (req, res) => {
const user = await User.findOne({ email });
if (user) {
if (verifyPassword(user, password)) {
console.log("All good");
return res.status(200).json({ status: "ok" });
} else return res.status(401).json({ error: "Incorrect login details" });
} else return res.status(401).json({ error: "Incorrect login details" });
@@ -0,0 +1,26 @@
import express from "express";
// import cfg from "config";
import User from "../models/user.js";
import AccountVerificationCode from "../models/accountVerificationCode.js";

const mode = process.env.NODE_ENV || "dev";
// const config = cfg.get(mode);
const router = express.Router();

router.post("/verify-account", async (req, res) => {
const { email, secretCode } = req.body;
try {
const verificationCode = await AccountVerificationCode.findOne({ code: secretCode });
const user = await User.findOne({ email: email });
if ((user && verificationCode) && verificationCode.email === user.email) {
await User.findOneAndUpdate({ email: email }, { status: "active" });
return res.status(200).json({ status: "Success" });
} else {
return res.status(401).json({ error: "Incorrect verification code" });
}
} catch (err) {
return res.status(500).json({ error: "Server error: " + err });
}
});

export default router;
@@ -10,6 +10,7 @@ import session from "express-session";
import errorHandler from "errorhandler";
import connectMongo from "connect-mongo";
import registerRoutes from "./routes/register.js";
import verificationRoutes from "./routes/verification.js";
import dbConnection from "./helpers/db.js";

const app = express();
@@ -39,7 +40,6 @@ app.use(
})
);


app.use(
bodyParser.urlencoded({
extended: false,
@@ -73,6 +73,7 @@ app.use(
app.use(errorHandler());

app.use("/api/v1", registerRoutes);
app.use("/api/v1/verification", verificationRoutes);

app.listen(process.env.PORT || config.port, () => {
console.log(chalk.yellow("......................................."));

0 comments on commit 625a9cb

Please sign in to comment.