diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..49c0fc0 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,4 @@ +{ + "directory": "vendor", + "strict-ssl": true +} diff --git a/Gruntfile.js b/Gruntfile.js index c9133f4..6c41589 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -3,14 +3,14 @@ var _ = require("lodash"), util = require("util"); -var appVersion = '2.0.5'; +var appVersion = '2.0.8'; var apiVersion = '1'; +var dateVersion = '14 August 2015'; var clientID = 'Angular'; var clientSecret = '00a11965ac0b47782ec7359c5af4dd79'; var BROWSERS = ["PhantomJS", "Chrome", "Firefox", "Safari"]; var API_TARGETS = { - prod: "https://dev.protonmail.ch/api", - dev: "https://test-api.protonmail.ch", + prod: "https://protonmail.ch/api", build: "/api" }; @@ -105,6 +105,7 @@ module.exports = function(grunt) { apiUrl: apiUrl(), app_version: appVersion, api_version: apiVersion, + date_version: dateVersion, clientID: clientID, clientSecret: clientSecret } @@ -117,6 +118,7 @@ module.exports = function(grunt) { apiUrl: apiUrl(), app_version: appVersion, api_version: apiVersion, + date_version: dateVersion, clientID: clientID, clientSecret: clientSecret } diff --git a/package.json b/package.json index 92c6192..aa486eb 100755 --- a/package.json +++ b/package.json @@ -51,8 +51,7 @@ "sinon": "^1.9.1", "sinon-chai": "^2.5.0" }, - "private": true, - "license": "All rights reserved.", + "license": "MIT", "scripts": { "test": "grunt compile" } diff --git a/src/app.html b/src/app.html index 5abc1d8..2b05e9f 100755 --- a/src/app.html +++ b/src/app.html @@ -18,7 +18,7 @@ <% styles.forEach(function (file) { %> <% }); %> - + 0) { notify.closeAll(); notify($translate.instant('MAXIMUM_COMPOSER_REACHED')); @@ -292,7 +296,7 @@ angular.module("proton.controllers.Messages.Compose", ["proton.constants"]) } // We need to hide EVERYHTING on mobile, otherwise we get lag. - if (tools.findBootstrapEnvironment()==='sm' || tools.findBootstrapEnvironment()==='xs') { + if (tools.findBootstrapEnvironment() === 'sm' || tools.findBootstrapEnvironment()==='xs') { $rootScope.mobileComposerIsOpen = true; } else { @@ -664,14 +668,21 @@ angular.module("proton.controllers.Messages.Compose", ["proton.constants"]) }); }; + /** + * Determine if we need to save the message + */ $scope.needToSave = function(message) { - if(angular.isDefined(message.old)) { - var currentMessage = _.pick(message, $scope.oldProperties); - var oldMessage = _.pick(message.old, $scope.oldProperties); - - return JSON.stringify(oldMessage) !== JSON.stringify(currentMessage); + if($scope.saving === true) { // Current backup + return false; } else { - return true; + if(angular.isDefined(message.old)) { + var currentMessage = _.pick(message, $scope.oldProperties); + var oldMessage = _.pick(message.old, $scope.oldProperties); + + return JSON.stringify(oldMessage) !== JSON.stringify(currentMessage); + } else { + return true; + } } }; @@ -744,13 +755,20 @@ angular.module("proton.controllers.Messages.Compose", ["proton.constants"]) return true; }; + $scope.saveNewContacts = function(message) { + // contactManager.save(message); + }; + $scope.save = function(message, silently, forward) { message.saved++; + var deferred = $q.defer(); var parameters = { Message: _.pick(message, 'ToList', 'CCList', 'BCCList', 'Subject', 'IsRead') }; + $scope.saving = true; + if (typeof parameters.Message.ToList === 'string') { parameters.Message.ToList = []; } @@ -834,6 +852,9 @@ angular.module("proton.controllers.Messages.Compose", ["proton.constants"]) var validate = $scope.validate(message); if(validate) { + if(authentication.user.AutoSaveContacts === 1) { + $scope.saveNewContacts(message); + } $scope.save(message, false).then(function() { var parameters = {}; @@ -974,7 +995,6 @@ angular.module("proton.controllers.Messages.Compose", ["proton.constants"]) }; $scope.openCloseModal = function(message, save) { - message.editor.removeEventListener('input', function() { $scope.saveLater(message); }); diff --git a/src/app/controllers/message.list.js b/src/app/controllers/message.list.js index 3ce9710..67056af 100755 --- a/src/app/controllers/message.list.js +++ b/src/app/controllers/message.list.js @@ -313,8 +313,10 @@ angular.module("proton.controllers.Messages.List", ["proton.constants"]) setTimeout( function() { $('#draggableMailsHelper strong b').text($scope.selectedMessages().length); }, 20); + $('body').addClass('dragging'); $('#main').append('
'); + if(message && !!!message.Selected) { message.Selected = true; $scope.$apply(); @@ -323,6 +325,7 @@ angular.module("proton.controllers.Messages.List", ["proton.constants"]) $scope.onEndDragging = function(event, ui, message) { $('body').removeClass('dragging'); + $('#dragOverlay').fadeOut(200, function() { $(this).remove(); }); @@ -447,8 +450,10 @@ angular.module("proton.controllers.Messages.List", ["proton.constants"]) }; $scope.unselectAllMessages = function() { - _.forEach($scope.messages, function(message) { - message.Selected = false; + $scope.$apply(function() { + _.forEach($scope.messages, function(message) { + message.Selected = false; + }); }); }; @@ -685,6 +690,8 @@ angular.module("proton.controllers.Messages.List", ["proton.constants"]) $scope.unselectAllMessages(); deferred.resolve(); } + + $scope.unselectAllLabels(); }); networkActivityTracker.track(deferred.promise); diff --git a/src/app/controllers/message.view.js b/src/app/controllers/message.view.js index e350117..91ba3f4 100755 --- a/src/app/controllers/message.view.js +++ b/src/app/controllers/message.view.js @@ -46,12 +46,14 @@ angular.module("proton.controllers.Messages.View", ["proton.constants"]) $scope.message = _.extend($scope.message, m); }); - $(window).on('resize', function() { + function onResize() { $scope.setMessageHeadHeight(); - }); + } + + $(window).on('resize', onResize); $scope.$on('$destroy', function() { - $(window).off('resize'); + $(window).off('resize', onResize); // cancel timer ago $interval.cancel($scope.agoTimer); }); @@ -108,19 +110,7 @@ angular.module("proton.controllers.Messages.View", ["proton.constants"]) }; $scope.saveNewContacts = function() { - var newContacts = _.filter(message.ToList.concat(message.CCList).concat(message.BCCList), function(email) { - return contactManager.isItNew(email); - }); - - _.each(newContacts, function(email) { - contactManager.add(email); - email.Email = email.Address; - email.Name = email.Name || email.Address; - }); - - if (newContacts.length > 0) { - contactManager.send(newContacts); - } + // contactManager.save(message); }; $scope.getFrom = function() { diff --git a/src/app/controllers/outside.js b/src/app/controllers/outside.js index 9885572..72e6289 100755 --- a/src/app/controllers/outside.js +++ b/src/app/controllers/outside.js @@ -60,11 +60,16 @@ angular.module("proton.controllers.Outside", [ $scope.addAttachment(file_array); }); }, 100); - +// http://localhost:8080/eo/fABD0Izp5boBsA3Q7BaP7F-nNeGvOPVLNIwW_oqUcHWqTlCojye_qm9-mHQLVjlbBCtw4W2vpyJBSdTccBxzGA== // start timer ago $scope.agoTimer = $interval(function() { var time = $filter('longReadableTime')($scope.message.Time); + if($scope.isExpired()) { + // Redirect to unlock view if the message is expire + $state.go('eo.unlock', {tag: $stateParams.tag}); + } + $scope.ago = time; }, 1000); @@ -73,6 +78,16 @@ angular.module("proton.controllers.Outside", [ $interval.cancel($scope.agoTimer); }); + /** + * Determine if the message is expire + */ + $scope.isExpired = function() { + var time = moment.unix($scope.message.Time); + var current = moment.unix(); + + return current.isAfter(time); + }; + $scope.selectFile = function() { $('#inputFile').click(); }; diff --git a/src/app/controllers/settings.js b/src/app/controllers/settings.js index 9c339ec..89277f6 100755 --- a/src/app/controllers/settings.js +++ b/src/app/controllers/settings.js @@ -5,26 +5,26 @@ angular.module("proton.controllers.Settings", [ ]) .controller("SettingsController", function( + $log, + $rootScope, + $scope, $state, $stateParams, - $scope, - $rootScope, - $log, $timeout, + $translate, $window, - authentication, - confirmModal, - labelModal, - url, Label, Logs, Setting, User, - tools, - pmcw, - notify, + authentication, + confirmModal, + labelModal, networkActivityTracker, - $translate + notify, + pmcw, + tools, + url ) { $rootScope.pageName = "settings"; $scope.tools = tools; @@ -122,7 +122,7 @@ angular.module("proton.controllers.Settings", [ $scope.exportPublicKey = function () { var pbk = authentication.user.PublicKey; - var blob = new Blob([pbk], { type: 'data:text/plain;base64;' }); + var blob = new Blob([pbk], { type: 'data:text/plain;charset=utf-8;' }); var filename = 'protonmail_public_' + authentication.user.Name + '.txt'; saveAs(blob, filename); @@ -131,7 +131,7 @@ angular.module("proton.controllers.Settings", [ // NOT USED $scope.exportEncPrivateKey = function () { var pbk = authentication.user.EncPrivateKey; - var blob = new Blob([pbk], { type: 'data:text/plain;base64;' }); + var blob = new Blob([pbk], { type: 'data:text/plain;charset=utf-8;' }); var filename = 'protonmail_private_'+authentication.user.Name+'.txt'; saveAs(blob, filename); @@ -247,19 +247,21 @@ angular.module("proton.controllers.Settings", [ $scope.saveMailboxPassword = function(form) { var oldMailPwd = $scope.oldMailboxPassword; var newMailPwd = $scope.newMailboxPassword; + var newEncPrivateKey = pmcrypto.getNewEncPrivateKey(authentication.user.EncPrivateKey, oldMailPwd, newMailPwd); - var currentMailboxPassword = $scope.currentMailboxPassword; + var currentLoginPassword = $scope.currentLoginPassword; if (newEncPrivateKey === -1) { notify($translate.instant('WRONG_CURRENT_MAILBOX_PASSWORD')); } - else if (newEncPrivateKey.length < 50) { - notify(newEncPrivateKey); + else if ( Error.prototype.isPrototypeOf(newEncPrivateKey) ) { + // Error messages from OpenPGP.js + notify(newEncPrivateKey.message); } else { networkActivityTracker.track( User.keys({ - "Password": currentMailboxPassword, + "Password": currentLoginPassword, "PublicKey": authentication.user.PublicKey, "PrivateKey": newEncPrivateKey }).$promise.then(function(response) { @@ -270,7 +272,7 @@ angular.module("proton.controllers.Settings", [ $scope.oldMailboxPassword = ''; $scope.newMailboxPassword = ''; $scope.confirmMailboxPassword = ''; - $scope.currentMailboxPassword = ''; + $scope.currentLoginPassword = ''; authentication.user.EncPrivateKey = newEncPrivateKey; authentication.savePassword(newMailPwd); form.$setUntouched(); @@ -355,11 +357,11 @@ angular.module("proton.controllers.Settings", [ notify($translate.instant('LABEL_CREATED')); $scope.labels.push(result.Label); } else { - notify(result.error); + notify(result.Error); $log.error(result); } }, function(result) { - notify(result.error); + notify(result.Error); $log.error(result); }) ); diff --git a/src/app/controllers/sidebar.js b/src/app/controllers/sidebar.js index c46fa2a..4fd38f2 100755 --- a/src/app/controllers/sidebar.js +++ b/src/app/controllers/sidebar.js @@ -36,15 +36,17 @@ angular.module("proton.controllers.Sidebar", ["proton.constants"]) $scope.labelScroller(); }); - $(window).bind('resize', function() { - $scope.labelScroller(); - }); + $(window).bind('resize', $scope.onResize); $scope.$on("$destroy", function() { - $(window).unbind('resize'); + $(window).unbind('resize', $scope.onResize); }); }; + $scope.onResize = function() { + $scope.labelScroller(); + }; + $scope.updateLabels = function () { $scope.labels = authentication.user.Labels; }; diff --git a/src/app/controllers/signup.js b/src/app/controllers/signup.js index b0cc634..a0b3416 100755 --- a/src/app/controllers/signup.js +++ b/src/app/controllers/signup.js @@ -36,6 +36,8 @@ angular.module("proton.controllers.Signup", ["proton.tools"]) $scope.getUserInfo = false; $scope.finishCreation = false; + $scope.maxPW = CONSTANTS.LOGIN_PW_MAX_LEN; + $scope.account = []; // Prepoppulate the username if from an invite link @@ -93,7 +95,7 @@ angular.module("proton.controllers.Signup", ["proton.tools"]) $log.debug('finish'); if (form.$valid) { $log.debug('finish: form valid'); - return $scope.generateKeys('UserID', $scope.account.mailboxPassword); + return $scope.generateKeys($scope.account.Username, $scope.account.mailboxPassword); } }; @@ -163,8 +165,8 @@ angular.module("proton.controllers.Signup", ["proton.tools"]) User.available({ username: $scope.account.Username }).$promise .then( function(response) { - if (response.error) { - var error_message = (response.error) ? response.error : (response.statusText) ? response.statusText : 'Error.'; + if (response.Error) { + var error_message = (response.Error) ? response.Error : (response.statusText) ? response.statusText : 'Error.'; $('#Username').focus(); deferred.reject(error_message); } @@ -194,7 +196,7 @@ angular.module("proton.controllers.Signup", ["proton.tools"]) else if ($scope.account.mailboxPassword!==undefined) { mbpw = $scope.account.mailboxPassword; } - return $scope.generateKeys('UserID', mbpw); + return $scope.generateKeys($scope.account.Username + '@protonmail.ch', mbpw); }; $scope.doCreateUser = function() { diff --git a/src/app/directives/countdown.js b/src/app/directives/countdown.js index c39cdbe..33442c2 100755 --- a/src/app/directives/countdown.js +++ b/src/app/directives/countdown.js @@ -39,7 +39,7 @@ angular.module("proton.countdown", []) var newTitle = days + ' days ' + hours + ' hours ' + minutes + ' minutes ' + seconds + ' seconds'; // Show how many days, hours, minutes and seconds are left - if($attr.outside === true) { + if($attrs.outside) { $($element).text(newTitle); } else { $($element).attr('title', newTitle) diff --git a/src/app/libraries/pmcrypto.js b/src/app/libraries/pmcrypto.js index 14868d3..59b4416 100755 --- a/src/app/libraries/pmcrypto.js +++ b/src/app/libraries/pmcrypto.js @@ -330,7 +330,7 @@ var pmcrypto = (function() { } var _prKey = openpgp.key.readArmored(prKey).keys[0]; if (_prKey === undefined) { - return new Error('Cant read PRK.'); + return new Error('Cannot read private key.'); } var ok = _prKey.decrypt(oldMailPwd); if (ok) { diff --git a/src/app/models/events.js b/src/app/models/events.js index 937c240..56031ec 100755 --- a/src/app/models/events.js +++ b/src/app/models/events.js @@ -6,9 +6,6 @@ angular.module("proton.models.events", []) }, getLatestID: function () { return $http.get(url.get() + '/events/latest'); - }, - getNoticies: function () { - return $http.get(url.get() + '/events/notices'); } }; }); diff --git a/src/app/models/message.js b/src/app/models/message.js index bdf1762..c41a2ae 100755 --- a/src/app/models/message.js +++ b/src/app/models/message.js @@ -412,7 +412,7 @@ angular.module("proton.models.message", ["proton.constants"]) generateReplyToken: function() { // Use a base64-encoded AES256 session key as the reply token - return pmcw.encode_base64(pmcw.generateKeyAES()); + return pmcw.encode_base64(pmcw.arrayToBinaryString(pmcw.generateKeyAES())); }, clearTextBody: function() { diff --git a/src/app/routes.js b/src/app/routes.js index c0b33f7..3b3aa22 100755 --- a/src/app/routes.js +++ b/src/app/routes.js @@ -442,7 +442,7 @@ angular.module("proton.routes", [ views: { "content": { templateUrl: "templates/views/outside.unlock.tpl.html", - controller: function($scope, $state, $stateParams, pmcw, encryptedToken, networkActivityTracker) { + controller: function($scope, $state, $stateParams, pmcw, encryptedToken, networkActivityTracker, notify) { $scope.params = {}; $scope.params.MessagePassword = ''; @@ -460,6 +460,8 @@ angular.module("proton.routes", [ window.sessionStorage["proton:decrypted_token"] = decryptedToken; window.sessionStorage["proton:encrypted_password"] = pmcw.encode_utf8_base64($scope.params.MessagePassword); $state.go('eo.message', {tag: $stateParams.tag}); + }, function(error) { + notify({message: error, classes: 'notification-danger'}); }); }; } diff --git a/src/app/services/contacts.js b/src/app/services/contacts.js index 11114c2..f99dd3b 100755 --- a/src/app/services/contacts.js +++ b/src/app/services/contacts.js @@ -2,6 +2,30 @@ angular.module("proton.contacts", []) .service('contactManager', function($rootScope, Contact) { return { + save: function(message) { + var list = message.ToList.concat(message.CCList).concat(message.BCCList); + + if(angular.isDefined(message.SenderAddress)) { + list.push({ + Address: message.SenderAddress, + Name: message.SenderName || message.SenderAddress + }); + } + + var newContacts = _.filter(list, function(email) { + return this.isItNew(email); + }.bind(this)); + + _.each(newContacts, function(email) { + this.add(email); + email.Email = email.Address; + email.Name = email.Name || email.Address; + }.bind(this)); + + if (newContacts.length > 0) { + this.send(newContacts); + } + }, isItNew: function(email) { return typeof _.findWhere($rootScope.user.Contacts, {Email: email.Address}) === 'undefined'; }, diff --git a/src/app/services/event.js b/src/app/services/event.js index 834590e..2ac29ba 100755 --- a/src/app/services/event.js +++ b/src/app/services/event.js @@ -1,6 +1,6 @@ angular.module("proton.event", ["proton.constants"]) .service("eventManager", function ( - $interval, + $timeout, $window, $state, $rootScope, @@ -31,11 +31,6 @@ angular.module("proton.event", ["proton.constants"]) isDifferent: function (eventID) { return this.ID !== eventID; }, - checkNotice: function() { - return Events.getNoticies({}).then(function(response) { - return response; - }); - }, manageLabels: function(labels) { if (angular.isDefined(labels)) { _.each(labels, function(label) { @@ -132,6 +127,7 @@ angular.module("proton.event", ["proton.constants"]) } }, manage: function (data) { + // Check if eventID is sent if (data.Error) { Events.getLatestID({}).then(function(response) { @@ -154,27 +150,45 @@ angular.module("proton.event", ["proton.constants"]) } this.manageNotices(data.Notices); messageCache.manageExpire(); + }, + interval: function() { + eventModel.get().then(function (result) { + + // Check for force upgrade + if ( result.data.Code && parseInt(result.data.Code) === 5003 ) { + // Force upgrade, kill event loop + eventModel.promiseCancel = undefined; + return; + } + + // Schedule next event API call, do it here so a crash in managing events doesn't kill the loop forever + if ( angular.isDefined(eventModel.promiseCancel) ) { + eventModel.promiseCancel = $timeout(eventModel.interval, CONSTANTS.INTERVAL_EVENT_TIMER); + } + + eventModel.manage(result.data); + }, + function(err) { + // Try again later + if ( angular.isDefined(eventModel.promiseCancel) ) { + eventModel.promiseCancel = $timeout(eventModel.interval, CONSTANTS.INTERVAL_EVENT_TIMER); + } + }); } }; - var started = false; + var api = _.bindAll({ start: function () { - if (!started) { + if (angular.isUndefined(eventModel.promiseCancel)) { eventModel.ID = window.sessionStorage[CONSTANTS.EVENT_ID]; - interval = function() { - eventModel.get().then(function (result) { - eventModel.manage(result.data); - }); - }; - interval(); - eventModel.promiseCancel = $interval(interval, CONSTANTS.INTERVAL_EVENT_TIMER); - started = true; + eventModel.promiseCancel = $timeout(eventModel.interval, 0); } }, stop: function () { messageCache.empty(); - if (angular.isDefinded(eventModel.promiseCancel)) { - $interval.cancel(eventModel.promiseCancel); + if (angular.isDefined(eventModel.promiseCancel)) { + $timeout.cancel(eventModel.promiseCancel); + eventModel.promiseCancel = undefined; } } diff --git a/src/app/services/modal.js b/src/app/services/modal.js index 7b34d2c..a9cde3c 100755 --- a/src/app/services/modal.js +++ b/src/app/services/modal.js @@ -1,6 +1,14 @@ angular.module("proton.modals", []) -.factory('pmModal', ['$animate', '$compile', '$rootScope', '$controller', '$q', '$http', '$templateCache', function($animate, $compile, $rootScope, $controller, $q, $http, $templateCache) { +.factory('pmModal', function( + $animate, + $compile, + $rootScope, + $controller, + $q, + $http, + $templateCache +) { return function modalFactory(config) { if (!(!config.template ^ !config.templateUrl)) { throw new Error('Expected modal to have exacly one of either template or templateUrl'); @@ -84,7 +92,7 @@ angular.module("proton.modals", []) active: active }; }; -}]) +}) // confirm modal .factory('confirmModal', function(pmModal) { @@ -221,20 +229,6 @@ angular.module("proton.modals", []) '#c6cd97', '#e7d292', '#dfb286' - // '#f66', - // '#ff9', - // '#f6f', - // '#6ff', - // '#66f', - // '#6f6', - // '#999', - // '#fcc', - // '#ffc', - // '#fcf', - // '#cff', - // '#ccf', - // '#cfc', - // '#ccc' ]; if(angular.isDefined(params.label)) { diff --git a/src/app/services/tools.js b/src/app/services/tools.js index a41131e..85c106c 100755 --- a/src/app/services/tools.js +++ b/src/app/services/tools.js @@ -359,7 +359,7 @@ angular.module("proton.tools", ["proton.constants"]) } function transform_links(id) { - $('#' + id).find('a[href^=http]').attr('target','_blank'); + $('#' + id).find('a[href^=http]').attr('target','_blank').attr('rel', 'noreferrer'); } function contains_image(content) { diff --git a/src/app/templates/directives/squire.tpl.html b/src/app/templates/directives/squire.tpl.html index 02b3a5d..5652d2d 100755 --- a/src/app/templates/directives/squire.tpl.html +++ b/src/app/templates/directives/squire.tpl.html @@ -24,7 +24,23 @@
  • - + + +
  • +
  • +
  • + + + +
  • +
  • + + + +
  • +
  • + +
  • diff --git a/src/app/templates/layout/login.tpl.html b/src/app/templates/layout/login.tpl.html index c41f7b7..f5c5726 100755 --- a/src/app/templates/layout/login.tpl.html +++ b/src/app/templates/layout/login.tpl.html @@ -10,8 +10,9 @@
    -

    v{{ app_version }}

    +

    v{{ app_version }} - {{ date_version }}

    +

    Click here for the old site.

    - \ No newline at end of file + diff --git a/src/app/templates/partials/composer.tpl.html b/src/app/templates/partials/composer.tpl.html index 2ff5337..495b88a 100755 --- a/src/app/templates/partials/composer.tpl.html +++ b/src/app/templates/partials/composer.tpl.html @@ -57,7 +57,7 @@ -
    +
    diff --git a/src/app/templates/partials/form.bug.tpl.html b/src/app/templates/partials/form.bug.tpl.html index 3816a37..5c3c079 100755 --- a/src/app/templates/partials/form.bug.tpl.html +++ b/src/app/templates/partials/form.bug.tpl.html @@ -49,7 +49,7 @@
    - +

    Please make sure to give us a way to contact you.

    diff --git a/src/app/templates/partials/sidebar.tpl.html b/src/app/templates/partials/sidebar.tpl.html index a73639b..8896ffe 100755 --- a/src/app/templates/partials/sidebar.tpl.html +++ b/src/app/templates/partials/sidebar.tpl.html @@ -121,7 +121,7 @@ -

    - {{ 'SIGN_UP' | translate }} -

    diff --git a/src/app/templates/views/security.tpl.html b/src/app/templates/views/security.tpl.html index 8ec7401..33ea6ab 100755 --- a/src/app/templates/views/security.tpl.html +++ b/src/app/templates/views/security.tpl.html @@ -4,8 +4,8 @@
    -

    Key Export

    -

    Download your PublicKey for use in other PGP compatible services.

    +

    Key Export (Experimental)

    +

    Download your Public Key for use with other PGP compatible services. Only incoming messages in inline OpenPGP format are currently supported.

    Download PublicKey @@ -44,9 +44,9 @@

    {{ 'AUTHENTICATION_LOGS' | translate }}

    No logs yet.

      -
    • diff --git a/src/app/templates/views/settings.tpl.html b/src/app/templates/views/settings.tpl.html index c661fa9..59bb98e 100755 --- a/src/app/templates/views/settings.tpl.html +++ b/src/app/templates/views/settings.tpl.html @@ -62,7 +62,7 @@
      - +
      @@ -80,7 +80,7 @@
      @@ -104,6 +104,7 @@
    diff --git a/src/app/templates/views/step1.tpl.html b/src/app/templates/views/step1.tpl.html index a7f4b05..5eb7964 100755 --- a/src/app/templates/views/step1.tpl.html +++ b/src/app/templates/views/step1.tpl.html @@ -84,6 +84,7 @@

    {{ 'CREATE_YOUR_ACCOUNT' | translate }}

    type="password" class="form-control" placeholder="Password" + maxlength="{{ maxPW }}" required />

    Login password is required.

    diff --git a/src/app/templates/views/theme.tpl.html b/src/app/templates/views/theme.tpl.html index a169920..a89029a 100755 --- a/src/app/templates/views/theme.tpl.html +++ b/src/app/templates/views/theme.tpl.html @@ -70,7 +70,8 @@
    Custom Theme
    -

    Custom themes from third-parties can potentially betray your privacy. Only use themes from trusted sources.

    +

    Custom themes from third-parties can potentially betray your privacy. Only use themes from trusted sources.

    +

    Themes are currently disabled because they are not compatible between versions 1.16 and 2.0. In the next few weeks, all current themes will be deleted and then custom themes will be re-enabled. Please archive any custom theme code you wish to keep.

    {{ 'THEMES_ARE_LIMITED' | translate }}.

    diff --git a/src/assets/locales/de_DE.json b/src/assets/locales/de_DE.json index aaa27eb..205f8a5 100755 --- a/src/assets/locales/de_DE.json +++ b/src/assets/locales/de_DE.json @@ -8,8 +8,12 @@ "ADVANCED_SEARCH": "", "ALIASES": "", "ALIASES_SAVED": "", + "ALIGN_CENTER": "", + "ALIGN_LEFT": "", + "ALIGN_RIGHT": "", "ALL": "", "ALL_MESSAGES": "", + "AND_ALSO_ARCHIVE": "", "ARCHIVE": "", "ATTACHMENTS": "", "AUTHENTICATION_LOGS": "", @@ -56,6 +60,7 @@ "DEFAULT_COMPOSER_MODE": "", "DEFAULT_LANGUAGE_CHANGED": "", "DELETE": "", + "DELETE_ALL_CONTACTS": "", "DELETE_CONTACT": "", "DELETE_CONTACTS": "", "DELETE_LABEL": "", @@ -93,6 +98,7 @@ "FOLDER": "", "FOLDER_EMPTIED": "", "FORGOT_PASSWORD?": "", + "FORGOT_USERNAME?": "", "FORWARD": "", "FROM": "", "FULLSCREEN": "", @@ -199,7 +205,7 @@ "SHOW": "", "SHOW_ALL": "", "SHOW_IMAGES": "", - "SIGN_UP": "", + "SIGN_UP_FOR_PROTONMAIL": "", "SIGNATURE": "", "SIGNATURE_CONTENT": "", "SIGNATURE_SAVED": "", @@ -242,6 +248,7 @@ "WARNING": "", "WHAT_ARE_ALIASES?": "", "WHAT_HAPPENED?": "", + "WHAT_IS_THE_DISPLAY_NAME?": "", "WIZARD": "", "WRONG_CURRENT_MAILBOX_PASSWORD": "", "YES": "", diff --git a/src/assets/locales/en_US.json b/src/assets/locales/en_US.json index f4c5e27..a167f68 100755 --- a/src/assets/locales/en_US.json +++ b/src/assets/locales/en_US.json @@ -8,8 +8,12 @@ "ADVANCED_SEARCH": "Advanced Search", "ALIASES": "Aliases", "ALIASES_SAVED": "Aliases Saved", + "ALIGN_CENTER": "Align Center", + "ALIGN_LEFT": "Align Left", + "ALIGN_RIGHT": "Align Right", "ALL": "All", "ALL_MESSAGES": "All Messages", + "AND_ALSO_ARCHIVE": "And Also Archive", "ARCHIVE": "Archive", "ATTACHMENTS": "Attachments", "AUTHENTICATION_LOGS": "Authentication Logs", @@ -56,6 +60,7 @@ "DEFAULT_COMPOSER_MODE": "Default Composer Mode", "DEFAULT_LANGUAGE_CHANGED": "Default Language Changed", "DELETE": "Delete", + "DELETE_ALL_CONTACTS": "Delete All Contacts", "DELETE_CONTACT": "Delete Contact", "DELETE_CONTACTS": "Delete Contacts", "DELETE_LABEL": "Delete Label", @@ -93,6 +98,7 @@ "FOLDER": "Folder", "FOLDER_EMPTIED": "Folder Emptied", "FORGOT_PASSWORD?": "Forgot Password?", + "FORGOT_USERNAME?": "Forgot Username?", "FORWARD": "Forward", "FROM": "From", "FULLSCREEN": "Fullscreen", @@ -199,7 +205,7 @@ "SHOW": "Show", "SHOW_ALL": "Show All", "SHOW_IMAGES": "Show Images", - "SIGN_UP": "Sign Up", + "SIGN_UP_FOR_PROTONMAIL": "Sign Up For ProtonMail", "SIGNATURE": "Signature", "SIGNATURE_CONTENT": "Signature Content", "SIGNATURE_SAVED": "Signature Saved", @@ -242,6 +248,7 @@ "WARNING": "Warning", "WHAT_ARE_ALIASES?": "What Are Aliases?", "WHAT_HAPPENED?": "What happened?", + "WHAT_IS_THE_DISPLAY_NAME?": "What Is The Display Name?", "WIZARD": "Wizard", "WRONG_CURRENT_MAILBOX_PASSWORD": "Wrong Current Mailbox Password", "YES": "Yes", diff --git a/src/assets/locales/es_ES.json b/src/assets/locales/es_ES.json index aaa27eb..205f8a5 100755 --- a/src/assets/locales/es_ES.json +++ b/src/assets/locales/es_ES.json @@ -8,8 +8,12 @@ "ADVANCED_SEARCH": "", "ALIASES": "", "ALIASES_SAVED": "", + "ALIGN_CENTER": "", + "ALIGN_LEFT": "", + "ALIGN_RIGHT": "", "ALL": "", "ALL_MESSAGES": "", + "AND_ALSO_ARCHIVE": "", "ARCHIVE": "", "ATTACHMENTS": "", "AUTHENTICATION_LOGS": "", @@ -56,6 +60,7 @@ "DEFAULT_COMPOSER_MODE": "", "DEFAULT_LANGUAGE_CHANGED": "", "DELETE": "", + "DELETE_ALL_CONTACTS": "", "DELETE_CONTACT": "", "DELETE_CONTACTS": "", "DELETE_LABEL": "", @@ -93,6 +98,7 @@ "FOLDER": "", "FOLDER_EMPTIED": "", "FORGOT_PASSWORD?": "", + "FORGOT_USERNAME?": "", "FORWARD": "", "FROM": "", "FULLSCREEN": "", @@ -199,7 +205,7 @@ "SHOW": "", "SHOW_ALL": "", "SHOW_IMAGES": "", - "SIGN_UP": "", + "SIGN_UP_FOR_PROTONMAIL": "", "SIGNATURE": "", "SIGNATURE_CONTENT": "", "SIGNATURE_SAVED": "", @@ -242,6 +248,7 @@ "WARNING": "", "WHAT_ARE_ALIASES?": "", "WHAT_HAPPENED?": "", + "WHAT_IS_THE_DISPLAY_NAME?": "", "WIZARD": "", "WRONG_CURRENT_MAILBOX_PASSWORD": "", "YES": "", diff --git a/src/assets/locales/fr_FR.json b/src/assets/locales/fr_FR.json index af2969d..4e85691 100755 --- a/src/assets/locales/fr_FR.json +++ b/src/assets/locales/fr_FR.json @@ -8,8 +8,12 @@ "ADVANCED_SEARCH": "Advanced Search", "ALIASES": "", "ALIASES_SAVED": "Alias sauve", + "ALIGN_CENTER": "", + "ALIGN_LEFT": "", + "ALIGN_RIGHT": "", "ALL": "Tous", "ALL_MESSAGES": "Tous Les Messages", + "AND_ALSO_ARCHIVE": "", "ARCHIVE": "Archive", "ATTACHMENTS": "Pieces Jointes", "AUTHENTICATION_LOGS": "", @@ -56,6 +60,7 @@ "DEFAULT_COMPOSER_MODE": "", "DEFAULT_LANGUAGE_CHANGED": "", "DELETE": "Supprimer", + "DELETE_ALL_CONTACTS": "", "DELETE_CONTACT": "", "DELETE_CONTACTS": "", "DELETE_LABEL": "", @@ -93,6 +98,7 @@ "FOLDER": "Dossier", "FOLDER_EMPTIED": "", "FORGOT_PASSWORD?": "", + "FORGOT_USERNAME?": "", "FORWARD": "Transferer", "FROM": "De", "FULLSCREEN": "", @@ -199,7 +205,7 @@ "SHOW": "", "SHOW_ALL": "", "SHOW_IMAGES": "", - "SIGN_UP": "", + "SIGN_UP_FOR_PROTONMAIL": "", "SIGNATURE": "", "SIGNATURE_CONTENT": "", "SIGNATURE_SAVED": "", @@ -242,6 +248,7 @@ "WARNING": "Attention", "WHAT_ARE_ALIASES?": "", "WHAT_HAPPENED?": "", + "WHAT_IS_THE_DISPLAY_NAME?": "", "WIZARD": "Assistant", "WRONG_CURRENT_MAILBOX_PASSWORD": "", "YES": "Oui", diff --git a/src/assets/locales/it_IT.json b/src/assets/locales/it_IT.json index aaa27eb..205f8a5 100755 --- a/src/assets/locales/it_IT.json +++ b/src/assets/locales/it_IT.json @@ -8,8 +8,12 @@ "ADVANCED_SEARCH": "", "ALIASES": "", "ALIASES_SAVED": "", + "ALIGN_CENTER": "", + "ALIGN_LEFT": "", + "ALIGN_RIGHT": "", "ALL": "", "ALL_MESSAGES": "", + "AND_ALSO_ARCHIVE": "", "ARCHIVE": "", "ATTACHMENTS": "", "AUTHENTICATION_LOGS": "", @@ -56,6 +60,7 @@ "DEFAULT_COMPOSER_MODE": "", "DEFAULT_LANGUAGE_CHANGED": "", "DELETE": "", + "DELETE_ALL_CONTACTS": "", "DELETE_CONTACT": "", "DELETE_CONTACTS": "", "DELETE_LABEL": "", @@ -93,6 +98,7 @@ "FOLDER": "", "FOLDER_EMPTIED": "", "FORGOT_PASSWORD?": "", + "FORGOT_USERNAME?": "", "FORWARD": "", "FROM": "", "FULLSCREEN": "", @@ -199,7 +205,7 @@ "SHOW": "", "SHOW_ALL": "", "SHOW_IMAGES": "", - "SIGN_UP": "", + "SIGN_UP_FOR_PROTONMAIL": "", "SIGNATURE": "", "SIGNATURE_CONTENT": "", "SIGNATURE_SAVED": "", @@ -242,6 +248,7 @@ "WARNING": "", "WHAT_ARE_ALIASES?": "", "WHAT_HAPPENED?": "", + "WHAT_IS_THE_DISPLAY_NAME?": "", "WIZARD": "", "WRONG_CURRENT_MAILBOX_PASSWORD": "", "YES": "", diff --git a/src/sass/mobile/_mobile-message-list.scss b/src/sass/mobile/_mobile-message-list.scss index b74579b..c9dd18c 100755 --- a/src/sass/mobile/_mobile-message-list.scss +++ b/src/sass/mobile/_mobile-message-list.scss @@ -12,9 +12,6 @@ color: #000; } } - &.starred { - background: $starred; - } h4 { word-break: break-word; font-size: 14px; @@ -40,4 +37,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/sass/partials/_bootstrap-custom.scss b/src/sass/partials/_bootstrap-custom.scss index bc0f020..5078b00 100755 --- a/src/sass/partials/_bootstrap-custom.scss +++ b/src/sass/partials/_bootstrap-custom.scss @@ -42,6 +42,7 @@ body .input-group-addon { display: block; height: $row-height; line-height: $row-height; + min-height: $row-height; box-shadow: inset 0 -1px 0 #ccc, inset -1px 0 0 #ccc; border: none; border-radius: 0; diff --git a/src/sass/partials/_email.scss b/src/sass/partials/_email.scss index 60b68b4..13407b6 100755 --- a/src/sass/partials/_email.scss +++ b/src/sass/partials/_email.scss @@ -26,4 +26,28 @@ html.angular-squire-iframe { text-decoration: underline; color: $primary-color; } + table { + display: table; + box-sizing: initial; + } + thead { + display: table-header-group; + box-sizing: initial; + } + tfoot { + display: table-footer-group; + box-sizing: initial; + } + tbody { + display: table-row-group; + box-sizing: initial; + } + tr { + display: table-row; + box-sizing: initial; + } + td { + display: table-cell; + box-sizing: initial; + } } diff --git a/src/sass/partials/_error-reporter.scss b/src/sass/partials/_error-reporter.scss index 4d8e837..3632aef 100755 --- a/src/sass/partials/_error-reporter.scss +++ b/src/sass/partials/_error-reporter.scss @@ -27,7 +27,11 @@ error-reporter, } } +.cg-notify-message.noclose { + pointer-events: none; +} + .alert a { text-decoration: underline; -} \ No newline at end of file +} diff --git a/src/sass/partials/_general-classes.scss b/src/sass/partials/_general-classes.scss index 5b20571..c98786c 100755 --- a/src/sass/partials/_general-classes.scss +++ b/src/sass/partials/_general-classes.scss @@ -5,6 +5,9 @@ .bold { font-weight: bold; } +.underline { + text-decoration: underline; +} .vcenter { vertical-align: middle; } diff --git a/src/sass/partials/_message-list.scss b/src/sass/partials/_message-list.scss index 50dd10f..8901ade 100755 --- a/src/sass/partials/_message-list.scss +++ b/src/sass/partials/_message-list.scss @@ -198,24 +198,6 @@ table.message-list { } } } - &.starred { - background-color: $tr-starred; - i.fa-paperclip, - i.fa-clock-o, - span.labels, - td { - background-color: $tr-starred; - } - &:hover, - &:active { - i.fa-paperclip, - i.fa-clock-o, - span.labels, - td { - background-color: $tr-starred-hovered; - } - } - } &.selected { i.fa-paperclip, i.fa-clock-o, diff --git a/src/sass/partials/_message-view.scss b/src/sass/partials/_message-view.scss index cdbe5f6..0d83272 100755 --- a/src/sass/partials/_message-view.scss +++ b/src/sass/partials/_message-view.scss @@ -16,7 +16,7 @@ #attachmentWrap { overflow: auto; max-height: (3*$row-height); - background-color: #f2f2f2; + background-color: #f2f2f2; } #attachmentArea { border-radius: 0; @@ -144,9 +144,6 @@ ul.attachments { font-weight: 700; color: #000; } - &.starred { - background: $starred; - } h1 { margin: 0; text-align: left; diff --git a/src/static/donate.html b/src/static/donate.html index 6e2af61..aec678a 100755 --- a/src/static/donate.html +++ b/src/static/donate.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/index.html b/src/static/index.html index c1bf8b7..8aabc93 100755 --- a/src/static/index.html +++ b/src/static/index.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/about.html b/src/static/pages/about.html index 8236ce0..04ba03b 100755 --- a/src/static/pages/about.html +++ b/src/static/pages/about.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/faq.html b/src/static/pages/faq.html index 6fc7729..704a7f1 100755 --- a/src/static/pages/faq.html +++ b/src/static/pages/faq.html @@ -36,38 +36,39 @@
    +

     

    Frequently Asked Questions

    -
    How can ProtonMail tell if I entered the wrong decryption password without knowing my decryption password?
    -
    +
    How can ProtonMail tell if I entered the wrong decryption password without knowing my decryption password?
    + -
    Can I change my Username?
    -
    +
    Can I change my Username?
    + -
    I forgot my Mailbox Password, can you recover it for me?
    -
    +
    I forgot my Mailbox Password, can you recover it for me?
    + -
    Can I change or reset my Mailbox password?
    -
    +
    Can I change or reset my Mailbox password?
    + -
    What's the difference between my Login and Mailbox password?
    -
    +
    What's the difference between my Login and Mailbox password?
    + -
    Why does ProtonMail use 2 passwords?
    -
    +
    Why does ProtonMail use 2 passwords?
    + -
    Is ProtonMail incompatible with certain browser extensions?
    -
    +
    Is ProtonMail incompatible with certain browser extensions?
    +
    - - + include "_footer.html" \ No newline at end of file diff --git a/src/static/pages/invite.html b/src/static/pages/invite.html index 3b8248f..64968d9 100755 --- a/src/static/pages/invite.html +++ b/src/static/pages/invite.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + @@ -102,7 +104,7 @@

    Success!

    request.setRequestHeader("x-pm-apiversion", "@@apiVersion"); request.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"); }, - url: "/api/users/available/"+$('#username').val(), + url: "https://api.protonmail.ch/users/available/"+$('#username').val(), success: function(msg) { if (msg.Code===1000) { if (msg.Available===1) { @@ -132,7 +134,7 @@

    Success!

    request.setRequestHeader("x-pm-apiversion", "@@apiVersion"); request.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"); }, - url: "/api/users/invite", + url: "https://api.protonmail.ch/users/invite", data: JSON.stringify({ "Username": $('#username').val(), "Email": $('#notification_email').val() @@ -147,7 +149,7 @@

    Success!

    alert(msg.Error); $('#invite-button').attr('disabled', false); } - console.log(msg); + // console.log(msg); } }); } diff --git a/src/static/pages/join-us.html b/src/static/pages/join-us.html index 1690428..e578dd3 100755 --- a/src/static/pages/join-us.html +++ b/src/static/pages/join-us.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/media.html b/src/static/pages/media.html index 238c21b..97cfc89 100755 --- a/src/static/pages/media.html +++ b/src/static/pages/media.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/press.html b/src/static/pages/press.html index 7faf75d..f4ec1bc 100755 --- a/src/static/pages/press.html +++ b/src/static/pages/press.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/privacy-policy.html b/src/static/pages/privacy-policy.html index 62f3329..b0eebb3 100755 --- a/src/static/pages/privacy-policy.html +++ b/src/static/pages/privacy-policy.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/security-details.html b/src/static/pages/security-details.html index 1047261..c871aed 100755 --- a/src/static/pages/security-details.html +++ b/src/static/pages/security-details.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/technical-details.html b/src/static/pages/technical-details.html index b614d88..1457b3d 100755 --- a/src/static/pages/technical-details.html +++ b/src/static/pages/technical-details.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/terms-and-conditions.html b/src/static/pages/terms-and-conditions.html index ecabbda..5db46f0 100755 --- a/src/static/pages/terms-and-conditions.html +++ b/src/static/pages/terms-and-conditions.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/pages/why-protonmail.html b/src/static/pages/why-protonmail.html index bb53755..dabdd1f 100755 --- a/src/static/pages/why-protonmail.html +++ b/src/static/pages/why-protonmail.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + diff --git a/src/static/support.html b/src/static/support.html index 6d0edad..ac39511 100755 --- a/src/static/support.html +++ b/src/static/support.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + @@ -34,7 +36,8 @@
    -
    + +

    Support Form

    @@ -53,15 +56,6 @@

    Support Form< - -

    @@ -74,7 +68,7 @@

    Support Form<
    - +

    We handle these bug reports in Zendesk. If you would like to keep the report within ProtonMail, please email the above info to support@protonmail.ch.
    @@ -83,6 +77,12 @@

    Support Form<

    + + +
    @@ -109,22 +109,30 @@

    Support Form< request.setRequestHeader("x-pm-apiversion", "@@apiVersion"); request.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"); }, - url: "https://dev.protonmail.ch/api/users/invite", + url: "https://api.protonmail.ch/bugs", data: JSON.stringify({ - "Username": $('#username').val(), - "Email": $('#notification_email').val() + "OS": $('#bug_os').val(), + "OSVersion": "Unknown", + "Browser": $('#bug_browser').val(), + "BrowserExtensions": $('#bug_plugins').val(), + "Client": "Web", + "ClientVersion" : "2.0.0", + "Title": "Support Form Entry", + "Description": $('#bug_description').val(), + "Username": $('#bug_acc').val(), + "Email": $('#bug_email').val() }), success: function(msg) { - if (msg.Code===1000) { + if (msg.Code==1000) { // success - $('#inviteSuccess').fadeIn(); - $('#inviteForm').hide(); + $('#supportSuccess').fadeIn(); + $('#supportForm').hide(); } - else if (msg.Code!==undefined) { + else if (msg.Code!=undefined) { alert(msg.Error); $('#invite-button').attr('disabled', false); } - console.log(msg); + // console.log(msg); } }); } diff --git a/src/static/username.html b/src/static/username.html index 973f92f..59fbb38 100755 --- a/src/static/username.html +++ b/src/static/username.html @@ -13,7 +13,9 @@ - Codestin Search App + Codestin Search App + + @@ -35,7 +37,8 @@
    -
    + +
    @@ -45,6 +48,11 @@
    + + +
    @@ -62,9 +70,9 @@ // disable button $('#forgotUsername-button').attr('disabled', true); - var formData = { + var formData = JSON.stringify({ NotificationEmail: email, - }; + }); // make api call $.ajax({ @@ -75,18 +83,17 @@ request.setRequestHeader("x-pm-apiversion", "@@apiVersion"); request.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"); }, - url: "/api/reset/username", + url: "https://api.protonmail.ch/reset/username", data: formData, success: function(msg) { - if (msg.Code === 1000) { - if (msg.Available === 1) { - createInvite(); - } + if (msg.Code == 1000) { + $('#usernameSuccess').fadeIn(); + $('#usernameForm').hide(); } else { alert('Something went wrong.'); $('#forgotUsername-button').attr('disabled', false); } - console.log(msg); + // console.log(msg); } }); }