Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Commit

Permalink
Refactor and fix uploads (#11)
Browse files Browse the repository at this point in the history
* Remove node_modules

* Refactor Dockerfile to only add required files

* Update dependencies

* Refactor app structure

* Add docker-compose file for running locally

* Remove deprecated code

* Fix proxy uploads

* Code review fixes

* Use config instead of env in view

* Restore upgrade event handler

* Remove unused require

* Typo in login view

* Fix websockets
  • Loading branch information
andyhd authored Oct 17, 2017
1 parent 6c05402 commit 2732a67
Show file tree
Hide file tree
Showing 162 changed files with 3,649 additions and 310,636 deletions.
4 changes: 4 additions & 0 deletions .Dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store
.*.sw?
.env
node_modules/
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store
.*.sw?
.env
node_modules/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6.11.4
10 changes: 6 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
FROM node:6.11-alpine

RUN mkdir /app
ADD package.json /app/
WORKDIR /app

ADD package.json ./
ADD package-lock.json ./
RUN npm install
ADD . /app

CMD ["node", "bin/www"]
ADD app app/

CMD ["npm", "start"]
95 changes: 0 additions & 95 deletions app.js

This file was deleted.

20 changes: 3 additions & 17 deletions auth.js → app/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,11 @@ function base64HMAC(message, key) {
}


function secureCookie(value, validDuration) {
function secureCookie(value, validDuration, cookieKey) {
var expires = formatDate(expiry(validDuration));
var hmac = base64HMAC(value + expires, process.env.SECURE_COOKIE_KEY);
var hmac = base64HMAC(value + expires, cookieKey);
return [value, expires, hmac].map(encodeURIComponent).join('|');
}


function setAuthCookie(req) {
var staySignedInDays = process.env.STAY_SIGNED_IN_DAYS || 1;
var duration = staySignedInDays * 24 * 60 * 60 * 1000;
var cookies = req._headers.cookie.split('; ');
for (var cookie in cookies) {
var [key, value] = cookie.split('=');
if (key == 'user-id') {
return;
}
}
cookies.push('user-id=' + secureCookie(process.env.USER, duration));
req.setHeader('Cookie', cookies.join('; '));
}

module.exports = setAuthCookie;
module.exports.cookie = secureCookie;
40 changes: 40 additions & 0 deletions app/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
var config = module.exports;


config.express = {
port: process.env.EXPRESS_PORT || 3000,
host: process.env.EXPRESS_HOST || '127.0.0.1'
};

config.log = {
level: process.env.LOG_LEVEL || 'debug'
};

config.session = {
secret: process.env.COOKIE_SECRET || 'shh-its-a-secret',
resave: true,
saveUninitialized: true
};

config.auth0 = {
domain: process.env.AUTH0_DOMAIN,
clientID: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
callbackURL: process.env.AUTH0_CALLBACK_URL || 'http://localhost:3000/callback'
};

config.proxy = {
target: {
host: process.env.PROXY_TARGET_HOST,
port: process.env.PROXY_TARGET_PORT
},
ws: true,
preserveHeaderKeyCase: true,
proxyTimeout: process.env.PROXY_TIMEOUT || (24 * 60 * 60 * 1000)
};

config.rstudio = {
user: process.env.RSTUDIO_USER || process.env.USER,
duration: (24 * 60 * 60 * 1000),
key: process.env.SECURE_COOKIE_KEY
};
6 changes: 6 additions & 0 deletions app/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// catch 404s and forward to error handler
module.exports = function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
}
Binary file added app/favicon.ico
Binary file not shown.
50 changes: 50 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require('dotenv').config();
var bole = require('bole');
var config = require('./config');
var morgan = require('morgan');
var nunjucks = require('nunjucks');
var passport = require('passport');
var path = require('path');
var Auth0Strategy = require('passport-auth0');


var app = require('express')();
app.set('views', path.join(__dirname, 'views'));

// add before logging to avoid favicon requests in logs
app.use(require('serve-favicon')(path.join(__dirname, 'favicon.ico')));

bole.output({level: config.log.level, stream: process.stdout});
app.use(morgan('combined'));

nunjucks.configure(path.join(__dirname, 'views'), {
autoescape: true,
express: app
});

app.use(require('cookie-parser')());
app.use(require('express-session')(config.session));

passport.use(new Auth0Strategy(
config.auth0,
function(accessToken, refreshToken, extraParams, profile, done) {
return done(null, profile);
}
));

passport.serializeUser(function(user, done) {
done(null, user);
});

passport.deserializeUser(function(user, done) {
done(null, user);
});

app.use(passport.initialize());
app.use(passport.session());

app.use(require('./routes'));
app.use(require('./errors'));


module.exports = app;
24 changes: 24 additions & 0 deletions app/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
var config = require('./config');


module.exports.denyUnauthorized = function (req, res, next) {

if (isAuthorized(req)) {
next();

} else {
res.sendStatus(403);
next(new Error('User is not authorized'));
}
};

function isAuthorized(req) {
try {
return req.user.nickname.toLowerCase() === config.rstudio.user;

} catch (error) {
// do nothing
}

return false;
}
62 changes: 62 additions & 0 deletions app/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
var auth = require('./auth');
var config = require('./config');
var httpProxy = require('http-proxy');
var log = require('bole')('proxy');


var proxy = httpProxy.createProxyServer(config.proxy);

proxy.on('proxyReq', function (proxyReq, req, res, options) {
proxyReq.setHeader('Cookie', insert_auth_cookie(req));
proxy_body(req, proxyReq);
});

proxy.on('proxyReqWs', function (proxyReqWs, req, res, options) {
proxyReqWs.setHeader('Cookie', insert_auth_cookie(req));
proxy_body(req, proxyReqWs);
});

proxy.on('error', function (err) {
log.error(err);
});

function insert_auth_cookie(req) {
return insert_cookie(req, 'user-id', auth.cookie(
config.rstudio.user, config.rstudio.duration, config.rstudio.key));
}

function insert_cookie(req, name, value) {
log.debug('cookie header:', req.headers['Cookie']);
var cookies = (req.headers['Cookie'] || '').split('; ');

// remove existing cookie
cookies = cookies.filter(function (cookie) {
return cookie.indexOf(name + '=') !== 0;
});

cookies.push(name + '=' + value);

return cookies.join('; ');
}

function proxy_body(req, proxyReq) {
if (req.body && req.body.length) {
proxyReq.setHeader('Content-Length', content_length(req));
write_body(req, proxyReq);
}
}

function content_length(req) {
return req.body.reduce(function (length, chunk) {
return length + chunk.byteLength;
}, 0);
}

function write_body(req, proxyReq) {
req.body.map(function (chunk) {
proxyReq.write(chunk);
});
}


module.exports = proxy;
52 changes: 52 additions & 0 deletions app/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
var config = require('./config');
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
var express = require('express');
var middleware = require('./middleware');
var passport = require('passport');
var proxy = require('./proxy');
var router = new express.Router();


router.get('/login', function(req, res) {
res.render('login.html', {auth0: config.auth0});
});

router.get('/logout', function(req, res) {
req.logout();
res.redirect('/login');
});

router.get('/auth-sign-out', function (req, res) {
req.logout();
res.redirect('/login');
});

router.get('/callback', [
passport.authenticate('auth0', { failureRedirect: '/login' }),
function(req, res) {
res.redirect(req.session.returnTo || '/');
}
]);

router.all(/.*/, [
ensureLoggedIn('/login'),
middleware.denyUnauthorized,
function(req, res) {
parseBody(req).then(function (body) {
req.body = body;
proxy.web(req, res);
});
}
]);

function parseBody(req) {
var body = [];
return new Promise(function (resolve, reject) {
req.on('data', function (chunk) { body.push(chunk); });
req.on('end', function () { resolve(body); });
req.on('error', function (err) { reject(err); });
});
}


module.exports = router;
Loading

0 comments on commit 2732a67

Please sign in to comment.