Revert "Email verification" (#265)

This commit is contained in:
Cassie Tarakajian 2017-01-13 10:35:39 -05:00 committed by GitHub
parent 2d781e22fb
commit 311e8442a1
9 changed files with 28 additions and 252 deletions

View file

@ -10,7 +10,7 @@
"build": "NODE_ENV=production webpack --config webpack.config.prod.js --progress", "build": "NODE_ENV=production webpack --config webpack.config.prod.js --progress",
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"fetch-examples": "node fetch-examples.js", "fetch-examples": "node fetch-examples.js",
"postinstall": "git submodule update --remote --recursive" "postinstall" : "git submodule update --remote --recursive"
}, },
"main": "index.js", "main": "index.js",
"author": "Cassie Tarakajian", "author": "Cassie Tarakajian",
@ -83,13 +83,10 @@
"express": "^4.13.4", "express": "^4.13.4",
"express-session": "^1.13.0", "express-session": "^1.13.0",
"file-type": "^3.8.0", "file-type": "^3.8.0",
"fs-promise": "^1.0.0",
"htmlhint": "^0.9.13", "htmlhint": "^0.9.13",
"is_js": "^0.9.0",
"js-beautify": "^1.6.4", "js-beautify": "^1.6.4",
"jsdom": "^9.8.3", "jsdom": "^9.8.3",
"jshint": "^2.9.2", "jshint": "^2.9.2",
"jsonwebtoken": "^7.2.1",
"lodash": "^4.16.4", "lodash": "^4.16.4",
"loop-protect": "git+https://git@github.com/catarak/loop-protect.git", "loop-protect": "git+https://git@github.com/catarak/loop-protect.git",
"moment": "^2.14.1", "moment": "^2.14.1",
@ -100,9 +97,8 @@
"passport": "^0.3.2", "passport": "^0.3.2",
"passport-github": "^1.1.0", "passport-github": "^1.1.0",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"project-name-generator": "^2.1.3",
"pug": "^2.0.0-beta6",
"q": "^1.4.1", "q": "^1.4.1",
"project-name-generator": "^2.1.3",
"react": "^15.1.0", "react": "^15.1.0",
"react-dom": "^15.1.0", "react-dom": "^15.1.0",
"react-inlinesvg": "^0.4.2", "react-inlinesvg": "^0.4.2",

View file

