mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 08:52:15 -05:00
Add server.js for potential selfhosting
This commit is contained in:
parent
ec2186080a
commit
14624c877e
21
Gruntfile.js
21
Gruntfile.js
@ -19,27 +19,6 @@ module.exports = function(grunt) {
|
|||||||
port: 8581,
|
port: 8581,
|
||||||
base: '.'
|
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)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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.
|
* [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.
|
* 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
|
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
|
grunt watch
|
||||||
|
|
||||||
|
34
package.json
34
package.json
@ -1,25 +1,35 @@
|
|||||||
{
|
{
|
||||||
"name": "mail-html5",
|
"name": "whiteout-mail",
|
||||||
"version": "0.0.0",
|
"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": {
|
"engines": {
|
||||||
"node": ">=0.8"
|
"node": ">=0.10"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "grunt dist-npm",
|
"postinstall": "grunt",
|
||||||
"test": "grunt && grunt test",
|
"test": "grunt && grunt test",
|
||||||
"start": "grunt && grunt dev"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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",
|
"axe-logger": "~0.0.2",
|
||||||
|
"compression": "^1.0.11",
|
||||||
|
"crypto-lib": "~0.2.1",
|
||||||
"dompurify": "~0.4.2",
|
"dompurify": "~0.4.2",
|
||||||
|
"express": "^4.8.3",
|
||||||
|
"imap-client": "~0.4.0",
|
||||||
"jquery": "~2.1.1",
|
"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": {
|
"devDependencies": {
|
||||||
"angularjs": "https://github.com/angular/angular.js/tarball/v1.2.8",
|
"angularjs": "https://github.com/angular/angular.js/tarball/v1.2.8",
|
||||||
|
49
server.js
Normal file
49
server.js
Normal file
@ -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');
|
@ -2,7 +2,7 @@
|
|||||||
<html ng-app="mail" ng-csp>
|
<html ng-app="mail" ng-csp>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Mail</title>
|
<title>Whiteout Mail</title>
|
||||||
|
|
||||||
<!-- Theses CSP rules are used as a fallback in runtimes such as Cordova -->
|
<!-- Theses CSP rules are used as a fallback in runtimes such as Cordova -->
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' chrome-extension: file: gap:; object-src 'none'; script-src 'self' 'unsafe-eval' chrome-extension: file: gap:; connect-src *; style-src 'self' 'unsafe-inline' chrome-extension: file: gap:; img-src 'self' chrome-extension: file: gap: data:">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self' chrome-extension: file: gap:; object-src 'none'; script-src 'self' 'unsafe-eval' chrome-extension: file: gap:; connect-src *; style-src 'self' 'unsafe-inline' chrome-extension: file: gap:; img-src 'self' chrome-extension: file: gap: data:">
|
||||||
|
@ -10,7 +10,7 @@ define(function(require) {
|
|||||||
var INIT_DISPLAY_LEN = 20,
|
var INIT_DISPLAY_LEN = 20,
|
||||||
SCROLL_DISPLAY_LEN = 10;
|
SCROLL_DISPLAY_LEN = 10;
|
||||||
|
|
||||||
var MailListCtrl = function($scope) {
|
var MailListCtrl = function($scope, $routeParams) {
|
||||||
//
|
//
|
||||||
// Init
|
// Init
|
||||||
//
|
//
|
||||||
@ -166,7 +166,7 @@ define(function(require) {
|
|||||||
$scope.searchText = undefined;
|
$scope.searchText = undefined;
|
||||||
|
|
||||||
// in development, display dummy mail objects
|
// in development, display dummy mail objects
|
||||||
if (!window.chrome || !chrome.identity) {
|
if ($routeParams.dev) {
|
||||||
updateStatus('Last update: ', new Date());
|
updateStatus('Last update: ', new Date());
|
||||||
currentFolder().messages = createDummyMails();
|
currentFolder().messages = createDummyMails();
|
||||||
return;
|
return;
|
||||||
|
@ -13,7 +13,7 @@ define(function(require) {
|
|||||||
// Controller
|
// Controller
|
||||||
//
|
//
|
||||||
|
|
||||||
var NavigationCtrl = function($scope) {
|
var NavigationCtrl = function($scope, $routeParams) {
|
||||||
emailDao = appController._emailDao;
|
emailDao = appController._emailDao;
|
||||||
outboxBo = appController._outboxBo;
|
outboxBo = appController._outboxBo;
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ define(function(require) {
|
|||||||
|
|
||||||
function initializeFolders() {
|
function initializeFolders() {
|
||||||
// create dummy folder in dev environment only
|
// create dummy folder in dev environment only
|
||||||
if (!window.chrome || !chrome.identity) {
|
if ($routeParams.dev) {
|
||||||
createDummyFolders();
|
createDummyFolders();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,8 @@ define(function(require) {
|
|||||||
|
|
||||||
scope.loadVisibleBodies = function() {};
|
scope.loadVisibleBodies = function() {};
|
||||||
ctrl = $controller(MailListCtrl, {
|
ctrl = $controller(MailListCtrl, {
|
||||||
$scope: scope
|
$scope: scope,
|
||||||
|
$routeParams: {}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -10,13 +10,9 @@ define(function(require) {
|
|||||||
appController = require('js/app-controller');
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
describe('Navigation Controller unit test', function() {
|
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) {
|
beforeEach(function(done) {
|
||||||
hasIdentity = !! window.chrome.identity;
|
|
||||||
if (!hasIdentity) {
|
|
||||||
window.chrome.identity = {};
|
|
||||||
}
|
|
||||||
// remember original module to restore later
|
// remember original module to restore later
|
||||||
origEmailDao = appController._emailDao;
|
origEmailDao = appController._emailDao;
|
||||||
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
@ -45,7 +41,8 @@ define(function(require) {
|
|||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
scope.state = {};
|
scope.state = {};
|
||||||
ctrl = $controller(NavigationCtrl, {
|
ctrl = $controller(NavigationCtrl, {
|
||||||
$scope: scope
|
$scope: scope,
|
||||||
|
$routeParams: {}
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -54,9 +51,6 @@ define(function(require) {
|
|||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
// restore the module
|
// restore the module
|
||||||
appController._emailDao = origEmailDao;
|
appController._emailDao = origEmailDao;
|
||||||
if (hasIdentity) {
|
|
||||||
delete window.chrome.identity;
|
|
||||||
}
|
|
||||||
onConnectStub.restore();
|
onConnectStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user