diff --git a/Gruntfile.js b/Gruntfile.js index 4f5d1a1..377eb50 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -19,27 +19,6 @@ module.exports = function(grunt) { port: 8581, base: '.' } - }, - prod: { - options: { - port: process.env.PORT || 8585, - base: './dist/', - keepalive: true, - middleware: function(connect, options) { - // Return array of whatever middlewares you want - return [ - - function(req, res, next) { - res.setHeader('Content-Security-Policy', "default-src 'self'; object-src 'none'; connect-src 'self' https://keys.whiteout.io; img-src 'self' data:;"); - - return next(); - }, - - // Serve static files. - connect.static(options.base) - ]; - } - } } }, diff --git a/README.md b/README.md index 5ca9adc..47e2e4b 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ We take the privacy of your data very seriously. Here are some of the technical * [Content Security Policy (CSP)](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) is enforced to prevent against injection attacks. -* HTML mails are sanitized with [DOMPurify](https://github.com/cure53/DOMPurify) and are rendered in a sandboxed iframe. +* HTML mails are sanitized with [DOMPurify](https://github.com/cure53/DOMPurify) and are rendered in a sandboxed iframe. * Displaying mail images is optional and opt-in by default. @@ -48,7 +48,7 @@ For development you can start a connect dev server: grunt dev -Then visit [http://localhost:8580/dist/#/desktop](http://localhost:8580/dist/#/desktop) for front-end code or [http://localhost:8580/test/unit/](http://localhost:8580/test/unit/) to test JavaScript changes. You can also start a watch task so you don't have rebuild everytime you make a change: +Then visit [http://localhost:8580/dist/#/desktop?dev=true](http://localhost:8580/dist/#/desktop?dev=true) for front-end code or [http://localhost:8580/test/unit/](http://localhost:8580/test/unit/) to test JavaScript changes. You can also start a watch task so you don't have rebuild everytime you make a change: grunt watch diff --git a/package.json b/package.json index ad33a93..9b32f76 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,35 @@ { - "name": "mail-html5", - "version": "0.0.0", + "name": "whiteout-mail", + "version": "0.0.1", + "description": "Mail App with integrated OpenPGP encryption.", + "author": "Whiteout Networks", + "homepage": "https://whiteout.io", + "repository": { + "type": "git", + "url": "https://github.com/whiteout-io/mail-html5.git" + }, + "keywords": ["email", "mail", "client", "app", "openpgp", "pgp", "gpg", "imap", "smtp"], "engines": { - "node": ">=0.8" + "node": ">=0.10" }, "scripts": { - "postinstall": "grunt dist-npm", + "postinstall": "grunt", "test": "grunt && grunt test", - "start": "grunt && grunt dev" + "start": "node server.js" }, "dependencies": { - "crypto-lib": "~0.2.1", - "imap-client": "~0.4.0", - "mailreader": "~0.3.5", - "pgpmailer": "~0.3.11", - "pgpbuilder": "~0.3.7", - "requirejs": "2.1.14", "axe-logger": "~0.0.2", + "compression": "^1.0.11", + "crypto-lib": "~0.2.1", "dompurify": "~0.4.2", + "express": "^4.8.3", + "imap-client": "~0.4.0", "jquery": "~2.1.1", - "ng-infinite-scroll": "~1.1.2" + "mailreader": "~0.3.5", + "ng-infinite-scroll": "~1.1.2", + "pgpbuilder": "~0.3.7", + "pgpmailer": "~0.3.11", + "requirejs": "~2.1.14" }, "devDependencies": { "angularjs": "https://github.com/angular/angular.js/tarball/v1.2.8", diff --git a/server.js b/server.js new file mode 100644 index 0000000..e949b62 --- /dev/null +++ b/server.js @@ -0,0 +1,49 @@ +'use strict'; + +var express = require('express'), + compression = require('compression'), + app = express(); + +// +// web server config +// + +var port = process.env.PORT || 8585, + oneDay = 86400000, + development = process.argv[2] === '--dev'; + +// set HTTP headers +app.use(function(req, res, next) { + // HSTS + res.set('Strict-Transport-Security', 'max-age=16070400; includeSubDomains'); + // CSP + res.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; connect-src *; style-src 'self' 'unsafe-inline'; img-src 'self' data:"); + return next(); +}); + +// redirect all http traffic to https +app.use(function(req, res, next) { + if ((!req.secure) && (req.get('X-Forwarded-Proto') !== 'https') && !development) { + res.redirect('https://' + req.hostname + req.url); + } else { + next(); + } +}); + +// use gzip compression +app.use(compression()); + +// server static files +app.use(express.static(__dirname + '/dist', { + maxAge: oneDay +})); + +// +// start server +// + +app.listen(port); +if (development) { + console.log(' > starting in development mode'); +} +console.log(' > listening on http://localhost:' + port + '\n'); \ No newline at end of file diff --git a/src/index.html b/src/index.html index 25bff32..05d59db 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,7 @@ - Mail + Whiteout Mail diff --git a/src/js/controller/mail-list.js b/src/js/controller/mail-list.js index 2fbcb83..1e862cf 100644 --- a/src/js/controller/mail-list.js +++ b/src/js/controller/mail-list.js @@ -10,7 +10,7 @@ define(function(require) { var INIT_DISPLAY_LEN = 20, SCROLL_DISPLAY_LEN = 10; - var MailListCtrl = function($scope) { + var MailListCtrl = function($scope, $routeParams) { // // Init // @@ -166,7 +166,7 @@ define(function(require) { $scope.searchText = undefined; // in development, display dummy mail objects - if (!window.chrome || !chrome.identity) { + if ($routeParams.dev) { updateStatus('Last update: ', new Date()); currentFolder().messages = createDummyMails(); return; diff --git a/src/js/controller/navigation.js b/src/js/controller/navigation.js index 8a52418..7d7ccb8 100644 --- a/src/js/controller/navigation.js +++ b/src/js/controller/navigation.js @@ -13,7 +13,7 @@ define(function(require) { // Controller // - var NavigationCtrl = function($scope) { + var NavigationCtrl = function($scope, $routeParams) { emailDao = appController._emailDao; outboxBo = appController._outboxBo; @@ -84,7 +84,7 @@ define(function(require) { function initializeFolders() { // create dummy folder in dev environment only - if (!window.chrome || !chrome.identity) { + if ($routeParams.dev) { createDummyFolders(); return; } diff --git a/test/unit/mail-list-ctrl-test.js b/test/unit/mail-list-ctrl-test.js index c762a27..f83ad78 100644 --- a/test/unit/mail-list-ctrl-test.js +++ b/test/unit/mail-list-ctrl-test.js @@ -79,7 +79,8 @@ define(function(require) { scope.loadVisibleBodies = function() {}; ctrl = $controller(MailListCtrl, { - $scope: scope + $scope: scope, + $routeParams: {} }); }); }); diff --git a/test/unit/navigation-ctrl-test.js b/test/unit/navigation-ctrl-test.js index 010a25e..9d977af 100644 --- a/test/unit/navigation-ctrl-test.js +++ b/test/unit/navigation-ctrl-test.js @@ -10,13 +10,9 @@ define(function(require) { appController = require('js/app-controller'); describe('Navigation Controller unit test', function() { - var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, hasIdentity, outboxFolder, onConnectStub; + var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub; beforeEach(function(done) { - hasIdentity = !! window.chrome.identity; - if (!hasIdentity) { - window.chrome.identity = {}; - } // remember original module to restore later origEmailDao = appController._emailDao; emailDaoMock = sinon.createStubInstance(EmailDAO); @@ -45,7 +41,8 @@ define(function(require) { scope = $rootScope.$new(); scope.state = {}; ctrl = $controller(NavigationCtrl, { - $scope: scope + $scope: scope, + $routeParams: {} }); done(); }); @@ -54,9 +51,6 @@ define(function(require) { afterEach(function() { // restore the module appController._emailDao = origEmailDao; - if (hasIdentity) { - delete window.chrome.identity; - } onConnectStub.restore(); });