Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve Authentication Issues #169

Merged
merged 19 commits into from
Dec 18, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
.DS_Store
/node_modules
/builtAssets
.env

.npm-*
10 changes: 10 additions & 0 deletions .jscsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"preset": "airbnb",

"excludeFiles": [
"node_modules/**"
],

"requireMultipleVarDecl": null,
"requireCamelCaseOrUpperCaseIdentifiers": null
}
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
language: node_js
node_js:
- '0.10'
- '0.10'
env:
- PLAN_SESSION_SECRET="SUPERSECRETOMG"
deploy:
provider: heroku
app: mofo-intake
Expand Down
40 changes: 31 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
# plan.webmaker.org
## build.webmaker.org

The site we're using to track initiatives. Live at http://mofo-intake.herokuapp.com/
[![Build Status](https://travis-ci.org/MozillaFoundation/plan.svg?branch=master)](https://travis-ci.org/MozillaFoundation/plan)

## Setup
Build is a site that we use to track what we are working on now and in the future. It provides a central resource for staff and contributors who are interested in the who, what, and how we build product for Webmaker.

* `git clone git@github.com:MozillaFoundation/plan.git`
* `cd plan`
* `cp env.sample .env`
* `npm install`
## Getting Started

Edit .env to have real secrets:
#### Clone & Install
```bash
git clone git@github.com:MozillaFoundation/plan.git
cd plan
cp env.sample .env
npm install
```

#### Edit .env
* `PLAN_SESSION_SECRET` should be whatever you want it to be.
* `PLAN_GITHUB_CLIENTID` and `PLAN_GITHUB_CLIENTSECRET` should be obtained by creating a new Developer Application in Github (https://github.com/settings/applications). For __Authorization callback URL__, make sure you use `/auth/github/callback` prefixed by the address of the host you use for the app.
* `PLAN_GITHUB_TOKEN` is optional but will help avoid rate limiting, and is a Personal Access Token generated on the same page.

I like to run the server using `nodemon app.js` (as it will do autoreload). It runs by default on port `3000`, but you can add a `PORT` variable to `.env` to choose your own.
#### Run
If you have [nodemon](https://github.com/remy/nodemon) installed, you can start the server by running:

```bash
nodemon app.js
```

Otherwise, you can start the server by simply running (note, you will have to restart the process to see changes):
```bash
node app.js
```

Once running you can view the local server by navigating to: 'http://localhost:3000'. If you prefer a different port, you can add a `PORT` variable to `.env`.

## Testing
```bash
npm test
```
137 changes: 59 additions & 78 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,127 +1,102 @@
/**
* Module dependencies.
* HTTP server for build.webmaker.org
*
* @package build
* @author David Ascher <davida@mozillafoundation.org>
* Andrew Sliwinski <a@mozillafoundation.org>
*/

var express = require('express');
var cookieParser = require('cookie-parser');
var compress = require('compression');
var session = require('express-session');
var bodyParser = require('body-parser');
var logger = require('morgan');
var errorHandler = require('errorhandler');
var csrf = require('lusca').csrf();
var methodOverride = require('method-override');

var _ = require('lodash');
var MongoStore = require('connect-mongo')(session);
var sessions = require('client-sessions');
var lusca = require('lusca');
var flash = require('express-flash');
var path = require('path');
var mongoose = require('mongoose');
var passport = require('passport');
var expressValidator = require('express-validator');
var connectAssets = require('connect-assets');

/**
* Controllers (route handlers).
*/

var simpleController = require('./controllers/simple');
var userController = require('./controllers/user');
var apiController = require('./controllers/api');
var intakeController = require('./controllers/intake');

/**
* API keys and Passport configuration.
* Import API keys from environment
*/

var secrets = require('./config/secrets');
var passportConf = require('./config/passport');

/**
* Create Express server.
*/

var app = express();

/**
* Connect to MongoDB.
* Github handlers
*/

mongoose.connect(secrets.db);
mongoose.connection.on('error', function() {
console.error('MongoDB Connection Error. Please make sure that MongoDB is running.');
var Github = require('./models/github');
var github = new Github(
secrets.github.clientID,
secrets.github.clientSecret
);

var oauth = require('github-oauth')({
githubClient: secrets.github.clientID,
githubSecret: secrets.github.clientSecret,
baseURL: secrets.github.host,
callbackURI: secrets.github.callbackURL,
loginURI: '/login',
scope: 'user,repo,public_repo'
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this entire patch was prompted in order to remove this >80-char line. ;) 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😉 That .. and not a fan of storing OAuth tokens and user email addresses if we don't have to.


/**
* CSRF whitelist.
* Create Express server.
*/

var csrfExclude = ['/url1', '/url2'];
var app = express();

/**
* Express configuration.
*/

app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('github_org', 'MozillaFoundation')
app.set('github_repo', 'plan')

app.set('github_org', 'MozillaFoundation');
app.set('github_repo', 'plan');
app.set('view engine', 'jade');

app.use(sessions({
cookieName: 'session',
secret: secrets.sessionSecret,
duration: 24 * 60 * 60 * 1000,
activeDuration: 1000 * 60 * 5
}));
app.use(compress());
app.use(connectAssets({
paths: [path.join(__dirname, 'public/css'), path.join(__dirname, 'public/js')]
}));
app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a personal preference of either commenting 1-year or showing the math (1000 * 3600 * 24 * 365.25) for readability

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.use(methodOverride());
app.use(lusca.csrf());
app.use(cookieParser());
app.use(session({
resave: true,
saveUninitialized: true,
secret: secrets.sessionSecret,
store: new MongoStore({ url: secrets.db, auto_reconnect: true })
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(github.middleware);

/**
* CORS
*/
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

app.use(function(req, res, next) {
// CSRF protection.
if (_.contains(csrfExclude, req.path)) return next();
csrf(req, res, next);
});
app.use(function(req, res, next) {
// Make user object available in templates.
res.locals.user = req.user;
next();
});

app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));

app.use(function(req, res, next) {
// Remember original destination before login.
var path = req.path.split('/')[1];
// this next bit is totally weird, needs documentation
if (/auth|login|logout|signup|fonts|smalllogo.png|api|now|next|design|tools|mentions|favicon/i.test(path)) {
return next();
}
req.session.returnTo = req.path;
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});

/**
* Main routes.
*/

app.get('/', simpleController.index);
app.get('/now', simpleController.now);
app.get('/next', simpleController.next);
Expand All @@ -131,35 +106,41 @@ app.get('/tools', simpleController.tools);
app.get('/mentions', simpleController.mentions);

app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);

app.get('/intake', passportConf.isAuthenticated, intakeController.getIntake);
app.get('/intake', function (req, res, next) {
if (req.session.token) return next();
req.flash('errors', {msg: 'You must be signed-in to add a project.'});
next();
}, intakeController.getIntake);
app.post('/intake', intakeController.postIntake);
app.get('/account', passportConf.isAuthenticated, userController.getAccount);

app.post('/account/delete', passportConf.isAuthenticated, userController.postDeleteAccount);

app.get('/api/issues', apiController.getIssues)
app.get('/api/user', apiController.getUser)

app.get('/auth/github', passport.authenticate('github', {scope: 'user,repo,public_repo'}));
app.get('/auth/github/callback', passport.authenticate('github', {scope: 'user,repo,public_repo', failureRedirect: '/login' }), function(req, res) {
res.redirect(req.session.returnTo || '/');
app.get('/auth/github', oauth.login);
app.get('/auth/github/callback', function (req, res) {
oauth.callback(req, res, function (err, body) {
if (err) {
req.flash('errors', {msg: err});
} else {
req.session.token = body.access_token;
}

res.redirect('/');
});
});

/**
* 500 Error Handler.
*/

app.use(errorHandler());

/**
* Start Express server.
*/

app.listen(app.get('port'), function() {
console.log('Express server listening on port %d in %s mode', app.get('port'), app.get('env'));
console.log('Server listening on port %d in %s mode', app.get('port'), app.get('env'));
});

module.exports = app;
module.exports = app;
1 change: 0 additions & 1 deletion config/github.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module.exports = {

github_org: 'MozillaFoundation',
github_repo: 'plan'
}
Loading