diff --git a/.gitignore b/.gitignore index 87f88f4b..ea36503e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dump.rdb public/* static/dist static/css/app.min.css +.env diff --git a/README.md b/README.md index 2743f19b..6ddd772d 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,5 @@ As this project is currently being developed, there is only development mode. * https://github.com/gajus/react-css-modules * https://github.com/jsbin/jsbin (especially look at the console) * Need to figure out how to solve the XSS issue, https://github.com/jsbin/jsbin/wiki/Best-practices-for-building-your-own-live-paste-bin - * https://www.npmjs.com/package/express-subdomain \ No newline at end of file + * https://www.npmjs.com/package/express-subdomain +* https://medium.com/@rajaraodv/securing-react-redux-apps-with-jwt-tokens-fcfe81356ea0#.i3agwmf2w \ No newline at end of file diff --git a/index.js b/index.js index 9ee452d7..e7fd2dc8 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ require('babel-register'); require('babel-polyfill'); +require('dotenv').config(); require('./server/server'); \ No newline at end of file diff --git a/package.json b/package.json index 2e572476..fc0599ec 100644 --- a/package.json +++ b/package.json @@ -40,10 +40,13 @@ "codemirror": "^5.14.2", "connect-mongo": "^1.2.0", "cookie-parser": "^1.4.1", + "dotenv": "^2.0.0", "express": "^4.13.4", + "jwt-simple": "^0.5.0", "mongoose": "^4.4.16", "passport": "^0.3.2", "passport-github": "^1.1.0", + "passport-jwt": "^2.0.0", "passport-local": "^1.0.0", "react": "^15.0.2", "react-dom": "^15.0.2", diff --git a/server/config/passport.js b/server/config/passport.js index fe6c7c2f..7ebf173d 100644 --- a/server/config/passport.js +++ b/server/config/passport.js @@ -1,9 +1,17 @@ const passport = require('passport'); +const JwtStrategy = require('passport-jwt').Strategy; +const ExtractJwt = require('passport-jwt').ExtractJwt; const GitHubStrategy = require('passport-github').Strategy; const LocalStrategy = require('passport-local').Strategy; const User = require('../models/user'); +// Setup options for JWT Strategy +const jwtOptions = { + jwtFromRequest: ExtractJwt.fromHeader('authorization'), + secretOrKey: "steve brule" +}; + passport.serializeUser((user, done) => { done(null, user.id); }); @@ -31,6 +39,22 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don }); })); +// Create JWT strategy +passport.use(new JwtStrategy(jwtOptions, function(payload, done) { + // See if the user ID in the payload exists in our database + // If it does, call 'done' with that other + // otherwise, call done without a user object + User.findById(payload.sub, function(err, user) { + if (err) { return done(err, false); } + + if (user) { + done(null, user); + } else { + done(null, false); + } + }); +})); + /** * Sign in with GitHub. */ diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index 3eecaebe..35e892ae 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -1,6 +1,7 @@ import User from '../models/user' import passport from 'passport' import path from 'path' +import { generateToken } from '../utils/jwt' export function newUser(req, res) { //eventually, it would be cool to have some isomorphic rendering @@ -8,6 +9,7 @@ export function newUser(req, res) { } export function createUser(req, res, next) { + console.log("in create user"); const user = new User({ email: req.body.email, password: req.body.password @@ -15,9 +17,7 @@ export function createUser(req, res, next) { User.findOne({email: req.body.email}, (err, existingUser) => { if (existingUser) { - //error, already registered - //should probably redirect client side though? - return res.redirect('/signup'); + return res.status(422).send({ error: 'Email is in use' }); } user.save((err) => { if (err) { return next(err); } @@ -25,7 +25,7 @@ export function createUser(req, res, next) { if (err) { return next(err); } - res.redirect('/'); + res.json({ token: generateToken(user) }); }); }); }); diff --git a/server/server.js b/server/server.js index 0dfc38e9..02fe4d1c 100644 --- a/server/server.js +++ b/server/server.js @@ -24,30 +24,25 @@ import serverConfig from './config'; import users from './routes/user.routes'; //Body parser, cookie parser, sessions, serve public assets -const MongoStore = require('connect-mongo')(session); app.use(Express.static(path.resolve(__dirname, '../static'))); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.use(cookieParser()); -app.use(session({ - //this should be SECRET AND IN A SECRET FILE - //TODO add dotenv - secret: 'steve brule', - resave: true, - saveUninitialized: true, - store: new MongoStore({ - // url: process.env.MONGODB_URI || process.env.MONGOLAB_URI, - url: serverConfig.mongoURL, - autoReconnect: true - }) -})); app.use(passport.initialize()); app.use(passport.session()); app.use('/', users); const passportConfig = require('./config/passport'); +//Connect to MongoDB +// mongoose.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI); +mongoose.connect(serverConfig.mongoURL); +mongoose.connection.on('error', () => { + console.error('MongoDB Connection Error. Please make sure that MongoDB is running.'); + process.exit(1); +}); + app.get("/", function(req, res) { res.sendFile(path.resolve(__dirname + '/../index.html')); }) diff --git a/shared/containers/SignupView/SignupView.jsx b/shared/containers/SignupView/SignupView.jsx index 8fcc4a3b..fa754b19 100644 --- a/shared/containers/SignupView/SignupView.jsx +++ b/shared/containers/SignupView/SignupView.jsx @@ -3,7 +3,7 @@ import React from 'react' class SignupView extends React.Component { render() { return ( -
+ diff --git a/shared/redux/constants/constants.js b/shared/redux/constants/constants.js index ad141573..a42e9a13 100644 --- a/shared/redux/constants/constants.js +++ b/shared/redux/constants/constants.js @@ -8,3 +8,6 @@ export const OPEN_PREFERENCES = 'OPEN_PREFERENCES'; export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES'; export const INCREASE_FONTSIZE = 'INCREASE_FONTSIZE'; export const DECREASE_FONTSIZE = 'DECREASE_FONTSIZE'; + +export const AUTH_USER = 'AUTH_USER'; +export const UNAUTH_USER = 'UNAUTH_USER';