diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/authentication/config/passport.ts | 2 | ||||
| -rw-r--r-- | src/server/authentication/controllers/user.ts | 76 | ||||
| -rw-r--r-- | src/server/authentication/models/User.ts | 3 | ||||
| -rw-r--r-- | src/server/index.ts | 140 |
4 files changed, 183 insertions, 38 deletions
diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts index 05f6c3133..9f1303135 100644 --- a/src/server/authentication/config/passport.ts +++ b/src/server/authentication/config/passport.ts @@ -18,7 +18,7 @@ passport.deserializeUser<any, any>((id, done) => { }); // AUTHENTICATE JUST WITH EMAIL AND PASSWORD -passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => { +passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { if (error) return done(error); if (!user) return done(undefined, false, { message: "Invalid email or password" }) // invalid email diff --git a/src/server/authentication/controllers/user.ts b/src/server/authentication/controllers/user.ts index f74ff9039..a496959d1 100644 --- a/src/server/authentication/controllers/user.ts +++ b/src/server/authentication/controllers/user.ts @@ -9,15 +9,30 @@ import * as session from "express-session"; import * as pug from 'pug'; /** + * GET / + * Whenever a user navigates to the root of Dash + * (doesn't specify a sub-route), redirect to login. + * If the user is already signed in, it will effectively + * automatically redirect them to /home instead + */ +export let getEntry = (req: Request, res: Response) => { + res.redirect("/login"); +} + +/** * GET /signup - * Signup page. + * Directs user to the signup page + * modeled by signup.pug in views */ export let getSignup = (req: Request, res: Response) => { if (req.user) { - return res.redirect("/"); + let user = req.user; + return res.redirect("/home"); } res.render("signup.pug", { - title: "Sign Up" + title: "Sign Up", + user: req.user, + errors: req.flash("Unable to facilitate sign up. Please try again.") }); }; @@ -31,21 +46,33 @@ 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) { - req.flash("errors", "Unable to facilitate sign up. Please try again."); + res.render("signup.pug", { + title: "Sign Up", + errors: req.flash("Unable to facilitate sign up. Please try again.") + }); return res.redirect("/signup"); } + const email = req.body.email; + const password = req.body.password; + const user = new User({ - email: req.body.email, - password: req.body.password + email, + password, + userDoc: "document here" }); - User.findOne({ email: req.body.email }, (err, existingUser) => { + User.findOne({ email }, (err, existingUser) => { if (err) { return next(err); } if (existingUser) { + if (existingUser) { + // existingUser.update({ $set: { email: please_work } }, (err, res) => { }); + } req.flash("errors", "Account with that email address already exists."); return res.redirect("/signup"); } @@ -59,6 +86,7 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => { }); }); }); + }; @@ -68,17 +96,18 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => { */ export let getLogin = (req: Request, res: Response) => { if (req.user) { - return res.redirect("/"); + return res.redirect("/home"); } - res.send("<p>dear lord please render</p>"); - // res.render("account/login", { - // title: "Login" - // }); + res.render("login.pug", { + title: "Log In", + user: req.user + }); }; /** * POST /login * Sign in using email and password. + * On failure, redirect to login page */ export let postLogin = (req: Request, res: Response, next: NextFunction) => { req.assert("email", "Email is not valid").isEmail(); @@ -89,19 +118,32 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => { if (errors) { req.flash("errors", "Unable to login at this time. Please try again."); - return res.redirect("/login"); + return res.redirect("/signup"); } passport.authenticate("local", (err: Error, user: UserModel, info: IVerifyOptions) => { if (err) { return next(err); } if (!user) { - req.flash("errors", info.message); - return res.redirect("/login"); + return res.redirect("/signup"); } req.logIn(user, (err) => { if (err) { return next(err); } req.flash("success", "Success! You are logged in."); - res.redirect("/"); + res.redirect("/home"); }); })(req, res, next); -};
\ No newline at end of file +}; + +/** + * GET /logout + * Invokes the logout function on the request + * and destroys the user's current session. + */ +export let getLogout = (req: Request, res: Response) => { + req.logout(); + const sess = req.session; + if (sess) { + sess.destroy((err) => { if (err) { console.log(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 9752c4260..30fcecd81 100644 --- a/src/server/authentication/models/User.ts +++ b/src/server/authentication/models/User.ts @@ -1,6 +1,5 @@ //@ts-ignore import * as bcrypt from "bcrypt-nodejs"; -import * as crypto from "crypto"; //@ts-ignore import * as mongoose from "mongoose"; var url = 'mongodb://localhost:27017/Dash' @@ -47,6 +46,8 @@ const userSchema = new mongoose.Schema({ passwordResetToken: String, passwordResetExpires: Date, + userDocumentId: String, + facebook: String, twitter: String, google: String, diff --git a/src/server/index.ts b/src/server/index.ts index f5e66b31b..baf360ffa 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -3,7 +3,6 @@ const app = express() import * as webpack from 'webpack' import * as wdm from 'webpack-dev-middleware'; import * as whm from 'webpack-hot-middleware'; -import * as path from 'path' import * as passport from 'passport'; import { MessageStore, Message, SetFieldArgs, GetFieldArgs, Transferable } from "./Message"; import { Client } from './Client'; @@ -14,48 +13,55 @@ import { FieldId, Field } from '../fields/Field'; import { Database } from './database'; import { ServerUtils } from './ServerUtil'; import { ObjectID } from 'mongodb'; +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 } from './authentication/controllers/user'; +import { getLogin, postLogin, getSignup, postSignup, getLogout, getEntry } from './authentication/controllers/user'; const config = require('../../webpack.config'); const compiler = webpack(config); const port = 1050; // default port to listen const serverPort = 1234; import * as expressValidator from 'express-validator'; import expressFlash = require('express-flash'); +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' +import User, { UserModel } from './authentication/models/User'; const mongoUrl = 'mongodb://localhost:27017/Dash'; -// mongoose.Promise = bluebird; -mongoose.connect(mongoUrl)//.then( -// () => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ }, -// ).catch((err: any) => { -// console.log("MongoDB connection error. Please make sure MongoDB is running. " + err); -// process.exit(); -// }); +mongoose.connect(mongoUrl) mongoose.connection.on('connected', function () { console.log("connected"); }) -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); -app.use(expressValidator()); -app.use(expressFlash()); -app.use(require('express-session')({ +// SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE +// ORDER OF IMPORTS MATTERS + +app.use(cookieParser("secret")); +app.use(session({ secret: `${c.randomBytes(64)}`, resave: true, + cookie: { maxAge: 60000 }, saveUninitialized: true, store: new MongoStore({ url: 'mongodb://localhost:27017/Dash' }) })); +app.use(flash()); +app.use(expressFlash()); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(expressValidator()); app.use(passport.initialize()); app.use(passport.session()); app.use((req, res, next) => { @@ -63,17 +69,113 @@ app.use((req, res, next) => { next(); }); +// AUTHENTICATION ROUTING + +// *** +// Look for the definitions of these get and post +// functions in the exports of user.ts + +// /home defines destination after a successful log in +app.get("/home", (req, res) => { + // if user is not logged in, redirect to log in page + if (!req.user) { + res.redirect("/login"); + return; + } + // otherwise, connect them to Dash + // TODO: store and manage users' workspaces + res.sendFile(path.join(__dirname, '../../deploy/index.html')); +}); + +app.get("/getUserDocId", (req, res) => { + console.log(req.user) + if (!req.user) { + return; + } + res.send(req.user.userDocumentId || ""); +}) + +app.post("/setUserDocId", (req, res) => { + if (!req.user) { + return; + } + req.user.update({ $set: { userDocumentId: req.body.userDocumentId } }, () => { }); +}) + +// anyone attempting to navigate to localhost at this port will +// first have to login +app.get("/", getEntry); + +// Sign Up app.get("/signup", getSignup); app.post("/signup", postSignup); + +// Log In app.get("/login", getLogin); app.post("/login", postLogin); -let FieldStore: ObservableMap<FieldId, Field> = new ObservableMap(); +// Log Out +app.get('/logout', getLogout); -// define a route handler for the default home page -app.get("/", (req, res) => { - res.sendFile(path.join(__dirname, '../../deploy/index.html')); -}); +// *** + +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("/hello", (req, res) => { res.send("<p>Hello</p>"); |
