From b0a7ed9388b37b03b79cda9bb54ac75f9e5df376 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 01:40:26 +0100 Subject: [PATCH 01/16] Don't change password in non-rpi app. --- coder-apps/common/auth/app/app.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/coder-apps/common/auth/app/app.js b/coder-apps/common/auth/app/app.js index dacd9034..93cc8af8 100644 --- a/coder-apps/common/auth/app/app.js +++ b/coder-apps/common/auth/app/app.js @@ -362,7 +362,7 @@ exports.api_addpassword_handler = function( req, res ) { //setpass.addListener( 'exit', function( code, signal ) { var completed = function( code, signal ) { - err = code; + err = code; if ( err ) { @@ -440,16 +440,17 @@ exports.api_changepassword_handler = function( req, res ) { //device_settings.device_name = devicename; var erroutput = ""; var output = ""; - var setpipass = process.cwd() + '/sudo_scripts/setpipass'; - var setpass = spawn( '/usr/bin/sudo', [setpipass] ); - setpass.stdout.on( 'data', function( d ) { - output += d; - }); - setpass.stderr.on( 'data', function( d ) { - erroutput += d; - }); + //var setpipass = process.cwd() + '/sudo_scripts/setpipass'; + //var setpass = spawn( '/usr/bin/sudo', [setpipass] ); + //setpass.stdout.on( 'data', function( d ) { + // output += d; + //}); + //setpass.stderr.on( 'data', function( d ) { + // erroutput += d; + //}); - setpass.addListener( 'exit', function( code, signal ) { + //setpass.addListener( 'exit', function( code, signal ) { + var completed = function( code, signal ) { err = code; @@ -479,11 +480,13 @@ exports.api_changepassword_handler = function( req, res ) { }); } - }); - setpass.stdin.write(pass + '\n'); - setpass.stdin.write(pass + '\n'); - setpass.stdin.end(); + }; + completed(); + + //setpass.stdin.write(pass + '\n'); + //setpass.stdin.write(pass + '\n'); + //setpass.stdin.end(); }; From c17662f46e67725f16c788fa446ecc92f908db74 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 01:44:23 +0100 Subject: [PATCH 02/16] Use integer port numbers. --- coder-base/config.js | 8 ++++---- coder-base/config.js.default | 8 ++++---- coder-base/config.js.localhost | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/coder-base/config.js b/coder-base/config.js index 19052a53..bb0980e1 100644 --- a/coder-base/config.js +++ b/coder-base/config.js @@ -1,10 +1,10 @@ exports.listenIP = null; //Defaults to * -exports.listenPort = '8081'; //the SSL port things run on -exports.httpListenPort = '8080'; //this will all be redirected to SSL +exports.listenPort = 8081; //the SSL port things run on +exports.httpListenPort = 8080; //this will all be redirected to SSL exports.cacheApps = true; -exports.httpVisiblePort = '80'; //forwarded http port the user sees -exports.httpsVisiblePort = '443'; //forwarded https port the user sees +exports.httpVisiblePort = 80; //forwarded http port the user sees +exports.httpsVisiblePort = 443; //forwarded https port the user sees //SSL Info diff --git a/coder-base/config.js.default b/coder-base/config.js.default index 19052a53..bb0980e1 100644 --- a/coder-base/config.js.default +++ b/coder-base/config.js.default @@ -1,10 +1,10 @@ exports.listenIP = null; //Defaults to * -exports.listenPort = '8081'; //the SSL port things run on -exports.httpListenPort = '8080'; //this will all be redirected to SSL +exports.listenPort = 8081; //the SSL port things run on +exports.httpListenPort = 8080; //this will all be redirected to SSL exports.cacheApps = true; -exports.httpVisiblePort = '80'; //forwarded http port the user sees -exports.httpsVisiblePort = '443'; //forwarded https port the user sees +exports.httpVisiblePort = 80; //forwarded http port the user sees +exports.httpsVisiblePort = 443; //forwarded https port the user sees //SSL Info diff --git a/coder-base/config.js.localhost b/coder-base/config.js.localhost index 3aa5890b..cd2ec915 100644 --- a/coder-base/config.js.localhost +++ b/coder-base/config.js.localhost @@ -1,10 +1,10 @@ exports.listenIP = '127.0.0.1'; //Defaults to * -exports.listenPort = '8081'; //the SSL port things run on -exports.httpListenPort = '8080'; //this will all be redirected to SSL +exports.listenPort = 8081; //the SSL port things run on +exports.httpListenPort = 8080; //this will all be redirected to SSL exports.cacheApps = true; -exports.httpVisiblePort = '8080'; //forwarded http port the user sees -exports.httpsVisiblePort = '8081'; //forwarded https port the user sees +exports.httpVisiblePort = 8080; //forwarded http port the user sees +exports.httpsVisiblePort = 8081; //forwarded https port the user sees //SSL Info From 857070a512485be79dbf6cf26e36bd41a07992c8 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 11:03:07 +0100 Subject: [PATCH 03/16] Put the config object in the global namespace. --- coder-base/localserver.js | 3 ++- coder-base/server.js | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/coder-base/localserver.js b/coder-base/localserver.js index 1ef8034f..0ec60cd3 100644 --- a/coder-base/localserver.js +++ b/coder-base/localserver.js @@ -26,13 +26,14 @@ var http = require('http'); var https = require('https'); var crypto = require('crypto'); var path = require('path'); -var config = require('./config'); var fs = require('fs'); var util = require('util'); var cons = require('consolidate'); var params = require('express-params'); var querystring = require('querystring'); +global.config = require('./config'); + var loadApp = function( loadpath ) { var userapp = null; diff --git a/coder-base/server.js b/coder-base/server.js index 10c8f049..0bf43333 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -26,19 +26,17 @@ var http = require('http'); var https = require('https'); var crypto = require('crypto'); var path = require('path'); -var config = require('./config'); var fs = require('fs'); var util = require('util'); var cons = require('consolidate'); var params = require('express-params'); var querystring = require('querystring'); -var path = require('path'); var cookie = require('cookie'); var connect = require('connect'); +global.config = require('./config'); var loadApp = function( loadpath ) { - var userapp = null; if ( config.cacheApps ) { userapp = require(loadpath); From 0eda02d8b00823c150025d73ade414a9c4775f4e Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 23:01:23 +0100 Subject: [PATCH 04/16] Merge server.js and localserver.js. --- coder-base/config.js | 18 ++-- coder-base/localserver.js | 178 -------------------------------------- coder-base/server.js | 112 ++++++++++++------------ 3 files changed, 68 insertions(+), 240 deletions(-) delete mode 100644 coder-base/localserver.js diff --git a/coder-base/config.js b/coder-base/config.js index bb0980e1..baab31df 100644 --- a/coder-base/config.js +++ b/coder-base/config.js @@ -1,18 +1,22 @@ exports.listenIP = null; //Defaults to * -exports.listenPort = 8081; //the SSL port things run on -exports.httpListenPort = 8080; //this will all be redirected to SSL exports.cacheApps = true; + +exports.httpListenPort = 8080; //this will all be redirected to SSL +exports.httpslistenPort = 8081; //the SSL port things run on + exports.httpVisiblePort = 80; //forwarded http port the user sees exports.httpsVisiblePort = 443; //forwarded https port the user sees //SSL Info -exports.country = "US"; -exports.state = "New York"; -exports.locale = "New York"; -exports.commonName = "coder.local"; -exports.subjectAltName = "DNS:192.168.0.1"; +exports.ssl = {} +exports.ssl.enable = true +exports.ssl.country = "US"; +exports.ssl.state = "New York"; +exports.ssl.locale = "New York"; +exports.ssl.commonName = "coder.local"; +exports.ssl.subjectAltName = "DNS:192.168.0.1"; //Experimental diff --git a/coder-base/localserver.js b/coder-base/localserver.js deleted file mode 100644 index 0ec60cd3..00000000 --- a/coder-base/localserver.js +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Coder for Raspberry Pi - * A simple platform for experimenting with web stuff. - * http://goo.gl/coder - * - * Copyright 2013 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -var express = require('express'); -var io = require('socket.io'); -var net = require('http'); -var http = require('http'); -var https = require('https'); -var crypto = require('crypto'); -var path = require('path'); -var fs = require('fs'); -var util = require('util'); -var cons = require('consolidate'); -var params = require('express-params'); -var querystring = require('querystring'); - -global.config = require('./config'); - -var loadApp = function( loadpath ) { - - var userapp = null; - if ( config.cacheApps ) { - userapp = require(loadpath); - } else { - - var cached = require.cache[loadpath + '.js']; - if ( cached ) { - userapp = require(loadpath); - if ( userapp.on_destroy ) { - userapp.on_destroy(); - } - delete require.cache[loadpath + ".js"]; - } - userapp = require(loadpath); - } - return userapp; -}; - - -var apphandler = function( req, res, appdir ) { - - var appname = req.params[0]; - var apppath = req.params[1]; - var modpath = appdir + appname; - var userapp = loadApp( modpath + "/app" ); - - - util.log( "GET: " + apppath + " " + appname ); - - //Redirect to sign-in for unauthenticated users - publicAllowed = ["auth"]; //apps that are exempt from any login (should only be auth) - auth = require(appdir + "auth" + "/app"); - user = auth.isAuthenticated(req, res); - if ( !user && publicAllowed.indexOf( appname ) < 0) { - util.log("redirect: " + "http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth'); - res.redirect("http://" + getHost(req) + ":" + config.httpVisiblePort + '/app/auth' ); - return; - } - - - if ( !apppath ) { - apppath = "/"; - } else { - apppath = "/" + apppath; - } - - userapp.settings.appname = appname; - userapp.settings.viewpath="apps/" + appname; - userapp.settings.appurl="/app/" + appname; - userapp.settings.staticurl = "/static/apps/" + appname; - userapp.settings.device_name = auth.getDeviceName(); - userapp.settings.coder_owner = auth.getCoderOwner(); - userapp.settings.coder_color = auth.getCoderColor(); - if ( userapp.settings.device_name === "" ) { - userapp.settings.device_name = "Coder"; - } - if ( userapp.settings.coder_color === "" ) { - userapp.settings.coder_color = "#3e3e3e"; - } - - var routes = []; - if ( req.route.method === 'get' ) { - routes = userapp.get_routes; - } else if ( req.route.method === 'post' ) { - routes = userapp.post_routes; - } - - if ( routes ) { - var found = false; - for ( var i in routes ) { - route = routes[i]; - if ( route['path'] instanceof RegExp ) { - var m = route['path'].exec( apppath ); - if ( m ) { - userapp[route['handler']]( req, res, m ); - found = true; - break; - } - - } else if ( route['path'] === apppath ) { - userapp[route['handler']]( req, res ); - found = true; - break; - } - - } - - if ( !found ) { - res.status( 404 ); - res.render('404', { - title: 'error' - }); - } - } -}; - - -var startLocal = function() { - http.createServer(localapp).listen( config.httpListenPort, '127.0.0.1' ); -}; - -var getHost = function( req ) { - var host = req.connection.address().address; - if ( typeof req.headers.host !== "undefined" ) { - host = req.headers.host; - if ( host.match(/:/g) ) { - host = host.slice( 0, host.indexOf(":") ); - } - } - return host; -}; - -//Traffic on 127.0.0.1 (localhost) only -var localapp = express(); -params.extend( localapp ); -localapp.engine( 'html', cons.mustache ); -localapp.set( 'view engine', 'html' ); -localapp.set( 'views', __dirname + '/views' ); -localapp.use( express.bodyParser() ); -localapp.use( express.cookieParser() ); -localapp.use( express.session({ - secret: crypto.randomBytes(16).toString('utf-8'), - store: new express.session.MemoryStore() -})); -localapp.use( '/static', express.static( __dirname + '/static' ) ); -localapp.get( '/', function( req, res ) { - util.log( 'GET: /' ); - res.redirect( '/app/auth' ); -}); -localapp.all( /^\/app\/(\w+)\/(.*)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); -localapp.all( /^\/app\/(\w+)\/$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); -localapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); - - -startLocal(); - -process.on('uncaughtException', function(err) { - console.log('WARNING: unhandled exception: ' + err ); -}); - diff --git a/coder-base/server.js b/coder-base/server.js index 0bf43333..2cbcb797 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -77,7 +77,7 @@ var apphandler = function( req, res, appdir ) { var apppath = req.params[1]; var modpath = appdir + appname; var userapp = loadApp( modpath + "/app" ); - + util.log( "GET: " + apppath + " " + appname ); @@ -86,8 +86,8 @@ var apphandler = function( req, res, appdir ) { auth = require(appdir + "auth" + "/app"); user = auth.isAuthenticated(req, res); if ( !user && publicAllowed.indexOf( appname ) < 0) { - util.log( "redirect: " + "https://" + getHost(req) + ":" + config.httpsVisiblePort + '/app/auth' ); - res.redirect("https://" + getHost(req) + ":" + config.httpsVisiblePort + '/app/auth' ); + util.log( "redirect: " + '/app/auth' ); + res.redirect('/app/auth'); return; } @@ -106,7 +106,7 @@ var apphandler = function( req, res, appdir ) { } else if ( req.route.method === 'post' ) { routes = userapp.post_routes; } - + if ( routes ) { var found = false; for ( var i in routes ) { @@ -118,7 +118,7 @@ var apphandler = function( req, res, appdir ) { found = true; break; } - + } else if ( route['path'] === apppath ) { userapp[route['handler']]( req, res ); found = true; @@ -136,15 +136,11 @@ var apphandler = function( req, res, appdir ) { } }; -var startSSLRedirect = function() { - http.createServer( redirectapp ).listen( config.httpListenPort, config.listenIP ); -}; - -var server; -var startSSL = function() { +var loadSslCert = function(callback) { privateKeyFile=path.normalize('certs/server.key'); certificateFile=path.normalize('certs/server.cert'); + var privateKey=""; var certificate=""; try { @@ -153,14 +149,12 @@ var startSSL = function() { } catch ( e ) { util.print( "no certificate found. generating self signed cert.\n" ); } - + if ( privateKey !== "" && certificate !== "" ) { - server = https.createServer({ key: privateKey, cert: certificate }, sslapp); - server.listen( config.listenPort, config.listenIP ); - initSocketIO( server ); + callback(privateKey, certificate); } else { var spawn = require('child_process').spawn; - + var genSelfSignedCert = function(keyFile, certFile) { var genkey = spawn( 'openssl', [ 'req', '-x509', '-nodes', @@ -181,9 +175,8 @@ var startSSL = function() { var loadServer = function() { privateKey = fs.readFileSync(privateKeyFile).toString(); certificate = fs.readFileSync(certificateFile).toString(); - server = https.createServer({ key: privateKey, cert: certificate }, sslapp); - server.listen( config.listenPort, config.listenIP ); - initSocketIO( server ); + + callback(privateKey, certificate); }; genSelfSignedCert(privateKeyFile, certificateFile); @@ -228,7 +221,7 @@ var initSocketIO = function( server ) { }); }); - + var genRandomID = function() { var id = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -245,7 +238,7 @@ var initSocketIO = function( server ) { var sess = socket.handshake.session; socket.socketID = genRandomID(); - socketMap[socket.socketID] = socket; + socketMap[socket.socketID] = socket; socket.emit('SOCKETID', socket.socketID); socket.on('disconnect', function() { @@ -259,9 +252,9 @@ var initSocketIO = function( server ) { if ( data.appid !== undefined && data.appid.match(/^\w+$/) && data.key !== undefined ) { var appname = data.appid; var userapp = loadApp( __dirname + '/apps/' + appname + "/app" ); - var auth = require( __dirname + "/apps/auth/app" ); + var auth = require( __dirname + "/apps/auth/app" ); applyAppSettings( userapp, appname, auth ); - + var route; var key = data.key; var routes = userapp.socketio_routes; @@ -276,7 +269,7 @@ var initSocketIO = function( server ) { found = true; break; } - + } else if ( route['key'] === key ) { userapp[route['handler']]( socket, data.data ); found = true; @@ -289,6 +282,7 @@ var initSocketIO = function( server ) { }); }); }; + // Allow front end console to receive server logs over a socket connection. // Note that util.log will still only go to stdout var origlog = console.log; @@ -317,11 +311,11 @@ var pingStatusServer = function() { if ( typeof server === 'undefined' || server === "" || !pingEnabled ) { return; } - + if ( typeof devicename === 'undefined' || devicename === "" ) { devicename = "Unconfigured Coder"; } - + var options = { host: server, port: '80', @@ -369,43 +363,51 @@ var getHost = function( req ) { return host; }; -//HTTPS handles all normal traffic -var sslapp = express(); -var storesecret = crypto.randomBytes(16).toString('utf-8'); -params.extend( sslapp ); -sslapp.sessionStore = new express.session.MemoryStore(); -sslapp.engine( 'html', cons.mustache ); -sslapp.set( 'view engine', 'html' ); -sslapp.set( 'views', __dirname + '/views' ); -sslapp.use( express.bodyParser() ); -sslapp.use( express.cookieParser() ); -sslapp.use( express.session({ - secret: storesecret, +var coderapp = express(); +params.extend( coderapp ); +coderapp.engine( 'html', cons.mustache ); +coderapp.set( 'view engine', 'html' ); +coderapp.set( 'views', __dirname + '/views' ); +coderapp.use( express.bodyParser() ); +coderapp.use( express.cookieParser() ); +coderapp.use( express.session({ key: 'connect.sid', - store: sslapp.sessionStore + secret: crypto.randomBytes(16).toString('utf-8'), + store: new express.session.MemoryStore() })); -sslapp.use( '/static', express.static( __dirname + '/static' ) ); -sslapp.get( '/', function( req, res ) { +coderapp.use( '/static', express.static( __dirname + '/static' ) ); +coderapp.get( '/', function( req, res ) { util.log( 'GET: /' ); res.redirect( '/app/auth' ); }); -sslapp.all( /^\/app\/(\w+)\/(.*)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); -sslapp.all( /^\/app\/(\w+)\/$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); -sslapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); - +coderapp.all( /^\/app\/(\w+)\/(.*)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); +coderapp.all( /^\/app\/(\w+)\/$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); +coderapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); + +if (config.ssl.enable) +{ + //HTTP is all redirected to HTTPS + var redirectapp = express(); + params.extend( redirectapp ); + redirectapp.engine( 'html', cons.mustache ); + redirectapp.all( /.*/, function( req, res ) { + util.log( 'redirect: ' + getHost(req) + ":" + config.httpsVisiblePort + " " + req.url ); + res.redirect("https://" + getHost(req) + ":" + config.httpsVisiblePort + req.url); + }); + http.createServer(redirectapp).listen(config.httpListenPort, config.listenIP); -//HTTP is all redirected to HTTPS -var redirectapp = express(); -params.extend( redirectapp ); -redirectapp.engine( 'html', cons.mustache ); -redirectapp.all( /.*/, function( req, res ) { - util.log( 'redirect: ' + getHost(req) + ":" + config.httpsVisiblePort + " " + req.url ); - res.redirect("https://" + getHost(req) + ":" + config.httpsVisiblePort + req.url); -}); + loadSslCert(function () { + var server = https.createServer({ key: privateKey, cert: certificate }, coderapp); + server.listen(config.httpsListenPort, config.listenIP); + initSocketIO(server); + }); +} +else +{ + http.createServer(coderapp).listen(config.httpListenPort, config.listenIP); +} -startSSL(); -startSSLRedirect(); pingStatusServer(); process.on('uncaughtException', function(err) { From 5db50c6038e65fcd30524bb7b86d41dbd56e54c6 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 23:09:21 +0100 Subject: [PATCH 05/16] Remove config.js, leave only samples. --- coder-base/config.js | 32 -------------------------------- coder-base/config.js.default | 22 ++++++++++++---------- coder-base/config.js.localhost | 17 +++++++---------- coder-base/server.js | 4 ++-- 4 files changed, 21 insertions(+), 54 deletions(-) delete mode 100644 coder-base/config.js diff --git a/coder-base/config.js b/coder-base/config.js deleted file mode 100644 index baab31df..00000000 --- a/coder-base/config.js +++ /dev/null @@ -1,32 +0,0 @@ - -exports.listenIP = null; //Defaults to * -exports.cacheApps = true; - -exports.httpListenPort = 8080; //this will all be redirected to SSL -exports.httpslistenPort = 8081; //the SSL port things run on - -exports.httpVisiblePort = 80; //forwarded http port the user sees -exports.httpsVisiblePort = 443; //forwarded https port the user sees - - -//SSL Info -exports.ssl = {} -exports.ssl.enable = true -exports.ssl.country = "US"; -exports.ssl.state = "New York"; -exports.ssl.locale = "New York"; -exports.ssl.commonName = "coder.local"; -exports.ssl.subjectAltName = "DNS:192.168.0.1"; - - -//Experimental -// -//Status Server -// This can be used in conjundtion with the sample findcoder -// appengine project. It allows multiple Coders on the same -// NAT network to be discoverable. Coder devices will ping the -// external server with their internal IP, and the server -// will list the devices for any requesting machine that -// originates from the same external IP. -exports.statusServer = '[yourpingserver].appspot.com'; -exports.enableStatusServer = false; diff --git a/coder-base/config.js.default b/coder-base/config.js.default index bb0980e1..207cfd3d 100644 --- a/coder-base/config.js.default +++ b/coder-base/config.js.default @@ -1,19 +1,20 @@ exports.listenIP = null; //Defaults to * -exports.listenPort = 8081; //the SSL port things run on exports.httpListenPort = 8080; //this will all be redirected to SSL -exports.cacheApps = true; -exports.httpVisiblePort = 80; //forwarded http port the user sees -exports.httpsVisiblePort = 443; //forwarded https port the user sees +exports.httpsListenPort = 8081; //the SSL port things run on +exports.httpsVisiblePort = 443; //forwarded https port the user sees, used to redirect from http to https -//SSL Info -exports.country = "US"; -exports.state = "New York"; -exports.locale = "New York"; -exports.commonName = "coder.local"; -exports.subjectAltName = "DNS:192.168.0.1"; +exports.cacheApps = true; +//SSL Info +exports.ssl = {} +exports.ssl.enable = true +exports.ssl.country = "US"; +exports.ssl.state = "New York"; +exports.ssl.locale = "New York"; +exports.ssl.commonName = "coder.local"; +exports.ssl.subjectAltName = "DNS:192.168.0.1"; //Experimental // @@ -26,3 +27,4 @@ exports.subjectAltName = "DNS:192.168.0.1"; // originates from the same external IP. exports.statusServer = '[yourpingserver].appspot.com'; exports.enableStatusServer = false; + diff --git a/coder-base/config.js.localhost b/coder-base/config.js.localhost index cd2ec915..c401c8c9 100644 --- a/coder-base/config.js.localhost +++ b/coder-base/config.js.localhost @@ -1,19 +1,15 @@ exports.listenIP = '127.0.0.1'; //Defaults to * -exports.listenPort = 8081; //the SSL port things run on exports.httpListenPort = 8080; //this will all be redirected to SSL -exports.cacheApps = true; -exports.httpVisiblePort = 8080; //forwarded http port the user sees -exports.httpsVisiblePort = 8081; //forwarded https port the user sees +//exports.httpsListenPort = 8081; //the SSL port things run on +//exports.httpsVisiblePort = 443; //forwarded https port the user sees, used to redirect from http to https -//SSL Info -exports.country = "US"; -exports.state = "New York"; -exports.locale = "New York"; -exports.commonName = "coder.local"; -exports.subjectAltName = "DNS:192.168.0.1"; +exports.cacheApps = true; +//SSL Info +exports.ssl = {} +exports.ssl.enable = false //Experimental // @@ -26,3 +22,4 @@ exports.subjectAltName = "DNS:192.168.0.1"; // originates from the same external IP. exports.statusServer = '[yourpingserver].appspot.com'; exports.enableStatusServer = false; + diff --git a/coder-base/server.js b/coder-base/server.js index 2cbcb797..1f9fe4eb 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -397,8 +397,8 @@ if (config.ssl.enable) http.createServer(redirectapp).listen(config.httpListenPort, config.listenIP); - loadSslCert(function () { - var server = https.createServer({ key: privateKey, cert: certificate }, coderapp); + loadSslCert(function (key, cert) { + var server = https.createServer({ key: key, cert: cert }, coderapp); server.listen(config.httpsListenPort, config.listenIP); initSocketIO(server); }); From 3231f036908a166e673b4bfdba2833eb2ee6607c Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 8 Mar 2014 23:57:11 +0100 Subject: [PATCH 06/16] Refactor slightly app loading. --- coder-base/server.js | 62 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/coder-base/server.js b/coder-base/server.js index 1f9fe4eb..38995633 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -36,7 +36,9 @@ var connect = require('connect'); global.config = require('./config'); -var loadApp = function( loadpath ) { +var loadApp = function( path, appname, auth ) { + var loadpath = path + appname + "/app"; + var userapp = null; if ( config.cacheApps ) { userapp = require(loadpath); @@ -52,38 +54,46 @@ var loadApp = function( loadpath ) { } userapp = require(loadpath); } - return userapp; -}; -var applyAppSettings = function( userapp, appname, auth ) { - userapp.settings.appname = appname; - userapp.settings.viewpath="apps/" + appname; - userapp.settings.appurl="/app/" + appname; - userapp.settings.staticurl = "/static/apps/" + appname; - userapp.settings.device_name = auth.getDeviceName(); - userapp.settings.coder_owner = auth.getCoderOwner(); - userapp.settings.coder_color = auth.getCoderColor(); - if ( userapp.settings.device_name === "" ) { - userapp.settings.device_name = "Coder"; - } - if ( userapp.settings.coder_color === "" ) { - userapp.settings.coder_color = "#3e3e3e"; + if (userapp) + { + userapp.settings.appname = appname; + userapp.settings.viewpath="apps/" + appname; + userapp.settings.appurl="/app/" + appname; + userapp.settings.staticurl = "/static/apps/" + appname; + userapp.settings.device_name = auth.getDeviceName(); + userapp.settings.coder_owner = auth.getCoderOwner(); + userapp.settings.coder_color = auth.getCoderColor(); + + if ( userapp.settings.device_name === "" ) { + userapp.settings.device_name = "Coder"; + } + if ( userapp.settings.coder_color === "" ) { + userapp.settings.coder_color = "#3e3e3e"; + } } -}; + + return userapp; +} var apphandler = function( req, res, appdir ) { var appname = req.params[0]; var apppath = req.params[1]; - var modpath = appdir + appname; - var userapp = loadApp( modpath + "/app" ); + auth = require(appdir + "auth" + "/app"); + var userapp = loadApp( appdir, appname, auth ); + + if ( !apppath ) { + apppath = "/"; + } else { + apppath = "/" + apppath; + } util.log( "GET: " + apppath + " " + appname ); //Redirect to sign-in for unauthenticated users publicAllowed = ["auth"]; //apps that are exempt from any login (should only be auth) - auth = require(appdir + "auth" + "/app"); user = auth.isAuthenticated(req, res); if ( !user && publicAllowed.indexOf( appname ) < 0) { util.log( "redirect: " + '/app/auth' ); @@ -91,15 +101,6 @@ var apphandler = function( req, res, appdir ) { return; } - - if ( !apppath ) { - apppath = "/"; - } else { - apppath = "/" + apppath; - } - - applyAppSettings( userapp, appname, auth ); - var routes = []; if ( req.route.method === 'get' ) { routes = userapp.get_routes; @@ -251,9 +252,8 @@ var initSocketIO = function( server ) { } if ( data.appid !== undefined && data.appid.match(/^\w+$/) && data.key !== undefined ) { var appname = data.appid; - var userapp = loadApp( __dirname + '/apps/' + appname + "/app" ); var auth = require( __dirname + "/apps/auth/app" ); - applyAppSettings( userapp, appname, auth ); + var userapp = loadApp( __dirname + '/apps/', appname, auth ); var route; var key = data.key; From 58d4c635f5acaf32ea8f20e7fb7200bd51c16d44 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 9 Mar 2014 00:14:10 +0100 Subject: [PATCH 07/16] Fix socket io. --- coder-base/server.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coder-base/server.js b/coder-base/server.js index 38995633..ef1a2799 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -405,7 +405,9 @@ if (config.ssl.enable) } else { - http.createServer(coderapp).listen(config.httpListenPort, config.listenIP); + var server = http.createServer(coderapp); + server.listen(config.httpListenPort, config.listenIP); + initSocketIO(server); } pingStatusServer(); From 0598a0a597f73d8d7d3ab7f3fc33f6febfcf557f Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 9 Mar 2014 00:24:06 +0100 Subject: [PATCH 08/16] Fix socketio. --- coder-base/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coder-base/server.js b/coder-base/server.js index ef1a2799..2fa1ec56 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -185,6 +185,7 @@ var loadSslCert = function(callback) { }; var io; +var storesecret = crypto.randomBytes(16).toString('utf-8') var socketMap={}; var initSocketIO = function( server ) { io = socketio.listen( server ); @@ -372,7 +373,7 @@ coderapp.use( express.bodyParser() ); coderapp.use( express.cookieParser() ); coderapp.use( express.session({ key: 'connect.sid', - secret: crypto.randomBytes(16).toString('utf-8'), + secret: storesecret, store: new express.session.MemoryStore() })); coderapp.use( '/static', express.static( __dirname + '/static' ) ); From 5c1e431bce79c127af5981f7c51a4d67b5772483 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 9 Mar 2014 02:05:45 +0100 Subject: [PATCH 09/16] Simplify socket sessions. --- coder-base/server.js | 56 +++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/coder-base/server.js b/coder-base/server.js index 2fa1ec56..a1b11614 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -184,42 +184,34 @@ var loadSslCert = function(callback) { } }; +var storeSecret = crypto.randomBytes(16).toString('utf-8'); +var sessionStore = new express.session.MemoryStore(); + var io; -var storesecret = crypto.randomBytes(16).toString('utf-8') var socketMap={}; var initSocketIO = function( server ) { io = socketio.listen( server ); + var sioCookieParser = express.cookieParser(storeSecret); + io.set('log level', 1); //TODO: hack to fix recursion problem since we are piping log info to a socket - // sync session data with socket - // via https://github.com/DanielBaulig/sioe-demo/blob/master/app.js io.set('authorization', function (handshake, accept) { - if (!handshake.headers.cookie) { - console.log('no cookie sent with socket connection'); - return accept('No cookie transmitted.', false); - } - - handshake.cookie = cookie.parse(handshake.headers.cookie); - handshake.sessionID = connect.utils.parseSignedCookie(handshake.cookie['connect.sid'], storesecret); - - if (handshake.cookie['connect.sid'] == handshake.sessionID) { - return accept('Cookie is invalid', false ); - } - - handshake.sessionStore = sslapp.sessionStore; - - if (!handshake.sessionID) { - return accept('Session cookie could not be found', false); - } - - handshake.sessionStore.get(handshake.sessionID, function (err, session) { + sioCookieParser(handshake, {}, function(err) { if (err) { - console.log( 'error loading session' ); - return accept('Error', false); + accept(err, false); + } + else { + sessionStore.get(handshake.signedCookies["connect.sid"], function(err, sessionData) { + if (err || !sessionData) { + accept('Session error', false); + } + else { + handshake.sessionStore = sessionStore; + handshake.session = new express.session.Session(handshake, sessionData); + accept(null, true); + } + }); } - - var s = handshake.session = new express.session.Session(handshake, session ); - return accept(null, true); }); }); @@ -237,7 +229,7 @@ var initSocketIO = function( server ) { io.sockets.on('connection', function (socket) { - var sess = socket.handshake.session; + socket.session = socket.handshake.session; socket.socketID = genRandomID(); socketMap[socket.socketID] = socket; @@ -248,7 +240,7 @@ var initSocketIO = function( server ) { }); socket.on('appdata', function(data) { - if ( !sess.authenticated ) { + if ( !socket.session.authenticated ) { return; } if ( data.appid !== undefined && data.appid.match(/^\w+$/) && data.key !== undefined ) { @@ -294,7 +286,7 @@ console.log = function(d) { var clients = io.sockets.clients(); for ( var x=0; x Date: Sun, 9 Mar 2014 04:02:56 +0100 Subject: [PATCH 10/16] Add git icon. --- .../static/common/media/coder_icons.png | Bin 3033 -> 2310 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/coder-base/static/common/media/coder_icons.png b/coder-base/static/common/media/coder_icons.png index 77e32941eaa2af252ad0eb9a1f034295981dc3cd..6a7c06d8cd3fa808658b857cf022a9a11cf246b8 100644 GIT binary patch literal 2310 zcmbW1c{J4T9>>47pRvRk*S-xUW#^V%80#RCiVVgsGX_N&Tt+oQKff5E#aPN9TT*81 zE?7A00av7Iu`N=e|5UMqRbC}gn76+0h<6BfNexSFys@l1h?~v03adzYYG7O$%=d^ znuI**EV>{hCM2bFcy;b606=adogB{K=h+NwPGGd!&<69iipykNy_j5>koy4bG*$fm zv`4jpd|ocjP+JkB(pRE=j_F1=+o^%KBA}95H+NiQoIFth26e}rs|V}HFVr8#G@doN ze0e0QO_O!S{Kt>5il(7OatHaI?VWoZ(Go^k%BbZgVU@gDny4nmuj%*r7H&NoH>?`+E;8NL$8`XG|MZ_ZLms?wjoCF}!C*Nz;;g*Fi>gKJH{BmCE*%#S?DLZMpNa6% z3jqC!PJwdzCP1Oy!wr~VM0e%9RLLpO0pl2a)zJQp;PYzzBbr1(Ole`##lGq?G0ng; z_BbPCz}W=clqON8L|IT+@dogKraW!-x@24=$Ow{MYIa+CN)MP7WHH^j?nv-ZkPb^1 ziPbi^bL=3ih*DK3g-kUju7|x5Txp~f=Vp&)L4!vc&#(*%stWhi_k)dCYC>B_8HHRo zWzrUag1?&;Y)S8+RJa8wXxuMIa)d0NFIigi>Kf$A2C1%CMepj-X5Lchq&zDZ-M!A_ z`SO=|woYtsiM36$@;D{8V8TBT62z@Kqkp; zJZsQh6bw zdW>VTv}72(dZt8KJ;jj-usqTmHh)T{;qzuQ4liTIv7ls^(X#FSC6UkbU|6|L-(S(8{n55eNfih283?RLOiBO+;pqS^Q)5)pZDsaCgGQ8pbw!mfp+Oc+R||UB2rz zxL$FzgVv}Q)f<`?=?fNbY`kp<6*ac^%q%*Ga$TIjkL7DxxTodELU^><4|}?7Fq3b9mVb_ zuYRsalgMjfjA{4iRKFoX`_sZpE0C!K_tM*i3-SmHzsZ}JXO!$i27gKisUYy3&b!z{ zJgq%zofs5kaiU(>4IOO5)(|N2pyD0X`PC5gGcGw6`wK4Gz0`a zV!3c5fV_mFPT|3x@{C&zD<9Shq5Z7T_d6EjT4&8)m^I8(IQ6q%{x+EZ7k$O*-E zamfjGaapeixrt{jltNz8?A5;vv}-*6RJ+x3BCpG5V*YR`!Rq~s_df^Z-Ne2I=kB#! z3uZE?j8=)OzFXr)+uNOm#Yx`I*fcmX0r|D|dSpWfujjSa2mg}9c8>c_#9(4PY0Dq7 zn8!Y7a3!=Xmw=v&vWiTfWWbWu^tYy5klt;I5#bN*aA_WAuY?}R{Wct~W|0b&Ic{lyiWV8i;NkDW0tEgp8^Z&7(s?71UITCaZ$0#4%J?XWqZ4W6ZM|)RQEIMSK zv2!{>nlR}Jbi>ov!21cBngaaxIftr3^Eclfbc)MIN%Go@hdnm7=AL3P^kQT!`i14E zHd9T060L)u1${-oTFRQMRvb3;aY=*>Smip2y@Q@5KY zuy`o^n>b01#)*@K#oQXoN{u;yQGE_}B+IF4)1tLQJ4UISebf7puZ8|4>;mD*BwReTqH*g>?GGn0Di8k~rN{7*CDM6eVK<2!CBrQ~1)h*s z0Ge-Zt6~3Zxw>CH%Y8u6WrnK!ND_JQLLY~5!-7%Aw_IJXa3K$g-#-0+3H$vy`Y=}m zxBr4`umu4sZ?AuU#J1cYO97L|{|RKq^asc2`wyUXATUeEZ$pIVMxqj$0v{P$${Xf zP(bnZdVABzv!(^5Y!%MZS|j)=22dO|$oCRlL4wSuJR6i2U_86nV(E&H5P6xNyAd3_ zi+9P1t@$WWxhL?odlM;9Fk}8#TKwRX{YpLyC|OaAN~x$xcbJ^48Jdo2E&I?Un7I>w zHI_AC*eF5cV3awRH;S08LH-*293jSt2$Zzw#C~L&{$9^Cw>j3EW>J=`XDbCFr#pxnwM@X8tZ`WT+=4f&YPbL)xKuCTA16-9@f?Zrnw>F?AQZH?@MJRti&O|9Kv=@QLnWdtiV)Bct`H#$NiYdJ^`YPbv`|FW zsw^rP3n&r-qAa59i;xOs(HKC21p){}ga#GbKc4Tr^X|E4?#!Ie_xtcH z049(T_8c$=fh6|hJiV#jC|4wwh}XreGrDvCVgdP_lsD=K*p5gBzzAIfC{_;+2OAmb!VM8dMsOXlz8+j3rYCxhpm0MZ z!U(Bv4F2*!MA68Br;+aVj$dMlMi!7@DwTwU!Duv^F3mufNDhL*O-)VLJ@oaVA_7Wb z5U3bBlt9tgaIgm`STc@8#SsbMbw^A9F`Q}v5oP*$33$?`ErIf7n?xH1qhm-gxUSy% zk~TmT>c69S{3cDIx&wdb`yY)do(vKIa|bBIa57eOaHloaLy?enWB@}Yl0AvU(2ZR@ z5=^8LDZxY%*v`WUtcAj0afJ1W?>{L}D5ML4Ld6iUfQ!8aMC751!v!K84Qvf;9Sx0) z93AxGa0deuV>=r=1l-in-V~v4uV=HNwI^c3@c@Ckp$+_7Yy4I1dNJThqR93D8Fv;4 zbR-k;;7^N2;=Z1X;aB~>Xam2V3*xIZD>q?7L&7#VV6^$}ftTL&GDk5QpRbvzz2haUrN8$ZJQP+1e&ox1>9m-E%Fbp}Iq z2djDeg-c8~ngxzl>m?o>Uz*$N-Z!$Gj!x+acV|Yvsn+0}B!7f(XzqPZtk|dhFYCxd z?DtE~%n!e(M+}K4y?a+Fn0wArGjno!JDX)(e5d4e&yy`a;E?HbwAHhP8Nt#%R!94S zwwONp@%p5X(0C!N43&jG;`p%CIeW2>H0uLfb)=s8gky%ZIn5pj zSE8PIGOrrWNeOX^U*Pz8o(+grhR)tcN0M_-`ncV5Yq%geoWl?2F=khY8JxwY-)5w< zTYu`&FeIF2es^qp$_~3L4}B52CN~Q?ZGN(EY=8@lj>q$6En7d9#rHc*XMMU_YR#yx-Uwt~n z8$kg=lW7CKx@~O3O*Ke$#RNVMox^9z^~UI-Qe90S`rW+>i|^>Wp_)0?*n+ zx2BFbl)M?dU5$ToefO|NM|dNCm!)6wXm;bag;pfm>RU;g_8P&YW2=JlWVeFJ8mcd` z^bvZjPEGucGRwcJWpOovsW?wM@S(`--_2U;J-l+L{L3=tn|!%mBbn6qsDXrqmWEHp5F;}OY(jHn^ScDf_%2Kv8HOm?gO1LB>}tlknDaR#cnS| zsVtwgynLVAR;=B5FTuLBxT3ek&pU|IKkm->sFv*=@>*t2_QDF`g>GqDWOb;rZv^VN zn1W`l->Nbtx@Tp1G;Y66r%LAPD>N~?p}(vCGPKp)Kglv=d|UG3 zqN^ZRyY*FBR~p_+u|F~3I?TCUE$$t`bcTNP^2E)z#6-%raoR4m zR|vV@*VP%F1?*ud?O&Sn@zN=nX$ixJ_LX4L+Yjf<=TxW;OsnEEo;~|K zDEk1k#_YxOZ<~LhPrW16HX;tPm5b_(yv|9U_jCSz-tzH;`p=HRNzy5K-j{r@p^w-G zHawnpApi>F4*nVZEK%u>-gUjvg!my}P&3j}aETEAzNS^q@CAdo%>X^vg^4)w~;h5YJ2~osd?^LVwl1T@3v5; zFBtz3|7?!?UK74+xj?XD!CP>O6s*RwESM+S1d%=3D!nK8_w7-{u_m!WZGzzL0|sDx5s~Dy(^!Co5R> zx7FxKiPHA6iwH`BrB7zS(zEJger;~8tX0WD4G4k_te-9)PMt_HHE3U22zazJItor7 z{bPVTUD#b`Eo*k7)hM>LlCW)uWMXb9fQ20J-qNKkWtKVq$~4=J!}o}@PI;HjWyCx@ z2e1hpW4#N)UEnV4zH3~@Q)6A|3~whB2jq<5vNrLMT-`h~K7*0tHTHa$X_9>09%+!cBuGp=4kY%u z-Mj!du0fFGC**Vc2^1kBd=r%3@%g^|0*Z-mI(|m}FHjUtty From 4e5b10c16188d367528753378e7fcffc75b3e136 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 9 Mar 2014 05:17:20 +0100 Subject: [PATCH 11/16] Put coderlib in a global. --- coder-base/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/coder-base/server.js b/coder-base/server.js index a1b11614..db002254 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -35,6 +35,7 @@ var cookie = require('cookie'); var connect = require('connect'); global.config = require('./config'); +global.coderlib = require('./apps/coderlib/app'); var loadApp = function( path, appname, auth ) { var loadpath = path + appname + "/app"; From f26f6e4e3bc73bf219515362dba7fc74a2b601ce Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Mon, 31 Mar 2014 18:37:02 +0200 Subject: [PATCH 12/16] Remove ssl support. This complicates the code, and can be handled by a reverse proxy. --- coder-base/config.js.default | 17 +------- coder-base/config.js.localhost | 12 +----- coder-base/server.js | 75 ++-------------------------------- 3 files changed, 7 insertions(+), 97 deletions(-) diff --git a/coder-base/config.js.default b/coder-base/config.js.default index 207cfd3d..d3e4ec06 100644 --- a/coder-base/config.js.default +++ b/coder-base/config.js.default @@ -1,21 +1,8 @@ - -exports.listenIP = null; //Defaults to * -exports.httpListenPort = 8080; //this will all be redirected to SSL -exports.httpsListenPort = 8081; //the SSL port things run on - -exports.httpsVisiblePort = 443; //forwarded https port the user sees, used to redirect from http to https +exports.listenIP = null; // All ips +exports.listenPort = 80; exports.cacheApps = true; -//SSL Info -exports.ssl = {} -exports.ssl.enable = true -exports.ssl.country = "US"; -exports.ssl.state = "New York"; -exports.ssl.locale = "New York"; -exports.ssl.commonName = "coder.local"; -exports.ssl.subjectAltName = "DNS:192.168.0.1"; - //Experimental // //Status Server diff --git a/coder-base/config.js.localhost b/coder-base/config.js.localhost index c401c8c9..9df58073 100644 --- a/coder-base/config.js.localhost +++ b/coder-base/config.js.localhost @@ -1,16 +1,8 @@ - -exports.listenIP = '127.0.0.1'; //Defaults to * -exports.httpListenPort = 8080; //this will all be redirected to SSL -//exports.httpsListenPort = 8081; //the SSL port things run on - -//exports.httpsVisiblePort = 443; //forwarded https port the user sees, used to redirect from http to https +exports.listenIP = '127.0.0.1'; +exports.httpListenPort = 8080; exports.cacheApps = true; -//SSL Info -exports.ssl = {} -exports.ssl.enable = false - //Experimental // //Status Server diff --git a/coder-base/server.js b/coder-base/server.js index db002254..61ca0556 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -23,7 +23,6 @@ var express = require('express'); var socketio = require('socket.io'); var net = require('http'); var http = require('http'); -var https = require('https'); var crypto = require('crypto'); var path = require('path'); var fs = require('fs'); @@ -138,53 +137,6 @@ var apphandler = function( req, res, appdir ) { } }; - -var loadSslCert = function(callback) { - privateKeyFile=path.normalize('certs/server.key'); - certificateFile=path.normalize('certs/server.cert'); - - var privateKey=""; - var certificate=""; - try { - privateKey = fs.readFileSync(privateKeyFile).toString(); - certificate = fs.readFileSync(certificateFile).toString(); - } catch ( e ) { - util.print( "no certificate found. generating self signed cert.\n" ); - } - - if ( privateKey !== "" && certificate !== "" ) { - callback(privateKey, certificate); - } else { - var spawn = require('child_process').spawn; - - var genSelfSignedCert = function(keyFile, certFile) { - var genkey = spawn( 'openssl', [ - 'req', '-x509', '-nodes', - '-days', '365', - '-newkey', 'rsa:2048', - '-keyout', keyFile, - '-out', certFile, - '-subj', - '/C=' + config.country + '/ST=' + config.state + "/L=" + config.locale + "/CN=" + config.commonName + "/subjectAltName=" + config.subjectAltName - ]); - genkey.stdout.on('data', function(d) { util.print(d) } ); - genkey.stderr.on('data', function(d) { util.print(d) } ); - genkey.addListener( 'exit', function( code, signal ) { - fs.chmodSync(privateKeyFile, '600'); - loadServer(); - }); - }; - var loadServer = function() { - privateKey = fs.readFileSync(privateKeyFile).toString(); - certificate = fs.readFileSync(certificateFile).toString(); - - callback(privateKey, certificate); - }; - - genSelfSignedCert(privateKeyFile, certificateFile); - } -}; - var storeSecret = crypto.randomBytes(16).toString('utf-8'); var sessionStore = new express.session.MemoryStore(); @@ -378,31 +330,10 @@ coderapp.all( /^\/app\/(\w+)\/(.*)$/, function( req, res ) { apphandler( req, re coderapp.all( /^\/app\/(\w+)\/$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); coderapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __dirname + '/apps/'); } ); -if (config.ssl.enable) -{ - //HTTP is all redirected to HTTPS - var redirectapp = express(); - params.extend( redirectapp ); - redirectapp.engine( 'html', cons.mustache ); - redirectapp.all( /.*/, function( req, res ) { - util.log( 'redirect: ' + getHost(req) + ":" + config.httpsVisiblePort + " " + req.url ); - res.redirect("https://" + getHost(req) + ":" + config.httpsVisiblePort + req.url); - }); - - http.createServer(redirectapp).listen(config.httpListenPort, config.listenIP); - loadSslCert(function (key, cert) { - var server = https.createServer({ key: key, cert: cert }, coderapp); - server.listen(config.httpsListenPort, config.listenIP); - initSocketIO(server); - }); -} -else -{ - var server = http.createServer(coderapp); - server.listen(config.httpListenPort, config.listenIP); - initSocketIO(server); -} +var server = http.createServer(coderapp); +server.listen(config.httpListenPort, config.listenIP); +initSocketIO(server); pingStatusServer(); From 9a92b5a2f2b7668847548ad7186a3c6557dd70e3 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Tue, 18 Mar 2014 17:57:43 +0100 Subject: [PATCH 13/16] Ignore application contents and config.js --- coder-base/.gitignore | 2 ++ coder-base/apps/.gitignore | 1 + coder-base/static/apps/.gitignore | 1 + coder-base/views/apps/.gitignore | 1 + 4 files changed, 5 insertions(+) create mode 100644 coder-base/.gitignore diff --git a/coder-base/.gitignore b/coder-base/.gitignore new file mode 100644 index 00000000..3343905d --- /dev/null +++ b/coder-base/.gitignore @@ -0,0 +1,2 @@ +config.js + diff --git a/coder-base/apps/.gitignore b/coder-base/apps/.gitignore index e69de29b..72e8ffc0 100644 --- a/coder-base/apps/.gitignore +++ b/coder-base/apps/.gitignore @@ -0,0 +1 @@ +* diff --git a/coder-base/static/apps/.gitignore b/coder-base/static/apps/.gitignore index e69de29b..72e8ffc0 100644 --- a/coder-base/static/apps/.gitignore +++ b/coder-base/static/apps/.gitignore @@ -0,0 +1 @@ +* diff --git a/coder-base/views/apps/.gitignore b/coder-base/views/apps/.gitignore index e69de29b..72e8ffc0 100644 --- a/coder-base/views/apps/.gitignore +++ b/coder-base/views/apps/.gitignore @@ -0,0 +1 @@ +* From f39c963f32cd918debd35e39e585db25fb98c959 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Mon, 31 Mar 2014 21:27:34 +0200 Subject: [PATCH 14/16] Update dependencies. --- coder-base/package.json | 32 +++++++++++++++++--------------- coder-base/server.js | 21 +++++++++++---------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/coder-base/package.json b/coder-base/package.json index e42be37a..851ef9e5 100644 --- a/coder-base/package.json +++ b/coder-base/package.json @@ -1,17 +1,19 @@ { - "name": "coder-base", - "description": "kid-friendly web programming environment for pi", - "version": "0.0.1", - "private": true, - "dependencies": { - "express": "3.1.0", - "redis": "0.8.2", - "mustache": "0.7.2", - "consolidate": "0.8.0", - "socket.io": "0.9.13", - "express-params": "0.0.3", - "bcrypt": "0.7.4", - "connect": "*", - "cookie": "*" - } + "name": "coder-base", + "description": "kid-friendly web programming environment for pi", + "version": "0.0.1", + "private": true, + "dependencies": { + "express": "~4.0", + "express-session": "~1.0", + "body-parser": "~1.0", + "cookie-parser": "~1.0", + "mustache": "~0.8", + "consolidate": "~0.10", + "socket.io": "~0.9", + "bcrypt": "~0.7", + "connect": "~3.0", + "cookie": "~0.1", + "express-params": "0.0.3" + } } diff --git a/coder-base/server.js b/coder-base/server.js index 61ca0556..b8cb649f 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -28,10 +28,12 @@ var path = require('path'); var fs = require('fs'); var util = require('util'); var cons = require('consolidate'); -var params = require('express-params'); var querystring = require('querystring'); var cookie = require('cookie'); var connect = require('connect'); +var session = require('express-session'); +var bodyParser = require('body-parser'); +var cookieParser = require('cookie-parser'); global.config = require('./config'); global.coderlib = require('./apps/coderlib/app'); @@ -102,9 +104,9 @@ var apphandler = function( req, res, appdir ) { } var routes = []; - if ( req.route.method === 'get' ) { + if ( req.method === 'GET' ) { routes = userapp.get_routes; - } else if ( req.route.method === 'post' ) { + } else if ( req.method === 'POST' ) { routes = userapp.post_routes; } @@ -138,13 +140,13 @@ var apphandler = function( req, res, appdir ) { }; var storeSecret = crypto.randomBytes(16).toString('utf-8'); -var sessionStore = new express.session.MemoryStore(); +var sessionStore = new session.MemoryStore(); var io; var socketMap={}; var initSocketIO = function( server ) { io = socketio.listen( server ); - var sioCookieParser = express.cookieParser(storeSecret); + var sioCookieParser = cookieParser(storeSecret); io.set('log level', 1); //TODO: hack to fix recursion problem since we are piping log info to a socket @@ -160,7 +162,7 @@ var initSocketIO = function( server ) { } else { handshake.sessionStore = sessionStore; - handshake.session = new express.session.Session(handshake, sessionData); + handshake.session = new session.Session(handshake, sessionData); accept(null, true); } }); @@ -310,13 +312,12 @@ var getHost = function( req ) { }; var coderapp = express(); -params.extend( coderapp ); coderapp.engine( 'html', cons.mustache ); coderapp.set( 'view engine', 'html' ); coderapp.set( 'views', __dirname + '/views' ); -coderapp.use( express.bodyParser() ); -coderapp.use( express.cookieParser() ); -coderapp.use( express.session({ +coderapp.use( bodyParser() ); +coderapp.use( cookieParser() ); +coderapp.use( session({ key: 'connect.sid', secret: storeSecret, store: sessionStore From b876ac315830e0c4fbef3dfc883a113e5ae10cab Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Mon, 31 Mar 2014 23:51:36 +0200 Subject: [PATCH 15/16] Add support for unix domain sockets and systems socket activation. --- coder-base/config.js.default | 8 ++++++-- coder-base/config.js.localhost | 8 ++++++-- coder-base/package.json | 2 +- coder-base/server.js | 24 +++++++++++++++++------- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/coder-base/config.js.default b/coder-base/config.js.default index d3e4ec06..79d38fde 100644 --- a/coder-base/config.js.default +++ b/coder-base/config.js.default @@ -1,5 +1,9 @@ -exports.listenIP = null; // All ips -exports.listenPort = 80; +// Listen can take different values : +// - port number +// - [port number, bind address] array +// - unix socket path +// - "systemd" for socket activation +exports.listen = 80; exports.cacheApps = true; diff --git a/coder-base/config.js.localhost b/coder-base/config.js.localhost index 9df58073..a79b6e8e 100644 --- a/coder-base/config.js.localhost +++ b/coder-base/config.js.localhost @@ -1,5 +1,9 @@ -exports.listenIP = '127.0.0.1'; -exports.httpListenPort = 8080; +// Listen can take different values : +// - port number +// - [port number, bind address] array +// - unix socket path +// - "systemd" for socket activation +exports.listen = [8080, '127.0.0.1']; exports.cacheApps = true; diff --git a/coder-base/package.json b/coder-base/package.json index 851ef9e5..4d0cf1d9 100644 --- a/coder-base/package.json +++ b/coder-base/package.json @@ -14,6 +14,6 @@ "bcrypt": "~0.7", "connect": "~3.0", "cookie": "~0.1", - "express-params": "0.0.3" + "systemd": "git+https://github.com/plietar/node-systemd.git" } } diff --git a/coder-base/server.js b/coder-base/server.js index b8cb649f..fe635246 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -34,6 +34,7 @@ var connect = require('connect'); var session = require('express-session'); var bodyParser = require('body-parser'); var cookieParser = require('cookie-parser'); +var systemd = require('systemd') global.config = require('./config'); global.coderlib = require('./apps/coderlib/app'); @@ -234,8 +235,8 @@ var initSocketIO = function( server ) { // Allow front end console to receive server logs over a socket connection. // Note that util.log will still only go to stdout var origlog = console.log; -console.log = function(d) { - origlog.call( console, d ); +console.log = function() { + origlog.apply( console, arguments ); if ( io ) { io.set('log level', 1); var clients = io.sockets.clients(); @@ -333,12 +334,21 @@ coderapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __ var server = http.createServer(coderapp); -server.listen(config.httpListenPort, config.listenIP); -initSocketIO(server); -pingStatusServer(); +if (Array.isArray(config.listen)) + var listenfn = server.listen.bind(server, config.listen[0], config.listen[1]); +else + var listenfn = server.listen.bind(server, config.listen); -process.on('uncaughtException', function(err) { - console.log('WARNING: unhandled exception: ' + err ); +listenfn(function() { + initSocketIO(server); + + pingStatusServer(); + + systemd.notify(); + + process.on('uncaughtException', function(err) { + console.log('WARNING: unhandled exception: ' + err ); + }); }); From 2519526fc93a72836caefb899dfaf83aa489a717 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Tue, 1 Apr 2014 00:29:12 +0200 Subject: [PATCH 16/16] Add support for automatic quit when idle for a long time. --- coder-base/config.js.default | 5 +++++ coder-base/config.js.localhost | 5 +++++ coder-base/package.json | 3 ++- coder-base/server.js | 4 ++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/coder-base/config.js.default b/coder-base/config.js.default index 79d38fde..01dbc10d 100644 --- a/coder-base/config.js.default +++ b/coder-base/config.js.default @@ -5,6 +5,11 @@ // - "systemd" for socket activation exports.listen = 80; +// Automatically stop the server if idle for a long amount of time. +// Designed to be used in conjunction with listen = "systemd". +// Disabled if timeout is 0 +exports.idleTimeout = 0; + exports.cacheApps = true; //Experimental diff --git a/coder-base/config.js.localhost b/coder-base/config.js.localhost index a79b6e8e..82f3df35 100644 --- a/coder-base/config.js.localhost +++ b/coder-base/config.js.localhost @@ -5,6 +5,11 @@ // - "systemd" for socket activation exports.listen = [8080, '127.0.0.1']; +// Automatically stop the server if idle for a long amount of time. +// Designed to be used in conjunction with listen = "systemd". +// Disabled if timeout is 0 +exports.idleTimeout = 0; + exports.cacheApps = true; //Experimental diff --git a/coder-base/package.json b/coder-base/package.json index 4d0cf1d9..e32c6fed 100644 --- a/coder-base/package.json +++ b/coder-base/package.json @@ -14,6 +14,7 @@ "bcrypt": "~0.7", "connect": "~3.0", "cookie": "~0.1", - "systemd": "git+https://github.com/plietar/node-systemd.git" + "systemd": "git+https://github.com/plietar/node-systemd.git", + "autoquit": "~0.1.6" } } diff --git a/coder-base/server.js b/coder-base/server.js index fe635246..0e45b696 100644 --- a/coder-base/server.js +++ b/coder-base/server.js @@ -35,6 +35,7 @@ var session = require('express-session'); var bodyParser = require('body-parser'); var cookieParser = require('cookie-parser'); var systemd = require('systemd') +require('autoquit'); global.config = require('./config'); global.coderlib = require('./apps/coderlib/app'); @@ -334,6 +335,9 @@ coderapp.all( /^\/app\/(\w+)$/, function( req, res ) { apphandler( req, res, __ var server = http.createServer(coderapp); +if (config.idleTimeout) { + server.autoQuit({ timeOut: config.idleTimeout }); +} if (Array.isArray(config.listen)) var listenfn = server.listen.bind(server, config.listen[0], config.listen[1]);