diff --git a/.gitignore b/.gitignore index 12db069..874db94 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ config.json */._* */*/._* coverage.* +*/*~ +.emacs* \ No newline at end of file diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..e348d1e Binary files /dev/null and b/assets/images/logo.png differ diff --git a/assets/scripts/login.js b/assets/scripts/login.js new file mode 100644 index 0000000..c34356f --- /dev/null +++ b/assets/scripts/login.js @@ -0,0 +1,11 @@ +document.onreadystatechange = function () { + + if (document.readyState === 'complete') { + + document.getElementById('btnLogin').addEventListener('click', function (event) { + + event.preventDefault(); + console.log('Login Button Clicked'); + }); + } +}; diff --git a/assets/styles/styles.css b/assets/styles/styles.css new file mode 100644 index 0000000..86775fd --- /dev/null +++ b/assets/styles/styles.css @@ -0,0 +1,4 @@ +h3 { + font-size: 24px; + font-weight: bold; +} \ No newline at end of file diff --git a/guides/git.md b/guides/git.md index 18f53bf..e34cc92 100755 --- a/guides/git.md +++ b/guides/git.md @@ -13,13 +13,13 @@ There are two main ways to get back to sync and one way to avoid this problem in This is the simplest. You just go to your fork on GitHub, go to **settings** and at the bottom click on **Delete this repository**. Once deleted, go back to -[the official repository](https://github.com/hueniverse/hueniversity) and fork it again. All set. +[the official repository](https://github.com/hapijs/university) and fork it again. All set. Remember to also delete your local directory and then to clone your new fork all over again. ### Replace your master branch with the remote branch. ``` -git remote add upstream https://github.com/hueniverse/hueniversity +git remote add upstream https://github.com/hapijs/university git fetch upstream git branch backup git checkout upstream/master -B master diff --git a/lib/certs/cert.crt b/lib/certs/cert.crt new file mode 100644 index 0000000..f7fcf80 --- /dev/null +++ b/lib/certs/cert.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICRzCCAbACCQDLKLdg5Wbn9TANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSEwHwYJKoZIhvcNAQkBFhJydXRhaWh3YUBnbWFpbC5jb20wHhcN +MTUwNjA4MTE1MjU1WhcNMTYwNjA3MTE1MjU1WjBoMQswCQYDVQQGEwJBVTETMBEG +A1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg +THRkMSEwHwYJKoZIhvcNAQkBFhJydXRhaWh3YUBnbWFpbC5jb20wgZ8wDQYJKoZI +hvcNAQEBBQADgY0AMIGJAoGBANIDuMQini8ttfexVQdmph6hjKXxVc1Zk8bX6z0O +b9uKw4SrHXDKYelgmvG9Gv8awl8hElbUamVNWe5U7sN3LxiTzTMu+rhScABzrt6X +VZEJxZsdFYgIzvzC6PUy1rBMb7MZGmdm5Cd5eaWAGQ/lPfI+dW604FKVo/xI5gPd +8lWbAgMBAAEwDQYJKoZIhvcNAQELBQADgYEArZPt5dJXnGQxWTt0FsGF9Mk6IsfJ +4sTS2vt9KND2i18RT0qyn3YUsqfnjieRKId5Ru2PYsqJEFz2/e0OwmAxjmrpiz2q +9yfTHFtWB3Rjt/O+IXN9D4otwb6ADrzkXDy1FWwPMDK9vJ3A/quBhN8iCpcr+FdH +MMbrPytUAKCaSLs= +-----END CERTIFICATE----- diff --git a/lib/certs/key.key b/lib/certs/key.key new file mode 100644 index 0000000..252e94c --- /dev/null +++ b/lib/certs/key.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDSA7jEIp4vLbX3sVUHZqYeoYyl8VXNWZPG1+s9Dm/bisOEqx1w +ymHpYJrxvRr/GsJfIRJW1GplTVnuVO7Ddy8Yk80zLvq4UnAAc67el1WRCcWbHRWI +CM78wuj1MtawTG+zGRpnZuQneXmlgBkP5T3yPnVutOBSlaP8SOYD3fJVmwIDAQAB +AoGARPLL2jizTjHnp+YkUEW3DB9lmaVd0gkypvmEVYtD1gP8pLW4+Kq48nGw7OR0 +1IPohGrLJo6eT5vRhpmDudCLOSIYPVqi/14kW+ahMJuMc2FGohRL89dIGEWvGPks +2c4YCtYhZL4sfFJwE2TVnOv8jmQM8l0Y/K/vXcLPrNFzfmECQQDvmo5mEYsVrV9/ +UFCEi7b38e2tLdo40U6eRm9yd6zK7XpYqQVMGJFB14EU4FSyUMk9lpvAiHJjFCG2 +alkR6mtnAkEA4GLQWGXkjNBn/5aUlbPsqGKzWfDQqMaGnsPCDEJsONAemPxqDsmO +5qBP3CWH093azT2NTWWDefM07KdciqKXrQJBANjzfE6lQeet5VN1GIL7sv+M2qW9 +Z+OcefBMXKsr+5R/NRHEcVx2vkf85w9NFMOk7KLMlVje85wM5X2zi9TyCq8CQQC7 +K1HVWvEhULpfZbD9iv8Omn42uPykvC0RBAO6jDGP1nKfdHXXbePolrLm1NuPLBFW +gFB8zf+02t07xoMYFXZlAkA5YaolWVD/IMb1H8UYh2enseR5IFVrrkbOAnTSHXzX +w1w+wU4rNow/hftjSuW7nnOozWYwI+HEmgvsf9P6Wnke +-----END RSA PRIVATE KEY----- diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..cb8f066 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,15 @@ +var Fs = require('fs'); + +var config = module.exports = {}; + +// Configuring TLS +config.tls = { + key: Fs.readFileSync('./lib/certs/key.key'), + cert: Fs.readFileSync('./lib/certs/cert.crt'), + + // Only necessary if using the client certificate authentication. + requestCert: true, + + // Only necessary only if client is using the self-signed certificate. + ca: [] +}; diff --git a/lib/home.js b/lib/home.js index fe34bed..0363fa0 100644 --- a/lib/home.js +++ b/lib/home.js @@ -12,29 +12,63 @@ var internals = { exports.register = function (server, options, next) { + // Future, put global view config into static plugin server.views({ engines: { html: require('handlebars') }, path: '../views', + partialsPath: '../views/partials', relativeTo: __dirname }); + // Routing for static files server.route({ method: 'GET', - path: '/home', - config: { - description: 'Returns the home page', - handler: { - view: { - template: 'home', - context: { - path: Path.relative(internals.rootPath, Path.resolve(internals.viewsPath, 'home.html')) + path: '/{assetpath*}', + handler: { + directory: { + path: './assets/' + } + } + }); + + // Home related routing + server.route([ + + // Index route + + // Login route + + { + method: 'GET', + path: '/login', + config: { + description: 'Returns a login form', + handler: { + view: { + template: 'login' + } + } + } + }, + + // Home route + + { + method: 'GET', + path: '/home', + config: { + description: 'Returns the home page', + handler: { + view: { + template: 'home' } } } } - }); + + ]); return next(); }; diff --git a/lib/index.js b/lib/index.js index 7e9170e..de36ee2 100755 --- a/lib/index.js +++ b/lib/index.js @@ -15,6 +15,15 @@ exports.init = function (manifest, composeOptions, next) { return next(err); } + // TLS everything + + server.select('web').ext('onRequest', function (request, reply) { + + return reply.redirect('https://localhost:8001' + request.url.path).permanent(); + }); + + // Start the server + server.start(function (err) { return next(err, server); diff --git a/lib/start.js b/lib/start.js index d98acf9..822793c 100755 --- a/lib/start.js +++ b/lib/start.js @@ -2,6 +2,7 @@ var Hoek = require('hoek'); var Server = require('./index'); +var Config = require('./config'); // Declare internals @@ -10,13 +11,27 @@ var internals = {}; internals.manifest = { connections: [ { - port: 8000 + host: 'localhost', + port: 8000, + labels: ['web'] + }, + { + host: 'localhost', + port: 8001, + labels: ['web-tls'], + tls: Config.tls } ], plugins: { - './version': {}, - './private': {}, - './home': {}, + './version': [{ + 'select': ['web', 'web-tls'] + }], + './private': [{ + 'select': ['web', 'web-tls'] + }], + './home': [{ + 'select': ['web', 'web-tls'] + }], './auth': {}, 'hapi-auth-basic': {} } @@ -29,5 +44,12 @@ internals.composeOptions = { Server.init(internals.manifest, internals.composeOptions, function (err, server) { Hoek.assert(!err, err); - console.log('Server started at: ' + server.info.uri); + + // Server connections + var web = server.select('web'); + var webTls = server.select('web-tls'); + + // Logging started server + console.log('Web server started at: ' + web.info.uri); + console.log('WebTLS server started at: ' + webTls.info.uri); }); diff --git a/test/home.js b/test/home.js index fb4219d..498e101 100644 --- a/test/home.js +++ b/test/home.js @@ -4,6 +4,7 @@ var Code = require('code'); var Lab = require('lab'); var University = require('../lib'); var Path = require('path'); +var Config = require('../lib/config'); // Declare internals @@ -19,17 +20,33 @@ var it = lab.test; describe('/home', function () { - it('returns home page containing relative path from root to home template', function (done) { + it('ensures that /home is always redirected to https', function (done) { University.init(internals.manifest, internals.composeOptions, function (err, server) { expect(err).to.not.exist(); var request = { method: 'GET', url: '/home' }; - server.inject(request, function (res) { + server.select('web').inject(request, function (res) { + + expect(res.statusCode, 'Status code').to.equal(301); + expect(res.headers.location).to.equal('https://localhost:8001/home'); + + server.stop(done); + }); + }); + }); + + it('returns an home page via https', function (done) { + + University.init(internals.manifest, internals.composeOptions, function (err, server) { + + expect(err).to.not.exist(); + + var request = { method: 'GET', url: '/home' }; + server.select('web-tls').inject(request, function (res) { expect(res.statusCode, 'Status code').to.equal(200); - expect(res.result, 'result').to.equal(Path.relative(Path.resolve('__dirname', '../'), Path.resolve('__dirname', '../views/home.html'))); server.stop(done); }); @@ -40,7 +57,15 @@ describe('/home', function () { internals.manifest = { connections: [ { - port: 0 + host: 'localhost', + port: 0, + labels: ['web'] + }, + { + host: 'localhost', + port: 0, + labels: ['web-tls'], + tls: Config.tls } ], plugins: { diff --git a/test/index.js b/test/index.js index 05e22ae..a49e285 100755 --- a/test/index.js +++ b/test/index.js @@ -6,6 +6,7 @@ var Lab = require('lab'); var University = require('../lib'); var Version = require('../lib/version'); var Path = require('path'); +var Config = require('../lib/config'); //declare internals @@ -14,64 +15,89 @@ var internals = {}; // Test shortcuts var lab = exports.lab = Lab.script(); +var describe = lab.experiment; var expect = Code.expect; var it = lab.test; +describe('/index', function () { -it('starts server and returns hapi server object', function (done) { + it('starts server and returns hapi server object', function (done) { - University.init({}, {}, function (err, server) { + University.init(internals.manifest, internals.composeOptions, function (err, server) { - expect(err).to.not.exist(); - expect(server).to.be.instanceof(Hapi.Server); + expect(err).to.not.exist(); + expect(server).to.be.instanceof(Hapi.Server); - server.stop(done); + server.stop(done); + }); }); -}); -it('starts server on provided port', function (done) { + it('starts server on provided port', function (done) { - University.init({connections: [{port: 5000}]}, {}, function (err, server) { + University.init({ connections: [{ port: 5000, labels: 'web' }] }, {}, function (err, server) { - expect(err).to.not.exist(); - expect(server.info.port).to.equal(5000); + expect(err).to.not.exist(); + expect(server.select('web').info.port).to.equal(5000); - server.stop(done); + server.stop(done); + }); }); -}); -it('handles register plugin errors', { parallel: false }, function (done) { + it('handles register plugin errors', { parallel: false }, function (done) { - var orig = Version.register; - Version.register = function (server, options, next) { + var orig = Version.register; + Version.register = function (server, options, next) { - Version.register = orig; - return next(new Error('register version failed')); - }; + Version.register = orig; + return next(new Error('register version failed')); + }; - Version.register.attributes = { - name: 'fake version' - }; + Version.register.attributes = { + name: 'fake version' + }; - University.init(internals.manifest, internals.composeOptions, function (err, server) { + University.init(internals.manifest, internals.composeOptions, function (err, server) { - expect(err).to.exist(); - expect(err.message).to.equal('register version failed'); + expect(err).to.exist(); + expect(err.message).to.equal('register version failed'); - done(); + done(); + }); }); -}); -internals.manifest = { - connections: [ + it('forces re-routing to https', function (done) { + + University.init(internals.manifest, internals.composeOptions, function (err, server) { + + server.inject('/version', function (res) { + + expect(res.statusCode).to.equal(301); + expect(res.headers.location).to.equal('https://localhost:8001/version'); + + server.stop(done); + }); + }); + }); + + internals.manifest = { + connections: [ { - port: 0 + host: 'localhost', + port: 0, + labels: ['web'] + }, + { + host: 'localhost', + port: 0, + labels: ['web-tls'], + tls: Config.tls + } + ], + plugins: { + './version': {} } - ], - plugins: { - './version': {} - } -}; + }; +}); internals.composeOptions = { relativeTo: Path.resolve(__dirname, '../lib') diff --git a/test/private.js b/test/private.js index 85cd85b..a714c8d 100755 --- a/test/private.js +++ b/test/private.js @@ -7,12 +7,12 @@ var Users = require('../lib/users.json'); var Auth = require('../lib/auth'); var Path = require('path'); var Hoek = require('hoek'); +var Config = require('../lib/config'); // Declare internals var internals = {}; - // Test shortcuts var lab = exports.lab = Lab.script(); @@ -20,9 +20,25 @@ var describe = lab.experiment; var expect = Code.expect; var it = lab.test; - describe('/private', function () { + it('ensures /private is always redirected to use https', function (done) { + + University.init(internals.manifest, internals.composeOptions, function (err, server) { + + expect(err).to.not.exist(); + + var request = { method: 'GET', url: '/private' }; + server.select('web').inject(request, function (res) { + + expect(res.statusCode, 'Status code').to.equal(301); + expect(res.headers.location).to.equal('https://localhost:8001/private'); + + server.stop(done); + }); + }); + }); + it('returns a greeting for the authenticated user', function (done) { University.init(internals.manifest, internals.composeOptions, function (err, server) { @@ -30,7 +46,7 @@ describe('/private', function () { expect(err).to.not.exist(); var request = { method: 'GET', url: '/private', headers: { authorization: internals.header('foo', Users.foo.password) } }; - server.inject(request, function (res) { + server.select('web-tls').inject(request, function (res) { expect(res.statusCode, 'Status code').to.equal(200); expect(res.result, 'result').to.equal('
Hello foo
'); @@ -47,7 +63,7 @@ describe('/private', function () { expect(err).to.not.exist(); var request = { method: 'GET', url: '/private', headers: { authorization: internals.header('foo', '') } }; - server.inject(request, function (res) { + server.select('web-tls').inject(request, function (res) { expect(res.statusCode, 'Status code').to.equal(401); @@ -63,7 +79,7 @@ describe('/private', function () { expect(err).to.not.exist(); var request = { method: 'GET', url: '/private', headers: { authorization: internals.header('I do not exist', '') } }; - server.inject(request, function (res) { + server.select('web-tls').inject(request, function (res) { expect(res.statusCode, 'Status code').to.equal(401); @@ -118,8 +134,16 @@ internals.header = function (username, password) { internals.manifest = { connections: [ + { + host: 'localhost', + port: 0, + labels: ['web'] + }, { - port: 0 + host: 'localhost', + port: 0, + labels: ['web-tls'], + tls: Config.tls } ], plugins: { diff --git a/test/version.js b/test/version.js index b960c5b..bb5f71b 100755 --- a/test/version.js +++ b/test/version.js @@ -5,12 +5,12 @@ var Lab = require('lab'); var Pkg = require('../package.json'); var University = require('../lib'); var Path = require('path'); +var Config = require('../lib/config'); // Declare internals var internals = {}; - // Test shortcuts var lab = exports.lab = Lab.script(); @@ -18,16 +18,32 @@ var describe = lab.experiment; var expect = Code.expect; var it = lab.test; - describe('/version', function () { + + it('ensures /version always redirected to use https', function (done) { + + University.init(internals.manifest, internals.composeOptions, function (err, server) { + + expect(err).to.not.exist(); + + server.select('web').inject('/version', function (res) { + + expect(res.statusCode).to.equal(301); + expect(res.headers.location).to.equal('https://localhost:8001/version'); + + server.stop(done); + }); + }); + }); + it('returns the version from package.json', function (done) { University.init(internals.manifest, internals.composeOptions, function (err, server) { expect(err).to.not.exist(); - server.inject('/version', function (res) { + server.select('web-tls').inject('/version', function (res) { expect(res.statusCode).to.equal(200); expect(res.result).to.deep.equal({ version: Pkg.version }); @@ -41,7 +57,15 @@ describe('/version', function () { internals.manifest = { connections: [ { - port: 0 + host: 'localhost', + port: 0, + labels: ['web'] + }, + { + host: 'localhost', + port: 0, + labels: ['web-tls'], + tls: Config.tls } ], plugins: { diff --git a/views/home.html b/views/home.html index 0457fcc..f03dd73 100644 --- a/views/home.html +++ b/views/home.html @@ -1 +1,13 @@ -{{path}} \ No newline at end of file + + + + hapi.js university + + + + Logo +

A Community Learning Experiment

+
+ Login + + diff --git a/views/login.html b/views/login.html new file mode 100644 index 0000000..c147f33 --- /dev/null +++ b/views/login.html @@ -0,0 +1,10 @@ + + + + hapi.js university + + + {{> form }} + + + diff --git a/views/partials/form.html b/views/partials/form.html new file mode 100644 index 0000000..fb5881f --- /dev/null +++ b/views/partials/form.html @@ -0,0 +1,5 @@ +
+ Username:
+ Password: 
+ +
diff --git a/views/partials/form.html~ b/views/partials/form.html~ new file mode 100644 index 0000000..f9ff50d --- /dev/null +++ b/views/partials/form.html~ @@ -0,0 +1,4 @@ +
+ Username:
+ Password:
+