Revert "Email verification" (#265)
This commit is contained in:
parent
2d781e22fb
commit
311e8442a1
9 changed files with 28 additions and 252 deletions
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
|
@ -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();
|
|
|
@ -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.
|
|
|
@ -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!
|
|
Loading…
Reference in a new issue