@ -53,7 +53,6 @@ passport.use(new GitHubStrategy({
existingEmailUser.username = existingEmailUser.username || profile.username; existingEmailUser.username = existingEmailUser.username || profile.username;
existingEmailUser.tokens.push({ kind: 'github', accessToken }); existingEmailUser.tokens.push({ kind: 'github', accessToken });
existingEmailUser.name = existingEmailUser.name || profile.displayName; existingEmailUser.name = existingEmailUser.name || profile.displayName;
existingEmailUser.verified = 0;
existingEmailUser.save((err) => { existingEmailUser.save((err) => {
return done(null, existingEmailUser); return done(null, existingEmailUser);
}); });
@ -64,7 +63,6 @@ passport.use(new GitHubStrategy({
user.username = profile.username; user.username = profile.username;
user.tokens.push({ kind: 'github', accessToken }); user.tokens.push({ kind: 'github', accessToken });
user.name = profile.displayName; user.name = profile.displayName;
user.verified = 0;
user.save((err) => { user.save((err) => {
return done(null, user); return done(null, user);
}); });

View file

@ -1,8 +1,8 @@
import User from '../models/user'; import User from '../models/user';
import crypto from 'crypto'; import crypto from 'crypto';
import async from 'async'; import async from 'async';
import mail from '../utils/mail'; import nodemailer from 'nodemailer';
import auth from '../utils/auth'; import mg from 'nodemailer-mailgun-transport';
export function createUser(req, res, next) { export function createUser(req, res, next) {
const user = new User({ const user = new User({
@ -24,19 +24,11 @@ export function createUser(req, res, next) {
if (loginErr) { if (loginErr) {
return next(loginErr); return next(loginErr);
} }
mail.send('email-verification', { res.json({
body: { email: req.user.email,
link: `http://${req.headers.host}/verify?t=${auth.createVerificationToken(req.body.email)}` username: req.user.username,
}, preferences: req.user.preferences,
to: req.body.email, id: req.user._id
subject: 'Email Verification',
}, (result) => { // eslint-disable-line no-unused-vars
res.json({
email: req.user.email,
username: req.user.username,
preferences: req.user.preferences,
id: req.user._id
});
}); });
}); });
}); });
@ -107,13 +99,27 @@ export function resetPasswordInitiate(req, res) {
}); });
}, },
(token, user, done) => { (token, user, done) => {
mail.send('reset-password', { const auth = {
body: { auth: {
link: `http://${req.headers.host}/reset-password/${token}`, api_key: process.env.MAILGUN_KEY,
}, domain: process.env.MAILGUN_DOMAIN
}
};
const transporter = nodemailer.createTransport(mg(auth));
const message = {
to: user.email, to: user.email,
from: 'p5.js Web Editor <noreply@p5js.org>',
subject: 'p5.js Web Editor Password Reset', subject: 'p5.js Web Editor Password Reset',
}, done); text: `You are receiving this email because you (or someone else) have requested the reset of the password for your account.
\n\nPlease click on the following link, or paste this into your browser to complete the process:
\n\nhttp://${req.headers.host}/reset-password/${token}
\n\nIf you did not request this, please ignore this email and your password will remain unchanged.
\n\nThanks for using the p5.js Web Editor!\n`
};
transporter.sendMail(message, (error) => {
done(error);
});
} }
], (err) => { ], (err) => {
if (err) { if (err) {
@ -134,28 +140,6 @@ export function validateResetPasswordToken(req, res) {
}); });
} }
export function verifyEmail(req, res) {
const token = req.query.t;
// verify the token
auth.verifyEmailToken(token)
.then((data) => {
const email = data.email;
// change the verified field for the user or throw if the user is not found
User.findOne({ email })
.then((user) => {
// change the field for the user, and send the new cookie
user.verified = 0; // eslint-disable-line
user.save()
.then((result) => { // eslint-disable-line
res.json({ user });
});
});
})
.catch((err) => {
res.json(err);
});
}
export function updatePassword(req, res) { export function updatePassword(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function (err, user) { User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function (err, user) {
if (!user) { if (!user) {

View file

@ -8,7 +8,6 @@ const userSchema = new Schema({
password: { type: String }, password: { type: String },
resetPasswordToken: String, resetPasswordToken: String,
resetPasswordExpires: Date, resetPasswordExpires: Date,
verified: { type: Number, default: -1 },
github: { type: String }, github: { type: String },
email: { type: String, unique: true }, email: { type: String, unique: true },
tokens: Array, tokens: Array,

View file

@ -14,6 +14,4 @@ router.route('/reset-password/:token').get(UserController.validateResetPasswordT
router.route('/reset-password/:token').post(UserController.updatePassword); router.route('/reset-password/:token').post(UserController.updatePassword);
router.route('/verify').get(UserController.verifyEmail);
export default router; export default router;

View file

@ -1,37 +0,0 @@
const jwt = require('jsonwebtoken');
class Auth {
/**
* Create a verification token using jwt
*/
createVerificationToken(email, fromEmail) {
return jwt.sign({
email,
fromEmail,
}, process.env.SECRET_TOKEN, {
expiresIn: '1 day',
subject: 'email-verification',
});
}
/**
* Verify token
*/
verifyEmailToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(token, process.env.SECRET_TOKEN, (err, data) => {
if (err) {
if (err.name === 'TokenExpiredError') {
reject('The verification link has expired');
} else if (err.name === 'JsonWebTokenError') {
reject('Verification link is malformend');
}
}
resolve(data);
});
});
}
}
export default new Auth();

View file

@ -1,80 +0,0 @@
'use strict';
/**
* Mail service wrapping around mailgun
*/
import fsp from 'fs-promise';
import pug from 'pug';
import is from 'is_js';
import nodemailer from 'nodemailer';
import mg from 'nodemailer-mailgun-transport';
const auth = {
api_key: process.env.MAILGUN_KEY,
domain: process.env.MAILGUN_DOMAIN,
};
class Mail {
constructor() {
this.client = nodemailer.createTransport(mg({ auth }));
this.sendOptions = {
from: process.env.EMAIL_SENDER,
replyTo: process.env.EMAIL_REPLY_TO,
};
}
getMailTemplate(type) {
let mailTemp;
switch (type) {
case 'reset-password':
mailTemp = 'server/views/mailTemplates/reset-password.pug';
break;
case 'email-verification':
mailTemp = 'server/views/mailTemplates/email-verification.pug';
break;
}
return mailTemp;
}
sendMail(mailOptions) {
return new Promise((resolve, reject) => {
this.client.sendMail(mailOptions, (err, info) => {
resolve(err, info);
});
});
}
dispatchMail(template, data, callback) {
const self = this;
return fsp.readFile(template, 'utf8')
.then((file) => {
const compiled = pug.compile(file, {
filename: template,
});
const body = compiled(data.body);
const mailOptions = {
to: data.to,
subject: data.subject,
from: self.sendOptions.from,
'h:Reply-To': self.sendOptions.replyTo,
html: body,
};
return self.sendMail(mailOptions);
})
.then((err, res) => {
callback(err, res);
});
}
send(type, data, callback) {
let template = null;
if (is.existy(data.template)) {
template = data.template;
} else {
template = this.getMailTemplate(type);
}
return this.dispatchMail(template, data, callback);
}
}
export default new Mail();

View file

@ -1,41 +0,0 @@
doctype html
html(xmlns='http://www.w3.org/1999/xhtml')
head
meta(http-equiv='Content-Type', content='text/html; charset=utf-8')
body(paddingwidth='0', paddingheight='0', style='padding-top: 0; padding-bottom: 0; background-repeat: repeat; width: 100% !important; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; -webkit-font-smoothing: antialiased;background-color:white color:black;', offset='0', toppadding='0', leftpadding='0')
table.tableContent(border='0', cellspacing='0', cellpadding='0', align='center', bgcolor='white', style='font-family: Helvetica, Arial,serif;')
tr
td
table(width='650', border='0', cellspacing='0', cellpadding='0', align='center')
tr
td
table(width='650', border='0', cellspacing='0', cellpadding='0', align='center', )
tr
td(valign='top', align='center')
//.contentEditableContainer.contentImageEditable
.contentEditable
//- img(src='/img/mail-header-new.png', width='100%',alt='', data-default='placeholder', data-max-width='650')
tr
td(height='20')
tr
td.movableContentContainer(valign='top')
table(cellspacing="15")
tbody(style="font-size : 15px")
tr
td(style='text-align: center;font-family: sans-serif;font-size: 18px;')
h3 Email Verification
tr
td(style="color:black;line-height: 130%;padding: 10px;white-space:pre;")
| Hello,
| To verify you email, click on the button below:
tr(style="color:black;text-align:center")
td
a(href="#{link}" style="text-align:center;font-size:20px;font-family:Helvetica,arial,sans-serif;color:white;font-weight:bold; padding-left: 10px;display:inline-block;min-height:27px;padding : 4px 25px 4px 25px;line-height:27px;border-radius:2px;border-width:1px; background-color:black;" target="_blank") Verify Email
tr
td(style="color:black;padding:10px 10px 0 10px") Or copy and paste the URL into your browser:
tr(style="color:black")
td(width="560px" style='padding:10px;') #{link}
tr(style="color:black;padding:0 10px")
td This link is only valid for the next 24 hours.

View file

@ -1,41 +0,0 @@
doctype html
html(xmlns='http://www.w3.org/1999/xhtml')
head
meta(http-equiv='Content-Type', content='text/html; charset=utf-8')
body(paddingwidth='0', paddingheight='0', style='padding-top: 0; padding-bottom: 0; background-repeat: repeat; width: 100% !important; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; -webkit-font-smoothing: antialiased;background-color:white color:black;', offset='0', toppadding='0', leftpadding='0')
table.tableContent(border='0', cellspacing='0', cellpadding='0', align='center', bgcolor='white', style='font-family: Helvetica, Arial,serif;')
tr
td
table(width='650', border='0', cellspacing='0', cellpadding='0', align='center')
tr
td
table(width='650', border='0', cellspacing='0', cellpadding='0', align='center', )
tr
td(valign='top', align='center')
//.contentEditableContainer.contentImageEditable
.contentEditable
//- img(src='/img/mail-header-new.png', width='100%',alt='', data-default='placeholder', data-max-width='650')
tr
td(height='20')
tr
td.movableContentContainer(valign='top')
table(cellspacing="15")
tbody(style="font-size : 15px")
tr
td(style='text-align: center;font-family: sans-serif;font-size: 18px;')
h3 Reset your password
tr
td(style="color:black;line-height: 130%;padding: 10px;white-space:pre;")
| Hello,
| We received a request to reset the password for your account. To reset your password, click on the button below:
tr(style="color:black;text-align:center")
td
a(href="#{link}" style="text-align:center;font-size:20px;font-family:Helvetica,arial,sans-serif;color:white;font-weight:bold; padding-left: 10px;display:inline-block;min-height:27px;padding : 4px 25px 4px 25px;line-height:27px;border-radius:2px;border-width:1px; background-color:black;" target="_blank") Reset password
tr
td(style="color:black;padding:10px 10px 0 10px") Or copy and paste the URL into your browser:
tr(style="color:black")
td(width="560px" style='padding:10px;') #{link}
tr(style="color:black;padding:0 10px")
td If you did not request this, please ignore this email and your password will remain unchanged. Thanks for using the p5.js Web Editor!