diff options
author | Andrew Kim <andrewdkim@users.noreply.github.com> | 2019-03-05 18:51:20 -0500 |
---|---|---|
committer | Andrew Kim <andrewdkim@users.noreply.github.com> | 2019-03-05 18:51:20 -0500 |
commit | 7f93e6639e8fee3e3760d13c69d65b343875091a (patch) | |
tree | d29b45310f92a53935177d969ce3c1bee9920c32 /src/server/authentication | |
parent | 9b839a93b98b850aa77087218d4862b97fb24d15 (diff) | |
parent | 2cc5eb6ff512dc6128d25903bcb852f25bcadcca (diff) |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into PDFNode
Diffstat (limited to 'src/server/authentication')
-rw-r--r-- | src/server/authentication/config/passport.ts | 49 | ||||
-rw-r--r-- | src/server/authentication/controllers/user.ts | 107 | ||||
-rw-r--r-- | src/server/authentication/models/User.ts | 89 |
3 files changed, 245 insertions, 0 deletions
diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts new file mode 100644 index 000000000..05f6c3133 --- /dev/null +++ b/src/server/authentication/config/passport.ts @@ -0,0 +1,49 @@ +import * as passport from 'passport' +import * as passportLocal from 'passport-local'; +import * as mongodb from 'mongodb'; +import * as _ from "lodash"; +import { default as User } from '../models/User'; +import { Request, Response, NextFunction } from "express"; + +const LocalStrategy = passportLocal.Strategy; + +passport.serializeUser<any, any>((user, done) => { + done(undefined, user.id); +}); + +passport.deserializeUser<any, any>((id, done) => { + User.findById(id, (err, user) => { + done(err, user); + }); +}); + +// AUTHENTICATE JUST WITH EMAIL AND PASSWORD +passport.use(new LocalStrategy({ usernameField: 'email' }, (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 + user.comparePassword(password, (error: Error, isMatch: boolean) => { + if (error) return done(error); + if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password + // valid authentication HERE + return done(undefined, user); + }); + }); +})); + +export let isAuthenticated = (req: Request, res: Response, next: NextFunction) => { + if (req.isAuthenticated()) { + return next(); + } + return res.redirect("/login"); +} + +export let isAuthorized = (req: Request, res: Response, next: NextFunction) => { + const provider = req.path.split("/").slice(-1)[0]; + + if (_.find(req.user.tokens, { kind: provider })) { + next(); + } else { + res.redirect(`/auth/${provider}`); + } +};
\ No newline at end of file diff --git a/src/server/authentication/controllers/user.ts b/src/server/authentication/controllers/user.ts new file mode 100644 index 000000000..f74ff9039 --- /dev/null +++ b/src/server/authentication/controllers/user.ts @@ -0,0 +1,107 @@ +import { default as User, UserModel, AuthToken } from "../models/User"; +import { Request, Response, NextFunction } from "express"; +import * as passport from "passport"; +import { IVerifyOptions } from "passport-local"; +import "../config/passport"; +import * as request from "express-validator"; +const flash = require("express-flash"); +import * as session from "express-session"; +import * as pug from 'pug'; + +/** + * GET /signup + * Signup page. + */ +export let getSignup = (req: Request, res: Response) => { + if (req.user) { + return res.redirect("/"); + } + res.render("signup.pug", { + title: "Sign Up" + }); +}; + +/** + * POST /signup + * Create a new local account. + */ +export let postSignup = (req: Request, res: Response, next: NextFunction) => { + req.assert("email", "Email is not valid").isEmail(); + 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); + req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); + + const errors = req.validationErrors(); + + if (errors) { + req.flash("errors", "Unable to facilitate sign up. Please try again."); + return res.redirect("/signup"); + } + + const user = new User({ + email: req.body.email, + password: req.body.password + }); + + User.findOne({ email: req.body.email }, (err, existingUser) => { + if (err) { return next(err); } + if (existingUser) { + req.flash("errors", "Account with that email address already exists."); + return res.redirect("/signup"); + } + user.save((err) => { + if (err) { return next(err); } + req.logIn(user, (err) => { + if (err) { + return next(err); + } + res.redirect("/"); + }); + }); + }); +}; + + +/** + * GET /login + * Login page. + */ +export let getLogin = (req: Request, res: Response) => { + if (req.user) { + return res.redirect("/"); + } + res.send("<p>dear lord please render</p>"); + // res.render("account/login", { + // title: "Login" + // }); +}; + +/** + * POST /login + * Sign in using email and password. + */ +export let postLogin = (req: Request, res: Response, next: NextFunction) => { + req.assert("email", "Email is not valid").isEmail(); + req.assert("password", "Password cannot be blank").notEmpty(); + req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); + + const errors = req.validationErrors(); + + if (errors) { + req.flash("errors", "Unable to login at this time. Please try again."); + return res.redirect("/login"); + } + + 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"); + } + req.logIn(user, (err) => { + if (err) { return next(err); } + req.flash("success", "Success! You are logged in."); + res.redirect("/"); + }); + })(req, res, next); +};
\ No newline at end of file diff --git a/src/server/authentication/models/User.ts b/src/server/authentication/models/User.ts new file mode 100644 index 000000000..9752c4260 --- /dev/null +++ b/src/server/authentication/models/User.ts @@ -0,0 +1,89 @@ +//@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' + +mongoose.connect(url, { useNewUrlParser: true }); + +mongoose.connection.on('connected', function () { + console.log('Stablished connection on ' + url); +}); +mongoose.connection.on('error', function (error) { + console.log('Something wrong happened: ' + error); +}); +mongoose.connection.on('disconnected', function () { + console.log('connection closed'); +}); +export type UserModel = mongoose.Document & { + email: string, + password: string, + passwordResetToken: string, + passwordResetExpires: Date, + tokens: AuthToken[], + + profile: { + name: string, + gender: string, + location: string, + website: string, + picture: string + }, + + comparePassword: comparePasswordFunction, +}; + +type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => {}) => void; + +export type AuthToken = { + accessToken: string, + kind: string +}; + +const userSchema = new mongoose.Schema({ + email: { type: String, unique: true }, + password: String, + passwordResetToken: String, + passwordResetExpires: Date, + + facebook: String, + twitter: String, + google: String, + tokens: Array, + + profile: { + name: String, + gender: String, + location: String, + website: String, + picture: String + } +}, { timestamps: true }); + +/** + * Password hash middleware. + */ +userSchema.pre("save", function save(next) { + const user = this as UserModel; + if (!user.isModified("password")) { return next(); } + bcrypt.genSalt(10, (err, salt) => { + if (err) { return next(err); } + bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => { + if (err) { return next(err); } + user.password = hash; + next(); + }); + }); +}); + +const comparePassword: comparePasswordFunction = function (this: UserModel, candidatePassword, cb) { + bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => { + cb(err, isMatch); + }); +}; + +userSchema.methods.comparePassword = comparePassword; + +const User = mongoose.model("User", userSchema); +export default User;
\ No newline at end of file |