mirror of
https://github.com/moparisthebest/mail
synced 2025-01-11 05:28:00 -05:00
Merge branch 'master' into dev/reader-zoom-to-fit
This commit is contained in:
commit
d93ee3be5d
@ -93,7 +93,7 @@ module.exports = function(grunt) {
|
||||
tasks: ['copy:lib', 'manifest']
|
||||
},
|
||||
app: {
|
||||
files: ['src/*.js', 'src/**/*.html', 'src/**/*.json', 'src/img/**/*', 'src/font/**/*'],
|
||||
files: ['src/*.js', 'src/**/*.html', 'src/**/*.json', 'src/manifest.*', 'src/img/**/*', 'src/font/**/*'],
|
||||
tasks: ['copy:app', 'copy:ca', 'copy:tpl', 'copy:img', 'copy:font', 'manifest-dev', 'manifest']
|
||||
}
|
||||
},
|
||||
@ -179,7 +179,7 @@ module.exports = function(grunt) {
|
||||
app: {
|
||||
expand: true,
|
||||
cwd: 'src/',
|
||||
src: ['*.html', '*.js', '*.json'],
|
||||
src: ['*.html', '*.js', '*.json', 'manifest.*'],
|
||||
dest: 'dist/'
|
||||
},
|
||||
integration: {
|
||||
@ -220,7 +220,7 @@ module.exports = function(grunt) {
|
||||
timestamp: true,
|
||||
hash: true,
|
||||
cache: ['socket.io/socket.io.js'],
|
||||
exclude: ['appcache.manifest'],
|
||||
exclude: ['appcache.manifest', 'manifest.webapp'],
|
||||
master: ['index.html']
|
||||
},
|
||||
src: ['**/*.*'],
|
||||
|
14
server.js
14
server.js
@ -71,7 +71,6 @@ app.disable('x-powered-by');
|
||||
//
|
||||
|
||||
var port = process.env.PORT || 8585,
|
||||
oneDay = 86400000,
|
||||
development = process.argv[2] === '--dev';
|
||||
|
||||
// set HTTP headers
|
||||
@ -81,7 +80,14 @@ app.use(function(req, res, next) {
|
||||
// CSP
|
||||
var iframe = development ? "http://" + req.hostname + ":" + port : "https://" + req.hostname; // allow iframe to load assets
|
||||
res.set('Content-Security-Policy', "default-src 'self' " + iframe + "; object-src 'none'; connect-src *; style-src 'self' 'unsafe-inline' " + iframe + "; img-src 'self' data:");
|
||||
return next();
|
||||
// set Cache-control Header (for AppCache)
|
||||
res.set('Cache-control', 'public, max-age=0');
|
||||
next();
|
||||
});
|
||||
|
||||
app.use('/appcache.manifest', function(req, res, next) {
|
||||
res.set('Cache-control', 'no-cache');
|
||||
next();
|
||||
});
|
||||
|
||||
// redirect all http traffic to https
|
||||
@ -97,9 +103,7 @@ app.use(function(req, res, next) {
|
||||
app.use(compression());
|
||||
|
||||
// server static files
|
||||
app.use(express.static(__dirname + '/dist', {
|
||||
maxAge: oneDay
|
||||
}));
|
||||
app.use(express.static(__dirname + '/dist'));
|
||||
|
||||
//
|
||||
// Socket.io proxy
|
||||
|
@ -44,12 +44,19 @@ define(function(require) {
|
||||
imap: {
|
||||
host: 'imap.wmail.io',
|
||||
port: 993,
|
||||
secure: true
|
||||
secure: true,
|
||||
ca: '-----BEGIN CERTIFICATE-----\r\nMIIGiTCCBXGgAwIBAgIDAn03MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ\r\nTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0\r\nYWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg\r\nMiBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTQwOTIxMTQ0ODQ0\r\nWhcNMTYwOTIxMTE0MzIxWjCBmTEZMBcGA1UEDRMQQ1NIeEdsdlg4Z3lRQ2c3TzEL\r\nMAkGA1UEBhMCREUxDzANBgNVBAgTBkJheWVybjEPMA0GA1UEBxMGTXVuaWNoMRUw\r\nEwYDVQQKEwxUYW5rcmVkIEhhc2UxEzARBgNVBAMUCioud21haWwuaW8xITAfBgkq\r\nhkiG9w0BCQEWEndlYm1hc3RlckB3bWFpbC5pbzCCASIwDQYJKoZIhvcNAQEBBQAD\r\nggEPADCCAQoCggEBAMkbMzFfZLYqfWG8yw2HvuNiFs5ajBFMrjG3fobePE674mPd\r\niFtXqbl3ydQ+umTtbJ6bztgxB3KgrL3lhp6IkD4VxB8YQJoYGhU6YH7FhP4QMm8l\r\ncnFLUZXEbcpcCg1tjL6+vvoTMUWEbV/zNtF/oiJ4AIOKwf0zUMZkTu1FCNrOrvpj\r\n6SAkOdBGzLTOAP5vxP43PfpZPZ4dLL2Be7ENYKXqPs0jSlUWpdT9l4AZG8rHKa2d\r\nccWvRoAsCfvpzGDoMYEx9+a1F1XjNZfzo7yJQcHdaE3Mj1eNqbjZe0+Vmact1S/3\r\nsubdcDVkFSfUMsAB5rH0D5mEhy7sMpt1WWCvOF8CAwEAAaOCAuMwggLfMAkGA1Ud\r\nEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD\r\nATAdBgNVHQ4EFgQUv+9x4PISm5Roq4pdNoaFJeIZFfUwHwYDVR0jBBgwFoAUEdsj\r\nRf1UzGpxb4SKA9e+9wEvJoYwHwYDVR0RBBgwFoIKKi53bWFpbC5pb4IId21haWwu\r\naW8wggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgIwggE7BgsrBgEEAYG1NwECAzCC\r\nASowLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w\r\nZGYwgfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0\r\naG9yaXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3Jk\r\naW5nIHRvIHRoZSBDbGFzcyAyIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRo\r\nZSBTdGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRl\r\nbmRlZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkg\r\nb2JsaWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRz\r\nc2wuY29tL2NydDItY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcw\r\nAYYtaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczIvc2VydmVyL2Nh\r\nMEIGCCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIu\r\nY2xhc3MyLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFy\r\ndHNzbC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQDEDbCBvdfs/lEsEJk0xGB6OghO\r\ngUAHplmWJEXoHb0h7p2QAIcs/QKorMDi35bu/J2vbVRIP7i5wBTZLIHBaf03mqAR\r\nZxYFy/ymyROVmmKl1x1/ry1aumomfU86UN8hCkvJc+40V2KC1lCZcjqPWufECjpo\r\n37QXFA+te/rVyVgvoMhIq+zOBZEK0/2mYGCwlpEQo3HElCQIwV9upChOHnQ2jZyF\r\nCmoUyv0JNr8dkh6H7+KTV6FzWaC+b6Liier9bpfEq/zDAp41GR+L/pdbaliSDtRg\r\nfPhAyCZqwsXid6HgIyTBqxUpGDGRiuygqghmqlFfppZuAqz02wrNceDHH7Up\r\n-----END CERTIFICATE-----\r\n',
|
||||
pinned: true,
|
||||
ignoreTLS: false
|
||||
|
||||
},
|
||||
smtp: {
|
||||
host: 'smtp.wmail.io',
|
||||
port: 465,
|
||||
secure: true
|
||||
secure: true,
|
||||
ca: '-----BEGIN CERTIFICATE-----\r\nMIIGiTCCBXGgAwIBAgIDAn03MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ\r\nTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0\r\nYWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg\r\nMiBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTQwOTIxMTQ0ODQ0\r\nWhcNMTYwOTIxMTE0MzIxWjCBmTEZMBcGA1UEDRMQQ1NIeEdsdlg4Z3lRQ2c3TzEL\r\nMAkGA1UEBhMCREUxDzANBgNVBAgTBkJheWVybjEPMA0GA1UEBxMGTXVuaWNoMRUw\r\nEwYDVQQKEwxUYW5rcmVkIEhhc2UxEzARBgNVBAMUCioud21haWwuaW8xITAfBgkq\r\nhkiG9w0BCQEWEndlYm1hc3RlckB3bWFpbC5pbzCCASIwDQYJKoZIhvcNAQEBBQAD\r\nggEPADCCAQoCggEBAMkbMzFfZLYqfWG8yw2HvuNiFs5ajBFMrjG3fobePE674mPd\r\niFtXqbl3ydQ+umTtbJ6bztgxB3KgrL3lhp6IkD4VxB8YQJoYGhU6YH7FhP4QMm8l\r\ncnFLUZXEbcpcCg1tjL6+vvoTMUWEbV/zNtF/oiJ4AIOKwf0zUMZkTu1FCNrOrvpj\r\n6SAkOdBGzLTOAP5vxP43PfpZPZ4dLL2Be7ENYKXqPs0jSlUWpdT9l4AZG8rHKa2d\r\nccWvRoAsCfvpzGDoMYEx9+a1F1XjNZfzo7yJQcHdaE3Mj1eNqbjZe0+Vmact1S/3\r\nsubdcDVkFSfUMsAB5rH0D5mEhy7sMpt1WWCvOF8CAwEAAaOCAuMwggLfMAkGA1Ud\r\nEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD\r\nATAdBgNVHQ4EFgQUv+9x4PISm5Roq4pdNoaFJeIZFfUwHwYDVR0jBBgwFoAUEdsj\r\nRf1UzGpxb4SKA9e+9wEvJoYwHwYDVR0RBBgwFoIKKi53bWFpbC5pb4IId21haWwu\r\naW8wggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgIwggE7BgsrBgEEAYG1NwECAzCC\r\nASowLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w\r\nZGYwgfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0\r\naG9yaXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3Jk\r\naW5nIHRvIHRoZSBDbGFzcyAyIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRo\r\nZSBTdGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRl\r\nbmRlZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkg\r\nb2JsaWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRz\r\nc2wuY29tL2NydDItY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcw\r\nAYYtaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczIvc2VydmVyL2Nh\r\nMEIGCCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIu\r\nY2xhc3MyLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFy\r\ndHNzbC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQDEDbCBvdfs/lEsEJk0xGB6OghO\r\ngUAHplmWJEXoHb0h7p2QAIcs/QKorMDi35bu/J2vbVRIP7i5wBTZLIHBaf03mqAR\r\nZxYFy/ymyROVmmKl1x1/ry1aumomfU86UN8hCkvJc+40V2KC1lCZcjqPWufECjpo\r\n37QXFA+te/rVyVgvoMhIq+zOBZEK0/2mYGCwlpEQo3HElCQIwV9upChOHnQ2jZyF\r\nCmoUyv0JNr8dkh6H7+KTV6FzWaC+b6Liier9bpfEq/zDAp41GR+L/pdbaliSDtRg\r\nfPhAyCZqwsXid6HgIyTBqxUpGDGRiuygqghmqlFfppZuAqz02wrNceDHH7Up\r\n-----END CERTIFICATE-----\r\n',
|
||||
pinned: true,
|
||||
ignoreTLS: false
|
||||
}
|
||||
},
|
||||
gmail: {
|
||||
|
@ -173,24 +173,7 @@ define(function(require) {
|
||||
};
|
||||
|
||||
self.checkForUpdate = function() {
|
||||
if (!window.chrome || !chrome.runtime || !chrome.runtime.onUpdateAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for update and restart
|
||||
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
||||
axe.debug("Updating to version " + details.version);
|
||||
chrome.runtime.reload();
|
||||
});
|
||||
chrome.runtime.requestUpdateCheck(function(status) {
|
||||
if (status === "update_found") {
|
||||
axe.debug("Update pending...");
|
||||
} else if (status === "no_update") {
|
||||
axe.debug("No update found.");
|
||||
} else if (status === "throttled") {
|
||||
axe.debug("Checking updates too frequently.");
|
||||
}
|
||||
});
|
||||
self._updateHandler.checkForUpdate(self.onError);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
// Check if a new ApaCache is available on page load.
|
||||
if (typeof window.applicationCache !== 'undefined') {
|
||||
window.onload = function() {
|
||||
window.applicationCache.onupdateready = function() {
|
||||
if (window.applicationCache.status === window.applicationCache.UPDATEREADY) {
|
||||
// Browser downloaded a new app cache
|
||||
if (window.confirm('A new version of Whiteout Mail is available. Restart the app to update?')) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// hey Angular, we're bootstrapping manually!
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||
|
||||
@ -54,8 +70,6 @@ requirejs([
|
||||
backButtonUtil,
|
||||
FastClick
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
// reset window.name
|
||||
window.name = util.UUID();
|
||||
|
||||
|
@ -29,7 +29,7 @@ define(function(require) {
|
||||
appCtrl._adminDao.createUser({
|
||||
emailAddress: $scope.emailAddress,
|
||||
password: $scope.pass,
|
||||
phone: $scope.phone,
|
||||
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
|
||||
betaCode: $scope.betaCode.toUpperCase()
|
||||
}, function(err) {
|
||||
$scope.busy = false;
|
||||
|
@ -4,8 +4,6 @@ define(function(require) {
|
||||
var appController = require('js/app-controller');
|
||||
|
||||
var LoginCtrl = function($scope, $location) {
|
||||
// check for app update
|
||||
appController.checkForUpdate();
|
||||
|
||||
// start main application controller
|
||||
appController.start({
|
||||
@ -16,6 +14,9 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for app update
|
||||
appController.checkForUpdate();
|
||||
|
||||
initializeUser();
|
||||
});
|
||||
|
||||
@ -92,8 +93,9 @@ define(function(require) {
|
||||
}
|
||||
|
||||
function goTo(location) {
|
||||
$location.path(location);
|
||||
$scope.$apply();
|
||||
$scope.$apply(function() {
|
||||
$location.path(location);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,6 @@ define(function(require) {
|
||||
_ = require('underscore'),
|
||||
appController = require('js/app-controller'),
|
||||
axe = require('axe'),
|
||||
aes = require('js/crypto/aes-gcm'),
|
||||
util = require('js/crypto/util'),
|
||||
str = require('js/app-config').string,
|
||||
pgp, emailDao, outbox, keychainDao, auth;
|
||||
@ -37,7 +36,6 @@ define(function(require) {
|
||||
|
||||
// fill fields depending on replyTo
|
||||
fillFields(replyTo, replyAll, forward);
|
||||
$scope.updatePreview();
|
||||
|
||||
$scope.verify($scope.to[0]);
|
||||
},
|
||||
@ -61,7 +59,6 @@ define(function(require) {
|
||||
$scope.bcc = [];
|
||||
$scope.subject = '';
|
||||
$scope.body = '';
|
||||
$scope.ciphertextPreview = '';
|
||||
$scope.attachments = [];
|
||||
$scope.addressBookCache = undefined;
|
||||
}
|
||||
@ -321,21 +318,6 @@ define(function(require) {
|
||||
// Editing email body
|
||||
//
|
||||
|
||||
// generate key,iv for encryption preview
|
||||
var key = util.random(128),
|
||||
iv = util.random(128);
|
||||
|
||||
$scope.updatePreview = function() {
|
||||
if (!$scope.sendBtnSecure || !$scope.body.trim()) {
|
||||
$scope.ciphertextPreview = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// Although this does encrypt live using AES, this is just for show. The plaintext is encrypted seperately before sending the email.
|
||||
$scope.ciphertextPreview = aes.encrypt($scope.body, key, iv);
|
||||
};
|
||||
$scope.$watch('sendBtnSecure', $scope.updatePreview);
|
||||
|
||||
$scope.sendToOutbox = function() {
|
||||
var email;
|
||||
|
||||
@ -466,27 +448,6 @@ define(function(require) {
|
||||
//
|
||||
|
||||
var ngModule = angular.module('write', []);
|
||||
ngModule.directive('contenteditable', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
// view -> model
|
||||
elm.on('keyup keydown', function() {
|
||||
// set model
|
||||
ctrl.$setViewValue(elm[0].innerText);
|
||||
scope.$digest();
|
||||
});
|
||||
|
||||
// model -> view
|
||||
ctrl.$render = function() {
|
||||
elm[0].innerText = ctrl.$viewValue;
|
||||
};
|
||||
|
||||
// load init value from DOM
|
||||
ctrl.$setViewValue(elm[0].innerText);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
ngModule.directive('focusMe', function($timeout, $parse) {
|
||||
return {
|
||||
@ -496,7 +457,12 @@ define(function(require) {
|
||||
scope.$watch(model, function(value) {
|
||||
if (value === true) {
|
||||
$timeout(function() {
|
||||
element[0].focus();
|
||||
var el = element[0];
|
||||
el.focus();
|
||||
if (typeof el.selectionStart !== 'undefined' && typeof el.selectionEnd !== 'undefined') {
|
||||
el.selectionStart = 0;
|
||||
el.selectionEnd = 0;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
@ -504,17 +470,6 @@ define(function(require) {
|
||||
};
|
||||
});
|
||||
|
||||
ngModule.directive('focusChild', function() {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
link: function(scope, element) {
|
||||
element.on('click', function() {
|
||||
element[0].children[0].focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
ngModule.directive('focusInput', function($timeout, $parse) {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
|
@ -1,7 +1,8 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var cfg = require('js/app-config').config,
|
||||
var axe = require('axe'),
|
||||
cfg = require('js/app-config').config,
|
||||
updateV1 = require('js/util/update/update-v1'),
|
||||
updateV2 = require('js/util/update/update-v2'),
|
||||
updateV3 = require('js/util/update/update-v3'),
|
||||
@ -92,5 +93,40 @@ define(function(require) {
|
||||
executeNextUpdate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check application version and update correspondingly
|
||||
*/
|
||||
UpdateHandler.prototype.checkForUpdate = function(dialog) {
|
||||
// Chrome Packaged App
|
||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.onUpdateAvailable) {
|
||||
// check for Chrome app update and restart
|
||||
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
||||
axe.debug('New Chrome App update... requesting reload.');
|
||||
// Chrome downloaded a new app version
|
||||
dialog({
|
||||
title: 'Update available',
|
||||
message: 'A new version ' + details.version + ' of the app is available. Restart the app to update?',
|
||||
positiveBtnStr: 'Restart',
|
||||
negativeBtnStr: 'Not now',
|
||||
showNegativeBtn: true,
|
||||
callback: function(agree) {
|
||||
if (agree) {
|
||||
chrome.runtime.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
chrome.runtime.requestUpdateCheck(function(status) {
|
||||
if (status === "update_found") {
|
||||
axe.debug("Update pending...");
|
||||
} else if (status === "no_update") {
|
||||
axe.debug("No update found.");
|
||||
} else if (status === "throttled") {
|
||||
axe.debug("Checking updates too frequently.");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return UpdateHandler;
|
||||
});
|
26
src/manifest.webapp
Normal file
26
src/manifest.webapp
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "Whiteout Mail",
|
||||
"description": "Simple and elegant email client with integrated end-to-end encryption. Keeping your emails safe has never been so easy.",
|
||||
"version": "0.17.1.0",
|
||||
"launch_path": "/index.html",
|
||||
"icons": {
|
||||
"128": "/img/icon-128.png"
|
||||
},
|
||||
"developer": {
|
||||
"name": "Whiteout Networks GmbH",
|
||||
"url": "https://whiteout.io"
|
||||
},
|
||||
"default_locale": "en",
|
||||
"type": "privileged",
|
||||
"permissions": {
|
||||
"tcp-socket": {
|
||||
"description": "Required to connect to mail servers via IMAP/SMTP"
|
||||
},
|
||||
"desktop-notification": {
|
||||
"description": "Required to show notifications on incoming mails."
|
||||
},
|
||||
"storage": {
|
||||
"description": "Required to store messages for offline use."
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,8 @@ textarea {
|
||||
line-height: inherit;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
// disable box shadow on firefox
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
|
@ -65,7 +65,7 @@
|
||||
.subject-box {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
margin: 20px 0 7px 0;
|
||||
margin: 20px 0;
|
||||
|
||||
input[type=file] {
|
||||
visibility: hidden;
|
||||
@ -146,33 +146,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
textarea {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: $color-grey-dark;
|
||||
line-height: 1.5em;
|
||||
user-select: text;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
// allow scrolling on iOS
|
||||
-webkit-overflow-scrolling: touch;
|
||||
// put layer on GPU
|
||||
transform: translatez(0);
|
||||
|
||||
*[contentEditable] {
|
||||
outline: 0px;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.encrypt-preview {
|
||||
font-size: 0.9em;
|
||||
margin-top: 3em;
|
||||
font-family: monospace;
|
||||
color: $color-grey-light;
|
||||
word-wrap: break-word;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.send-control {
|
||||
|
@ -16,7 +16,7 @@
|
||||
<input type="file" accept=".asc" file-reader tabindex="1">
|
||||
</div>
|
||||
<div>
|
||||
<input class="input-text" type="password" ng-model="passphrase" ng-class="{'input-text-error':incorrect}" placeholder="Passphrase" tabindex="2" focus-me="true">
|
||||
<input class="input-text" type="password" ng-model="passphrase" ng-class="{'input-text-error':incorrect}" placeholder="Passphrase" tabindex="2">
|
||||
</div>
|
||||
<a href="https://whiteout.io/revocation.html" title="Click here to reset your account." target="_blank">Lost your keyfile or passphrase?</a>
|
||||
<div><button type="submit" wo-touch="confirmPassphrase()" class="btn" ng-disabled="!key" tabindex="3">Import</button>
|
||||
|
@ -58,13 +58,7 @@
|
||||
</span><!--/.attachment-->
|
||||
</div><!--/.attachments-box-->
|
||||
|
||||
<div class="body" focus-child>
|
||||
<p ng-model="body" contentEditable="true" ng-change="updatePreview()" tabindex="3" focus-me="state.lightbox === 'write' && writerTitle === 'Reply'"></p>
|
||||
|
||||
<div class="encrypt-preview" ng-show="ciphertextPreview && sendBtnSecure">
|
||||
<p>-----BEGIN ENCRYPTED PREVIEW-----<br>{{ciphertextPreview}}<br>-----END ENCRYPTED PREVIEW-----</p>
|
||||
</div><!--/.encrypt-preview-->
|
||||
</div><!--/.body-->
|
||||
<textarea ng-model="body" spellcheck="true" focus-me="state.lightbox === 'write' && writerTitle === 'Reply'" tabindex="3"></textarea>
|
||||
|
||||
<div class="send-control">
|
||||
<button wo-touch="sendToOutbox()" class="btn" ng-class="{'btn-primary': sendBtnSecure === false}" ng-disabled="!okToSend" tabindex="4">{{sendBtnText || 'Send'}}</button>
|
||||
|
@ -60,6 +60,7 @@ define(function(require) {
|
||||
it('should fail to error creating user', function(done) {
|
||||
scope.form.$invalid = false;
|
||||
scope.betaCode = 'asfd';
|
||||
scope.phone = '12345';
|
||||
adminStub.createUser.yieldsAsync(new Error('asdf'));
|
||||
|
||||
scope.$apply = function() {
|
||||
@ -76,6 +77,7 @@ define(function(require) {
|
||||
it('should work', function(done) {
|
||||
scope.form.$invalid = false;
|
||||
scope.betaCode = 'asfd';
|
||||
scope.phone = '12345';
|
||||
adminStub.createUser.yieldsAsync();
|
||||
|
||||
scope.$apply = function() {
|
||||
|
@ -64,7 +64,6 @@ define(function(require) {
|
||||
expect(scope.state.writer.close).to.exist;
|
||||
expect(scope.verify).to.exist;
|
||||
expect(scope.checkSendStatus).to.exist;
|
||||
expect(scope.updatePreview).to.exist;
|
||||
expect(scope.sendToOutbox).to.exist;
|
||||
expect(scope.tagStyle).to.exist;
|
||||
expect(scope.lookupAddressBook).to.exist;
|
||||
@ -91,7 +90,6 @@ define(function(require) {
|
||||
expect(scope.to).to.deep.equal([]);
|
||||
expect(scope.subject).to.equal('');
|
||||
expect(scope.body).to.equal('');
|
||||
expect(scope.ciphertextPreview).to.equal(undefined);
|
||||
expect(verifyMock.calledOnce).to.be.true;
|
||||
|
||||
scope.verify.restore();
|
||||
@ -124,7 +122,6 @@ define(function(require) {
|
||||
expect(scope.subject).to.equal('Re: ' + subject);
|
||||
expect(scope.body).to.contain(body);
|
||||
expect(scope.references).to.deep.equal(['ghi', 'def', 'abc']);
|
||||
expect(scope.ciphertextPreview).to.not.be.empty;
|
||||
expect(verifyMock.called).to.be.true;
|
||||
|
||||
scope.verify.restore();
|
||||
@ -156,7 +153,6 @@ define(function(require) {
|
||||
expect(scope.to).to.deep.equal([]);
|
||||
expect(scope.subject).to.equal('Fwd: ' + subject);
|
||||
expect(scope.body).to.contain(body);
|
||||
expect(scope.ciphertextPreview).to.be.undefined;
|
||||
expect(verifyMock.called).to.be.true;
|
||||
expect(scope.attachments).to.not.equal(re.attachments); // not the same reference
|
||||
expect(scope.attachments).to.deep.equal(re.attachments); // but the same content
|
||||
|
Loading…
Reference in New Issue
Block a user