diff options
author | Sam Wilkins <samwilkins333@gmail.com> | 2019-02-25 03:38:02 -0500 |
---|---|---|
committer | Sam Wilkins <samwilkins333@gmail.com> | 2019-02-25 03:38:02 -0500 |
commit | 0d36924c90682c57e96c1e7bfd95a3cc10e6c662 (patch) | |
tree | 483d5ee1c3ef0d7bffc90f6d631bf3cea2256ff0 | |
parent | 47152d960e5b79f395fb4ecc421e5aac0c12883e (diff) |
after pop, hard reset
-rw-r--r-- | src/client/views/Main.tsx | 6 | ||||
-rw-r--r-- | src/server/authentication/controllers/user.ts | 135 | ||||
-rw-r--r-- | src/server/authentication/models/User.ts | 4 | ||||
-rw-r--r-- | src/server/index.ts | 68 | ||||
-rw-r--r-- | views/reset.pug | 22 | ||||
-rw-r--r-- | views/signup.pug | 2 | ||||
-rw-r--r-- | views/stylesheets/authentication.css | 6 |
7 files changed, 176 insertions, 67 deletions
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index cbc19d7fe..567f17752 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -171,6 +171,12 @@ function init() { right: '0px', width: '150px' }} onClick={() => UndoManager.Redo()}>Redo</button> + <button style={{ + position: 'absolute', + top: '24px', + right: '0px', + width: '150px' + }} onClick={() => window.location.pathname = "/logout"}>Logout</button> </div>), document.getElementById('root')); }) diff --git a/src/server/authentication/controllers/user.ts b/src/server/authentication/controllers/user.ts index a496959d1..19cd09676 100644 --- a/src/server/authentication/controllers/user.ts +++ b/src/server/authentication/controllers/user.ts @@ -7,6 +7,10 @@ import * as request from "express-validator"; const flash = require("express-flash"); import * as session from "express-session"; import * as pug from 'pug'; +import * as async from 'async'; +import * as nodemailer from 'nodemailer'; +import c = require("crypto"); + /** * GET / @@ -46,8 +50,6 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => { req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); - req.flash("Working on something!!!"); - const errors = req.validationErrors(); if (errors) { @@ -146,4 +148,133 @@ export let getLogout = (req: Request, res: Response) => { sess.destroy((err) => { if (err) { console.log(err); } }); } res.redirect('/login'); +} + +export let getForgot = function (req: Request, res: Response) { + res.render("forgot.pug", { + title: "Recover Password", + user: req.user, + }); +} + +export let postForgot = function (req: Request, res: Response, next: NextFunction) { + const email = req.body.email; + async.waterfall([ + function (done: any) { + let token: string; + c.randomBytes(20, function (err: any, buffer: Buffer) { + if (err) { + done(null); + return; + } + done(null, buffer.toString('hex')); + }) + }, + function (token: Buffer, done: any) { + User.findOne({ email }, function (err, user: UserModel) { + if (!user) { + // NO ACCOUNT WITH SUBMITTED EMAIL + return res.redirect('/forgot'); + } + user.passwordResetToken = token.toString('utf8'); + console.log(user.passwordResetToken); + user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR + user.save(function (err: any) { + done(null, token, user); + }); + }); + }, + function (token: Uint16Array, user: UserModel, done: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: user.email, + from: 'brownptcdash@gmail.com', + subject: 'Dash Password Reset', + text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + + 'http://' + req.headers.host + '/reset/' + token + '\n\n' + + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' + }; + smtpTransport.sendMail(mailOptions, function (err) { + // req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); + done(null, err, 'done'); + }); + } + ], function (err) { + if (err) return next(err); + res.redirect('/forgot'); + }) +} + +export let getReset = function (req: Request, res: Response) { + User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: UserModel) { + if (!user || err) { + return res.redirect('/forgot'); + } + res.render("reset.pug", { + title: "Reset Password", + user: req.user, + }); + }); +} + +export let postReset = function (req: Request, res: Response) { + async.waterfall([ + function (done: any) { + User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: UserModel) { + if (!user || err) { + return res.redirect('back'); + } + + req.assert("password", "Password must be at least 4 characters long").len({ min: 4 }); + req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); + + if (req.validationErrors()) { + return res.redirect('back'); + } + + user.password = req.body.password; + user.passwordResetToken = undefined; + user.passwordResetExpires = undefined; + + user.save(function (err) { + req.logIn(user, function (err) { + if (err) { + console.log(err); + return; + } + }); + done(user, err); + }); + }); + }, + function (user: UserModel, done: any) { + console.log(`SENDING EMAIL TO ${user.email}`); + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: user.email, + from: 'brownptcdash@gmail.com', + subject: 'Your password has been changed', + text: 'Hello,\n\n' + + 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' + }; + smtpTransport.sendMail(mailOptions, function (err) { + done(null, err); + }); + } + ], function (err) { + res.redirect('/login'); + }); }
\ No newline at end of file diff --git a/src/server/authentication/models/User.ts b/src/server/authentication/models/User.ts index 30fcecd81..433e2f6c3 100644 --- a/src/server/authentication/models/User.ts +++ b/src/server/authentication/models/User.ts @@ -18,8 +18,8 @@ mongoose.connection.on('disconnected', function () { export type UserModel = mongoose.Document & { email: string, password: string, - passwordResetToken: string, - passwordResetExpires: Date, + passwordResetToken: string | undefined, + passwordResetExpires: Date | undefined, tokens: AuthToken[], profile: { diff --git a/src/server/index.ts b/src/server/index.ts index baf360ffa..f2b26afec 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -17,7 +17,7 @@ import * as bcrypt from "bcrypt-nodejs"; import { Document } from '../fields/Document'; import * as io from 'socket.io' import * as passportConfig from './authentication/config/passport'; -import { getLogin, postLogin, getSignup, postSignup, getLogout, getEntry } from './authentication/controllers/user'; +import { getLogin, postLogin, getSignup, postSignup, getLogout, getEntry, postReset, getForgot, postForgot, getReset } from './authentication/controllers/user'; const config = require('../../webpack.config'); const compiler = webpack(config); const port = 1050; // default port to listen @@ -28,11 +28,9 @@ import flash = require('express-flash'); import * as bodyParser from 'body-parser'; import * as session from 'express-session'; import * as cookieParser from 'cookie-parser'; -import * as nodemailer from 'nodemailer'; import c = require("crypto"); const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); -import * as async from 'async'; const bluebird = require('bluebird'); import { performance } from 'perf_hooks' import * as path from 'path' @@ -88,7 +86,6 @@ app.get("/home", (req, res) => { }); app.get("/getUserDocId", (req, res) => { - console.log(req.user) if (!req.user) { return; } @@ -119,64 +116,15 @@ app.get('/logout', getLogout); // *** -app.get('/forgot', function (req, res) { - res.render("forgot.pug", { - title: "Recover Password", - user: req.user, - }); -}) - // FORGOT PASSWORD EMAIL HANDLING -app.post('/forgot', function (req, res, next) { - const email = req.body.email; - async.waterfall([ - function (done: any) { - const seed = new Uint32Array(20); - let token = seed; - done(null, token); - }, - function (token: Uint32Array, done: any) { - User.findOne({ email }, function (err, user: UserModel) { - if (!user) { - // NO ACCOUNT WITH SUBMITTED EMAIL - return res.redirect('/forgot'); - } - user.passwordResetToken = token.toString(); - user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR - user.save(function (err: any) { - done(null, token, user); - }); - }); - }, - function (token: Uint16Array, user: UserModel, done: any) { - const smptTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: user.email, - from: 'brownptcdash@gmail.com', - subject: 'Dash Password Reset', - text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + - 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + - 'http://' + req.headers.host + '/reset/' + token + '\n\n' + - 'If you did not request this, please ignore this email and your password will remain unchanged.\n' - }; - smptTransport.sendMail(mailOptions, function (err) { - // req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); - done(null, err, 'done'); - }); - } - ], function (err) { - if (err) return next(err); - res.redirect('/forgot'); - }) -}) -let FieldStore: ObservableMap<FieldId, Field> = new ObservableMap(); +app.get('/forgot', getForgot) +app.post('/forgot', postForgot) +// RESET PASSWORD EMAIL HANDLING +app.get('/reset/:token', getReset); +app.post('/reset/:token', postReset); + +let FieldStore: ObservableMap<FieldId, Field> = new ObservableMap(); app.get("/hello", (req, res) => { res.send("<p>Hello</p>"); }) diff --git a/views/reset.pug b/views/reset.pug new file mode 100644 index 000000000..8b6fa952b --- /dev/null +++ b/views/reset.pug @@ -0,0 +1,22 @@ + +extends ./layout + +block content + style + include ./stylesheets/authentication.css + form.form-horizontal(id='reset-form', method='POST') + input(type='hidden', name='_csrf', value=_csrf) + .overlay(id='overlay_reset') + .inner.reset + h3.auth_header Reset Password + .form-group + .col-sm-7 + input.form-control(type='password', name='password', id='password', placeholder='Password', required) + .form-group + .col-sm-7 + input.form-control(type='password', name='confirmPassword', id='confirmPassword', placeholder='Confirm Password', required) + .form-group + .col-sm-offset-3.col-sm-7 + button.btn.btn-success(type='submit') + i.fa.fa-user-plus + | Reset
\ No newline at end of file diff --git a/views/signup.pug b/views/signup.pug index 374710e6f..11b02a5eb 100644 --- a/views/signup.pug +++ b/views/signup.pug @@ -24,4 +24,4 @@ block content .col-sm-offset-3.col-sm-7 button.btn.btn-success(type='submit') i.fa.fa-user-plus - | Signup
\ No newline at end of file + | Sign Up
\ No newline at end of file diff --git a/views/stylesheets/authentication.css b/views/stylesheets/authentication.css index 0922ad730..bce8223ec 100644 --- a/views/stylesheets/authentication.css +++ b/views/stylesheets/authentication.css @@ -26,7 +26,8 @@ body { text-align: left; } -.login { +.login, +.reset { height: 220px; } @@ -46,7 +47,8 @@ body { font-style: oblique; } -#overlay_signup { +#overlay_signup, +#overlay_reset { height: 345px; } |