email verification

This commit is contained in:
lukew3 2021-05-27 11:08:40 -04:00
parent b669e1b107
commit e2920fbec2
7 changed files with 101 additions and 13 deletions

View file

@ -21,8 +21,9 @@ const userSchema = new Schema(
favouriteThemes: [],
refactored: { type: Boolean, default: true },
banned: { type: Boolean, default: false },
verified: { type: Boolean, default: false }, //what's the difference between verified and email verified
verified: { type: Boolean, default: false }, //Verified is actually whether or not discord account is connected
emailVerified: { type: Boolean, default: false },
verificationHashes: [{ type: String }],
lbMemory: {
//short for leaderboard memory
time15: {

View file

@ -1,8 +1,7 @@
## Todo
# Todo
- Get google login working
- Account data should be updated when new result is added/test completed
- Add email verification
- Fix localhost, production, development server detection
- Should be a setting in the .env
- Maybe it could be set through package.json
@ -12,13 +11,17 @@
- Check for tag pb doesn't always work
- Leaderboard doesn't show the time until the daily reset
- User's Leaderboard history is not edited, and therefore distance moved on leaderboard does not work properly
- Graph bugs out when new result is added but page is not refreshed
- Graph loops back from earliest point to the new points
- Results list isn't updated either
### leaderboard
- Does clearDailyLeaderboards cause a memory leak?
- Try commenting it out and seeing if it makes a difference
- Identify bugs
- Username not highlighted and added to the bottom if current user made the leaderboard
- Leaderboard says glb is undefined on first item
- No global or daily items are returned
## After beta is ready

View file

@ -3,6 +3,7 @@ const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const jwt = require("jsonwebtoken");
const nodemailer = require("nodemailer");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const { User } = require("./models/user");
@ -20,6 +21,19 @@ mongoose.connect("mongodb://localhost:27017/monkeytype", {
useUnifiedTopology: true,
});
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
//should use OAuth in production
//type: 'OAuth2',
user: process.env.MAIL_ADDRESS,
pass: process.env.MAIL_PASSWORD,
//clientId: process.env.OAUTH_CLIENTID,
//clientSecret: process.env.OAUTH_CLIENT_SECRET,
//refreshToken: process.env.OAUTH_REFRESH_TOKEN
},
});
const mtRootDir = __dirname.substring(0, __dirname.length - 8); //will this work for windows and mac computers?
app.use(express.static(mtRootDir + "/dist"));
app.use(bodyParser.json());
@ -557,10 +571,57 @@ app.post("/api/updateName", (req, res) => {
const name = req.body.name;
});
app.post("/api/sendEmailVerification", (req, res) => {
const uid = req.body.uid;
//Add send Email verification code here
//should be a seperate sendEmailVerification function that can be called from sign up as well
function sendVerificationEmail(username, email) {
const host = "localhost:5000";
const hash = Math.random().toString(16).substr(2, 12);
const link = `http://${host}/verifyEmail?name=${username}&hash=${hash}`;
User.findOne({ name: username }, (err, user) => {
user.verificationHashes.push(hash);
user.save();
});
const mailOptions = {
from: process.env.MAIL_ADDRESS,
to: email,
subject: "Monkeytype User Verification",
text: `Hello ${username},\nFollow this link to verify your email address:\n${link}\nIf you didnt ask to verify this address, you can ignore this email.\nThanks,\nYour monkeytype team`,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log("Email sent: " + info.response);
}
});
}
app.get("/verifyEmail", (req, res) => {
let success = false;
User.findOne({ name: req.query.name }, (err, user) => {
if (user.verificationHashes.includes(req.query.hash)) {
success = true;
user.verificationHashes = [];
user.verified = true;
user.emailVerified = true;
user.save();
}
}).then(() => {
if (success) {
res.send(
"<h3>Email verified successfully</h3><p>Go back to <a href='https://monkeytype.com'>monkeytype</a></p>"
);
} else {
res.send(
"<h3>Email verification failed</h3><p>Go back to <a href='https://monkeytype.com'>monkeytype</a></p>"
);
}
});
});
app.post("/api/sendEmailVerification", authenticateToken, (req, res) => {
User.findOne({ name: req.name }, (err, user) => {
sendVerificationEmail(req.name, user.email);
});
res.sendStatus(200);
});
@ -569,8 +630,9 @@ app.post("/api/signIn", (req, res) => {
//Login and send tokens
User.findOne({ email: req.body.email }, (err, user) => {
if (err) res.status(500).send({ error: err });
if (user == null) {
if (user === null) {
res.status(500).send({ error: "No user found with that email" });
return;
}
bcrypt.compare(req.body.password, user.password, (err, result) => {
if (err)
@ -628,7 +690,7 @@ app.post("/api/signUp", (req, res) => {
.save()
.then((user) => {
//send email verification
sendVerificationEmail(user.name, user.email);
//add account created event to analytics
//return user data and access token

9
example.env Normal file
View file

@ -0,0 +1,9 @@
# Secrets can be generated at https://www.grc.com/passwords.htm
ACCESS_TOKEN_SECRET=6JlduNw96JONRtmg7Ru6tCW0UN42LQyzlHE0e03p2HO4m5Gm7PrYjRCinHCfeMM
REFRESH_TOKEN_SECRET=bnTfeI0J84XucqTWkHRPBCrewoJGIQySdHnL2bDrZp212tDyMG0fs5nf9aUXT9N
#Gmail login for email verification
#App password can be generated on account page under security, sigining in to Google
#Must enable 2 step verification before generating app password
MAIL_ADDRESS=youremail@gmail.com
MAIL_PASSWORD=cqvpgasbggytzfjq

14
package-lock.json generated
View file

@ -20,6 +20,7 @@
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.12.8",
"nodemailer": "^6.6.1",
"tinycolor2": "^1.4.2"
},
"devDependencies": {
@ -9032,6 +9033,14 @@
"node": ">=0.8.0"
}
},
"node_modules/nodemailer": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.1.tgz",
"integrity": "sha512-1xzFN3gqv+/qJ6YRyxBxfTYstLNt0FCtZaFRvf4Sg9wxNGWbwFmGXVpfSi6ThGK6aRxAo+KjHtYSW8NvCsNSAg==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz",
@ -20602,6 +20611,11 @@
}
}
},
"nodemailer": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.1.tgz",
"integrity": "sha512-1xzFN3gqv+/qJ6YRyxBxfTYstLNt0FCtZaFRvf4Sg9wxNGWbwFmGXVpfSi6ThGK6aRxAo+KjHtYSW8NvCsNSAg=="
},
"nodemon": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz",

View file

@ -53,6 +53,7 @@
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.12.8",
"nodemailer": "^6.6.1",
"tinycolor2": "^1.4.2"
}
}

View file

@ -317,9 +317,7 @@ export function sendVerificationEmail() {
Loader.show();
let cu = DB.currentUser();
axiosInstance
.post("/api/sendEmailVerification", {
uid: cu.uid,
})
.post("/api/sendEmailVerification", {})
.then(() => {
Loader.hide();
showNotification("Email sent to " + cu.email, 4000);