Skip to content

Instantly share code, notes, and snippets.

@toddjcrane
Created December 28, 2017 05:37
Show Gist options
  • Select an option

  • Save toddjcrane/2d7ac50853f8f5eefc39d0ee420a9245 to your computer and use it in GitHub Desktop.

Select an option

Save toddjcrane/2d7ac50853f8f5eefc39d0ee420a9245 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
/**
* protonmail-web - 3.12.13 - 2017-12-06 14:26:36
*
* copyright 2017 Proton Technologies AG
* MIT
*/
"use strict";
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function generateDirective(attrName) {
function assert(condition, missing, found) {
if (!condition) throw new Error("You should add a " + missing + " attribute whenever you add a " + found + " attribute.")
}
var normAttrName = function(attributeName) {
function camelCase(name) {
return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
return offset ? letter.toUpperCase() : letter
}).replace(MOZ_HACK_REGEXP, "Moz$1")
}
var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g,
MOZ_HACK_REGEXP = /^moz([A-Z])/,
PREFIX_REGEXP = /^(x[:\-_]|data[:\-_])/i;
return function(name) {
return camelCase(name.replace(PREFIX_REGEXP, ""))
}(attributeName)
}(attrName);
return ["gettextCatalog", "$parse", "$animate", "$compile", function(gettextCatalog, $parse, $animate, $compile) {
return {
restrict: "A",
terminal: !0,
priority: 1e3,
compile: function(element, attrs) {
if (!attrs[normAttrName + "Translate"]) throw new Error("Missing " + normAttrName + "-translate attribute!");
assert(!attrs[normAttrName + "TranslatePlural"] || attrs[normAttrName + "TranslateN"], normAttrName + "translate-n", normAttrName + "translate-plural"), assert(!attrs[normAttrName + "TranslateN"] || attrs[normAttrName + "TranslatePlural"], normAttrName + "translate-plural", normAttrName + "translate-n");
var msgid = attrs[normAttrName + "Translate"],
translatePlural = attrs[normAttrName + "TranslatePlural"],
translateContext = attrs[normAttrName + "TranslateContext"];
return {
pre: function(scope, element, attrs) {
function update() {
var translated = void 0;
translatePlural ? (scope = pluralScope || (pluralScope = scope.$new()), scope.$count = countFn(scope), translated = gettextCatalog.getPlural(scope.$count, msgid, translatePlural, {}, translateContext)) : translated = gettextCatalog.getString(msgid, null, translateContext), translated !== attrs[normAttrName] && 8 !== element[0].nodeType && element[0].setAttribute(attrName, translated)
}
var attribute = attrs[normAttrName + "TranslateN"],
countFn = attribute ? angular.noop : $parse(attribute),
pluralScope = null;
attribute && scope.$watch(attribute, update), scope.$on("gettextLanguageChanged", update), update(), element.removeAttr(attrName + "-translate"), $compile(element)(scope)
}
}
}
}
}]
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _taggedTemplateLiteral(strings, raw) {
return Object.freeze(Object.defineProperties(strings, {
raw: {
value: Object.freeze(raw)
}
}))
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toArray(arr) {
return Array.isArray(arr) ? arr : Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _taggedTemplateLiteral(strings, raw) {
return Object.freeze(Object.defineProperties(strings, {
raw: {
value: Object.freeze(raw)
}
}))
}
function _toArray(arr) {
return Array.isArray(arr) ? arr : Array.from(arr)
}
function _toArray(arr) {
return Array.isArray(arr) ? arr : Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function")
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2
}
return Array.from(arr)
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg),
value = info.value
} catch (error) {
return void reject(error)
}
if (!info.done) return Promise.resolve(value).then(function(value) {
step("next", value)
}, function(err) {
step("throw", err)
});
resolve(value)
}
return step("next")
})
}
}
function _defineProperty(obj, key, value) {
return key in obj ? Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = value, obj
}
angular.module("proton.address", []),
angular.module("proton.analytics", []).run(function(analytics, eventListener) {
analytics.init(), eventListener.init()
}),
angular.module("proton.attachments", ["proton.authentication", "proton.utils"]),
angular.module("proton.authentication", ["proton.constants", "proton.utils", "proton.settings", "proton.keys"]).run(function($rootScope, authentication) {
authentication.detectAuthenticationState(), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured()
}),
angular.module("proton.autoresponder", []),
angular.module("proton.blackFriday", []).run(function(blackFridayModel) {
return blackFridayModel.init()
}),
angular.module("proton.bridge", []),
angular.module("proton.browserSupport", []).run(function(browserFixes) {
return browserFixes.init()
}),
angular.module("proton.bugReport", []).run(function(bugReportModel) {
return bugReportModel.init()
}),
angular.module("proton.commons", []),
angular.module("proton.composer", ["proton.constants"]),
angular.module("proton.contact", ["vs-repeat"]).run(function(contactEditor, contactMerger) {
contactEditor.init(), contactMerger.init()
}).config(function($stateProvider) {
$stateProvider.state("secured.contacts", {
url: "/contacts?sort&page&keyword",
params: {
page: {
value: null,
squash: !0
},
keyword: {
value: null,
squash: !0
},
sort: {
value: null,
squash: !0
}
},
resolve: {
delinquent: function(user, isDelinquent) {
return isDelinquent()
}
},
views: {
"content@secured": {
template: "<contact-view></contact-view>"
}
},
onEnter: function(AppModel) {
AppModel.set("contactSidebar", !0)
},
onExit: function(AppModel) {
AppModel.set("contactSidebar", !1)
}
}).state("secured.contacts.details", {
url: "/:id",
params: {
id: null
},
views: {
"[email protected]": {
template: '<div class="contactsDetails-body"><contact-details ng-if="contact" data-contact="contact"></contact-details><loader-tag></loader-tag></div>',
controller: function($scope, $stateParams, contactCache) {
contactCache.find($stateParams.id).then(function(data) {
return $scope.$applyAsync(function() {
$scope.contact = data
})
})
}
}
}
})
}),
angular.module("proton.conversation", []).config(function($httpProvider) {
$httpProvider.interceptors.push("conversationsInterceptor")
}),
angular.module("proton.core", ["proton.constants", "proton.utils"]).run(function(paginationModel, cachePages) {
paginationModel.init(), cachePages.init()
}),
angular.module("proton.dashboard", []),
angular.module("proton.dnd", []).run(function(actionDnd) {
return actionDnd.init()
}),
angular.module("proton.domains", []),
angular.module("proton.elements", ["proton.constants"]),
angular.module("proton.filter", ["proton.constants", "proton.utils"]).run(function(sieveLint) {
return sieveLint.init()
}),
angular.module("proton.formUtils", ["ngIntlTelInput"]),
angular.module("proton.keys", ["proton.elements"]),
angular.module("proton.labels", []),
angular.module("proton.members", []),
angular.module("proton.message", ["ngSanitize"]).run(function(unsubscribeModel) {
return unsubscribeModel.init()
}),
angular.module("proton.organization", []),
angular.module("proton.outside", ["proton.routes", "proton.constants", "proton.utils"]).run(function(attachmentModelOutside) {
return attachmentModelOutside.load()
}),
angular.module("proton.payment", []).config(function($httpProvider) {
$httpProvider.interceptors.push("paymentsInterceptor")
}),
angular.module("proton.search", []).run(function(wildcardModel) {
return wildcardModel.init()
}),
angular.module("proton.settings", []),
angular.module("proton.sidebar", []),
angular.module("proton.squire", []),
angular.module("proton.ui", ["ui.indeterminate"]).run(function(backState) {
return backState.init()
}),
angular.module("proton.user", []),
angular.module("proton.utils", ["proton.constants"]).run(function(resurrecter) {
return resurrecter.init()
}),
angular.module("proton.vpn", []),
angular.module("proton.wizard", []),
angular.module("proton.address").directive("addressBtnActions", function(addressModel, gettextCatalog) {
var I18N = {
makeDefault: gettextCatalog.getString("Make default", null, "Action"),
editSignature: gettextCatalog.getString("Edit signature", null, "Action"),
disable: gettextCatalog.getString("Disable", null, "Action"),
enable: gettextCatalog.getString("Enable", null, "Action"),
remove: gettextCatalog.getString("Delete", null, "Action"),
generate: gettextCatalog.getString("Generate missing keys", null, "Action"),
add: gettextCatalog.getString("Add address", null, "Action")
};
return {
replace: !0,
scope: {
model: "=?",
model2: "=?"
},
template: '<button type="button" class="addressBtnActions-container">' + I18N.editSignature + "</button>",
link: function(scope, el, _ref) {
var _ref$action = _ref.action,
action = void 0 === _ref$action ? "editSignature" : _ref$action;
"editSignature" !== action && el.text(I18N[action]);
var onClick = function() {
return addressModel[action](scope.model, scope.model2)
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick)
})
}
}
}),
angular.module("proton.address").directive("addressKeysView", function($rootScope, downloadFile, authentication, gettextCatalog, tools, notification, Key, keyPasswordModal, pmcw, networkActivityTracker, eventManager) {
var I18N = {
ERROR: gettextCatalog.getString("Error reactivating key. Please try again", null, "Error"),
SUCCESS: gettextCatalog.getString("Key reactivated", null, "Info")
},
reactivateProcess = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(decryptedKey, key) {
var PrivateKey, _ref2, _ref2$data, data;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.prev = 0, _context.next = 3, pmcw.encryptPrivateKey(decryptedKey, authentication.getPassword());
case 3:
return PrivateKey = _context.sent, _context.next = 6, Key.reactivate(key.ID, {
PrivateKey: PrivateKey
});
case 6:
if (_ref2 = _context.sent, _ref2$data = _ref2.data, data = void 0 === _ref2$data ? {} : _ref2$data, 1e3 === data.Code) {
_context.next = 11;
break
}
throw new Error(data.Error || I18N.ERROR);
case 11:
return key.decrypted = !0, notification.success(I18N.SUCCESS), _context.abrupt("return", eventManager.call());
case 16:
throw _context.prev = 16, _context.t0 = _context.catch(0), new Error(I18N.ERROR);
case 19:
case "end":
return _context.stop()
}
}, _callee, void 0, [
[0, 16]
])
}));
return function(_x, _x2) {
return _ref.apply(this, arguments)
}
}(),
reactivate = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(key) {
var _ref4, _ref4$data, data, _ref5, salt;
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return _context2.prev = 0, _context2.next = 3, Key.salts();
case 3:
_ref4 = _context2.sent, _ref4$data = _ref4.data, data = void 0 === _ref4$data ? {} : _ref4$data, _ref5 = _.findWhere(data.KeySalts, {
ID: key.ID
}) || {}, salt = _ref5.KeySalt, keyPasswordModal.activate({
params: {
salt: salt,
privateKey: key.PrivateKey,
submit: function(decryptedKey) {
keyPasswordModal.deactivate(), networkActivityTracker.track(reactivateProcess(decryptedKey, key))
},
cancel: function() {
keyPasswordModal.deactivate()
}
}
}), _context2.next = 12;
break;
case 10:
_context2.prev = 10, _context2.t0 = _context2.catch(0);
case 12:
case "end":
return _context2.stop()
}
}, _callee2, void 0, [
[0, 10]
])
}));
return function(_x3) {
return _ref3.apply(this, arguments)
}
}();
return {
replace: !0,
restrict: "E",
templateUrl: "templates/address/addressKeysView.tpl.html",
link: function(scope) {
function populateKeys() {
authentication.user.Addresses.forEach(function(_ref6) {
var _ref6$Keys = _ref6.Keys,
Keys = void 0 === _ref6$Keys ? [] : _ref6$Keys,
_ref6$ID = _ref6.ID,
ID = void 0 === _ref6$ID ? "" : _ref6$ID,
_ref6$Email = _ref6.Email,
Email = void 0 === _ref6$Email ? "" : _ref6$Email,
Order = _ref6.Order;
if (Keys.length) {
var _Keys$ = Keys[0],
fingerprint = _Keys$.fingerprint,
created = _Keys$.created,
bitSize = _Keys$.bitSize,
PublicKey = _Keys$.PublicKey,
index = _.findIndex(scope.addresses, {
addressID: ID
}),
address = {
order: Order,
addressID: ID,
email: Email,
fingerprint: fingerprint,
created: created,
bitSize: bitSize,
publicKey: PublicKey,
keys: Keys
};
index > -1 ? angular.extend(scope.addresses[index], address) : scope.addresses.push(address)
}
})
}
var unsubscribe = $rootScope.$on("updateUser", function() {
populateKeys()
});
scope.isSubUser = authentication.user.subuser, scope.addresses = [], scope.download = function(key, email, type) {
var blob = new Blob([key], {
type: "data:text/plain;charset=utf-8;"
});
downloadFile(blob, type + "key." + email + ".asc")
}, scope.reactivate = reactivate, scope.$on("$destroy", function() {
unsubscribe()
}), populateKeys()
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.address").factory("addressModel", function($state, gettextCatalog, networkActivityTracker, notification, organizationModel, organizationKeysModel, pmDomainModel, domainModel, memberModel, addressModal, membersValidator, memberModal, eventManager, confirmModal, signatureModal, Address, authentication, addressWithoutKeysManager, CONSTANTS, $rootScope) {
function generate(address) {
var member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : memberModel.getSelf();
if (canAdd(member, !1)) return addressWithoutKeysManager.manageOne(address, member).then(function(_ref6) {
var _ref7 = _slicedToArray(_ref6, 1),
_ref7$ = _ref7[0],
adr = void 0 === _ref7$ ? {} : _ref7$,
index = _.findIndex(authentication.user.Addresses, function(_ref8) {
return _ref8.ID === adr.ID
});
adr.Receive = +(1 === adr.Status), -1 !== index && authentication.user.Addresses.splice(index, 1, adr), $rootScope.$emit("addressModel", {
type: "generateKey.success",
data: {
address: address
}
})
}).catch(_.noop)
}
var I18N = {
ERROR_DO_UPGRADE: gettextCatalog.getString("You have used all addresses in your plan. Please upgrade your plan to add a new address", null, "Error"),
ERROR_MUST_BE_ADMIN: gettextCatalog.getString("Administrator privileges must be activated", null, "Error"),
SUCCESS_DISABLED: gettextCatalog.getString("Address disabled", null, "Info"),
SUCCESS_ENABLE: gettextCatalog.getString("Address enabled", null, "Info"),
SUCCESS_REMOVE: gettextCatalog.getString("Address deleted", null, "Info"),
SUCCESS_EDIT: gettextCatalog.getString("Address updated", null, "Info"),
SUCCESS_ORDER: gettextCatalog.getString("Order saved", null, "Info"),
DISABLE_MODAL: {
title: gettextCatalog.getString("Disable address", null, "Title"),
message: gettextCatalog.getString("Are you sure you want to disable this address?", null, "Info")
},
DELETE_MODAL: {
title: gettextCatalog.getString("Delete address", null, "Title"),
message: gettextCatalog.getString("Are you sure you want to delete this address?", null, "Info")
},
EDIT_MODAL: {
title: gettextCatalog.getString("Name / Signature", null, "Title")
},
FREE_ADD_ERROR: gettextCatalog.getString('Please <a href="/dashboard">upgrade</a> to a paid account to use this feature', null, "Error")
},
canAdd = function() {
var member = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
redirect = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1],
_ref = organizationModel.get() || {},
MaxAddresses = _ref.MaxAddresses,
UsedAddresses = _ref.UsedAddresses,
HasKeys = _ref.HasKeys;
return MaxAddresses - UsedAddresses < 1 ? (notification.error(I18N.ERROR_DO_UPGRADE), !1) : !(1 === HasKeys && organizationKeysModel.get("keyStatus") > 0 && !member.Private) || (notification.error(I18N.ERROR_MUST_BE_ADMIN), redirect && $state.go("secured.members"), !1)
},
formatDomains = function(domain, member) {
var config = {
pmDomains: [],
domains: [domain],
members: [member]
};
return 0 === member.Type && (config.pmDomains = pmDomainModel.get().map(function(domain) {
return {
DomainName: domain
}
})), !domain.ID && (config.domains = config.pmDomains.concat(domainModel.query())), !member.ID && (config.members = memberModel.getAll()), config
},
add = function() {
var domain = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
if (authentication.user.Role === CONSTANTS.FREE_USER_ROLE) return notification.error(I18N.FREE_ADD_ERROR);
var _formatDomains = formatDomains(domain, member),
domains = _formatDomains.domains,
members = _formatDomains.members;
if (!domains || 0 === domains.length) return $state.go("secured.domains");
if (canAdd(member)) {
var organizationKey = organizationKeysModel.get("organizationKey");
addressModal.activate({
params: {
domains: domains,
members: members,
organizationKey: organizationKey,
cancel: addressModal.deactivate,
addMember: function() {
membersValidator.canAdd(organizationKeysModel.get("keyStatus")) && (addressModal.deactivate(), memberModal.activate({
params: {
organization: organizationModel.get(),
organizationKey: organizationKey,
domains: domains,
submit: memberModal.deactivate,
cancel: memberModal.deactivate
}
}))
},
submit: function(address, member) {
if (addressModal.deactivate(), !member.Private) return generate(address, member).then(eventManager.call);
eventManager.call()
}
}
})
}
},
disable = function(_ref2) {
var ID = _ref2.ID;
confirmModal.activate({
params: {
title: I18N.DISABLE_MODAL.title,
message: I18N.DISABLE_MODAL.message,
cancel: confirmModal.deactivate,
confirm: function() {
var promise = Address.disable(ID).then(eventManager.call).then(function() {
notification.success(I18N.SUCCESS_DISABLED), confirmModal.deactivate()
});
networkActivityTracker.track(promise)
}
}
})
},
enable = function(_ref3) {
var ID = _ref3.ID,
promise = Address.enable(ID).then(function() {
return eventManager.call()
}).then(function() {
return notification.success(I18N.SUCCESS_ENABLE)
});
networkActivityTracker.track(promise)
},
disableFirst = function() {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(_ref5) {
var ID = _ref5.ID,
Status = _ref5.Status;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
if (0 !== Status) {
_context.next = 2;
break
}
return _context.abrupt("return");
case 2:
return _context.next = 4, Address.disable(ID);
case 4:
notification.success(I18N.SUCCESS_DISABLED);
case 5:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x5) {
return _ref4.apply(this, arguments)
}
}(),
remove = function(address) {
confirmModal.activate({
params: {
title: I18N.DELETE_MODAL.title,
message: I18N.DELETE_MODAL.message,
confirm: function() {
var promise = disableFirst(address).then(function() {
return Promise.all([eventManager.call(), Address.remove(address.ID)])
}).then(function() {
notification.success(I18N.SUCCESS_REMOVE), confirmModal.deactivate()
}).then(eventManager.call).catch(function(e) {
throw confirmModal.deactivate(), e
});
networkActivityTracker.track(promise)
},
cancel: function() {
confirmModal.deactivate()
}
}
})
},
editSignature = function(address) {
signatureModal.activate({
params: {
address: address,
title: I18N.EDIT_MODAL.title,
cancel: signatureModal.deactivate,
confirm: function(address) {
!1 === address.custom && (address.DisplayName = null, address.Signature = null);
var promise = Address.edit(address.ID, {
DisplayName: address.DisplayName,
Signature: address.Signature
}).then(function() {
eventManager.call(), notification.success(I18N.SUCCESS_EDIT), signatureModal.deactivate()
});
networkActivityTracker.track(promise)
}
}
})
},
saveOrder = function(Order) {
var promise = Address.order({
Order: Order
}).then(eventManager.call).then(function() {
return notification.success(I18N.SUCCESS_ORDER)
});
networkActivityTracker.track(promise)
},
getActive = function() {
var active = _.where(authentication.user.Addresses, {
Status: 1,
Receive: 1
});
return {
active: active,
disabled: _.difference(authentication.user.Addresses, active)
}
};
return {
add: add,
disable: disable,
enable: enable,
remove: remove,
makeDefault: function(address) {
var _getActive = getActive(),
active = _getActive.active,
disabled = _getActive.disabled,
addresses = [].concat(active, disabled),
index = _.findIndex(addresses, {
ID: address.ID
});
addresses.splice(index, 1), addresses.unshift(address);
var order = _.pluck(addresses, "Order");
saveOrder(order)
},
editSignature: editSignature,
saveOrder: saveOrder,
generate: generate,
getActive: getActive
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.address").factory("addressWithoutKeys", function(memberModel, authentication, AppModel) {
var isDirtyAddress = function(_ref) {
var Keys = _ref.Keys,
Status = _ref.Status;
return !Keys.length && 1 === Status
},
filterDirty = function(user) {
var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [];
return _.filter(list, function(adr) {
return isDirtyAddress(adr) && 1 === user.Private
})
},
fromUser = function() {
var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user;
return filterDirty(user, user.Addresses)
},
getListAddresses = function(_ref2, user) {
var _ref3 = _slicedToArray(_ref2, 1),
member = _ref3[0];
if (!member.Private) return member.Addresses;
var mapAddresses = user.Addresses.reduce(function(acc, _ref4) {
return acc[_ref4.ID] = !0, acc
}, {});
return user.Addresses.concat(member.Addresses.filter(function(_ref5) {
var ID = _ref5.ID;
return !mapAddresses[ID]
}))
};
return {
get: function() {
var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
memberList = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : memberModel.getAll(),
isEvent = arguments[2];
if (1 === memberList.length && !isEvent) {
var addresses = getListAddresses(memberList, user);
return {
addresses: filterDirty(user, addresses)
}
}
return {
addresses: filterDirty(user, user.Addresses)
}
},
fromUser: fromUser,
allDirty: function() {
var _ref6 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user,
_ref6$Addresses = _ref6.Addresses,
Addresses = void 0 === _ref6$Addresses ? [] : _ref6$Addresses;
if (!1 === AppModel.get("allDirtyAddresses")) return !1;
var test = Addresses.filter(function(_ref7) {
return _ref7.Status
}).every(isDirtyAddress);
return AppModel.set("allDirtyAddresses", test), test
}
}
}),
angular.module("proton.address").factory("addressModal", function(pmModal, $rootScope, $state, networkActivityTracker, notification, Address, gettextCatalog, organizationModel, CONSTANTS) {
var I18N = {
ERROR_DECRYPT_ORG_KEY: gettextCatalog.getString("Cannot decrypt organization key", null, "Error"),
SUCCESS_ADD: gettextCatalog.getString("Address added", null, "Info")
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/addAddress.tpl.html",
controller: function(params) {
var _this = this,
_params$domains = params.domains,
domains = void 0 === _params$domains ? [] : _params$domains,
_params$organizationK = params.organizationKey,
organizationKey = void 0 === _params$organizationK ? null : _params$organizationK,
_params$members = params.members,
members = void 0 === _params$members ? [] : _params$members,
organization = organizationModel.get();
this.domain = domains[0], this.domains = domains, this.address = "", this.size = CONSTANTS.ENCRYPTION_DEFAULT, this.members = members, this.member = members[0], this.showAddMember = 1 === organization.HasKeys && $state.is("secured.domains"), this.addMember = params.addMember, this.cancel = params.cancel, this.open = function(name) {
return $rootScope.$broadcast(name, params.domain)
}, this.submit = function() {
if (0 === _this.member.Private && !organizationKey) return notification.error(I18N.ERROR_DECRYPT_ORG_KEY);
var promise = Address.create({
Local: _this.address,
Domain: _this.domain.DomainName,
MemberID: _this.member.ID
}).then(function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
notification.success(I18N.SUCCESS_ADD), params.submit(data.Address, _this.member)
});
networkActivityTracker.track(promise)
}
}
})
}),
angular.module("proton.address").factory("addressesModal", function(pmModal, CONSTANTS, addressModal, memberModal, $rootScope, organizationModel) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/address.tpl.html",
controller: function(params) {
var domain = params.domain,
members = params.members,
step = params.step,
addressParams = params.addressParams,
memberParams = params.memberParams,
_params$showMember = params.showMember,
showMember = void 0 === _params$showMember || _params$showMember,
organization = organizationModel.get();
this.keyPhase = CONSTANTS.KEY_PHASE, this.domain = domain, this.step = step, this.showMember = showMember && 1 === organization.HasKeys && this.keyPhase > 3, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.getMember = function(id) {
var index = _.findIndex(members, {
ID: id
});
return -1 !== index ? members[index] : {}
}, this.addAddress = function() {
params.cancel(), addressModal.activate(addressParams)
}, this.addMember = function() {
params.cancel(), memberModal.activate(memberParams)
}, this.next = function() {
params.next()
}, this.close = function() {
params.cancel()
}
}
})
}), angular.module("proton.address").factory("addressWithoutKeysManager", function(addressWithoutKeys, authentication, generateModal, $injector) {
var openModal = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(_ref2) {
var organizationModel, organizationKeysModel, addresses = _ref2.addresses,
password = _ref2.password,
_ref2$memberMap = _ref2.memberMap,
memberMap = void 0 === _ref2$memberMap ? {} : _ref2$memberMap;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return organizationModel = $injector.get("organizationModel"), organizationKeysModel = $injector.get("organizationKeysModel"), _context.next = 4, organizationKeysModel.manage(organizationModel.get());
case 4:
if (!addresses.length || generateModal.active()) {
_context.next = 6;
break
}
return _context.abrupt("return", new Promise(function(resolve, reject) {
generateModal.activate({
params: {
memberMap: memberMap,
password: password,
addresses: addresses,
organizationKey: organizationKeysModel.get("organizationKey"),
onSuccess: function() {
$injector.get("eventManager").call(), resolve(addresses), generateModal.deactivate()
},
close: function() {
reject(new Error("generateModal:close")), generateModal.deactivate()
}
}
})
}));
case 6:
organizationKeysModel.clear();
case 7:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x) {
return _ref.apply(this, arguments)
}
}();
return {
manage: function() {
var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user,
memberList = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
isEvent = arguments[2],
_addressWithoutKeys$g = addressWithoutKeys.get(user, memberList, isEvent),
addresses = _addressWithoutKeys$g.addresses,
memberMap = _addressWithoutKeys$g.memberMap,
password = authentication.getPassword();
return openModal({
addresses: addresses,
memberMap: memberMap,
password: password
})
},
manageOne: function(address) {
var member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
password = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : authentication.getPassword(),
addresses = [address],
memberMap = _defineProperty({}, address.ID, member);
return openModal(member.Private ? {
addresses: addresses,
password: password
} : {
addresses: addresses,
memberMap: memberMap,
password: password
})
}
}
}), angular.module("proton.analytics").factory("analytics", function(CONFIG, CONSTANTS, aboutClient) {
function getTrackerAsync() {
return state.tracker ? Promise.resolve(state.tracker) : new Promise(function(resolve) {
loadQueue.push(resolve)
})
}
function trackPage(_ref) {
var url = _ref.url,
referrer = _ref.referrer,
title = _ref.title;
getTrackerAsync().then(function(tracker) {
tracker.setDocumentTitle(title), tracker.setReferrerUrl(referrer), tracker.setCustomUrl(url), tracker.trackPageView()
})
}
function trackGoals(goals) {
getTrackerAsync().then(function(tracker) {
tracker.trackGoal(goals)
})
}
var _CONFIG$statsConfig = CONFIG.statsConfig,
isEnabled = _CONFIG$statsConfig.isEnabled,
_CONFIG$statsConfig$c = _CONFIG$statsConfig.cookieDomain,
cookieDomain = void 0 === _CONFIG$statsConfig$c ? "" : _CONFIG$statsConfig$c,
_CONFIG$statsConfig$d = _CONFIG$statsConfig.domains,
domains = void 0 === _CONFIG$statsConfig$d ? [] : _CONFIG$statsConfig$d,
_CONFIG$statsConfig$s = _CONFIG$statsConfig.statsHost,
statsHost = void 0 === _CONFIG$statsConfig$s ? "" : _CONFIG$statsConfig$s,
_CONFIG$statsConfig$s2 = _CONFIG$statsConfig.siteId,
siteId = void 0 === _CONFIG$statsConfig$s2 ? -1 : _CONFIG$statsConfig$s2,
_CONFIG$statsConfig$a = _CONFIG$statsConfig.abSiteId,
abSiteId = void 0 === _CONFIG$statsConfig$a ? -1 : _CONFIG$statsConfig$a;
if (!isEnabled || aboutClient.doNotTrack()) return {
init: angular.noop,
trackGoals: angular.noop,
trackPage: angular.noop
};
var loadQueue = [],
state = {};
window.piwikAsyncInit = function() {
state.tracker = window.Piwik.getTracker("//" + statsHost + "/" + CONSTANTS.TRACKER_ROUTE, siteId), state.tracker.setCookieDomain(cookieDomain), state.tracker.setDomains(domains), state.tracker.enableCrossDomainLinking(), state.tracker.setCustomVariable(1, "siteFrontEndId", abSiteId, "visit"), state.tracker.setCustomVariable(1, "enablePMRequestCombiner", "yes", "page"), loadQueue.forEach(function(resolve) {
return resolve(state.tracker)
})
};
var piwikScript = document.createElement("script");
return piwikScript.type = "text/javascript", piwikScript.async = !0, piwikScript.defer = !0, piwikScript.src = "https://" + statsHost + "/" + CONSTANTS.PIWIK_SCRIPT, document.head.appendChild(piwikScript), {
init: angular.noop,
trackGoals: trackGoals,
trackPage: trackPage
}
}), angular.module("proton.analytics").factory("eventListener", function(CONSTANTS, CONFIG, $rootScope, analytics, pageTitlesModel) {
function generateTitle(state) {
return document.domain + "/" + pageTitlesModel.find(state, !1)
}
var TRACKED_STATES = ["signup", "secured.dashboard", "login", "secured.inbox"],
state = {
lastLocation: document.referrer
};
return $rootScope.$on("$stateChangeSuccess", function(event, toState) {
var referrer = state.lastLocation;
if (state.lastLocation = location.href, TRACKED_STATES.includes(toState.name)) {
var title = generateTitle(toState),
page = {
title: title,
referrer: referrer,
url: location.href
};
analytics.trackPage(page)
}
}), $rootScope.$on("signup", function(event, _ref) {
var type = _ref.type,
data = _ref.data;
if ("user.subscription.finished" === type) {
var plan = data.plan || {
Name: "free"
},
goals = [CONSTANTS.METRIC_GOALS.SIGNUP_ALL];
"free" === plan.Name ? goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_FREE) : goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_PAID), "plus" === plan.Name && goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_PLUS), "visionary" === plan.Name && goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_VISIONARY), analytics.trackGoals(goals)
}
}), {
init: angular.noop
}
}),
angular.module("proton", ["gettext", "as.sortable", "cgNotify", "ngCookies", "ngIcal", "ngMessages", "ngSanitize", "ngScrollbars", "pikaday", "ui.router", "ui.codemirror", "proton.constants", "proton.core", "proton.outside", "proton.utils", "proton.user", "templates-app", "proton.routes", "proton.composer", "proton.commons", "proton.bugReport", "proton.browserSupport", "proton.config", "proton.analytics", "proton.search", "proton.ui", "proton.dnd", "proton.sidebar", "proton.attachments", "proton.authentication", "proton.elements", "proton.members", "proton.bridge", "proton.labels", "proton.autoresponder", "proton.filter", "proton.domains", "proton.address", "proton.message", "proton.conversation", "proton.organization", "proton.squire", "proton.wizard", "proton.contact", "proton.blackFriday", "proton.settings", "proton.dashboard", "proton.vpn", "proton.payment", "proton.formUtils"]).config(function(urlProvider, CONFIG, notificationProvider) {
urlProvider.setBaseUrl(CONFIG.apiUrl), notificationProvider.template("templates/notifications/base.tpl.html")
}).run(function($rootScope, $state, logoutManager, authentication, networkActivityTracker, CONSTANTS, tools) {
FastClick.attach(document.body), window.addEventListener("resize", _.debounce(tools.mobileResponsive, 50)), window.addEventListener("orientationchange", tools.mobileResponsive), tools.mobileResponsive(), $rootScope.showWelcome = !0, window.svg4everybody(), moment.relativeTimeThreshold("s", 59), moment.relativeTimeThreshold("m", 59), moment.relativeTimeThreshold("h", 23), $rootScope.networkActivity = networkActivityTracker
}).config(function($httpProvider, CONFIG) {
$httpProvider.interceptors.push("authHttpResponseInterceptor"), $httpProvider.interceptors.push("formatResponseInterceptor"), $httpProvider.defaults.headers.common["x-pm-appversion"] = "Web_" + CONFIG.app_version, $httpProvider.defaults.headers.common["x-pm-apiversion"] = CONFIG.api_version, $httpProvider.defaults.headers.common.Accept = "application/vnd.protonmail.v1+json", $httpProvider.defaults.withCredentials = !0, angular.isUndefined($httpProvider.defaults.headers.get) && ($httpProvider.defaults.headers.get = {}), $httpProvider.defaults.headers.get["Cache-Control"] = "no-cache", $httpProvider.defaults.headers.get.Pragma = "no-cache"
}).run(function($rootScope, $location, $state, authentication, $log, networkActivityTracker, AppModel) {
$rootScope.$on("$stateChangeStart", function(event, toState) {
networkActivityTracker.clear();
var isLogin = "login" === toState.name,
isSub = "login.sub" === toState.name,
isUpgrade = "upgrade" === toState.name,
isSupport = toState.name.includes("support"),
isAccount = "account" === toState.name,
isSignup = "signup" === toState.name || "pre-invite" === toState.name,
isUnlock = "login.unlock" === toState.name,
isOutside = toState.name.includes("eo"),
isReset = toState.name.includes("reset"),
isPrinter = "printer" === toState.name,
isPgp = "pgp" === toState.name;
return isUnlock && $rootScope.isLoggedIn ? void $log.debug("appjs:(isUnlock && $rootScope.isLoggedIn)") : $rootScope.isLoggedIn && !$rootScope.isLocked && isUnlock ? ($log.debug("appjs:($rootScope.isLoggedIn && !$rootScope.isLocked && isUnlock)"), event.preventDefault(), void $state.go("secured.inbox")) : isLogin || isSub || isSupport || isAccount || isSignup || isOutside || isUpgrade || isReset || isPrinter || isPgp ? void $log.debug("appjs:(isLogin || isSub || isSupport || isAccount || isSignup || isOutside || isUpgrade || isReset || isPrinter || isPgp)") : void(authentication.isLoggedIn() || (event.preventDefault(), $state.go("login")))
}), $rootScope.$on("$stateChangeSuccess", function() {
AppModel.set("requestTimeout", !1), $(".tooltip").not(void 0).hide(), $(".navbar-toggle").click(), $("#loading_pm, #pm_slow, #pm_slow2").remove()
})
}).run(function($rootScope, $state) {
$rootScope.$on("$stateChangeError", function(event, current, previous, rejection) {
for (var _len = arguments.length, arg = Array(_len > 4 ? _len - 4 : 0), _key = 4; _key < _len; _key++) arg[_key - 4] = arguments[_key];
console.error("stateChangeError", event, current, previous, rejection, arg), $state.go("support.message", {
data: {}
})
})
}).run(function(consoleMessage) {
return consoleMessage()
}).config(function($logProvider, $compileProvider, $qProvider, CONFIG) {
var debugInfo = CONFIG.debug || !1;
$logProvider.debugEnabled(debugInfo), $compileProvider.debugInfoEnabled(debugInfo), $qProvider.errorOnUnhandledRejections(debugInfo)
}).config(function(CONFIG, CONSTANTS) {
var localhost = "NODE@ENV".replace("@", "_"),
REGEXP_HOST = /proton(mail|vpn)\.(com|blue|host)$/;
if ("build" !== localhost && !REGEXP_HOST.test(window.location.host)) {
var img = new Image;
img.width = 0, img.height = 0, img.src = CONSTANTS.URL_INFO, document.body.appendChild(img)
}
}), angular.module("proton.attachments").directive("btnDownloadAttachments", function(attachmentDownloader) {
return {
scope: {
model: "="
},
replace: !0,
templateUrl: "templates/attachments/btnDownloadAttachments.tpl.html",
link: function(scope, el) {
var reset = function() {
return el[0].classList.remove("btnDownloadAttachments-load")
},
onClick = function(e) {
if (attachmentDownloader.isNotSupported(e)) return !1;
el[0].classList.add("btnDownloadAttachments-load"), attachmentDownloader.all(scope.model, el[0]).then(reset)
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick)
})
}
}
}), angular.module("proton.attachments").directive("iconAttachment", function(embedded) {
var MAP_CLASSNAME = {
zip: "fa-archive-o",
mp3: "fa-audio-o",
javascript: "fa-code-o",
xls: "fa-excel-o",
mov: "fa-movie-o",
pdf: "fa-pdf-o",
power: "fa-powerpoint-o",
word: "fa-word-o"
},
getFileIconsType = function(_ref) {
var MIMEType = _ref.MIMEType;
return Object.keys(MAP_CLASSNAME).filter(function(key) {
return MIMEType.includes(key)
}).reduce(function(acc, key) {
return acc.push(MAP_CLASSNAME[key]), acc
}, [])
},
getAttachmentType = function(attachment) {
if (embedded.isEmbedded(attachment)) return ["fa-picture-o", "embedded"];
var list = ["fa-file-o"];
return attachment.MIMEType.includes("image") && list.push("fa-image-o"), list
};
return {
replace: !0,
template: '<i class="fa"></i>',
link: function(scope, el) {
var classNames = [].concat(getAttachmentType(scope.attachment)).concat(getFileIconsType(scope.attachment));
_rAF(function() {
var _el$0$classList;
(_el$0$classList = el[0].classList).add.apply(_el$0$classList, _toConsumableArray(classNames))
})
}
}
}), angular.module("proton.attachments").directive("listAttachments", function($state, $rootScope, attachmentDownloader, notification, AppModel) {
return {
scope: {
model: "="
},
replace: !0,
templateUrl: "templates/directives/attachments/listAttachments.tpl.html",
link: function(scope, el) {
var $list = el[0].querySelector(".listAttachments-list"),
hide = function() {
return !scope.model.Attachments.length && el[0].classList.add("hidden")
},
show = function() {
return scope.model.Attachments.length && el[0].classList.remove("hidden")
},
unsubscribe = $rootScope.$on("attachmentAdded", show);
hide(), $state.is("eo.reply") && el[0].classList.add("state-eoReply");
var onClick = function(e) {
var target = e.target;
if ("A" === target.nodeName) {
var ID = target.getAttribute("data-attachment-id"),
attachment = _.findWhere(scope.model.Attachments, {
ID: ID
});
if (target.classList.add("listAttachments-item-decrypt"), attachmentDownloader.isNotSupported(e)) return !1;
attachmentDownloader.download(attachment, scope.model, target).then(function() {
target.classList.add("listAttachments-item-download")
}).catch(function(error) {
target.classList.remove("listAttachments-item-decrypt"), AppModel.is("onLine") && notification.error(error)
})
}
if ("BUTTON" === target.nodeName) {
var _ID = target.getAttribute("data-attachment-id");
$state.is("eo.reply") && $rootScope.$emit("attachment.upload.outside", {
type: "remove",
data: {
id: target.getAttribute("data-attachment-id"),
message: scope.model
}
}), scope.$applyAsync(function() {
1 === (_.findWhere(scope.model.Attachments, {
ID: _ID
}).Headers || {}).embedded && scope.model.NumEmbedded--, scope.model.Attachments = scope.model.Attachments.filter(function(att) {
return att.ID !== _ID
}), hide()
})
}
};
$list.addEventListener("click", onClick, !1), scope.$on("$destroy", function() {
$list.removeEventListener("click", onClick, !1), unsubscribe()
})
}
}
}), angular.module("proton.attachments").factory("attachmentFileFormat", function(aboutClient) {
var embedded = ["image/gif", "image/jpeg", "image/png", "image/bmp"],
isSafari = function() {
return aboutClient.isSafari()
},
isUploadMIMEType = function(type) {
return aboutClient.isIE11() ? "Text" !== type : "text/html" !== type && "text/plain" !== type && "text/uri-list" !== type
};
return {
isEmbedded: function(key) {
return _.contains(embedded, key)
},
getEmbedded: function() {
return embedded
},
isUploadAbleType: function(_ref) {
var dataTransfer = _ref.dataTransfer,
list = [].concat(_toConsumableArray(dataTransfer.types || []));
return !(aboutClient.isIE11() && !list.length) && (isSafari() ? list.some(function(type) {
return "Files" === type
}) : list.every(isUploadMIMEType))
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.attachments").factory("attachmentModel", function($q, attachmentApi, AttachmentLoader, authentication, $rootScope, embedded, notification, networkActivityTracker, composerRequestModel, attachmentDownloader, gettextCatalog) {
function buildQueue(_ref2) {
var messageID = _ref2.messageID,
message = _ref2.message,
queue = _ref2.queue;
queue.files.length && (queueMessage[messageID] = queue, queue.hasEmbedded || dispatch("upload", {
messageID: messageID,
message: message,
action: "attachment"
}))
}
function create(file, message) {
var insert = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2],
cid = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "";
return upload([{
file: file,
isEmbedded: insert
}], message, insert && "inline", !1, cid).then(function(_ref3) {
var _ref4 = _slicedToArray(_ref3, 1),
upload = _ref4[0];
return message.uploading = 0, upload
}).catch(function(err) {
throw console.error(err), err
})
}
function uploadQueue(_ref5) {
var messageID = _ref5.messageID,
message = _ref5.message,
action = _ref5.action;
if ("cancel" === action) return void delete queueMessage[messageID];
upload(queueMessage[messageID].files, message, action).then(function() {
message.uploading = 0, delete queueMessage[messageID]
})
}
function upload() {
var queue = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
action = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "attachment",
triggerEvent = !(arguments.length > 3 && void 0 !== arguments[3]) || arguments[3],
cid = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : "",
deferred = $q.defer(),
promises = _.map(queue, function(_ref6, i, list) {
var file = _ref6.file,
isEmbedded = _ref6.isEmbedded;
return file.inline = +(isEmbedded && "inline" === action), addAttachment(file, message, list.length, cid)
});
return message.uploading = promises.length, message.encryptingAttachment = !0, dispatchMessageAction(message), composerRequestModel.save(message, deferred), networkActivityTracker.track(deferred.promise), Promise.all(promises).then(function(upload) {
return upload.filter(Boolean)
}).then(function(upload) {
message.uploading = 0, message.encryptingAttachment = !1, dispatchMessageAction(message);
var embeddedMap = addEmbedded(upload, message);
return _.map(upload, function(config) {
return embeddedMap[config.attachment.ID] || config
})
}).then(function(upload) {
return message.addAttachments(upload.map(function(_ref7) {
return _ref7.attachment
})), updateMapAttachments(upload), triggerEvent && upload.length && dispatch("upload.success", {
upload: upload,
message: message,
messageID: message.ID
}), deferred.resolve(), upload
}).catch(function(err) {
dispatchMessageAction(message), deferred.reject(err)
})
}
function isEmbedded(_ref8) {
var _ref8$Headers = _ref8.Headers;
return "inline" === (void 0 === _ref8$Headers ? {} : _ref8$Headers)["content-disposition"]
}
function addEmbedded() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return _.chain(list).filter(function(_ref9) {
var _ref9$attachment = _ref9.attachment;
return isEmbedded(void 0 === _ref9$attachment ? {} : _ref9$attachment)
}).filter(function(_ref10) {
return _ref10.cid
}).map(function(_ref11) {
var packets = _ref11.packets,
attachment = _ref11.attachment,
sessionKey = _ref11.sessionKey,
cid = _ref11.cid,
REQUEST_ID = _ref11.REQUEST_ID;
return {
packets: packets,
sessionKey: sessionKey,
attachment: attachment,
cid: cid,
url: embedded.addEmbedded(message, cid, packets.Preview, attachment.MIMEType).url,
REQUEST_ID: REQUEST_ID
}
}).reduce(function(acc, o) {
return acc[o.attachment.ID] = o, acc
}, {}).value()
}
function getConfigMapAttachment(id, attachment) {
return MAP_ATTACHMENTS[id] ? MAP_ATTACHMENTS[id] : _.filter(MAP_ATTACHMENTS, function(config) {
return config.attachment.ID === attachment.ID
})[0]
}
function cleanMap(_ref12) {
var REQUEST_ID = _ref12.REQUEST_ID;
delete MAP_ATTACHMENTS[REQUEST_ID]
}
function remove(data) {
var id = data.id,
message = data.message,
packet = data.packet,
messageID = data.messageID,
msg = message || {
ID: messageID
},
attachment = data.attachment || getAttachment(msg, id);
attachmentApi.remove(msg, attachment).then(function() {
var attConf = getConfigMapAttachment(id, attachment),
state = _.extend({}, attConf || data, {
message: message,
attachment: attachment,
id: id
});
1 === packet.Inline && "text/plain" !== message.MIMEType && dispatch("remove.embedded", state), message.removeAttachment(attachment), dispatch("remove.success", state), cleanMap(state)
}).catch(function(exception) {
dispatch("remove.error", {
message: message,
exception: exception
})
})
}
function removeAll(_ref13) {
var message = _ref13.message;
_ref13.list.forEach(function(attachment) {
remove({
id: attachment.ID,
attachment: attachment,
message: message,
packet: {
Inline: +isEmbedded(attachment)
}
})
})
}
function addAttachment(file, message) {
var total = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1,
cid = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "",
tempPacket = {
filename: file.name,
uploading: !0,
Size: file.size,
ContentID: cid,
Inline: file.inline || 0
};
return tempPacket.Inline && message.NumEmbedded++, message.attachmentsToggle = !0, AttachmentLoader.load(file, message.From.Keys[0].PublicKey).then(function(packets) {
return attachmentApi.upload(packets, message, tempPacket, total).then(function(_ref14) {
var attachment = _ref14.attachment,
sessionKey = _ref14.sessionKey,
REQUEST_ID = _ref14.REQUEST_ID,
isAborted = _ref14.isAborted,
isError = _ref14.isError;
if (isAborted || isError) throw new Error("Request error");
var contentId = (attachment.Headers || {})["content-id"] || "",
cid = contentId.replace(/[<>]+/g, "");
return {
attachment: attachment,
sessionKey: sessionKey,
packets: packets,
cid: cid,
REQUEST_ID: REQUEST_ID
}
}).catch(function(err) {
console.error(err), notification.error(I18N.ERROR_UPLOAD)
})
}).catch(function(err) {
throw console.error(err), notification.error(I18N.ERROR_ENCRYPT), err
})
}
function downloadFromComposer(_ref16) {
var id = _ref16.id,
message = _ref16.message,
config = MAP_ATTACHMENTS[id] || {
attachment: message.getAttachment(id)
};
config.attachment && attachmentDownloader.download(config.attachment, message)
}
var queueMessage = {},
MAP_ATTACHMENTS = {},
I18N = {
ERROR_UPLOAD: gettextCatalog.getString("Error during file upload", null, "Compose message"),
ERROR_ENCRYPT: gettextCatalog.getString("Error encrypting attachment", null, "Compose message")
},
dispatch = function(type, data) {
return $rootScope.$emit("attachment.upload", {
type: type,
data: data
})
},
dispatchMessageAction = function(message) {
return $rootScope.$emit("actionMessage", message)
},
updateMapAttachments = function() {
var uploads = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
MAP_ATTACHMENTS = uploads.reduce(function(acc, att) {
return acc[att.REQUEST_ID] = att, acc
}, MAP_ATTACHMENTS)
},
getAttachment = function(message, id) {
return MAP_ATTACHMENTS[id] ? MAP_ATTACHMENTS[id].attachment : _.findWhere(message.Attachments, {
ID: id
})
};
return $rootScope.$on("attachment.upload", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
switch (type) {
case "close":
attachmentApi.killUpload(data);
break;
case "uploading":
data.message.encryptingAttachment = !1, dispatchMessageAction(data.message);
break;
case "cancel":
dispatchMessageAction(data.message);
break;
case "remove":
remove(data);
break;
case "remove.all":
removeAll(data);
break;
case "drop":
buildQueue(data);
break;
case "upload":
uploadQueue(data);
break;
case "download.composer":
downloadFromComposer(data)
}
}), {
create: create,
getCurrentQueue: function(_ref15) {
var ID = _ref15.ID;
return queueMessage[ID]
}
}
}), angular.module("proton.attachments").factory("embeddedStore", function($rootScope, embeddedUtils) {
function getHashKey(msg) {
return ("" + (!!msg.isDraft && msg.isDraft() ? PREFIX_DRAFT : "") + (msg.ConversationID || msg.ID)).trim()
}
function deallocateList(key) {
var list = MAP_BLOBS[key] || [];
_.each(list, function(cid) {
Blobs[cid] && (urlCreator().revokeObjectURL(Blobs[cid].url), delete Blobs[cid])
}), delete MAP_BLOBS[key]
}
function deallocate() {
var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
key = getHashKey(message);
Object.keys(MAP_BLOBS).filter(function(k) {
return k !== key && 0 !== k.indexOf(PREFIX_DRAFT)
}).forEach(deallocateList)
}
var Blobs = {},
MAP_BLOBS = {},
CIDList = {},
PREFIX_DRAFT = "draft_",
urlCreator = function() {
return window.URL || window.webkitURL
};
$rootScope.$on("composer.update", function(e, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if ("close" === type) {
var _data$message = data.message,
ID = _data$message.ID,
ConversationID = _data$message.ConversationID,
key = "" + PREFIX_DRAFT + (ConversationID || ID);
CIDList[ID] && delete CIDList[ID], MAP_BLOBS[key] && deallocateList(key)
}
});
var store = function() {
var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {
isDraft: angular.noop
},
cid = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
Attachments = CIDList[message.ID] || {},
_ref2 = Attachments[cid] || {},
_ref2$Headers = _ref2.Headers,
Headers = void 0 === _ref2$Headers ? {} : _ref2$Headers,
key = getHashKey(message);
return MAP_BLOBS[key] = MAP_BLOBS[key] || [],
function(data, MIME) {
if (MAP_BLOBS[key]) {
var blob = new Blob([data], {
type: MIME
}),
imageUrl = urlCreator().createObjectURL(blob);
Blobs[cid] = {
url: imageUrl,
isContentLocation: void 0 !== Headers["content-location"] && void 0 === Headers["content-id"]
}, blob = null, imageUrl = null, MAP_BLOBS[key].push(cid)
}
}
},
getBlob = function(cid) {
return Blobs[cid] || {}
},
hasBlob = function(cid) {
return !!Blobs[cid]
},
getMessageCIDs = function(_ref3) {
var ID = _ref3.ID;
return CIDList[ID] || {}
},
containsMessageCIDs = function(_ref4) {
var ID = _ref4.ID;
return Object.keys(CIDList[ID] || {}).length > 0
},
addMessageCID = function(message, _ref5) {
var _ref5$Headers = _ref5.Headers,
Headers = void 0 === _ref5$Headers ? {} : _ref5$Headers,
_ref5$Name = _ref5.Name,
Name = void 0 === _ref5$Name ? "" : _ref5$Name;
!CIDList[message.ID] && (CIDList[message.ID] = {}), !message.NumEmbedded && (message.NumEmbedded = 0);
var cid = embeddedUtils.readCID(Headers);
Headers.embedded = 1, message.NumEmbedded++, CIDList[message.ID][cid] = {
Headers: Headers,
Name: Name
}
},
existMessageCID = function(message, cid) {
return !!getMessageCIDs(message)[cid]
};
return {
store: store,
deallocate: deallocate,
getBlob: getBlob,
hasBlob: hasBlob,
getBlobValue: function(cid) {
var _getBlob = getBlob(cid),
url = _getBlob.url;
return embeddedUtils.getBlobFromURL(url)
},
cid: {
contains: containsMessageCIDs,
exist: existMessageCID,
add: addMessageCID,
get: getMessageCIDs
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.attachments").factory("AttachmentLoader", function($cacheFactory, $log, $q, pmcw, authentication, $state, $stateParams, Eo, secureSessionStorage, attachmentApi) {
function load(file, pubKeys, privKey) {
var deferred = $q.defer(),
reader = new FileReader;
return file ? (reader.onloadend = function() {
encrypt(reader.result, pubKeys, privKey, file).then(deferred.resolve).catch(function() {
return deferred.reject("Failed to encrypt attachment. Please try again.")
})
}, reader.readAsArrayBuffer(file), deferred.promise) : deferred.reject(new TypeError("You did not provide a file"))
}
var cache = $cacheFactory("attachments"),
getCacheKey = function(_ref) {
return "attachment." + _ref.ID
},
isOutside = function() {
return $state.is("eo.message") || $state.is("eo.reply")
},
getRequest = function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
ID = _ref2.ID;
if (isOutside()) {
var decryptedToken = secureSessionStorage.getItem("proton:decrypted_token"),
token = $stateParams.tag;
return Eo.attachment(decryptedToken, token, ID)
}
return attachmentApi.get(ID)
},
decrypt = function(attachment, pubKey) {
var sessionKey = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
at = new Uint8Array(attachment);
return pmcw.decryptMessage({
message: pmcw.getMessage(at),
sessionKey: sessionKey,
format: "binary",
publicKeys: pubKey ? pmcw.getKeys(pubKey) : []
}).then(function(_ref3) {
return _ref3.data
}).catch(function(err) {
return $log.error(err), err
})
},
encrypt = function(attachment, publicKeys, privateKeys) {
var _ref4 = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {},
name = _ref4.name,
type = _ref4.type,
size = _ref4.size,
inline = _ref4.inline,
data = new Uint8Array(attachment);
return pmcw.encryptMessage({
passwords: [],
filename: name,
armor: !1,
data: data,
publicKeys: pmcw.getKeys(publicKeys),
privateKeys: privateKeys
}).then(function(_ref5) {
var message = _ref5.message,
_pmcw$splitMessage = pmcw.splitMessage(message),
asymmetric = _pmcw$splitMessage.asymmetric,
encrypted = _pmcw$splitMessage.encrypted;
return {
Filename: name,
MIMEType: type,
FileSize: size,
Inline: inline,
Preview: data,
keys: asymmetric[0],
data: encrypted[0]
}
})
},
getSessionKey = function(message, attachment) {
if (attachment.sessionKey) return Promise.resolve(attachment);
var keyPackets = pmcw.binaryStringToArray(pmcw.decode_base64(attachment.KeyPackets)),
options = {
message: pmcw.getMessage(keyPackets)
};
return isOutside() ? options.password = pmcw.decode_utf8_base64(secureSessionStorage.getItem("proton:encrypted_password")) : options.privateKeys = authentication.getPrivateKeys(message.AddressID), pmcw.decryptSessionKey(options).then(function(sessionKey) {
return angular.extend({}, attachment, {
sessionKey: sessionKey
})
})
};
return {
get: function() {
var attachment = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
if (cache.get("attachment." + attachment.ID)) return Promise.resolve(cache.get(getCacheKey(attachment)));
if (attachment.Preview) return Promise.resolve(attachment.Preview);
var request = getRequest(attachment),
key = getSessionKey(message, attachment);
return Promise.all([request, key]).then(function(_ref6) {
var _ref7 = _slicedToArray(_ref6, 2),
data = _ref7[0].data,
sessionKey = _ref7[1].sessionKey;
return decrypt(data, null, sessionKey)
}).then(function(data) {
return cache.put(getCacheKey(attachment), data), data
}).catch(function(err) {
throw err
})
},
load: load,
flushCache: function() {
return cache.removeAll()
},
getSessionKey: getSessionKey
}
}), angular.module("proton.attachments").factory("attachmentApi", function($http, url, $q, $rootScope, authentication, pmcw, CONFIG, CONSTANTS, secureSessionStorage, gettextCatalog, notification) {
function killUpload(_ref) {
var id = _ref.id,
messageID = _ref.messageID;
_.findWhere(pendingUpload, {
id: id,
messageID: messageID
}).request.abort(), pendingUpload = pendingUpload.filter(function(up) {
return up.id !== id
})
}
var pendingUpload = [],
requestURL = url.build("attachments"),
dispatch = function(type, data) {
return $rootScope.$emit("attachment.upload", {
type: type,
data: data
})
},
dispatchUpload = function(REQUEST_ID, message, packet) {
return function(progress, status) {
var isStart = arguments.length > 2 && void 0 !== arguments[2] && arguments[2];
dispatch("uploading", {
id: REQUEST_ID,
messageID: message.ID,
message: message,
status: status,
progress: progress,
packet: packet,
isStart: isStart
})
}
},
parseJSON = function(xhr) {
var response = function(json) {
return {
json: json,
isInvalid: arguments.length > 1 && void 0 !== arguments[1] && arguments[1]
}
};
try {
return response(JSON.parse(xhr.responseText))
} catch (e) {
return response({
Error: "JSON parsing error: " + xhr.responseText
}, !0)
}
},
makeFormUpload = function(packets, message, tempPacket) {
var data = new FormData;
return data.append("Filename", packets.Filename), data.append("MessageID", message.ID), data.append("ContentID", tempPacket.ContentID), data.append("MIMEType", packets.MIMEType), data.append("Inline", packets.Inline), data.append("KeyPackets", new Blob([packets.keys])), data.append("DataPacket", new Blob([packets.data])), data
};
return {
get: function(ID) {
return $http.get(requestURL(ID), {
responseType: "arraybuffer"
})
},
upload: function(packets, message, tempPacket, total) {
var REQUEST_ID = Math.random().toString(32).slice(2, 12) + "-" + Date.now(),
dispatcher = dispatchUpload(REQUEST_ID, message, tempPacket),
deferred = $q.defer(),
xhr = new XMLHttpRequest,
keys = authentication.getPrivateKeys(message.AddressID),
unsubscribe = $rootScope.$on("AppModel", function(e, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"onLine" !== type || data.value || xhr.abort()
});
return pendingUpload.push({
id: REQUEST_ID,
messageID: message.ID,
packet: tempPacket,
request: xhr
}), dispatcher(1, !0, !0), xhr.upload.onprogress = function(event) {
var progress = event.loaded / event.total * 99;
dispatcher(progress, !0)
}, xhr.onerror = function() {
pendingUpload = _.reject(pendingUpload, {
id: REQUEST_ID,
messageID: message.ID
}), message.uploading = _.where(pendingUpload, {
messageID: message.ID
}).length, dispatch("error", {
id: REQUEST_ID,
messageID: message.ID,
message: message
}), deferred.resolve({
id: REQUEST_ID,
isError: !0
}), unsubscribe()
}, xhr.onabort = function() {
pendingUpload = _.reject(pendingUpload, {
id: REQUEST_ID,
messageID: message.ID
}), message.uploading = _.where(pendingUpload, {
messageID: message.ID
}).length, dispatch("cancel", {
id: REQUEST_ID,
messageID: message.ID,
message: message
}), deferred.resolve({
id: REQUEST_ID,
isAborted: !0
}), unsubscribe()
}, xhr.onload = function() {
var _parseJSON = parseJSON(xhr),
json = _parseJSON.json,
isInvalid = _parseJSON.isInvalid,
statusCode = this.status;
if (unsubscribe(), 200 !== statusCode) return notification.error(gettextCatalog.getString("Unable to upload file. Please try again", null, "Error")), deferred.reject(json);
if (json.Error) {
var msgError = isInvalid ? gettextCatalog.getString("Unable to upload file. Please try again", null, "Error") : json.Error;
return notification.error(msgError), deferred.reject(json)
}
dispatcher(100, !1), dispatch("uploaded.success", {
id: REQUEST_ID,
messageID: message.ID,
packet: tempPacket,
total: total,
message: message
}), pendingUpload = _.reject(pendingUpload, {
id: REQUEST_ID,
messageID: message.ID
});
var msg = pmcw.getMessage(packets.keys);
pmcw.decryptSessionKey({
message: msg,
privateKeys: keys
}).then(function(sessionKey) {
return {
REQUEST_ID: REQUEST_ID,
sessionKey: sessionKey,
attachment: _.extend({}, json.Attachment || {}, {
sessionKey: sessionKey
})
}
}).then(deferred.resolve).catch(deferred.reject)
}, xhr.open("post", requestURL("upload"), !0), xhr.withCredentials = !0, xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"), xhr.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"), xhr.setRequestHeader("x-pm-appversion", "Web_" + CONFIG.app_version), xhr.setRequestHeader("x-pm-apiversion", CONFIG.api_version), xhr.setRequestHeader("x-pm-session", pmcw.decode_base64(secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken") || "")), xhr.send(makeFormUpload(packets, message, tempPacket)), deferred.promise
},
killUpload: killUpload,
remove: function(message, attachment) {
return $http.delete(requestURL(attachment.ID), {
MessageID: message.ID
}).then(function(_ref3) {
var _ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
if (1e3 !== data.Code) {
var error = data.Error || "Error during the remove request";
throw new Error(error)
}
return data
}).catch(function(error) {
notification.error(error), console.error(error)
})
}
}
}), angular.module("proton.attachments").factory("attachmentDownloader", function(gettextCatalog, AttachmentLoader, embeddedUtils, aboutClient, notification) {
var isFileSaverSupported = aboutClient.isFileSaverSupported(),
I18N = {
NOT_SUPPORTED: gettextCatalog.getString("Your browser lacks features needed to download encrypted attachments directly. Please right-click on the attachment and select Save/Download As.", null, "Error"),
ERROR_ZIP: gettextCatalog.getString("Cannot generate a zip of your attachments.", null, "Error")
},
isNotSupported = function(e) {
return !(!e.target.href || -1 === e.target.href.search(/^data.*/)) && (alert(I18N.NOT_SUPPORTED), e.preventDefault(), e.stopPropagation(), !0)
},
downloadFile = function(blob, name, el) {
try {
if (isFileSaverSupported) return window.saveAs(blob, name);
var reader = new FileReader;
reader.onloadend = function() {
el.href = reader.result
}, reader.readAsDataURL(blob)
} catch (error) {
console.error(error)
}
},
generateDownload = function(attachment) {
downloadFile(new Blob([attachment.data], {
type: attachment.MIMEType
}), attachment.Name, attachment.el)
},
formatDownload = function(attachment, message, el) {
return AttachmentLoader.get(attachment, message).then(function(buffer) {
return {
data: buffer,
Name: attachment.Name,
MIMEType: attachment.MIMEType,
el: el
}
})
};
return {
isNotSupported: isNotSupported,
download: function(attachment, message, el) {
return formatDownload(attachment, message, el).then(generateDownload)
},
all: function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
var promises, list, zip, content, message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
el = arguments[1];
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.prev = 0, promises = (message.Attachments || []).filter(function(att) {
return !embeddedUtils.isEmbedded(att)
}).map(function(att) {
return formatDownload(att, message)
}), _context.next = 4, Promise.all(promises);
case 4:
return list = _context.sent, zip = new window.JSZip, list.forEach(function(_ref2) {
var Name = _ref2.Name,
data = _ref2.data;
return zip.file(Name, data)
}), _context.next = 9, zip.generateAsync({
type: "blob"
});
case 9:
content = _context.sent, downloadFile(content, "Attachments-" + message.Subject + ".zip", el), _context.next = 17;
break;
case 13:
_context.prev = 13, _context.t0 = _context.catch(0), console.error(_context.t0), notification.error(I18N.ERROR_ZIP);
case 17:
case "end":
return _context.stop()
}
}, _callee, void 0, [
[0, 13]
])
}));
return function() {
return _ref.apply(this, arguments)
}
}()
}
}), angular.module("proton.attachments").factory("embedded", function(embeddedFinder, embeddedStore, embeddedParser, embeddedUtils) {
var REGEXP_CID_START = /^cid:/g;
return {
parser: function(message) {
var _ref = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref$direction = _ref.direction,
direction = void 0 === _ref$direction ? "blob" : _ref$direction,
_ref$text = _ref.text,
text = void 0 === _ref$text ? "" : _ref$text,
_ref$isOutside = _ref.isOutside,
isOutside = void 0 !== _ref$isOutside && _ref$isOutside,
content = text || message.getDecryptedBody();
return embeddedFinder.find(message) ? embeddedParser.decrypt(message).then(function() {
return embeddedParser.escapeHTML(message, direction, content)
}).catch(function(error) {
throw console.error(error), error
}) : isOutside ? Promise.resolve(embeddedParser.escapeHTML(message, direction, content)) : Promise.resolve(content)
},
addEmbedded: function(message, cid, data, MIME) {
return embeddedStore.store(message, cid)(data, MIME), embeddedStore.getBlob(cid)
},
getUrl: function(node) {
var cid = embeddedUtils.srcToCID(node),
_embeddedStore$getBlo = embeddedStore.getBlob(cid),
_embeddedStore$getBlo2 = _embeddedStore$getBlo.url;
return void 0 === _embeddedStore$getBlo2 ? "" : _embeddedStore$getBlo2
},
getAttachment: function(message, src) {
var cid = src.replace(REGEXP_CID_START, "");
if (embeddedFinder.find(message)) return embeddedStore.cid.get(message)[cid] || {}
},
isEmbedded: embeddedUtils.isEmbedded,
getCid: embeddedUtils.readCID,
getBlob: embeddedStore.getBlobValue,
deallocator: embeddedStore.deallocate,
clean: embeddedStore.cleanMemory,
removeEmbedded: embeddedParser.removeEmbeddedHTML,
exist: embeddedStore.cid.exist,
generateCid: embeddedUtils.generateCid
}
}), angular.module("proton.attachments").factory("embeddedFinder", function(embeddedStore, embeddedUtils) {
return {
find: function(message) {
var list = message.getAttachments();
return message.NumEmbedded = 0, !!list.length && (_.each(list, function(attachment) {
embeddedUtils.isEmbedded(attachment) && embeddedStore.cid.add(message, attachment)
}), embeddedStore.cid.contains(message))
},
listInlineAttachments: function(message) {
var list = message.getAttachments(),
MAP_CID = embeddedStore.cid.get(message);
return Object.keys(MAP_CID).reduce(function(acc, cid) {
var contentId = MAP_CID[cid].Headers["content-id"],
contentName = embeddedUtils.getAttachementName(MAP_CID[cid].Headers),
attachment = list.filter(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$Headers = _ref.Headers,
Headers = void 0 === _ref$Headers ? {} : _ref$Headers,
_ref$Name = _ref.Name,
Name = void 0 === _ref$Name ? "" : _ref$Name;
return Headers["content-location"] ? Name === contentName : Headers["content-id"] === contentId
})[0];
return attachment && acc.push({
cid: cid,
attachment: attachment
}), acc
}, [])
}
}
}), angular.module("proton.attachments").factory("embeddedParser", function(embeddedStore, embeddedFinder, embeddedUtils, AttachmentLoader, attachmentFileFormat, authentication, $state) {
var DIV = document.createElement("DIV"),
getBodyParser = function() {
return DIV.innerHTML = "", DIV
},
actionDirection = {
blob: function(nodes, cid, url) {
_.each(nodes, function(node) {
node.src = url, node.setAttribute("data-embedded-img", cid), node.removeAttribute("data-src"), node.classList.add("proton-embedded")
})
},
cid: function(nodes, _cid) {
_.each(nodes, function(node) {
node.removeAttribute("data-embedded-img"), node.removeAttribute("src"), node.setAttribute("data-src", "cid:" + _cid)
})
}
};
return {
escapeHTML: function(message, direction, body) {
var testDiv = getBodyParser();
return testDiv.innerHTML = body.replace(/src="cid/g, 'data-src="cid'), Object.keys(embeddedStore.cid.get(message)).forEach(function(cid) {
var current = embeddedStore.getBlob(cid),
url = current ? current.url : "",
selector = 'img[src="' + cid + '"], img[data-embedded-img="cid:' + cid + '"], img[data-embedded-img="' + cid + '"], img[data-src="cid:' + cid + '"]',
nodes = [].slice.call(testDiv.querySelectorAll(selector));
nodes.length && (actionDirection[direction] || angular.noop)(nodes, cid, url)
}), testDiv.innerHTML.replace(/data-src/g, "src")
},
removeEmbeddedHTML: function(message) {
var Headers = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
content = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "";
if (embeddedUtils.isInline(Headers)) {
var cid = embeddedUtils.readCID(Headers),
tempDOM = $("<div>" + (content || message.getDecryptedBody()) + "</div>");
message.NumEmbedded--;
var nodes = tempDOM.find('img[src="cid:' + cid + '"], img[data-embedded-img="cid:' + cid + '"], img[data-embedded-img="' + cid + '"]');
nodes.length && nodes.remove(), message.setDecryptedBody(tempDOM.html(), !0)
}
return message.getDecryptedBody()
},
decrypt: function(message) {
var list = embeddedFinder.listInlineAttachments(message),
user = authentication.user || {
ShowEmbedded: 0
},
show = !0 === message.showEmbedded || 1 === user.ShowEmbedded,
isDraft = $state.includes("secured.drafts.**") || message.isDraft(),
promise = _.chain(list).filter(function(_ref) {
return _ref.attachment.KeyPackets
}).filter(function(_ref2) {
var cid = _ref2.cid;
return !embeddedStore.hasBlob(cid) && (show || isDraft)
}).map(function(_ref3) {
var cid = _ref3.cid,
attachment = _ref3.attachment,
storeAttachement = embeddedStore.store(message, cid);
return AttachmentLoader.get(attachment, message).then(function(buffer) {
return storeAttachement(buffer, attachment.MIMEType)
})
}).value();
return promise.length ? Promise.all(promise).then(function() {
return list.reduce(function(acc, _ref4) {
var cid = _ref4.cid;
return acc[cid] = embeddedStore.getBlob(cid), acc
}, Object.create(null))
}) : Promise.resolve({})
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.attachments").factory("embeddedUtils", function(attachmentFileFormat, tools) {
function trimQuotes(input) {
var value = (input || "").trim();
return ['"', "'", "<"].indexOf(value.charAt(0)) > -1 && ['"', "'", ">"].indexOf(value.charAt(value.length - 1)) > -1 ? value.substr(1, value.length - 2) : value
}
function isEmbedded(_ref) {
var _ref$Headers = _ref.Headers,
Headers = void 0 === _ref$Headers ? {} : _ref$Headers,
_ref$MIMEType = _ref.MIMEType,
MIMEType = void 0 === _ref$MIMEType ? "" : _ref$MIMEType;
return isInline(Headers) && attachmentFileFormat.isEmbedded(MIMEType)
}
var DIV = document.createElement("DIV"),
REGEXP_CID_START = /^cid:/g,
getBodyParser = function() {
return DIV.innerHTML = "", DIV
},
readCID = function() {
var Headers = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return Headers["content-id"] ? trimQuotes(Headers["content-id"]) : Headers["content-location"] ? trimQuotes(Headers["content-location"]) : ""
},
isInline = function() {
return !!(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {})["content-id"]
};
return {
isInline: isInline,
isEmbedded: isEmbedded,
getAttachementName: function() {
var Headers = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
if ("inline" !== Headers["content-disposition"]) {
var _Headers$contentDisp = Headers["content-disposition"].split("filename="),
_Headers$contentDisp2 = _slicedToArray(_Headers$contentDisp, 2),
name = _Headers$contentDisp2[1];
if (name) return name.replace(/"/g, "")
}
return ""
},
generateCid: function(input, email) {
return tools.hash(input).toString(16) + "@" + email.split("@")[1]
},
srcToCID: function(node) {
return (node.getAttribute("data-embedded-img") || "").replace(REGEXP_CID_START, "")
},
readCID: readCID,
trimQuotes: trimQuotes,
getBodyParser: getBodyParser,
getBlobFromURL: function() {
var url = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
xhr = new XMLHttpRequest;
return new Promise(function(resolve, reject) {
xhr.open("GET", url, !0), xhr.responseType = "blob", xhr.onload = function() {
if (200 === xhr.status) return resolve(xhr.response);
reject(xhr.response)
}, xhr.send()
})
}
}
}), angular.module("proton.authentication").controller("LoginController", function($rootScope, $state, $stateParams, $scope, $log, $timeout, $http, $location, CONSTANTS, CONFIG, gettextCatalog, authentication, networkActivityTracker, notify, helpLoginModal, AppModel, pmcw, tempStorage, aboutClient, settingsApi, srp) {
function clearErrors() {
$scope.error = null, notify.closeAll()
}
function setLoggedIn() {
$rootScope.isLoggedIn = !$state.is("login")
}
function focusInput() {
$timeout(function() {
return $("#username").focus()
}, 30, !1)
}
function selectPassword() {
var input = document.getElementById("password");
input.focus(), input.select()
}
function selectTwoFactor() {
var input = document.getElementById("twoFactorCode");
input.focus(), input.select()
}
function checkHelpTag() {
"help" === $location.hash() && $scope.displayHelpModal()
}
function testSessionStorage() {
!1 === aboutClient.hasSessionStorage() && notify({
message: gettextCatalog.getString('You are in Private Mode or have Session Storage disabled.\nPlease deactivate Private Mode and then reload the page.\n<a href="https://protonmail.com/support/knowledge-base/enabling-cookies/" target="_blank">More information here</a>.', null, "Error"),
classes: "notification-danger",
duration: "0"
})
}
function testCookie() {
!1 === aboutClient.hasCookie() && notify({
message: gettextCatalog.getString('Cookies are disabled.\nPlease activate it and then reload the page.\n<a href="https://protonmail.com/support/knowledge-base/enabling-cookies/" target="_blank">More information here</a>.', null, "Error"),
classes: "notification-danger",
duration: "0"
})
}
function autoLogin() {
if ($scope.creds = tempStorage.getItem("creds"), $state.is("login.unlock")) {
if (!$scope.creds) return $state.go("login");
if (!$scope.creds.authResponse) return tempStorage.setItem("creds", $scope.creds), $state.go("login");
if (1 === $scope.creds.authResponse.PasswordMode) return unlock($scope.creds.password, $scope.creds.authResponse);
AppModel.set("domoArigato", !1)
} else if ($state.is("login.sub")) {
var url = window.location.href,
arr = url.split("/"),
domain = arr[0] + "//" + arr[2],
_login = function _login(event) {
if (event.origin === domain) {
window.removeEventListener("message", _login);
var sessionToken = event.data.SessionToken,
adminPassword = event.data.MailboxPassword;
authentication.savePassword(adminPassword), authentication.saveAuthData({
SessionToken: sessionToken
}), $rootScope.isSecure = !0, $rootScope.isLoggedIn = !0, $state.go("secured.inbox")
}
};
window.addEventListener("message", _login), window.opener.postMessage("ready", domain)
} else {
if (!$scope.creds || !$scope.creds.username || !$scope.creds.password) return void delete $scope.creds;
srp.info($scope.creds.username).then(function(resp) {
0 === resp.data.TwoFactor ? login($scope.creds.username, $scope.creds.password, null, resp) : ($scope.twoFactor = 1, $scope.initialInfoResponse = resp, $timeout(selectTwoFactor, 100, !1))
}).catch(function(error) {
console.log(error)
})
}
}
function resetLoginInputs() {
$scope.password = "", $scope.twoFactorCode = ""
}
function login(username, password, twoFactorCode, initialInfoResponse) {
networkActivityTracker.track(authentication.loginWithCredentials({
Username: username,
Password: password,
TwoFactorCode: twoFactorCode
}, initialInfoResponse).then(function(result) {
if ($log.debug("loginWithCredentials:result.data ", result), angular.isDefined(result.data) && angular.isDefined(result.data.Code) && 401 === result.data.Code) selectPassword(), notify({
message: result.data.ErrorDescription,
classes: "notification-danger"
});
else if (result.data && 10002 === result.data.Code) {
var message = void 0;
message = result.data.Error ? result.data.Error : "Your account has been disabled.", notify({
message: message,
classes: "notification-danger"
})
} else if (result.data && void 0 === result.data.PrivateKey) authentication.receivedCredentials({
AccessToken: result.data.AccessToken,
RefreshToken: result.data.RefreshToken,
Uid: result.data.Uid,
ExpiresIn: result.data.ExpiresIn,
EventID: result.data.EventID
}), authentication.setAuthCookie(result.data).then(function() {
$rootScope.isLoggedIn = !0, $state.go("login.setup")
}).catch(function(error) {
notify({
message: error.message,
classes: "notification-danger"
}), $state.go("login")
});
else if (result.data && result.data.AccessToken) {
$rootScope.isLoggedIn = !0;
var creds = {
username: username,
password: password,
authResponse: result.data
};
1 === result.data.PasswordMode && AppModel.set("domoArigato", !0), tempStorage.setItem("creds", creds), $state.go("login.unlock")
} else if (result.data && 5003 === result.data.Code);
else if (result.data && result.data.Error) {
var error = result.data.ErrorDescription ? result.data.ErrorDescription : result.data.Error;
notify({
message: error,
classes: "notification-danger"
}), resetLoginInputs()
} else notify({
message: "Unable to log you in.",
classes: "notification-danger"
}), resetLoginInputs()
}, function(result) {
void 0 === result.message && (result.message = "Sorry, our login server is down. Please try again later."), $scope.twoFactor = 0, $timeout(selectPassword, 100, !1), notify({
message: result.message,
classes: "notification-danger"
}), console.error(result), resetLoginInputs()
}))
}
function unlock() {
var mailboxPassword = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
authResponse = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return authentication.unlockWithPassword(mailboxPassword, authResponse).then(function(resp) {
return $log.debug("unlockWithPassword:resp" + resp), authentication.setAuthCookie(authResponse).then(function(resp) {
$log.debug("setAuthCookie:resp" + resp), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured(), $state.go("secured.inbox")
})
}).catch(function(error) {
$log.error("login.unlock", error), selectPassword(), notify({
message: error.message,
classes: "notification-danger"
})
})
}
$scope.twoFactor = 0, $scope.showOld = "old.protonmail.com" !== window.location.hostname, $scope.domoArigato = !0;
var unsubscribe = $rootScope.$on("AppModel", function(event, _ref) {
var type = _ref.type,
data = _ref.data;
switch (type) {
case "domoArigato":
$scope.domoArigato = data.value
}
});
$scope.$on("$destroy", function() {
return unsubscribe()
}), $scope.displayHelpModal = function() {
helpLoginModal.activate({
params: {
close: function() {
helpLoginModal.deactivate()
}
}
})
}, $scope.enterLoginPassword = function() {
angular.element("input").blur(), angular.element("#pm_login").attr({
action: "/*"
}), clearErrors();
var _$scope$username = $scope.username,
username = void 0 === _$scope$username ? "" : _$scope$username,
_$scope$password = $scope.password,
password = void 0 === _$scope$password ? "" : _$scope$password;
try {
if (!username || !password) throw new Error(gettextCatalog.getString("Please enter your username and password", null, "Login error"));
var usernameLowerCase = username.toLowerCase();
if (!pmcw.encode_utf8(password)) throw new Error(gettextCatalog.getString("Your password is missing", null, "Login error"));
networkActivityTracker.track(srp.info(usernameLowerCase).then(function(resp) {
$scope.initialInfoResponse = resp, 0 === resp.data.TwoFactor ? login(usernameLowerCase, password, null, $scope.initialInfoResponse) : ($scope.twoFactor = 1, $timeout(selectTwoFactor, 100, !1))
}, function(error) {
return Promise.reject(error)
}))
} catch (error) {
var message = error.message;
notify({
message: message,
classes: "notification-danger"
})
}
}, $scope.enterTwoFactor = function() {
if (angular.isUndefined($scope.twoFactorCode) || 0 === $scope.twoFactorCode.length) return void notify({
message: gettextCatalog.getString("Please enter your two-factor passcode", null, "Error"),
classes: "notification-danger"
});
login($scope.username, $scope.password, $scope.twoFactorCode, $scope.initialInfoResponse)
}, $scope.unlock = function(e) {
e.preventDefault(), angular.element("[type=password]").blur();
var mailboxPassword = $scope.mailboxPassword;
clearErrors(), networkActivityTracker.track(unlock(mailboxPassword, $scope.creds.authResponse))
}, $scope.reset = function() {
CONSTANTS.KEY_PHASE > 2 ? ($rootScope.isLoggedIn = !1, $state.go("support.reset-password")) : (tempStorage.setItem("creds", $scope.creds), $state.go("reset"))
},
function() {
AppModel.set("domoArigato", !0), setLoggedIn(), focusInput(), checkHelpTag(), testSessionStorage(), testCookie(), autoLogin()
}()
}), angular.module("proton.authentication").directive("loginForm", function() {
return {
replace: !0,
templateUrl: "templates/authentication/loginForm.tpl.html"
}
}), angular.module("proton.authentication").directive("loginTwoFactorForm", function() {
return {
replace: !0,
templateUrl: "templates/authentication/loginTwoFactorForm.tpl.html"
}
}), angular.module("proton.authentication").directive("twoFaField", function() {
return {
restrict: "E",
replace: !0,
templateUrl: "templates/authentication/twoFaField.tpl.html"
}
}), angular.module("proton.authentication").factory("authHttpResponseInterceptor", function($q, $injector, $rootScope, AppModel, networkUtils) {
var notification = !1,
upgradeNotification = !1,
NOTIFS = void 0,
buildNotifs = function() {
var gettextCatalog = $injector.get("gettextCatalog");
return {
newVersion: gettextCatalog.getString("A new version of ProtonMail is available. Please refresh this page."),
nonIntegerVersion: gettextCatalog.getString("Non-integer API version requested.", null, "Error"),
unsupported: gettextCatalog.getString("Unsupported API version.", null, "Error"),
offline: gettextCatalog.getString("The ProtonMail API is offline: ", null, "Error"),
noInternet: gettextCatalog.getString("No Internet connection found.", null, "Error"),
noServer: gettextCatalog.getString("Could not connect to server.", null, "Error"),
timeout: gettextCatalog.getString("Request timed out, please try again.", null, "Error"),
noReachProton: gettextCatalog.getString("ProtonMail cannot be reached right now, please try again later.", null, "Error")
}
},
notifyError = function(message) {
return $injector.get("notification").error(message)
};
return {
response: function(_response) {
if (/^(?!.*templates)/.test(_response.config.url) && AppModel.set("onLine", !0), !NOTIFS && (NOTIFS = buildNotifs()), notification && (notification.close(), notification = !1), angular.isDefined(_response.data) && angular.isDefined(_response.data.Code))
if (5003 === _response.data.Code) upgradeNotification && upgradeNotification.close(), upgradeNotification = $injector.get("notify")({
classes: "notification-info noclose",
message: NOTIFS.newVersion,
duration: "0"
});
else if (5004 === _response.data.Code) notifyError(NOTIFS.nonIntegerVersion);
else if (5005 === _response.data.Code) notifyError(NOTIFS.unsupported);
else if (7001 === _response.data.Code) notifyError(NOTIFS.offline + _response.data.Error);
else if (9001 === _response.data.Code) {
var handle9001 = $injector.get("handle9001");
return handle9001(_response.config)
}
return _response || $q.when(_response)
},
responseError: function(rejection) {
if (0 !== rejection.status && -1 !== rejection.status || networkUtils.isCancelledRequest(rejection)) {
if (401 === rejection.status) {
return $injector.get("handle401")(rejection)
}
if (403 === rejection.status) {
return $injector.get("handle403")(rejection.config)
}
504 === rejection.status ? (notification = notifyError(NOTIFS.timeout), AppModel.set("requestTimeout", !0)) : [408, 503].indexOf(rejection.status) > -1 && (notification = notifyError(NOTIFS.noReachProton))
} else {
var key = !0 === navigator.onLine ? "noServer" : "noInternet";
notifyError(NOTIFS[key]), AppModel.set("onLine", !1)
}
return $q.reject(rejection)
}
}
}), angular.module("proton.core").factory("helpLoginModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/authentication/modals/helpLoginModal.tpl.html",
controller: function(params) {
this.cancel = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("loginPasswordModal", function($timeout, pmModal, srp, networkActivityTracker, authentication) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/authentication/modals/loginPassword.tpl.html",
controller: function(params) {
var _this = this;
if (this.loginPassword = "", this.twoFactorCode = "", this.userPasswordMode = authentication.user.PasswordMode, this.submit = function() {
return params.submit(_this.loginPassword, _this.twoFactorCode)
}, this.cancel = function() {
return params.cancel()
}, params.hasTwoFactor) this.hasTwoFactor = 1 === params.hasTwoFactor;
else {
var promise = srp.info().then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
1e3 === data.Code && (_this.hasTwoFactor = 1 === data.TwoFactor)
});
networkActivityTracker.track(promise)
}
$timeout(function() {
return document.getElementById("loginPassword").focus()
}, 100, !1)
}
})
}), angular.module("proton.authentication").provider("pmcw", function() {
pmcrypto.checkMailboxPassword = function(prKey, prKeyPassCode, accessToken) {
return new Promise(function(resolve, reject) {
return void 0 === prKey ? reject(new Error("Missing private key.")) : void 0 === prKeyPassCode ? reject(new Error("Missing Mailbox Password.")) : void pmcrypto.decryptPrivateKey(prKey, prKeyPassCode).then(function(privateKey) {
var message = pmcrypto.getMessage(accessToken);
pmcrypto.decryptMessage({
message: message,
privateKey: privateKey
}).then(function(_ref) {
var data = _ref.data;
return resolve({
password: prKeyPassCode,
token: data
})
}).catch(function() {
return reject(new Error("Unable to get Access Token."))
})
}).catch(function() {
return reject(new Error("Wrong Mailbox Password."))
})
})
}, this.$get = function() {
return pmcrypto
}
}), angular.module("proton.authentication").factory("authentication", function($http, $location, $log, $q, $rootScope, $state, $injector, $exceptionHandler, authApi, checkKeysFormat, CONFIG, CONSTANTS, contactEmails, Contact, errorReporter, gettextCatalog, upgradePassword, Key, Label, networkActivityTracker, pmcw, secureSessionStorage, organizationApi, User, passwords, srp, labelsModel, setupKeys, AppModel, tempStorage, sanitize, upgradeKeys) {
function saveAuthData(data) {
data.SessionToken ? (secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":SessionToken", pmcw.encode_base64(data.SessionToken)), auth.data = data) : (secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":Uid", data.Uid), secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":AccessToken", data.AccessToken), secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":RefreshToken", data.RefreshToken), auth.data = _.pick(data, "Uid", "AccessToken", "RefreshToken")), auth.setAuthHeaders()
}
function savePassword(pwd) {
secureSessionStorage.setItem(CONSTANTS.MAILBOX_PASSWORD_KEY, pmcw.encode_utf8_base64(pwd))
}
function receivedCredentials(data) {
var eventManager = $injector.get("eventManager");
saveAuthData(data), eventManager.setEventID(data.EventID)
}
var _api, keys = {},
auth = {
headersSet: !1,
setAuthHeaders: function() {
this.headersSet = !0, auth.data.SessionToken ? ($http.defaults.headers.common["x-pm-session"] = auth.data.SessionToken, $http.defaults.headers.common.Authorization = void 0, $http.defaults.headers.common["x-pm-uid"] = void 0, secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":AccessToken"), secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":Uid"), secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":RefreshToken")) : ($http.defaults.headers.common["x-pm-session"] = void 0, $http.defaults.headers.common.Authorization = "Bearer " + auth.data.AccessToken, $http.defaults.headers.common["x-pm-uid"] = auth.data.Uid)
},
fetchUserInfo: function() {
return networkActivityTracker.track(User.get().then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data.User;
throw new Error(data.Error || "Error during user request")
}).then(function(user) {
if (0 === user.Keys.length) return $state.go("login.setup"), Promise.resolve(user);
user.subuser = angular.isDefined(user.OrganizationPrivateKey);
return $q.all({
labels: Label.query(),
contacts: contactEmails.load(),
fix: function() {
return user.Role === CONSTANTS.FREE_USER_ROLE && user.Subscribed ? setupKeys.generateOrganization(api.getPassword()).then(function(response) {
return {
DisplayName: "My Organization",
PrivateKey: response.privateKeyArmored
}
}).then(function(params) {
return organizationApi.create(params)
}) : Promise.resolve()
}(),
organizationKey: function() {
return user.subuser ? pmcw.decryptPrivateKey(user.OrganizationPrivateKey, api.getPassword()) : Promise.resolve()
}()
}).then(function(_ref2) {
var labels = _ref2.labels,
organizationKey = _ref2.organizationKey;
if (labels.data && 1e3 === labels.data.Code) return labelsModel.set(labels.data.Labels), {
user: user,
organizationKey: organizationKey
};
if (labels.data && labels.data.Error) throw new Error(labels.data.Error);
throw new Error("Error during label / contact request")
}).then(function(_ref3) {
var user = _ref3.user,
organizationKey = _ref3.organizationKey,
storeKeys = function(keys) {
api.clearKeys(), _.each(keys, function(_ref4) {
var address = _ref4.address,
key = _ref4.key,
pkg = _ref4.pkg;
api.storeKey(address.ID, key.ID, pkg)
})
};
return setupKeys.decryptUser(user, organizationKey, api.getPassword()).then(function(_ref5) {
var keys = _ref5.keys;
return storeKeys(keys), user
}).catch(function(error) {
throw $exceptionHandler(error), error
})
})
}))
}
},
api = (_api = {
user: {},
saveAuthData: saveAuthData,
savePassword: savePassword,
receivedCredentials: receivedCredentials,
detectAuthenticationState: function() {
var session = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken");
session && (auth.data = {
SessionToken: pmcw.decode_base64(session)
}, this.getRefreshCookie())
}
}, _defineProperty(_api, "savePassword", function(pwd) {
this.user && this.user.OrganizationPrivateKey || secureSessionStorage.setItem(CONSTANTS.MAILBOX_PASSWORD_KEY, pmcw.encode_utf8_base64(pwd))
}), _defineProperty(_api, "getPassword", function() {
var value = secureSessionStorage.getItem(CONSTANTS.MAILBOX_PASSWORD_KEY);
return value ? pmcw.decode_utf8_base64(value) : void 0
}), _defineProperty(_api, "randomString", function(length) {
var charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
i = void 0,
result = "",
isOpera = "[object Opera]" === Object.prototype.toString.call(window.opera);
if (window.crypto && window.crypto.getRandomValues) {
var values = new Uint32Array(length);
for (window.crypto.getRandomValues(values), i = 0; i < length; i++) result += charset[values[i] % charset.length];
return result
}
if (isOpera) {
for (i = 0; i < length; i++) result += charset[Math.floor(Math.random() * charset.length)];
return result
}
return this.semiRandomString(length)
}), _defineProperty(_api, "semiRandomString", function(size) {
for (var string = "", i = 0; i++ < size;) string += "0123456789ABCDEF" [Math.floor(16 * Math.random())];
return string
}), _defineProperty(_api, "getPrivateKeys", function(addressID) {
return keys[addressID]
}), _defineProperty(_api, "storeKey", function(addressID, keyID, pkg) {
pkg.ID = keyID, keys[addressID] = keys[addressID] || [], keys[addressID].push(pkg)
}), _defineProperty(_api, "clearKeys", function() {
keys = {}
}), _defineProperty(_api, "getRefreshCookie", function() {
return $log.debug("getRefreshCookie"), authApi.refresh({}).then(function(response) {
return $log.debug(response), void 0 !== response.data.SessionToken ? ($log.debug("new token", response.data.SessionToken), $log.debug("before", $http.defaults.headers.common["x-pm-session"]), $http.defaults.headers.common["x-pm-session"] = response.data.SessionToken, secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":SessionToken", pmcw.encode_base64(response.data.SessionToken)), $log.debug("after", $http.defaults.headers.common["x-pm-session"]), response) : $q.reject(response.data.Error)
})
}), _defineProperty(_api, "setAuthCookie", function(authResponse) {
return $log.debug("setAuthCookie"), authApi.cookies({
ResponseType: "token",
ClientID: CONFIG.clientID,
GrantType: "refresh_token",
RefreshToken: authResponse.RefreshToken,
Uid: authResponse.Uid,
RedirectURI: "https://protonmail.com",
State: this.randomString(24)
}).then(function(result) {
return $log.debug(result), 1e3 === result.data.Code ? ($log.debug("/auth/cookies:", result), $log.debug("/auth/cookies1: resolved"), AppModel.set("domoArigato", !0), $log.debug("/auth/cookies2: resolved"), $log.debug("headers change", $http.defaults.headers), saveAuthData({
SessionToken: result.data.SessionToken
}), $rootScope.isLocked = !1, result) : Promise.reject({
message: result.data.Error
})
}, function(error) {
return $log.error("setAuthCookie2", error), error.data && error.data.Error ? Promise.reject({
message: error.data.Error
}) : Promise.reject({
message: "Error setting authentication cookies."
})
})
}), _defineProperty(_api, "loginWithCredentials", function(creds, initialInfoResponse) {
var deferred = $q.defer();
return creds.Username && creds.Password ? (delete $http.defaults.headers.common.Accept, srp.performSRPRequest("POST", "/auth", {
Username: creds.Username,
ClientID: CONFIG.clientID,
ClientSecret: CONFIG.clientSecret
}, creds, initialInfoResponse).then(function(resp) {
resp.authVersion < passwords.currentAuthVersion ? srp.getPasswordParams(creds.Password).then(function(data) {
upgradePassword.store(data), deferred.resolve(resp)
}) : deferred.resolve(resp)
}, function(error) {
console.error(error), deferred.reject({
message: error.error_description
})
})) : deferred.reject({
message: "Username and Password are required to login"
}), deferred.promise
}), _defineProperty(_api, "sessionTokenIsDefined", function() {
var isDefined = !1;
return auth.data && void 0 !== auth.data.SessionToken && "undefined" !== auth.data.SessionToken && (isDefined = !0), isDefined
}), _defineProperty(_api, "isLoggedIn", function() {
var loggedIn = this.sessionTokenIsDefined();
return !0 === loggedIn && !1 === auth.headersSet && auth.setAuthHeaders(), loggedIn
}), _defineProperty(_api, "isLocked", function() {
return !1 === this.isLoggedIn() || angular.isUndefined(this.getPassword())
}), _defineProperty(_api, "hasPaidMail", function() {
return 1 & this.user.Subscribed
}), _defineProperty(_api, "hasPaidVpn", function() {
return 4 & this.user.Subscribed
}), _defineProperty(_api, "isSecured", function() {
return this.isLoggedIn() && angular.isDefined(this.getPassword())
}), _defineProperty(_api, "state", function() {
return this.isLoggedIn() ? this.isLocked() ? "login.unlock" : null : "login"
}), _defineProperty(_api, "redirectIfNecessary", function() {
var newState = this.state();
newState && $state.go(newState)
}), _defineProperty(_api, "logout", function(redirect) {
var _this = this,
callApi = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1],
sessionToken = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken"),
uid = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":Uid"),
process = function() {
_this.clearData(), !0 === redirect && $state.go("login")
};
$rootScope.loggingOut = !0, callApi && (angular.isDefined(sessionToken) || angular.isDefined(uid)) ? authApi.revoke().then(process, process) : process()
}), _defineProperty(_api, "clearData", function() {
$http.defaults.headers.common["x-pm-session"] = void 0, $http.defaults.headers.common.Authorization = void 0, $http.defaults.headers.common["x-pm-uid"] = void 0, secureSessionStorage.clear(), delete auth.data, keys = {}, auth.headersSet = !1, this.user = {}, window.onbeforeunload = void 0, $rootScope.loggingOut = !1, $rootScope.isLoggedIn = this.isLoggedIn(), $rootScope.isLocked = this.isLocked(), $rootScope.isSecure = this.isSecured(), AppModel.set("domoArigato", !1), AppModel.set("loggedIn", !1), contactEmails.clear()
}), _defineProperty(_api, "unlockWithPassword", function(pwd) {
var _ref6 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref6$PrivateKey = _ref6.PrivateKey,
PrivateKey = void 0 === _ref6$PrivateKey ? "" : _ref6$PrivateKey,
_ref6$AccessToken = _ref6.AccessToken,
AccessToken = void 0 === _ref6$AccessToken ? "" : _ref6$AccessToken,
_ref6$RefreshToken = _ref6.RefreshToken,
RefreshToken = void 0 === _ref6$RefreshToken ? "" : _ref6$RefreshToken,
_ref6$Uid = _ref6.Uid,
Uid = void 0 === _ref6$Uid ? "" : _ref6$Uid,
_ref6$ExpiresIn = _ref6.ExpiresIn,
ExpiresIn = void 0 === _ref6$ExpiresIn ? 0 : _ref6$ExpiresIn,
_ref6$EventID = _ref6.EventID,
EventID = void 0 === _ref6$EventID ? "" : _ref6$EventID,
_ref6$KeySalt = _ref6.KeySalt,
KeySalt = void 0 === _ref6$KeySalt ? "" : _ref6$KeySalt,
req = $q.defer();
return pwd ? (tempStorage.setItem("plainMailboxPass", pwd), passwords.computeKeyPassword(pwd, KeySalt).then(function(pwd) {
return pmcw.checkMailboxPassword(PrivateKey, pwd, AccessToken)
}).then(function(_ref7) {
var token = _ref7.token;
savePassword(_ref7.password), receivedCredentials({
AccessToken: token,
RefreshToken: RefreshToken,
Uid: Uid,
ExpiresIn: ExpiresIn,
EventID: EventID
}), upgradePassword.send(), req.resolve(200)
}, function() {
req.reject({
message: "Wrong decryption password."
})
})) : req.reject({
message: "Password is required."
}), req.promise
}), _defineProperty(_api, "fetchUserInfo", function() {
var _this2 = this;
return auth.fetchUserInfo().then(function(user) {
0 === user.DisplayName.length && (user.DisplayName = user.Name), $rootScope.isLoggedIn = !0, _this2.user = user, $rootScope.user = user;
var plainMailboxPass = tempStorage.getItem("plainMailboxPass");
return tempStorage.removeItem("plainMailboxPass"), !plainMailboxPass || user.OrganizationPrivateKey || checkKeysFormat(user) ? (AppModel.set("editorMode", user.DraftMIMEType || "text/html"), user) : (AppModel.set("upgradingKeys", !0), upgradeKeys({
mailboxPassword: plainMailboxPass,
oldSaltedPassword: _this2.getPassword(),
user: user
}).then(function() {
return Promise.resolve(user)
}))
}).catch(function(error) {
throw $state.go("support.message", {
data: {}
}), error
})
}), _defineProperty(_api, "params", function(_params) {
return _params
}), _api);
return api
}), angular.module("proton.authentication").factory("authApi", function($http, url) {
var requestURL = url.build("auth");
return {
authenticate: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestURL(), params)
},
refresh: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestURL("refresh"), params)
},
cookies: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestURL("cookies"), params)
},
info: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestURL("info"), params)
},
modulus: function() {
return $http.get(requestURL("modulus"))
},
revoke: function() {
return $http.delete(requestURL())
},
revokeOthers: function() {
return $http.delete(requestURL("others"))
}
}
}), angular.module("proton.authentication").factory("handle401", function($http, authentication) {
var CACHE = {
promises: []
},
clearPromise = function() {
return CACHE.promises.length = 0
},
logout = function() {
return clearPromise(), authentication.logout(!0, !1)
},
recall = function(_ref) {
var config = _ref.config;
return _.extend(config.headers, $http.defaults.headers.common), $http(config)
};
return function(rejection) {
if (!CACHE.promises.length) return CACHE.promises.push(rejection), authentication.getRefreshCookie().then(function() {
return Promise.all(CACHE.promises.map(function(rejection) {
return recall(rejection)
}))
}).then(function() {
return clearPromise()
}).catch(function() {
return logout()
});
CACHE.promises.push(rejection)
}
}), angular.module("proton.authentication").factory("handle403", function($http, $q, loginPasswordModal, User, authentication, notification) {
return function(config) {
var deferred = $q.defer();
return loginPasswordModal.activate({
params: {
submit: function(Password, TwoFactorCode) {
User.unlock({
Password: Password,
TwoFactorCode: TwoFactorCode
}).then(function() {
loginPasswordModal.deactivate(), deferred.resolve($http(config))
}, function(error) {
notification.error(error.error_description)
})
},
cancel: function() {
loginPasswordModal.deactivate(), deferred.reject(new Error("loginPassword:cancel"))
}
}
}), deferred.promise
}
}), angular.module("proton.authentication").factory("handle9001", function($q, $http, humanVerificationModal) {
return function(config) {
var deferred = $q.defer();
return humanVerificationModal.activate({
params: {
close: function() {
var resend = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
humanVerificationModal.deactivate(), resend ? deferred.resolve($http(config)) : deferred.resolve()
}
}
}), deferred.promise
}
}), angular.module("proton.authentication").factory("passwords", function($q, gettextCatalog, webcrypto) {
function bcrypt(str, salt) {
var deferred = $q.defer();
return dcodeIO.bcrypt.hash(str, salt, function(err, hash) {
"string" != typeof hash ? deferred.reject(err) : deferred.resolve(hash)
}), deferred.promise
}
function cleanUsername(name) {
return name.replace(/\.|-|_/g, "").toLowerCase()
}
function expandHash(str) {
return openpgp.util.concatUint8Array([openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "\0")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + ""))])
}
function computeKeyPassword(password, salt) {
if (salt && salt.length) {
var saltBinary = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(salt));
return bcrypt(password, "$2y$10$" + dcodeIO.bcrypt.encodeBase64(saltBinary, 16)).then(function(hash) {
return hash.slice(29)
})
}
var deferred = $q.defer();
return deferred.resolve(password), deferred.promise
}
function generateKeySalt() {
return pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(webcrypto.getRandomValues(new Uint8Array(16))))
}
var hashPasswordVersion = {
4: function(password, salt, modulus) {
return hashPasswordVersion[3](password, salt, modulus)
},
3: function(password, salt, modulus) {
var saltBinary = pmcrypto.binaryStringToArray(salt + "proton");
return bcrypt(password, "$2y$10$" + dcodeIO.bcrypt.encodeBase64(saltBinary, 16)).then(function(unexpandedHash) {
return expandHash(unexpandedHash + pmcrypto.arrayToBinaryString(modulus))
})
},
2: function(password, userName, modulus) {
return hashPasswordVersion[1](password, cleanUsername(userName), modulus)
},
1: function(password, userName, modulus) {
for (var salt = openpgp.crypto.hash.md5(pmcrypto.binaryStringToArray(pmcrypto.encode_utf8(userName.toLowerCase()))), encodedSalt = "", i = 0; i < salt.length; i++) {
var byte = salt[i].toString(16);
1 === byte.length && (byte = "0" + byte), encodedSalt += byte
}
return bcrypt(password, "$2y$10$" + encodedSalt).then(function(unexpandedHash) {
return expandHash(unexpandedHash + pmcrypto.arrayToBinaryString(modulus))
})
},
0: function(password, userName, modulus) {
var prehashed = pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(userName.toLowerCase() + pmcrypto.encode_utf8(password)))));
return hashPasswordVersion[1](prehashed, userName, modulus)
}
};
return {
currentAuthVersion: 4,
cleanUsername: cleanUsername,
expandHash: expandHash,
hashPassword: function(version, password, salt, userName, modulus) {
switch (version) {
case 4:
case 3:
return hashPasswordVersion[version](password, salt, modulus);
case 2:
case 1:
case 0:
return hashPasswordVersion[version](password, userName, modulus);
default:
$q.reject({
message: gettextCatalog.getString("Unsupported auth version", null, "Error")
})
}
},
computeKeyPassword: computeKeyPassword,
generateKeySalt: generateKeySalt
}
}), angular.module("proton.authentication").factory("srp", function($http, CONFIG, webcrypto, passwords, url, authApi) {
function generateProofs(len, hash, modulus, hashedPassword, serverEphemeral) {
function toBN(arr) {
for (var reversed = new Uint8Array(arr.length), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i];
return new asmCrypto.BigNumber(reversed)
}
function fromBN(bn) {
for (var arr = bn.toBytes(), reversed = new Uint8Array(len / 8), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i];
return reversed
}
var generator = new asmCrypto.BigNumber(2),
multiplier = toBN(hash(openpgp.util.concatUint8Array([fromBN(generator), modulus])));
modulus = toBN(modulus), serverEphemeral = toBN(serverEphemeral), hashedPassword = toBN(hashedPassword);
var modulusMinusOne = modulus.subtract(1);
if (modulus.bitLength !== len) return {
Type: "Error",
Description: "SRP modulus has incorrect size"
};
if (modulus = new asmCrypto.Modulus(modulus), multiplier = modulus.reduce(multiplier), multiplier.compare(1) <= 0 || multiplier.compare(modulusMinusOne) >= 0) return {
Type: "Error",
Description: "SRP multiplier is out of bounds"
};
if (generator.compare(1) <= 0 || generator.compare(modulusMinusOne) >= 0) return {
Type: "Error",
Description: "SRP generator is out of bounds"
};
if (serverEphemeral.compare(1) <= 0 || serverEphemeral.compare(modulusMinusOne) >= 0) return {
Type: "Error",
Description: "SRP server ephemeral is out of bounds"
};
var clientSecret = void 0,
clientEphemeral = void 0,
scramblingParam = void 0;
do {
do {
clientSecret = toBN(webcrypto.getRandomValues(new Uint8Array(len / 8)))
} while (clientSecret.compare(2 * len) <= 0);
clientEphemeral = modulus.power(generator, clientSecret), scramblingParam = toBN(hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), fromBN(serverEphemeral)])))
} while (0 === scramblingParam.compare(0));
var subtracted = serverEphemeral.subtract(modulus.reduce(modulus.power(generator, hashedPassword).multiply(multiplier)));
subtracted.compare(0) < 0 && (subtracted = subtracted.add(modulus));
var exponent = scramblingParam.multiply(hashedPassword).add(clientSecret).divide(modulus.subtract(1)).remainder,
sharedSession = modulus.power(subtracted, exponent),
clientProof = hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), fromBN(serverEphemeral), fromBN(sharedSession)])),
serverProof = hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), clientProof, fromBN(sharedSession)]));
return {
Type: "Success",
ClientEphemeral: fromBN(clientEphemeral),
ClientProof: clientProof,
ExpectedServerProof: serverProof
}
}
function generateVerifier(len, hashedPassword, modulus) {
function toBN(arr) {
for (var reversed = new Uint8Array(arr.length), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i];
return new asmCrypto.BigNumber(reversed)
}
var generator = new asmCrypto.BigNumber(2);
modulus = new asmCrypto.Modulus(toBN(modulus)), hashedPassword = toBN(hashedPassword);
var verifier = modulus.power(generator, hashedPassword);
return function(bn) {
for (var arr = bn.toBytes(), reversed = new Uint8Array(len / 8), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i];
return reversed
}(verifier)
}
function tryRequest(method, endpoint, req, creds, headers, fallbackAuthVersion) {
return authInfo(creds.Username).then(function(resp) {
return tryAuth(resp, method, endpoint, req, creds, headers, fallbackAuthVersion)
})
}
function tryAuth(infoResp, method, endpoint, req, creds, headers, fallbackAuthVersion) {
function srpHasher(arr) {
return passwords.expandHash(pmcrypto.arrayToBinaryString(arr))
}
var proofs = void 0,
useFallback = void 0,
session = infoResp.data.SRPSession,
modulus = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(openpgp.cleartext.readArmored(infoResp.data.Modulus).getText())),
serverEphemeral = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(infoResp.data.ServerEphemeral)),
authVersion = infoResp.data.Version;
if (useFallback = 0 === authVersion, useFallback && (authVersion = fallbackAuthVersion), authVersion < 3 && (creds.Username = infoResp.data.Username), 2 === authVersion && passwords.cleanUsername(creds.Username) !== passwords.cleanUsername(infoResp.data.Username) || authVersion <= 1 && creds.Username.toLowerCase() !== infoResp.data.Username.toLowerCase()) return Promise.reject({
error_description: "Please login with just your ProtonMail username (without @protonmail.com or @protonmail.ch)."
});
var salt = "";
return authVersion >= 3 && (salt = pmcrypto.decode_base64(infoResp.data.Salt)), passwords.hashPassword(authVersion, creds.Password, salt, creds.Username, modulus).then(function(hashed) {
if (proofs = generateProofs(2048, srpHasher, modulus, hashed, serverEphemeral), "Success" !== proofs.Type) return Promise.reject({
error_description: proofs.Description
});
var httpReq = {
method: method,
url: url.get() + endpoint,
data: _.extend(req, {
SRPSession: session,
ClientEphemeral: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ClientEphemeral)),
ClientProof: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ClientProof)),
TwoFactorCode: creds.TwoFactorCode
})
};
return angular.isDefined(headers) && (httpReq.headers = headers), $http(httpReq)
}, function(err) {
return Promise.reject({
error_description: err.message
})
}).then(function(resp) {
return 1e3 !== resp.data.Code ? Promise.reject({
error_description: resp.data.Error,
usedFallback: useFallback
}) : pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ExpectedServerProof)) === resp.data.ServerProof ? Promise.resolve(_.extend(resp, {
authVersion: authVersion
})) : Promise.reject({
error_description: "Invalid server authentication"
})
}, function(error) {
return Promise.reject(error)
})
}
function randomVerifier(password) {
return authApi.modulus().then(function(resp) {
if (1e3 !== resp.data.Code) return Promise.reject({
error_description: resp.data.Error
});
var modulus = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(openpgp.cleartext.readArmored(resp.data.Modulus).getText())),
salt = pmcrypto.arrayToBinaryString(webcrypto.getRandomValues(new Uint8Array(10)));
return passwords.hashPassword(passwords.currentAuthVersion, password, salt, void 0, modulus).then(function(hashedPassword) {
var verifier = generateVerifier(2048, hashedPassword, modulus);
return {
Auth: {
Version: passwords.currentAuthVersion,
ModulusID: resp.data.ModulusID,
Salt: pmcrypto.encode_base64(salt),
Verifier: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(verifier))
}
}
})
})
}
function authInfo(Username) {
return authApi.info({
Username: Username,
ClientID: CONFIG.clientID,
ClientSecret: CONFIG.clientSecret
}).then(function(resp) {
if (1e3 === resp.data.Code) return resp;
if (resp.data.Error) throw new Error(resp.data.Error);
var error = new Error("Cannot get auth information");
throw error.noNotify = !0, error
})
}
function performSRPRequest(method, endpoint, req, creds, initialInfoResp, headers) {
var ret = void 0;
return ret = initialInfoResp ? tryAuth(initialInfoResp, method, endpoint, req, creds, headers, 2) : tryRequest(method, endpoint, req, creds, headers, 2), ret = ret.catch(function(err) {
return !0 === err.usedFallback && passwords.cleanUsername(creds.Username) !== creds.Username.toLowerCase() ? tryRequest(method, endpoint, req, creds, headers, 1) : Promise.reject(err)
}), ret = ret.catch(function(err) {
return !0 === err.usedFallback ? tryRequest(method, endpoint, req, creds, headers, 0) : Promise.reject(err)
})
}
function getPasswordParams(password) {
var config = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return randomVerifier(password).then(function(data) {
return _.extend({}, config, data)
})
}
return {
randomVerifier: randomVerifier,
info: authInfo,
performSRPRequest: performSRPRequest,
getPasswordParams: getPasswordParams
}
}), angular.module("proton.authentication").factory("upgradePassword", function(settingsApi, tempStorage) {
function store(value) {
tempStorage.setItem(key, value, tenMinutes)
}
function send() {
var Auth = tempStorage.getItem(key);
return Auth ? (tempStorage.removeItem(key), settingsApi.passwordUpgrade(Auth)) : Promise.resolve()
}
var key = "auth",
tenMinutes = 6e5;
return {
store: store,
send: send
}
}), angular.module("proton.autoresponder").directive("autoresponder", function(autoresponderModel, timepickerModel, $rootScope, autoresponderLanguage) {
var frequencies = [{
label: autoresponderLanguage.DURATION_FOREVER,
value: autoresponderModel.constants.FOREVER
}, {
label: autoresponderLanguage.DURATION_FIXED,
value: autoresponderModel.constants.FIXED_INTERVAL
}, {
label: autoresponderLanguage.DURATION_DAILY,
value: autoresponderModel.constants.DAILY
}, {
label: autoresponderLanguage.DURATION_WEEKLY,
value: autoresponderModel.constants.WEEKLY
}, {
label: autoresponderLanguage.DURATION_MONTHLY,
value: autoresponderModel.constants.MONTHLY
}];
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/autoresponder.tpl.html",
scope: {},
link: function(scope, elem, _ref) {
var mock = _ref.mock,
unsubscribe = [];
scope.mock = "true" === mock, scope.frequencies = frequencies, scope.datetimepickerStartTime = "startTimePickerKey", scope.datetimepickerEndTime = "endTimePickerKey", scope.submitting = !1, scope.model = {
isEnabled: !1,
message: null,
repeat: 0,
subject: null,
startTime: null,
endTime: null,
daysSelected: {
0: !0,
1: !0,
2: !0,
3: !0,
4: !0,
5: !0,
6: !0
}
};
var isEmpty = function(message) {
return null !== message && 0 === $(message).text().trim().length
};
scope.isValid = function() {
return !scope.model.isEnabled || !isEmpty(scope.model.message) && scope.model.message.length < autoresponderModel.constants.MAX_MESSAGE_LENGTH && (scope.model.repeat === autoresponderModel.constants.FOREVER || null !== scope.model.startTime && null !== scope.model.endTime)
};
var onFormSubmit = function() {
scope.$applyAsync(function() {
scope.submitting = !0, $rootScope.$emit("autoresponder", {
type: "save",
data: {
autoresponder: scope.model
}
})
})
};
if (scope.timezones = autoresponderModel.timezones, scope.mock) unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"update" === type && (scope.model = data.autoresponder)
})), autoresponderModel.mock();
else {
unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref3) {
var type = _ref3.type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
switch (type) {
case "update":
scope.model = data.autoresponder;
break;
case "saved_success":
case "saved_error":
scope.submitting = !1
}
})), unsubscribe.push($rootScope.$on("autoresponder.toggle", function() {
return autoresponderModel.set(scope.model)
}));
var form = elem.find("form");
form.on("submit", onFormSubmit), unsubscribe.push(function() {
return form.off("submit", onFormSubmit)
}), autoresponderModel.load()
}
scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").directive("autoresponderMessage", function(autoresponderModel, $rootScope) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/autoresponderMessage.tpl.html",
scope: {
message: "="
},
link: function(scope, elem, _ref) {
var disabled = _ref.disabled,
unsubscribe = [];
scope.disabled = "true" === disabled, scope.halfMessageLength = autoresponderModel.constants.HALF_MESSAGE_LENGTH, scope.maxMessageLength = autoresponderModel.constants.MAX_MESSAGE_LENGTH, scope.isEmpty = function(message) {
return null !== message && 0 === $(message).text().trim().length
}, unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"update" === type && (scope.message = data.autoresponder.message)
})), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").directive("autoresponderTimePicker", function($rootScope, autoresponderModel, timepickerModel) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/autoresponderTimePicker.tpl.html",
scope: {
form: "="
},
link: function(scope, elem, _ref) {
var datePickerKey = _ref.datePickerKey,
labelId = _ref.labelId,
repeat = _ref.repeat,
zone = _ref.zone,
timestamp = _ref.timestamp,
disableInput = _ref.disableInput,
unsubscribe = [];
scope.repeat = Number(repeat), scope.timestamp = String(Number(timestamp)) === timestamp ? Number(timestamp) : null, scope.disableInput = "true" === disableInput, scope.zone = zone, scope.constants = autoresponderModel.constants, scope.labelId = labelId, scope.datePickerKey = datePickerKey, repeat === autoresponderModel.constants.DAILY && timepickerModel.initTimePicker(datePickerKey, {
disableInput: disableInput,
labelId: labelId
}), unsubscribe.push($rootScope.$on("timepicker", function(event, _ref2) {
var type = _ref2.type,
data = _ref2.data;
"update" === type && data.eventKey === datePickerKey && (scope.timestamp = data.timestamp, autoresponderModel.set(_defineProperty({}, labelId, data.timestamp)))
})), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref3) {
var type = _ref3.type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
if ("update" === type) {
var refresh = data.autoresponder.repeat !== scope.repeat || scope.timestamp !== data.autoresponder[labelId];
scope.repeat = data.autoresponder.repeat, scope.timestamp = data.autoresponder[labelId], scope.zone = data.autoresponder.zone, data.autoresponder.repeat === autoresponderModel.constants.DAILY && timepickerModel.initTimePicker(datePickerKey, {
disableInput: disableInput,
labelId: labelId
}), refresh && timepickerModel.refresh(scope.datePickerKey, scope.timestamp, scope.zone)
}
})), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").directive("autoresponderTimeSection", function(autoresponderModel, dateUtils, $rootScope) {
var days = _.map(dateUtils.getSortedWeekdays(), function(day) {
return {
value: day.value,
label: day.shortLabel
}
});
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/autoresponderTimeSection.tpl.html",
scope: {
form: "="
},
link: function(scope, elem, _ref) {
var mock = _ref.mock,
unsubscribe = [];
scope.days = days, scope.constants = autoresponderModel.constants, scope.timezones = autoresponderModel.timezones, scope.mock = "true" === mock, scope.model = autoresponderModel.get(), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"update" === type && (scope.model = data.autoresponder)
})), unsubscribe.push($rootScope.$on("multiselect", function(event, _ref3) {
var type = _ref3.type,
name = _ref3.name,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
"update" === type && "autoresponder.daysSelected" === name && autoresponderModel.set({
daysSelected: data.value
})
})), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").directive("autoresponderView", function(authentication) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/autoresponderView.tpl.html",
scope: {},
link: function(scope) {
scope.isFree = !(1 & authentication.user.Subscribed)
}
}
}), angular.module("proton.autoresponder").directive("durationselect", function($rootScope, autoresponderModel, autoresponderLanguage) {
var frequencies = [{
label: autoresponderLanguage.DURATION_FIXED,
value: autoresponderModel.constants.FIXED_INTERVAL
}, {
label: autoresponderLanguage.DURATION_DAILY,
value: autoresponderModel.constants.DAILY
}, {
label: autoresponderLanguage.DURATION_WEEKLY,
value: autoresponderModel.constants.WEEKLY
}, {
label: autoresponderLanguage.DURATION_MONTHLY,
value: autoresponderModel.constants.MONTHLY
}, {
label: autoresponderLanguage.DURATION_FOREVER,
value: autoresponderModel.constants.FOREVER
}];
return {
replace: !0,
restrict: "E",
templateUrl: "templates/autoresponder/durationselect.tpl.html",
scope: {},
link: function(scope, elem, _ref) {
function onInput() {
scope.$applyAsync(function() {
autoresponderModel.set({
repeat: scope.repeat.value
})
})
}
var disableInput = _ref.disableInput,
repeat = _ref.repeat,
unsubscribe = [];
scope.frequencies = frequencies, scope.repeat = _.findWhere(scope.frequencies, {
value: Number(repeat)
}), "true" === disableInput && elem.attr("disabled", "disabled"), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"update" === type && (scope.repeat = _.findWhere(scope.frequencies, {
value: data.autoresponder.repeat
}))
})), elem.on("change", onInput), unsubscribe.push(function() {
return elem.off("change", onInput)
}), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").directive("zoneselect", function($rootScope, autoresponderModel) {
return {
replace: !0,
restrict: "E",
template: '<select id="time-zone" name="time-zone" ng-options="zone.label for zone in timezones track by zone.value" ng-model="zone"></select>',
scope: {},
link: function(scope, elem, _ref) {
var zone = _ref.zone,
disableInput = _ref.disableInput,
unsubscribe = [];
scope.timezones = autoresponderModel.timezones, "true" === disableInput && elem.attr("disabled", "disabled"), scope.zone = _.findWhere(scope.timezones, {
value: zone
});
var onChange = function() {
scope.$applyAsync(function() {
return autoresponderModel.set({
zone: scope.zone.value
})
})
};
unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"update" === type && (scope.zone = _.findWhere(scope.timezones, {
value: data.autoresponder.zone
}))
})), elem.on("change", onChange), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.autoresponder").factory("autoresponderModel", function($rootScope, gettextCatalog, authentication, tools, settingsApi, networkActivityTracker, notification, eventManager, autoresponderLanguage, signatureBuilder) {
function getBaseResponder() {
var base = _.extend({}, authentication.user.AutoResponder);
if (null === base || !base.isEnabled) return getDefaultAutoResponder();
var daysSelected = base.daysSelected;
return base.daysSelected = daysSelected.reduce(function(previous, value) {
return previous[value] = !0, previous
}, _.extend({}, [].concat(_toConsumableArray(new Array(7))).map(function() {
return !1
}))), base
}
function getDefaultAutoResponder() {
var defaultAutoresponder = {
isEnabled: !1,
startTime: Math.floor(Date.now() / 1e3) + constants.HOUR,
endTime: null,
daysSelected: _.extend({}, [].concat(_toConsumableArray(new Array(7))).map(function() {
return !0
})),
repeat: constants.FIXED_INTERVAL,
subject: autoresponderLanguage.DEFAULT_SUBJECT_PREFIX,
message: null,
zone: moment.tz.guess()
},
body = autoresponderLanguage.DEFAULT_BODY,
bodyPlusSig = signatureBuilder.insert({
getDecryptedBody: function() {
return body
}
}, {
action: "new",
isAfter: !0
}).replace(/<img[^>]*>/g, "");
return bodyPlusSig.length > constants.MAX_MESSAGE_LENGTH ? defaultAutoresponder.message = body : defaultAutoresponder.message = bodyPlusSig, defaultAutoresponder
}
function load() {
clearChangedAutoresponder();
var data = get();
dispatch("update", {
autoresponder: data
})
}
function mock() {
var data = getDefaultAutoResponder();
data.isEnabled = !0, data.repeat = 0, data.startTime = Math.floor(Date.now() / 1e3), data.endTime = data.startTime + 7 * constants.DAY + 8 * constants.HOUR, updateChangedAutoresponder(data);
var outData = get();
dispatch("update", {
autoresponder: outData
})
}
function set(autoresponderIn) {
var newAutoresponder = _.extend({}, autoresponderIn),
oldAutoresponder = get(),
tempAutoresponder = _.extend({}, oldAutoresponder, newAutoresponder);
if (tempAutoresponder.zone !== oldAutoresponder.zone && tempAutoresponder.repeat === constants.FIXED_INTERVAL) {
var startTime = tempAutoresponder.startTime,
endTime = tempAutoresponder.endTime,
oldZone = oldAutoresponder.zone,
newZone = newAutoresponder.zone;
null !== startTime && (newAutoresponder.startTime = Number(moment.tz(moment.tz(1e3 * startTime, oldZone).format("YYYY-MM-DDTHH:mm:ss"), newZone).format("X"))), null !== endTime && (newAutoresponder.endTime = Number(moment.tz(moment.tz(1e3 * endTime, oldZone).format("YYYY-MM-DDTHH:mm:ss"), newZone).format("X")))
}
if (void 0 !== newAutoresponder.repeat && oldAutoresponder.repeat !== newAutoresponder.repeat) {
var isForever = newAutoresponder.repeat === constants.FOREVER;
newAutoresponder.startTime = isForever ? 0 : null, newAutoresponder.endTime = isForever ? 0 : null, newAutoresponder.repeat === constants.FIXED_INTERVAL && (newAutoresponder.startTime = Math.floor(Date.now() / 1e3) + constants.HOUR), void 0 === newAutoresponder.daysSelected && (newAutoresponder.daysSelected = {
0: !0,
1: !0,
2: !0,
3: !0,
4: !0,
5: !0,
6: !0
})
}
updateChangedAutoresponder(newAutoresponder);
var data = get();
dispatch("update", {
autoresponder: data
})
}
function getAutoresponderInAPIFormat() {
var autoresponder = get();
return autoresponder.daysSelected = Object.keys(_.pick(autoresponder.daysSelected, Boolean)).map(Number), autoresponder.isEnabled ? (autoresponder.repeat === constants.FOREVER && (autoresponder.startTime = 0, autoresponder.endTime = 0), autoresponder) : _.extend(autoresponder, {
repeat: constants.FOREVER,
startTime: 0,
endTime: 0,
daysSelected: [0, 1, 2, 3, 4, 5, 6],
zone: "utc",
message: "",
subject: null
})
}
function getResponseMessage(oldEnabled, newEnabled) {
return oldEnabled === newEnabled ? autoresponderLanguage.AUTORESPONDER_UPDATED_MESSAGE : newEnabled ? autoresponderLanguage.AUTORESPONDER_INSTALLED_MESSAGE : autoresponderLanguage.AUTORESPONDER_REMOVED_MESSAGE
}
function save() {
var autoresponder = getAutoresponderInAPIFormat(),
original = authentication.user.AutoResponder || getDefaultAutoResponder(),
responseMessage = getResponseMessage(original.isEnabled, autoresponder.isEnabled),
promise = settingsApi.setAutoresponder({
Parameters: autoresponder
}).then(function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (data.Error) throw dispatch("saved_error", data), new Error(data.Error);
if (1e3 === data.Code) return dispatch("saved_success", data), eventManager.call().then(function() {
return notification.success(responseMessage)
})
}).catch(function(error) {
return dispatch("saved_error", {
Error: error
})
});
networkActivityTracker.track(promise)
}
var now = new Date,
momentNow = moment(now),
timezones = _.map(moment.tz.names(), function(name) {
return {
label: name + ": UTC " + momentNow.tz(name).format("Z"),
value: name
}
}),
constants = {
FIXED_INTERVAL: 0,
DAILY: 1,
WEEKLY: 2,
MONTHLY: 3,
FOREVER: 4,
HALF_MESSAGE_LENGTH: 2048,
MAX_MESSAGE_LENGTH: 4096,
HOUR: 3600,
DAY: 86400
},
changedAutoresponder = {},
getChangedAutoresponder = function() {
return changedAutoresponder
},
updateChangedAutoresponder = function(autoresponder) {
return changedAutoresponder = _.extend({}, changedAutoresponder, autoresponder)
},
clearChangedAutoresponder = function() {
return changedAutoresponder = {}
},
get = function() {
return _.extend({}, getBaseResponder(), getChangedAutoresponder())
},
dispatch = function(type, data) {
return $rootScope.$emit("autoresponder", {
type: type,
data: data
})
};
return $rootScope.$on("autoresponder", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"save" === type && (set(data.autoresponder), save())
}), $rootScope.$on("autoresponder.isEnabled", function(event, _ref3) {
set({
isEnabled: _ref3.status
})
}), {
init: angular.noop,
constants: constants,
load: load,
mock: mock,
get: get,
set: set,
timezones: timezones
}
}), angular.module("proton.autoresponder").factory("autoresponderLanguage", function(gettextCatalog) {
return {
AUTORESPONDER_UPDATED_MESSAGE: gettextCatalog.getString("Autoresponder updated", null, "Success"),
AUTORESPONDER_INSTALLED_MESSAGE: gettextCatalog.getString("Autoresponder installed", null, "Success"),
AUTORESPONDER_REMOVED_MESSAGE: gettextCatalog.getString("Autoresponder removed", null, "Success"),
DEFAULT_SUBJECT_PREFIX: "Auto",
DEFAULT_BODY: gettextCatalog.getString("<div>I'm out of the office with limited access to my email.</div>", null, "Default autoresponder message without signature (no regards, etcetera)"),
DURATION_FOREVER: gettextCatalog.getString("Permanent", null, "Duration/repetition of autoresponder"),
DURATION_FIXED: gettextCatalog.getString("Fixed duration", null, "Duration/repetition of autoresponder"),
DURATION_DAILY: gettextCatalog.getString("Repeat daily", null, "Duration/repetition of autoresponder"),
DURATION_WEEKLY: gettextCatalog.getString("Repeat weekly", null, "Duration/repetition of autoresponder"),
DURATION_MONTHLY: gettextCatalog.getString("Repeat monthly", null, "Duration/repetition of autoresponder")
}
}), angular.module("proton.blackFriday").directive("blackFridayFree", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/blackFriday/blackFridayFree.tpl.html"
}
}), angular.module("proton.blackFriday").directive("blackFridayPaid", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/blackFriday/blackFridayPaid.tpl.html"
}
}), angular.module("proton.blackFriday").directive("blackFridayPrice", function() {
return {
restrict: "E",
replace: !0,
scope: {
amount: "=",
strike: "=",
currency: "="
},
templateUrl: "templates/blackFriday/blackFridayPrice.tpl.html"
}
}), angular.module("proton.blackFriday").factory("blackFridayModel", function($rootScope, authentication, CONSTANTS, dashboardModel, networkActivityTracker, Payment, paymentModal, subscriptionModel, paymentModel) {
function isBlackFridayPeriod() {
var force = arguments.length > 0 && void 0 !== arguments[0] && arguments[0],
subscription = subscriptionModel.get(),
isLifetime = "LIFETIME" === subscription.CouponCode,
isMember = authentication.user.Role === PAID_MEMBER_ROLE,
isSubuser = authentication.user.subuser,
isTwoYears = subscription.Cycle === TWO_YEARS;
return !isLifetime && (!isMember && !isSubuser && (!isTwoYears && (!(!force && localStorage.getItem(BLACK_FRIDAY_ITEM)) && inInterval())))
}
function loadPlanIDs() {
var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "current";
return dashboardModel.fetchPlans(CACHE.currency, TWO_YEARS).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$Plans = _ref.Plans,
Plans = void 0 === _ref$Plans ? [] : _ref$Plans,
PlanIDs = [],
MAP_PLAN_ID = _.reduce(Plans, function(acc, _ref2) {
var Name = _ref2.Name,
ID = _ref2.ID;
return acc[Name] = ID, acc
}, {});
if (plan === PLUS && PlanIDs.push(MAP_PLAN_ID[PLUS]), plan === VPN_PLUS && PlanIDs.push(MAP_PLAN_ID[VPN_PLUS]), plan === PLUS + "+" + VPN_PLUS && PlanIDs.push(MAP_PLAN_ID[PLUS], MAP_PLAN_ID[VPN_PLUS]), "current" === plan) {
var subscription = subscriptionModel.get();
PlanIDs.push.apply(PlanIDs, _toConsumableArray(subscription.Plans.map(function(_ref3) {
var Name = _ref3.Name;
return MAP_PLAN_ID[Name]
})))
}
return PlanIDs
})
}
function buy(_ref4) {
var _ref4$plan = _ref4.plan,
plan = void 0 === _ref4$plan ? "current" : _ref4$plan,
promise = loadPlanIDs(plan).then(function(PlanIDs) {
return Payment.valid({
Cycle: TWO_YEARS,
Currency: CACHE.currency,
PlanIDs: PlanIDs,
Coupon: subscriptionModel.coupon()
}).then(function() {
var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref5$data = _ref5.data,
valid = void 0 === _ref5$data ? {} : _ref5$data;
paymentModal.activate({
params: {
planIDs: PlanIDs,
valid: valid,
cancel: function() {
paymentModal.deactivate()
}
}
})
}).catch(function() {
var _ref6 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref6$data = _ref6.data,
data = void 0 === _ref6$data ? {} : _ref6$data;
throw Error(data.Error)
})
});
networkActivityTracker.track(promise)
}
function set(key, value) {
CACHE[key] = value
}
function saveClose() {
localStorage.setItem(BLACK_FRIDAY_ITEM, "closed")
}
function load() {
Promise.all([paymentModel.getMethods(), paymentModel.getStatus()]).then(function() {
return $rootScope.$emit("blackFriday", {
type: "loaded"
})
})
}
var PAID_MEMBER_ROLE = CONSTANTS.PAID_MEMBER_ROLE,
CYCLE = CONSTANTS.CYCLE,
PLANS = CONSTANTS.PLANS,
BLACK_FRIDAY_INTERVAL = CONSTANTS.BLACK_FRIDAY_INTERVAL,
TWO_YEARS = CYCLE.TWO_YEARS,
_PLANS$PLAN = PLANS.PLAN,
PLUS = _PLANS$PLAN.PLUS,
VPN_PLUS = _PLANS$PLAN.VPN_PLUS,
CACHE = {},
BLACK_FRIDAY_ITEM = "protonmail_black_friday",
inInterval = function() {
return moment().isBetween("2017-11-24", "2017-11-28")
};
return setInterval(function() {
$rootScope.$emit("blackFriday", {
type: "tictac"
})
}, BLACK_FRIDAY_INTERVAL), $rootScope.$on("blackFriday", function(event, _ref7) {
var _ref7$type = _ref7.type,
type = void 0 === _ref7$type ? "" : _ref7$type,
_ref7$data = _ref7.data,
data = void 0 === _ref7$data ? {} : _ref7$data;
"buy" === type && buy(data), "load" === type && load()
}), {
init: angular.noop,
isBlackFridayPeriod: isBlackFridayPeriod,
set: set,
saveClose: saveClose,
inInterval: inInterval
}
}), angular.module("proton.blackFriday").factory("blackFridayModal", function($rootScope, $state, authentication, CONSTANTS, pmModal, blackFridayModel, subscriptionModel) {
var TWO_YEARS = CONSTANTS.CYCLE.TWO_YEARS;
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/blackFriday/blackFridayModal.tpl.html",
controller: function(params, $scope) {
var _this = this,
unsubscribe = $rootScope.$on("blackFriday", function(event, _ref) {
var _ref$type = _ref.type;
"loaded" === (void 0 === _ref$type ? "" : _ref$type) && $scope.$applyAsync(function() {
_this.loaded = !0
})
});
this.loaded = !1, this.isFreeUser = !authentication.user.Subscribed, this.isPaidUser = authentication.user.Subscribed, this.close = function() {
blackFridayModel.saveClose(), params.close()
}, this.dashboard = function() {
$state.is("secured.dashboard") || $state.go("secured.dashboard", {
noBlackFridayModal: !0,
currency: _this.currency,
cycle: TWO_YEARS
}), _this.close()
}, this.buy = function() {
var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "current";
$rootScope.$emit("blackFriday", {
type: "buy",
data: {
plan: plan
}
}), _this.close()
}, this.changeCurrency = function() {
var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "EUR";
_this.currency = currency, blackFridayModel.set("currency", currency), $rootScope.$emit("closeDropdown")
}, this.$onDestroy = function() {
unsubscribe()
}, this.currency = subscriptionModel.currency(), this.changeCurrency(this.currency), $rootScope.$emit("blackFriday", {
type: "load"
})
}
})
}), angular.module("proton.bridge").directive("bridgeFreePanel", function(gettextCatalog, notification) {
var I18N = {
info: gettextCatalog.getString("This feature is only available for paid users.", null, "Info")
},
onClick = function() {
return notification.info(I18N.info)
};
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/bridge/bridgeFreePanel.tpl.html",
link: function(scope, el) {
var $btn = el.find(".bridgeFreePanel-btn");
$btn.on("click", onClick), scope.$on("$destroy", function() {
$btn.off("click", onClick)
})
}
}
}), angular.module("proton.bridge").directive("bridgePaidPanel", function() {
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/bridge/bridgePaidPanel.tpl.html"
}
}), angular.module("proton.bridge").directive("bridgeView", function(authentication) {
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/bridge/bridgeView.tpl.html",
link: function(scope) {
scope.isFree = !(1 & authentication.user.Subscribed)
}
}
}), angular.module("proton.browserSupport").factory("browserFixes", function(safari) {
function applyFixes() {
_.each(browsers, function(browser) {
browser.isCurrentBrowser() && browser.applyFixes()
})
}
var browsers = [safari];
return {
init: applyFixes
}
}), angular.module("proton.browserSupport").factory("safari", function(aboutClient) {
var fixes = [function() {
$(document).on("click.fixSafariDownloadBug", function(e) {
var target = e.target;
target && "A" === target.tagName && "_blank" === target.getAttribute("target") && target.hasAttribute("href") && (e.preventDefault(), window.open(target.href))
})
}],
applyFixes = function() {
return _.each(fixes, function(fix) {
return fix()
})
};
return {
isCurrentBrowser: aboutClient.isSafari,
applyFixes: applyFixes
}
}), angular.module("proton.bugReport").directive("newBugReport", function($rootScope) {
return {
replace: !0,
templateUrl: "templates/bugReport/newBugReport.tpl.html",
link: function(scope, el) {
var onClick = function() {
$rootScope.$emit("bugReport", {
type: "new",
data: {}
})
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick)
})
}
}
}), angular.module("proton.bugReport").factory("bugReportModel", function($rootScope, bugReportApi, bugModal) {
function open() {
bugModal.activate(getModalParam())
}
$rootScope.$on("bugReport", function(e, _ref) {
"new" === _ref.type && open()
});
var takeScreenshot = function(_ref2) {
return _ref2.attachScreenshot ? bugReportApi.takeScreenshot() : Promise.resolve()
},
getModalParam = function() {
return {
params: {
form: bugReportApi.getForm(),
submit: function(data) {
var form = angular.copy(data);
bugModal.deactivate(), takeScreenshot(form).then(function(screenshot) {
return bugReportApi.report(form, screenshot)
})
},
cancel: function() {
bugModal.deactivate()
}
}
}
};
return {
init: angular.noop
}
}), angular.module("proton.bugReport").factory("Bug", function($http, $q, url, gettextCatalog) {
var ERROR_REPORT = gettextCatalog.getString("Error communicating with the server", null, "Report bug request");
return {
crash: function(data) {
return $http.post(url.get() + "/bugs/crash", data)
},
report: function(data) {
return $http.post(url.get() + "/bugs", data).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data;
throw new Error(data.Error || ERROR_REPORT)
})
},
uploadScreenshot: function(image, form) {
var deferred = $q.defer();
return $.ajax({
url: "https://api.imgur.com/3/image",
headers: {
Authorization: "Client-ID 864920c2f37d63f"
},
type: "POST",
data: {
image: image
},
dataType: "json",
success: function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
data.link ? deferred.resolve(angular.extend({}, form, {
Description: form.Description + "\n\n\n\n" + data.link
})) : deferred.reject()
},
error: function() {
deferred.reject()
}
}), deferred.promise
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.bugReport").factory("bugReportApi", function(Bug, CONFIG, $state, aboutClient, authentication, gettextCatalog, networkActivityTracker, notification, CONSTANTS) {
var _layout, _view, ROW_MODE = CONSTANTS.ROW_MODE,
COLUMN_MODE = CONSTANTS.COLUMN_MODE,
MESSAGE_VIEW_MODE = CONSTANTS.MESSAGE_VIEW_MODE,
CONVERSATION_VIEW_MODE = CONSTANTS.CONVERSATION_VIEW_MODE,
MAP_MODE = {
layout: (_layout = {}, _defineProperty(_layout, ROW_MODE, "row"), _defineProperty(_layout, COLUMN_MODE, "column"), _layout),
view: (_view = {}, _defineProperty(_view, MESSAGE_VIEW_MODE, "row"), _defineProperty(_view, CONVERSATION_VIEW_MODE, "column"), _view)
},
getViewLayout = function(type) {
return MAP_MODE.layout[type] || "unknown"
},
getViewMode = function(type) {
return MAP_MODE.view[type] || "undefined"
},
getClient = function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$ViewLayout = _ref.ViewLayout,
ViewLayout = void 0 === _ref$ViewLayout ? "" : _ref$ViewLayout,
_ref$ViewMode = _ref.ViewMode,
ViewMode = void 0 === _ref$ViewMode ? "" : _ref$ViewMode,
os = aboutClient.getOS(),
browser = aboutClient.getBrowser(),
device = aboutClient.getDevice();
return {
OS: os.name,
OSVersion: os.version || "",
Browser: browser.name,
BrowserVersion: browser.version,
Client: "Angular",
ClientVersion: CONFIG.app_version,
ViewLayout: getViewLayout(ViewLayout),
ViewMode: getViewMode(ViewMode),
DeviceName: device.vendor,
DeviceModel: device.model
}
},
getForm = function() {
var _authentication$user = authentication.user,
_authentication$user$ = _authentication$user.Name,
Name = void 0 === _authentication$user$ ? "" : _authentication$user$,
_authentication$user$2 = _authentication$user.Addresses,
Addresses = void 0 === _authentication$user$2 ? [] : _authentication$user$2,
_$sortBy = _.sortBy(Addresses, "Order"),
_$sortBy2 = _slicedToArray(_$sortBy, 1),
_$sortBy2$ = _$sortBy2[0];
_$sortBy2$ = void 0 === _$sortBy2$ ? {} : _$sortBy2$;
var _$sortBy2$$Email = _$sortBy2$.Email,
Email = void 0 === _$sortBy2$$Email ? "" : _$sortBy2$$Email;
return _.extend(getClient(authentication.user), {
Resolution: window.innerHeight + " x " + window.innerWidth,
Title: "[Angular] Bug [" + $state.$current.name + "]",
Description: "",
Username: Name,
Email: Email,
attachScreenshot: !1
})
},
takeScreenshot = function() {
return new Promise(function(resolve) {
if (!window.html2canvas) return resolve();
window.html2canvas(document.body, {
onrendered: function(canvas) {
try {
resolve(canvas.toDataURL("image/jpeg", .9).split(",")[1])
} catch (e) {
resolve(canvas.toDataURL().split(",")[1])
}
}
})
})
},
send = function(form) {
return Bug.report(form).then(function() {
return notification.success(gettextCatalog.getString("Bug reported", null, "Bug report successfully"))
})
};
return {
getForm: getForm,
takeScreenshot: takeScreenshot,
report: function(form, screenshot) {
var promise = void 0;
return promise = form.attachScreenshot ? Bug.uploadScreenshot(screenshot, form).then(send) : send(form), networkActivityTracker.track(promise), promise
},
getClient: getClient,
crash: function(error) {
var crashData = _.extend(getClient(authentication.user), {
Debug: {
state: $state.$current.name,
error: error
}
});
return Bug.crash(crashData).catch(angular.noop)
}
}
}), angular.module("proton.commons").directive("appConfigBody", function($rootScope, AppModel) {
var className = function() {
return "appConfigBody-" + (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "")
},
mapClassNames = {
mobile: className("is-mobile"),
tablet: className("is-tablet"),
requestTimeout: className("request-timeout"),
tourActive: className("tourActive"),
activeComposer: className("activeComposer"),
maximizedComposer: className("maximizedComposer"),
modalOpen: className("modalOpen"),
showSidebar: className("showSidebar")
};
return {
link: function(scope, el) {
AppModel.is("mobile") && el[0].classList.add(mapClassNames.mobile), AppModel.is("tablet") && el[0].classList.add(mapClassNames.tablet);
var toggleClass = function(className) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
method = data.value ? "add" : "remove";
_rAF(function() {
return el[0].classList[method](className)
})
};
$rootScope.$on("AppModel", function(e, _ref) {
var type = _ref.type,
data = _ref.data,
className = mapClassNames[type];
className && toggleClass(className, data)
}), $rootScope.$on("$stateChangeSuccess", function(e, toState) {
el[0].id = toState.name.replace(/[.]+/g, "-")
})
}
}
}), angular.module("proton.commons").directive("appCopyright", function(CONFIG, gettextCatalog) {
var label = gettextCatalog.getString("ProtonMail.com - Made globally, hosted in Switzerland.", null, "copyright");
return {
replace: !0,
template: '<span class="appCopyright-container">' + CONFIG.year + " " + label + "</span>"
}
}), angular.module("proton.commons").directive("copy", function(gettextCatalog, notification) {
var I18N = {
copy: gettextCatalog.getString("Copy to your clipboard", null),
copied: gettextCatalog.getString("Copied to clipboard", null)
};
return {
restrict: "E",
replace: !0,
scope: {
value: "="
},
template: '\n <button class="copy-button" type="button" data-tooltip="' + I18N.copy + '">\n <span class="copy-icon"></span>\n </button>\n ',
link: function(scope, element) {
var clipboard = new Clipboard(element[0], {
text: function() {
return scope.value
}
});
clipboard.on("success", function() {
element.attr("data-tooltip", I18N.copied), notification.success(I18N.copied)
}), clipboard.on("error", function() {
element.addClass("error")
}), scope.$on("$destroy", function() {
return clipboard.destroy()
})
}
}
}), angular.module("proton.commons").directive("placeholderTranslate", generateDirective("placeholder")).directive("titleTranslate", generateDirective("title")).directive("ptTooltipTranslate", generateDirective("pt-tooltip")), angular.module("proton.commons").factory("AppModel", function($rootScope) {
var MODEL = {},
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("AppModel", {
type: type,
data: data
})
},
set = function() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
value = arguments[1],
previous = MODEL[key];
MODEL[key] = value, previous !== value && dispatch(key, {
value: value
})
},
is = function() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return !!MODEL[key]
},
get = function() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return MODEL[key]
};
return {
is: is,
set: set,
store: function() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
value = arguments[1];
return MODEL[key] = value
},
get: get
}
}), angular.module("proton.commons").factory("contactEncryption", function($injector, $rootScope, CONSTANTS, chunk, gettextCatalog, pmcw, vcard) {
function generateUID() {
var s4 = function() {
return Math.floor(65536 * (1 + Math.random())).toString(16).substring(1)
};
return "proton-web-" + s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4()
}
function mergeContactData() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
vcfString = _.reduce(data, function(acc, _ref2) {
return "" + acc + _ref2.data + "\r\n"
}, ""),
vcards = vcard.from(vcfString);
return vcard.merge(vcards)
}
function prepareCards(_ref3) {
function getGroupName() {
itemCounter++;
var groupName = "item" + itemCounter;
return _.contains(groups, groupName) ? getGroupName() : groupName
}
var data = _ref3.data,
publicKeys = _ref3.publicKeys,
privateKeys = _ref3.privateKeys,
promises = [],
itemCounter = 0,
properties = vcard.extractProperties(data),
groups = _.reduce(properties, function(acc, property) {
var group = property.getGroup();
return -1 === acc.indexOf(group) && acc.push(group), acc
}, []),
_$reduce = _.reduce(vcard.extractProperties(data), function(acc, property) {
var key = property.getField(),
isClear = _.contains(CLEAR_FIELDS, key),
isSigned = _.contains(SIGNED_FIELDS, key);
return _.contains(GROUP_FIELDS, key) && !property.group && (property.group = getGroupName()), isClear && acc.clearText.push(property), isSigned && acc.toSign.push(property), isClear || isSigned || acc.toEncryptAndSign.push(property), acc
}, {
toEncryptAndSign: [],
toSign: [],
clearText: []
}),
toEncryptAndSign = _$reduce.toEncryptAndSign,
toSign = _$reduce.toSign,
clearText = _$reduce.clearText;
if (toEncryptAndSign.length > 0) {
var _data = vcard.build(toEncryptAndSign).toString(VCARD_VERSION);
promises.push(pmcw.encryptMessage({
data: _data,
publicKeys: publicKeys,
privateKeys: privateKeys,
armor: !0,
detached: !0
}).then(function(_ref4) {
var data = _ref4.data,
signature = _ref4.signature;
return {
Type: ENCRYPTED_AND_SIGNED,
Data: data,
Signature: signature
}
}))
}
if (toSign.length > 0) {
var signedFields = _.pluck(toSign, "_field");
if (-1 === signedFields.indexOf("uid") && toSign.push(new vCard.Property("uid", generateUID())), -1 === signedFields.indexOf("fn")) {
var fn = gettextCatalog.getString("Unknown", null, "Default display name vcard"),
nameProperty = _.findWhere(toEncryptAndSign, {
_field: "n"
});
if (nameProperty) fn = nameProperty.valueOf().split(";").join(" ");
else {
var firstEmail = _.findWhere(toSign, {
_field: "email"
});
firstEmail && (fn = firstEmail.valueOf())
}
toSign.push(new vCard.Property("fn", fn))
}
var _data2 = vcard.build(toSign).toString(VCARD_VERSION);
promises.push(pmcw.signMessage({
data: _data2,
privateKeys: privateKeys,
armor: !0,
detached: !0
}).then(function(_ref5) {
var signature = _ref5.signature;
return {
Type: SIGNED,
Data: _data2,
Signature: signature
}
}))
}
if (clearText.length > 0) {
var _data3 = vcard.build(clearText).toString(VCARD_VERSION);
promises.push(Promise.resolve({
Type: CLEAR_TEXT,
Data: _data3,
Signature: null
}))
}
return Promise.all(promises)
}
function extractCards(_ref6) {
var _ref6$cards = _ref6.cards,
cards = void 0 === _ref6$cards ? [] : _ref6$cards,
_ref6$privateKeys = _ref6.privateKeys,
privateKeys = void 0 === _ref6$privateKeys ? [] : _ref6$privateKeys,
_ref6$publicKeys = _ref6.publicKeys,
publicKeys = void 0 === _ref6$publicKeys ? [] : _ref6$publicKeys,
promises = _.map(cards, function(_ref7) {
var Type = _ref7.Type,
_ref7$Data = _ref7.Data,
Data = void 0 === _ref7$Data ? "" : _ref7$Data,
_ref7$Signature = _ref7.Signature,
Signature = void 0 === _ref7$Signature ? "" : _ref7$Signature;
switch (Type) {
case ENCRYPTED_AND_SIGNED:
return pmcw.decryptMessage({
message: pmcw.getMessage(Data),
privateKeys: privateKeys,
publicKeys: publicKeys,
armor: !0,
signature: pmcw.getSignature(Signature)
}).then(function(_ref8) {
var data = _ref8.data;
return 1 !== _ref8.verified ? {
error: TYPE3_CONTACT_VERIFICATION,
data: data
} : {
data: data
}
}).catch(function() {
return {
error: TYPE3_CONTACT_DECRYPTION,
data: (new vCard).toString(VCARD_VERSION)
}
});
case SIGNED:
return pmcw.verifyMessage({
message: pmcw.getCleartextMessage(Data),
publicKeys: publicKeys,
signature: pmcw.getSignature(Signature)
}).then(function(_ref9) {
return 1 !== _ref9.verified ? {
error: TYPE2_CONTACT,
data: Data
} : {
data: Data
}
});
case ENCRYPTED:
return pmcw.decryptMessage({
message: pmcw.getMessage(Data),
privateKeys: privateKeys,
armor: !0
}).catch(function() {
return {
error: TYPE1_CONTACT,
data: (new vCard).toString(VCARD_VERSION)
}
});
case CLEAR_TEXT:
return Promise.resolve({
data: Data
})
}
});
return Promise.all(promises)
}
function decrypt() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
authentication = $injector.get("authentication"),
privateKeys = authentication.getPrivateKeys(MAIN_KEY),
publicKeys = pmcw.getKeys(authentication.user.Keys[0].PublicKey),
total = contacts.length,
count = 0;
return _.reduce(chunk(contacts, CONTACTS_LIMIT_ENCRYPTION), function(promise, chunkedContacts) {
return promise.then(function() {
var previousContacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return Promise.all(chunkedContacts.map(function(_ref10) {
var ID = _ref10.ID,
_ref10$Cards = _ref10.Cards,
Cards = void 0 === _ref10$Cards ? [] : _ref10$Cards;
return extractCards({
cards: Cards,
privateKeys: privateKeys,
publicKeys: publicKeys
}).then(function(data) {
count++;
var progress = Math.floor(100 * count / total);
return $rootScope.$emit("progressBar", {
type: "contactsProgressBar",
data: {
progress: progress
}
}), buildContact(ID, data, Cards)
})
})).then(function(newContacts) {
return previousContacts.concat(newContacts)
})
}, [])
}, Promise.resolve())
}
function encrypt() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
authentication = $injector.get("authentication"),
privateKeys = authentication.getPrivateKeys(MAIN_KEY),
publicKeys = pmcw.getKeys(authentication.user.Keys[0].PublicKey),
total = contacts.length,
count = 0;
return _.reduce(chunk(contacts, CONTACTS_LIMIT_ENCRYPTION), function(promise, chunkedContacts) {
return promise.then(function() {
var previousContacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return Promise.all(chunkedContacts.map(function(contact) {
return prepareCards({
data: contact.vCard,
publicKeys: publicKeys,
privateKeys: privateKeys
}).then(function(Cards) {
count++;
var progress = Math.floor(50 * count / total);
return $rootScope.$emit("progressBar", {
type: "contactsProgressBar",
data: {
progress: progress
}
}), {
Cards: Cards
}
})
})).then(function(newContacts) {
return previousContacts.concat(newContacts)
})
})
}, Promise.resolve())
}
var KEY_FIELDS = ["key", "x-pm-mimetype", "x-pm-encrypt", "x-pm-sign", "x-pm-scheme", "x-pm-tls", "x-pm-dane"],
CLEAR_FIELDS = ["version", "prodid", "x-pm-label", "x-pm-group"],
SIGNED_FIELDS = ["version", "prodid", "fn", "uid", "email"].concat(KEY_FIELDS),
GROUP_FIELDS = ["email"],
CONTACT_MODE = CONSTANTS.CONTACT_MODE,
CONTACTS_LIMIT_ENCRYPTION = CONSTANTS.CONTACTS_LIMIT_ENCRYPTION,
MAIN_KEY = CONSTANTS.MAIN_KEY,
VCARD_VERSION = CONSTANTS.VCARD_VERSION,
CONTACT_ERROR = CONSTANTS.CONTACT_ERROR,
CLEAR_TEXT = CONTACT_MODE.CLEAR_TEXT,
ENCRYPTED_AND_SIGNED = CONTACT_MODE.ENCRYPTED_AND_SIGNED,
ENCRYPTED = CONTACT_MODE.ENCRYPTED,
SIGNED = CONTACT_MODE.SIGNED,
TYPE3_CONTACT_VERIFICATION = CONTACT_ERROR.TYPE3_CONTACT_VERIFICATION,
TYPE3_CONTACT_DECRYPTION = CONTACT_ERROR.TYPE3_CONTACT_DECRYPTION,
TYPE2_CONTACT = CONTACT_ERROR.TYPE2_CONTACT,
TYPE1_CONTACT = CONTACT_ERROR.TYPE1_CONTACT,
getErrors = function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.pluck(data, "error").filter(Boolean)
},
buildContact = function(ID) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
cards = arguments[2];
return {
ID: ID,
vCard: mergeContactData(data),
errors: getErrors(data),
types: cards.map(function(_ref) {
return _ref.Type
})
}
};
return {
decrypt: decrypt,
encrypt: encrypt
}
}), angular.module("proton.commons").factory("pmModal", function($animate, $compile, $rootScope, $controller, $q, $http, AppModel, $templateCache) {
var $body = $("#body");
return function(config) {
function activate(locals) {
return html.then(function(html) {
element || attach(html, locals), $body.append('<div class="modal-backdrop fade in"></div>'), AppModel.set("modalOpen", !0);
var id = setTimeout(function() {
$(".modal").addClass("in"), window.scrollTo(0, 0), Mousetrap.bind("escape", function() {
return deactivate()
}), clearTimeout(id)
}, 100);
unsubscribeLogoutListener = $rootScope.$on("logout", function() {
deactivate()
})
})
}
function attach(html, locals) {
if (element = angular.element(html), 0 === element.length) throw new Error("The template contains no elements; you need to wrap text nodes");
if (scope = $rootScope.$new(!0), controller) {
locals || (locals = {}), locals.$scope = scope;
var ctrl = $controller(controller, locals);
controllerAs && (scope[controllerAs] = ctrl)
} else if (locals)
for (var prop in locals) scope[prop] = locals[prop];
return $compile(element)(scope), $animate.enter(element, container)
}
function deactivate() {
return element ? (unsubscribeLogoutListener(), $animate.leave(element).then(function() {
element && (Mousetrap.unbind("escape"), scope && scope.$destroy(), (scope[controllerAs].$onDestroy || angular.noop)(), scope = null, element.remove(), element = null, AppModel.set("modalOpen", !1), $(".modal-backdrop").remove())
})) : $q.when()
}
function active() {
return !!element
}
if (!(!config.template ^ !config.templateUrl)) throw new Error("Expected modal to have exactly one of either template or templateUrl");
var controller = config.controller || null,
controllerAs = config.controllerAs,
container = angular.element(config.container || document.body),
element = null,
html = void 0,
scope = void 0,
unsubscribeLogoutListener = angular.noop;
return html = config.template ? $q.when(config.template) : $http.get(config.templateUrl, {
cache: $templateCache
}).then(function(_ref) {
return _ref.data
}), {
activate: activate,
deactivate: deactivate,
active: active
}
}
}), angular.module("proton.commons").factory("tempStorage", function($timeout) {
function deleteKey(key) {
return function() {
delete data[key]
}
}
function cancelTimeout(key) {
timeouts[key] && ($timeout.cancel(timeouts[key]), delete timeouts[key])
}
var data = {},
timeouts = {};
return {
getItem: function(key) {
if (angular.isString(key) && data[key]) {
cancelTimeout(key);
var rv = data[key];
return deleteKey(key)(), rv
}
return null
},
setItem: function(key, value) {
var lifetime = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1e4;
angular.isString(key) && (cancelTimeout(key), data[key] = value, timeouts[key] = $timeout(deleteKey(key), lifetime, !1))
},
removeItem: function(key) {
angular.isString(key) && data[key] && (cancelTimeout(key), delete data[key])
},
clear: function() {
Object.keys(timeouts).forEach(cancelTimeout), data = {}
}
}
}), angular.module("proton.commons").factory("Address", function($http, url, gettextCatalog) {
var I18N = {
ERROR_UPDATE: gettextCatalog.getString("Error during updating", null, "Error"),
ERROR_ORDER: gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error"),
ERROR_DELETE: gettextCatalog.getString("Error during deletion", null, "Error"),
ERROR_DISABLE: gettextCatalog.getString("Error during disable request", null, "Error"),
ERROR_ENABLE: gettextCatalog.getString("Error during enable request", null, "Error"),
ERROR_CREATE: gettextCatalog.getString("Address creation failed", null, "Error")
},
requestUrl = url.build("addresses"),
filterError = function(error) {
return function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 !== data.Code) throw new Error(data.Error || error);
return data
}
};
return {
create: function(address) {
return $http.post(requestUrl(), address).then(filterError(I18N.ERROR_CREATE))
},
setup: function(params) {
return $http.post(requestUrl("setup"), params)
},
edit: function(addressID, params) {
return $http.put(requestUrl(addressID), params).then(filterError(I18N.ERROR_UPDATE))
},
enable: function(addressID) {
return $http.put(requestUrl(addressID, "enable")).then(filterError(I18N.ERROR_ENABLE))
},
disable: function(addressID) {
return $http.put(requestUrl(addressID, "disable")).then(filterError(I18N.ERROR_DISABLE))
},
remove: function(addressID) {
return $http.delete(requestUrl(addressID)).then(filterError(I18N.ERROR_DELETE))
},
order: function(params) {
return $http.post(requestUrl("order"), params).then(filterError(I18N.ERROR_ORDER))
}
}
}), angular.module("proton.commons").factory("Contact", function($http, $rootScope, CONSTANTS, url, chunk, contactEncryption, sanitize) {
function clearContacts() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).map(function(contact) {
return contact.Email = sanitize.input(contact.Email), contact.Name = sanitize.input(contact.Name), contact
})
}
function request(route) {
var params = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $http.get(route, {
params: params
}).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (data.Error) throw new Error(data.Error);
return data
})
}
function hydrate() {
var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : CONSTANTS.CONTACT_EMAILS_LIMIT;
return queryContacts(requestURL("emails"), {
key: "ContactEmails",
PageSize: PageSize
}).then(clearContacts)
}
function get(contactID) {
return request(requestURL(contactID)).then(function(_ref4) {
var Contact = _ref4.Contact;
return contactEncryption.decrypt([Contact])
}).then(function(contacts) {
return contacts[0]
})
}
function handleUpload() {
var result = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
_$reduce = _.reduce(result, function(acc) {
var _ref5 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref5$data = _ref5.data,
data = void 0 === _ref5$data ? {} : _ref5$data;
return data.Error ? (acc.errors.push({
code: data.Code,
error: data.Error
}), acc) : (_.each(data.Responses, function(_ref6) {
var _ref6$Response = _ref6.Response,
Response = void 0 === _ref6$Response ? {} : _ref6$Response;
acc.total++, Response.Error && acc.errors.push({
code: Response.Code,
name: Response.Name,
emails: Response.Emails,
error: Response.Error
}), 1e3 === Response.Code && acc.created.push(Response.Contact)
}), acc)
}, {
created: [],
total: 0,
errors: []
}),
_$reduce$created = _$reduce.created,
created = void 0 === _$reduce$created ? [] : _$reduce$created,
_$reduce$total = _$reduce.total,
total = void 0 === _$reduce$total ? 0 : _$reduce$total,
_$reduce$errors = _$reduce.errors;
return {
created: created,
total: total,
errors: void 0 === _$reduce$errors ? [] : _$reduce$errors
}
}
function uploadContacts() {
var cards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
total = arguments[1],
progress = 50,
chunkCards = chunk(cards, CONTACTS_LIMIT_UPLOAD),
promises = _.map(chunkCards, function(Contacts) {
var params = {
Contacts: Contacts,
Groups: 1,
Overwrite: 1,
Labels: 1
};
return $http.post(requestURL(), params).then(function(data) {
return progress += Math.floor(50 * Contacts.length / total), $rootScope.$emit("progressBar", {
type: "contactsProgressBar",
data: {
progress: progress
}
}), data
})
});
return Promise.all(promises).then(handleUpload)
}
function add() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return contactEncryption.encrypt(contacts).then(function() {
return uploadContacts(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], contacts.length)
}).then(function(data) {
return $rootScope.$emit("contacts", {
type: "contactsUpdated"
}), data
})
}
function update(contact) {
return contactEncryption.encrypt([contact]).then(function(contacts) {
return $http.put(requestURL(contact.ID), contacts[0]).then(function() {
var _ref7 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref7$data = _ref7.data,
data = void 0 === _ref7$data ? {} : _ref7$data;
if (data.Error) throw new Error(data.Error);
return data.cards = contacts[0].Cards, data
})
})
}
function exportAll() {
var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : EXPORT_CONTACTS_LIMIT;
return queryContacts(requestURL("export"), {
key: "Contacts",
PageSize: PageSize
}).then(function(contacts) {
return contactEncryption.decrypt(contacts)
})
}
var queryContacts = function() {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
var data, promises, n, list, route = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
_ref3 = arguments[1],
PageSize = _ref3.PageSize,
_ref3$key = _ref3.key,
key = void 0 === _ref3$key ? "" : _ref3$key;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.next = 2, request(route, {
PageSize: PageSize
});
case 2:
return data = _context.sent, promises = [Promise.resolve(data[key])], n = Math.ceil(data.Total / PageSize) - 1, n > 0 && _.times(n, function(index) {
var promise = request(route, {
PageSize: PageSize,
Page: index + 1
}).then(function(data) {
return data[key]
});
promises.push(promise)
}), _context.next = 8, Promise.all(promises);
case 8:
return list = _context.sent, _context.abrupt("return", list.reduce(function(acc, item) {
return acc.concat(item)
}, []));
case 10:
case "end":
return _context.stop()
}
}, _callee, this)
}));
return function() {
return _ref2.apply(this, arguments)
}
}(),
requestURL = url.build("contacts"),
CONTACTS_LIMIT_UPLOAD = CONSTANTS.CONTACTS_LIMIT_UPLOAD,
EXPORT_CONTACTS_LIMIT = CONSTANTS.EXPORT_CONTACTS_LIMIT,
all = function() {
var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : CONSTANTS.CONTACTS_LIMIT;
return queryContacts(requestURL(), {
key: "Contacts",
PageSize: PageSize
})
},
load = function() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return request(type ? requestURL(type) : requestURL(), {
PageSize: type ? CONSTANTS.CONTACT_EMAILS_LIMIT : CONSTANTS.CONTACTS_LIMIT / 10
})
};
return {
hydrate: hydrate,
all: all,
get: get,
add: add,
update: update,
remove: function(contacts) {
return $http.put(requestURL("delete"), contacts)
},
clear: function() {
return $http.delete(requestURL())
},
exportAll: exportAll,
groups: function() {
return $http.get(requestURL("groups"))
},
load: load
}
}), angular.module("proton.commons").factory("Eo", function($http, url, CONFIG) {
var requestURL = url.build("eo"),
parseJSON = function(xhr) {
var response = function(json) {
return {
json: json,
isInvalid: arguments.length > 1 && void 0 !== arguments[1] && arguments[1]
}
};
try {
return response(JSON.parse(xhr.responseText))
} catch (e) {
return response({
Error: "JSON parsing error: " + xhr.responseText
}, !0)
}
};
return {
token: function(tokenID) {
return $http.get(requestURL("token", encodeURIComponent(tokenID)), {
headers: {
"Content-Type": "application/json;charset=utf-8",
Accept: "application/vnd.protonmail.v1+json"
}
})
},
message: function(Authorization, token) {
return $http.get(requestURL("message"), {
headers: {
Authorization: Authorization,
"x-eo-uid": token
}
})
},
attachment: function(Authorization, token, attachmentID) {
return $http.get(requestURL("attachment", attachmentID), {
responseType: "arraybuffer",
headers: {
Authorization: Authorization,
"x-eo-uid": token
}
})
},
reply: function(decryptedToken, token, data) {
var fd = new FormData,
xhr = new XMLHttpRequest;
return Object.keys(data || {}).forEach(function(key) {
Array.isArray(data[key]) ? _.each(data[key], function(v) {
return fd.append(key, v)
}) : fd.append(key + "", data[key])
}), new Promise(function(resolve, reject) {
xhr.onload = function() {
var _parseJSON = parseJSON(xhr),
json = _parseJSON.json,
isInvalid = _parseJSON.isInvalid;
if (200 !== xhr.status) return reject(new Error("Unable to send the message"));
if (json.Error) {
var msgError = isInvalid ? "Unable to send the message." : json.Error;
return reject(new Error(msgError))
}
resolve("Message send")
}, xhr.open("post", requestURL("reply"), !0), xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"), xhr.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"), xhr.setRequestHeader("x-pm-appversion", "Web_" + CONFIG.app_version), xhr.setRequestHeader("x-pm-apiversion", CONFIG.api_version), xhr.setRequestHeader("Authorization", decryptedToken), xhr.setRequestHeader("x-eo-uid", token), xhr.send(fd)
})
}
}
}), angular.module("proton.commons").factory("Events", function($http, url) {
var requestURL = url.build("events");
return {
get: function(id) {
return $http.get(requestURL(id))
},
getLatestID: function() {
return $http.get(requestURL("latest"))
}
}
}), angular.module("proton.commons").factory("Filter", function($http, url) {
function transformRequestFilter(filter) {
return angular.isDefined(filter.Simple) && (filter.Tree = Sieve.toTree(filter.Simple)), angular.toJson(filter)
}
function transformResponseFilter(data) {
var json = angular.fromJson(data);
return json && 1e3 === json.Code && _.each(json.Filters, function(filter) {
var simple = Sieve.fromTree(filter.Tree);
_.isEqual(filter.Tree, Sieve.toTree(simple)) ? filter.Simple = simple : delete filter.Simple
}), json || {}
}
return {
create: function(filter) {
return $http.post(url.get() + "/filters", filter, {
transformRequest: transformRequestFilter
})
},
check: function(filter) {
return $http.post(url.get() + "/filters/check", filter, {
transformRequest: transformRequestFilter
})
},
query: function() {
return $http.get(url.get() + "/filters", {
transformResponse: transformResponseFilter
})
},
update: function(filter) {
return $http.put(url.get() + "/filters/" + filter.ID, filter, {
transformRequest: transformRequestFilter
})
},
enable: function(filter) {
return $http.put(url.get() + "/filters/" + filter.ID + "/enable")
},
disable: function(filter) {
return $http.put(url.get() + "/filters/" + filter.ID + "/disable")
},
order: function(_order) {
return $http.put(url.get() + "/filters/order", _order)
},
delete: function(filter) {
return $http.delete(url.get() + "/filters/" + filter.ID)
},
clear: function() {
return $http.delete(url.get() + "/filters")
}
}
}), angular.module("proton.commons").factory("IncomingDefault", function($http, url) {
var requestURL = url.build("incomingdefaults");
return {
get: function(params) {
return $http.get(requestURL(), {
params: params
})
},
add: function(params) {
return $http.post(requestURL(), params)
},
update: function() {
var opt = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.put(requestURL(opt.ID), opt)
},
delete: function(params) {
return $http.put(requestURL("delete"), params)
},
clear: function() {
return $http.delete(requestURL())
}
}
}), angular.module("proton.commons").factory("Invite", function($http, url) {
var requestURL = url.build("invites");
return {
check: function(Token, Selector, Type) {
return $http.post(requestURL("check"), {
Token: Token,
Selector: Selector,
Type: Type
})
}
}
}), angular.module("proton.commons").factory("Key", function($http, url, srp) {
var requestUrl = url.build("keys"),
create = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestUrl(), params)
},
setup = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) {
return $http.post(requestUrl("setup"), authParams)
}) : $http.post(requestUrl("setup"), params)
},
reset = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) {
return $http.post(requestUrl("reset"), authParams)
}) : $http.post(requestUrl("reset"), params)
},
order = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(requestUrl("order"), params)
},
activate = function(keyID) {
var params = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $http.put(requestUrl(keyID, "activate"), params)
},
privateKey = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) {
return $http.put(requestUrl("private"), authParams)
}) : $http.put(requestUrl("private"), params)
};
return {
create: create,
setup: setup,
reset: reset,
order: order,
activate: activate,
upgrade: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) {
return $http.put(requestUrl("private", "upgrade"), authParams)
}) : $http.put(requestUrl("private", "upgrade"), params)
},
private: privateKey,
delete: function(keyID) {
return $http.delete(requestUrl(keyID))
},
salts: function() {
return $http.get(requestUrl("salts"))
},
reactivate: function(keyID, params) {
return $http.put(requestUrl(keyID), params)
}
}
}), angular.module("proton.commons").factory("Label", function($http, url) {
return {
query: function() {
return $http.get(url.get() + "/labels")
},
apply: function(labelID, messageIDs) {
return $http.put(url.get() + "/labels/apply/" + labelID, messageIDs)
},
remove: function(labelID, messageIDs) {
return $http.put(url.get() + "/labels/remove/" + labelID, messageIDs)
},
order: function(newOrder) {
return $http.put(url.get() + "/labels/order", newOrder)
},
update: function(label) {
return $http.put(url.get() + "/labels/" + label.ID, label)
},
create: function(label) {
return $http.post(url.get() + "/labels", label)
},
delete: function(labelID) {
return $http.delete(url.get() + "/labels/" + labelID)
}
}
}), angular.module("proton.commons").factory("Logs", function($http, url) {
var requestURL = url.build("logs");
return {
get: function() {
return $http.get(requestURL("auth"))
},
clear: function() {
return $http.delete(requestURL("auth"))
}
}
}), angular.module("proton.commons").factory("MemberKey", function($http, url, srp) {
return {
create: function(Obj) {
return $http.post(url.get() + "/memberkeys", Obj)
},
setup: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
password = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return srp.randomVerifier(password).then(function(passParams) {
return $http.post(url.get() + "/memberkeys/setup", _.extend(params, passParams))
})
},
order: function(Obj) {
return $http.post(url.get() + "/memberkeys/order", Obj)
},
update: function(keyID, Obj) {
return $http.put(url.get() + "/memberkeys" + keyID, Obj)
},
delete: function(keyID) {
return $http.delete(url.get() + "/memberkeys/" + keyID)
}
}
}), angular.module("proton.commons").factory("Payment", function($http, authentication, url, brick, paymentPlansFormator) {
function generateFingerprint() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
paymentMethodID = params.PaymentMethodID,
payment = getPayment(params);
return new Promise(function(resolve, reject) {
try {
if (void 0 === paymentMethodID && "card" === payment.Type) return brick.getFingerprint(function(fingerprint) {
payment.Fingerprint = fingerprint, resolve(params)
});
resolve(params)
} catch (e) {
reject(e)
}
})
}
var requestUrl = url.build("payments"),
transformRepBillingCycle = function(data) {
var json = angular.fromJson(data);
if (json && 1e3 === json.Code) {
_.each(json.Payments, function(invoice) {
1 === parseInt((invoice.PeriodEnd - invoice.PeriodStart) / 2592e3, 10) ? invoice.BillingCycle = 12 : invoice.BillingCycle = 1
})
}
return json || {}
},
getPayment = function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return params.Payment ? params.Payment : params.PaymentMethod ? params.PaymentMethod : params
},
credit = function(params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("credit"), params)
})
},
validateCredit = function(params) {
return $http.post(requestUrl("credit", "check"), params)
},
validateVerify = function(params) {
return $http.post(requestUrl("verify", "check"), params)
},
donate = function(params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("donate"), params)
})
},
unsubscribe = function(opt) {
return $http.post(requestUrl("unsubscribe"), opt)
},
paypal = function(opt) {
var config = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $http.post(requestUrl("paypal"), opt, config)
},
verify = function(params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("verify"), params)
})
},
status = function() {
return $http.get(requestUrl("status"))
},
invoices = function(params) {
return $http.get(requestUrl("invoices"), {
params: params
})
},
invoice = function(id) {
return $http.get(requestUrl("invoices", id), {
responseType: "arraybuffer"
})
},
check = function(id) {
return $http.post(requestUrl("invoices", id, "check"))
},
pay = function(id, params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("invoices", id), params)
})
},
plans = function(Currency, Cycle) {
return $http.get(requestUrl("plans"), {
params: {
Currency: Currency,
Cycle: Cycle
}
}).then(paymentPlansFormator(Currency, Cycle)).then(function(data) {
return {
data: data
}
})
},
subscription = function() {
if (authentication.user.Role > 1) return $http.get(requestUrl("subscription"), {
transformResponse: function(datas) {
var json = angular.fromJson(datas);
if (json && 1e3 === json.Code) {
var _ref = _.findWhere(json.Subscription.Plans, {
Type: 1
}) || {},
Name = _ref.Name,
Title = _ref.Title;
json.Subscription.Name = Name, json.Subscription.Title = Title
}
return json || {}
}
});
var sub = {
Name: "free",
Title: "ProtonMail Free",
MaxDomains: 0,
CouponCode: null,
MaxAddresses: 1,
MaxSpace: 5368709120,
MaxMembers: 1,
Cycle: 12,
Currency: authentication.user.Currency
};
return Promise.resolve({
data: {
Code: 1e3,
Subscription: sub
}
})
},
valid = function(opt) {
return $http.post(requestUrl("subscription", "check"), opt)
},
updateMethod = function(params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("methods"), params)
})
},
deleteMethod = function(id) {
return $http.delete(requestUrl("methods", id))
},
methods = function() {
return $http.get(requestUrl("methods"))
},
order = function(opt) {
return $http.post(requestUrl("methods", "order"), opt)
},
subscribe = function(params) {
return generateFingerprint(params).then(function(params) {
return $http.post(requestUrl("subscription"), params)
})
},
destroy = function() {
return $http.delete(requestUrl("subscription"))
},
user = function(Time, Limit) {
return $http.get(requestUrl("user"), {
params: {
Time: Time,
Limit: Limit
},
transformResponse: transformRepBillingCycle
})
},
organization = function(Time, Limit) {
return $http.get(requestUrl("organization"), {
params: {
Time: Time,
Limit: Limit
},
transformResponse: transformRepBillingCycle
})
};
return {
credit: credit,
donate: donate,
paypal: paypal,
validateCredit: validateCredit,
validateVerify: validateVerify,
invoices: invoices,
invoice: invoice,
order: order,
verify: verify,
status: status,
check: check,
pay: pay,
valid: valid,
plans: plans,
subscription: subscription,
updateMethod: updateMethod,
deleteMethod: deleteMethod,
methods: methods,
subscribe: subscribe,
unsubscribe: unsubscribe,
delete: destroy,
btc: function(Amount, Currency) {
return $http.post(requestUrl("bcinfo"), {
Amount: Amount,
Currency: Currency
})
},
organization: organization,
user: user
}
}), angular.module("proton.commons").factory("Reset", function($http, url, srp) {
return {
requestResetToken: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(url.get() + "/reset", params)
},
resetPassword: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
request = function(data) {
var requestUrl = url.get() + "/reset/" + encodeURIComponent(data.Token);
return $http.post(requestUrl, data)
};
return srp.getPasswordParams(newPassword, params).then(request)
},
getMailboxResetToken: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(url.get() + "/reset/mailbox", params)
},
resetMailbox: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.post(url.get() + "/reset/mailbox/" + encodeURIComponent(params.Token), params)
},
validateResetToken: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http.get(url.get() + "/reset/" + params.Username + "/" + encodeURIComponent(params.Token))
}
}
}), angular.module("proton.commons").factory("User", function($http, url, srp) {
var requestURL = url.build("users");
return {
create: function(params, password) {
return srp.getPasswordParams(password, params).then(function(data) {
return $http.post(requestURL(), data)
})
},
code: function(params) {
return $http.post(requestURL("code"), params)
},
get: function() {
return $http.get(requestURL())
},
human: function() {
return $http.get(url.get() + "/users/human")
},
check: function(params) {
return $http.post(url.get() + "/users/human", params)
},
pubkeys: function(emails) {
return $http.get(requestURL("pubkeys", window.encodeURIComponent(emails)))
},
available: function(username) {
return $http.get(requestURL("available", username))
},
direct: function() {
return $http.get(requestURL("direct"))
},
lock: function() {
return $http.put(requestURL("lock"))
},
unlock: function() {
var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return srp.performSRPRequest("PUT", "/users/unlock", {}, creds)
},
password: function() {
var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return srp.performSRPRequest("PUT", "/users/password", {}, creds)
},
delete: function() {
var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return srp.performSRPRequest("PUT", "/users/delete", {}, creds)
}
}
}), angular.module("proton.commons").provider("notification", function() {
var CONFIG = {
classNames: {
error: "notification-danger",
success: "notification-success",
info: "notification-info"
}
};
this.typeClasses = function() {
var config = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return _.extend(CONFIG.classNames, config)
}, this.duration = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 6e3;
return CONFIG.duration = value
}, this.template = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return CONFIG.template = value
}, this.$get = ["notify", function(notify) {
var action = function(type) {
return function(input) {
var options = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
message = input instanceof Error ? input.message : input;
options.classes = ((options.classes || "") + " " + CONFIG.classNames[type]).trim(), "error" === type && (options.duration = 1e4), notify(_.extend({
message: message
}, options))
}
},
config = {
position: "center",
maximumOpen: 5,
duration: 6e3
};
return CONFIG.template && (config.templateUrl = CONFIG.template), notify.config(config), {
success: action("success"),
error: action("error"),
info: action("info")
}
}]
}), angular.module("proton.commons").provider("url", function() {
var base = void 0,
make = function(key) {
var prefix = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return function() {
for (var _len = arguments.length, path = Array(_len), _key = 0; _key < _len; _key++) path[_key] = arguments[_key];
return [(prefix + "/" + key).trim()].concat(path).join("/")
}
};
this.setBaseUrl = function(newUrl) {
base = newUrl
}, this.$get = function() {
return {
host: function() {
var link = document.createElement("a");
return link.href = base, link.host
},
get: function() {
return base
},
make: make,
build: function(key) {
return make(key, this.get())
}
}
}
});
var _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
return typeof obj
} : function(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
};
angular.module("proton.commons").factory("aboutClient", function() {
var hasSessionStorage = function() {
var mod = "modernizr";
try {
return sessionStorage.setItem(mod, mod), sessionStorage.removeItem(mod), !0
} catch (error) {
return !1
}
},
hasCookie = function() {
return navigator.cookieEnabled
},
getBrowser = function() {
return $.ua.browser
},
getDevice = function() {
return $.ua.device
},
getOS = function() {
var _$$ua$os = $.ua.os,
_$$ua$os$name = _$$ua$os.name,
name = void 0 === _$$ua$os$name ? "other" : _$$ua$os$name,
_$$ua$os$version = _$$ua$os.version;
return {
name: name,
version: void 0 === _$$ua$os$version ? "" : _$$ua$os$version
}
},
isSafari = function() {
var browsers = ["Safari", "Mobile Safari"];
return _.contains(browsers, $.ua.browser.name)
},
isSafariMobile = function() {
return "Mobile Safari" === $.ua.browser.name
},
isIE11 = function() {
return "IE" === $.ua.browser.name && "11" === $.ua.browser.major
},
isEdge = function() {
return "Edge" === $.ua.browser.name
},
isFirefox = function() {
return "Firefox" === $.ua.browser.name
},
isMac = function() {
return "Mac OS" === getOS().name
},
isFileSaverSupported = function() {
return "download" in document.createElement("a") || navigator.msSaveOrOpenBlob
},
prngAvailable = function() {
return !("undefined" == typeof window || !window.crypto || !window.crypto.getRandomValues) || "undefined" != typeof window && "object" === _typeof(window.msCrypto) && "function" == typeof window.msCrypto.getRandomValues
};
return {
doNotTrack: function() {
return "1" === navigator.doNotTrack || "yes" === navigator.doNotTrack || "1" === navigator.msDoNotTrack || "1" === window.doNotTrack
},
hasSessionStorage: hasSessionStorage,
hasCookie: hasCookie,
getOS: getOS,
getBrowser: getBrowser,
getDevice: getDevice,
isMac: isMac,
isIE11: isIE11,
isEdge: isEdge,
isSafari: isSafari,
isFirefox: isFirefox,
isSafariMobile: isSafariMobile,
isFileSaverSupported: isFileSaverSupported,
prngAvailable: prngAvailable
}
}), angular.module("proton.commons").factory("dedentTpl", function() {
function dedent(callSite) {
function format() {
var str = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
size = -1;
return str.replace(/\n(\s+)/g, function(m, m1) {
return size < 0 && (size = m1.replace(/\t/g, " ").length), "\n" + m1.slice(Math.min(m1.length, size))
})
}
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) args[_key - 1] = arguments[_key];
return "string" == typeof callSite ? format(callSite) : "function" == typeof callSite ? function() {
return format(callSite.apply(void 0, arguments))
} : format(callSite.slice(0, args.length + 1).map(function(text, i) {
return (0 === i ? "" : args[i - 1]) + text
}).join(""))
}
return dedent
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.commons").factory("dispatchers", function($rootScope) {
var createMap = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, key) {
return "$" !== key.charAt(0) && (acc[key] = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
$rootScope.$emit(key, {
type: type,
data: data
})
}), acc
}, Object.create(null))
},
log = function(type, cb) {
return function() {
for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) arg[_key] = arguments[_key];
var namespace = "type [" + type + "]:",
_arg$slice = arg.slice(-1),
_arg$slice2 = _slicedToArray(_arg$slice, 1),
data = _arg$slice2[0];
console.group(namespace), console.log(data), cb.apply(void 0, arg), console.groupEnd(namespace)
}
};
return function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
verbose = arguments[1],
listeners = [];
return {
dispatcher: createMap(list),
on: function(type, cb) {
var callback = verbose ? log(type, cb) : cb;
listeners.push($rootScope.$on(type, callback))
},
unsubscribe: function() {
listeners.forEach(function(cb) {
return cb()
}), listeners.length = 0
}
}
}
}), angular.module("proton.commons").factory("errorReporter", function(notify) {
var newNotification = function(msg) {
return msg && notify(msg)
};
return {
clear: notify.closeAll,
catcher: function(msg, promise) {
return function(error) {
newNotification(msg), promise && promise.reject()
}
},
resolve: function(msg, currentPromise, defaultResult) {
return new Promise(function(resolve) {
currentPromise.then(resolve, function(error) {
newNotification(msg), resolve(defaultResult)
})
})
},
notify: newNotification
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.commons").factory("i18nLoader", function(CONFIG, $rootScope, gettextCatalog, pikadayConfiguration, dateUtils) {
var upperCaseLocale = function() {
var locale = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return ("en" === locale ? "us" : locale).toUpperCase()
},
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("i18n", {
type: type,
data: data
})
},
formatLocale = function(locale) {
var firstLanguage = window.navigator.languages && window.navigator.languages.length ? window.navigator.languages[0] : null,
value = (locale || firstLanguage || window.navigator.userLanguage || window.navigator.language).replace("-", "_");
return 2 === value.length ? value + "_" + upperCaseLocale(value) : value
},
getLocale = function() {
try {
var queryParams = new window.URL(window.location).searchParams;
return formatLocale(queryParams.get("language"))
} catch (e) {
var _ref = location.search.match(/language=(([a-z]{2,}(_|-)[A-Z]{2,})|([a-z]{2,}))/) || [],
_ref2 = _slicedToArray(_ref, 2),
locale = _ref2[1];
return formatLocale(locale)
}
},
localeRanker = function(navigatorLocaleData) {
return function(localeA, localeB) {
var localeAData = moment.localeData(localeA),
localeBData = moment.localeData(localeB),
localeAfirstday = localeAData.firstDayOfWeek(),
localeBfirstday = localeBData.firstDayOfWeek(),
navigatorFirstDay = navigatorLocaleData.firstDayOfWeek();
if (localeAfirstday !== localeBfirstday && (localeAfirstday === navigatorFirstDay || localeBfirstday === navigatorFirstDay)) return localeAfirstday === navigatorFirstDay ? -1 : 1;
var localeADateFormat = localeAData.longDateFormat("L"),
localeBDatelformat = localeBData.longDateFormat("L"),
navigatorDateformat = navigatorLocaleData.longDateFormat("L");
if (localeADateFormat !== localeBDatelformat && (localeADateFormat === navigatorDateformat || localeBDatelformat === navigatorDateformat)) return localeADateFormat === navigatorDateformat ? -1 : 1;
var woSymbols = function(str) {
return str.replace(/[^a-zA-Z]/g, "")
},
localeAStrippedFormat = woSymbols(localeADateFormat),
localeBStrippedFormat = woSymbols(localeBDatelformat),
navigatorStrippedFormat = woSymbols(navigatorDateformat);
return localeAStrippedFormat === localeBStrippedFormat || localeAStrippedFormat !== navigatorStrippedFormat && localeBStrippedFormat !== navigatorStrippedFormat ? "en-gb" === localeA || "en-gb" === localeB ? "en-gb" === localeA ? -1 : 1 : localeA.length - localeB.length : localeAStrippedFormat === navigatorStrippedFormat ? -1 : 1
}
},
selectLocale = function(baseLocale, navigatorLocale) {
var navigatorLocaleData = moment.localeData(navigatorLocale),
normalizedNavLocale = navigatorLocale.toLowerCase().replace("_", "-");
if (null !== navigatorLocaleData) {
var possibleLocales = moment.locales().filter(function(val) {
return 0 === val.lastIndexOf(baseLocale, 0)
});
if (possibleLocales.sort(localeRanker(navigatorLocaleData)), _.contains(possibleLocales, normalizedNavLocale)) return normalizedNavLocale;
if (possibleLocales.length) return possibleLocales[0]
}
return baseLocale
},
localizePikaday = function(response) {
var americanDays = _.sortBy(dateUtils.I18N.days.slice(), function(day) {
return day.value
}),
locale = {
previousMonth: gettextCatalog.getString("Previous Month", null, "Pikaday"),
nextMonth: gettextCatalog.getString("Next Month", null, "Pikaday"),
months: dateUtils.I18N.months,
weekdays: americanDays.map(function(day) {
return day.longLabel
}),
weekdaysShort: americanDays.map(function(day) {
return day.shortLabel
})
};
return pikadayConfiguration.update({
i18n: locale,
firstDay: moment.localeData().firstDayOfWeek(),
format: moment.localeData().longDateFormat("L")
}), response
},
localizeDateUtils = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", dateUtils.init());
case 1:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function() {
return _ref3.apply(this, arguments)
}
}(),
loadGettextCatalog = function(lang) {
var navigatorLocale = getLocale(),
locale = lang || navigatorLocale;
gettextCatalog.debugPrefix = "", gettextCatalog.setCurrentLanguage(locale), gettextCatalog.debug = CONFIG.debug || !1;
var _locale$split = locale.split("_"),
_locale$split2 = _slicedToArray(_locale$split, 1),
shortLocale = _locale$split2[0];
if (moment.locale(selectLocale(shortLocale, navigatorLocale)), document.documentElement.lang = shortLocale, CONFIG.translations.includes(locale)) return gettextCatalog.loadRemote("/i18n/" + locale + ".json");
var languageMatch = _.find(CONFIG.translations, function(lang) {
return lang.substr(0, 2) === shortLocale
});
return languageMatch ? gettextCatalog.loadRemote("/i18n/" + languageMatch + ".json") : Promise.resolve()
};
return function load(lang) {
return loadGettextCatalog(lang).then(localizeDateUtils).then(localizePikaday).then(function() {
return load.langCountry = moment.locale()
}).then(function() {
return dispatch("load", {
lang: load.langCountry
})
})
}
});
var _templateObject = _taggedTemplateLiteral(["\n >>> ", "\n Code: ", "\n Original: ", ",\n Stack: ", "\n "], ["\n >>> ", "\n Code: ", "\n Original: ", ",\n Stack: ", "\n "]);
angular.module("proton.commons").factory("networkActivityTracker", function(errorReporter, $rootScope, notification, dedentTpl) {
var promises = [],
dispatch = function(action) {
return $rootScope.$emit("networkActivity", action)
},
loading = function() {
return !_.isEmpty(promises)
},
formatError = function() {
var error = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return error.originalMessage ? dedentTpl(_templateObject, error.message, error.code, error.originalMessage, error.stack) : error
},
track = function(promise) {
function cleanup() {
promises = _.without(promises, promise), promises.length || dispatch("close")
}
return errorReporter.clear(), promises.length || dispatch("load"), promises = _.union(promises, [promise]), promise.catch(function(error) {
if (console.error(formatError(error)), angular.isString(error) && notification.error(error), angular.isObject(error) && !error.noNotify) {
var _error$data = error.data,
data = void 0 === _error$data ? {} : _error$data,
message = void 0;
return message = error.message ? error.message : error.Error ? error.Error : error.error_description ? error.error_description : data.Error ? data.Error : "An error has occurred. <br> Please try again or refresh the page.", "loginPassword:cancel" !== message && notification.error(message), Promise.reject(error)
}
}), promise.then(cleanup, cleanup), promise
};
return {
loading: loading,
clear: function() {
return errorReporter.clear(), promises.length = 0, promises
},
track: track,
dispatch: dispatch
}
}), angular.module("proton.commons").factory("networkUtils", function(CONSTANTS) {
var CANCEL_REQUEST = CONSTANTS.CANCEL_REQUEST;
return {
isCancelledRequest: function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$config = _ref.config;
return (((void 0 === _ref$config ? {} : _ref$config).timeout || {}).$$state || {}).value === CANCEL_REQUEST
}
}
}), angular.module("proton.commons").factory("secureSessionStorage", function(CONSTANTS, webcrypto) {
var storage = window.sessionStorage,
nameStorage = void 0;
try {
nameStorage = JSON.parse(window.name)
} catch (e) {
nameStorage = {}
}
for (var data = {}, whitelist = [CONSTANTS.MAILBOX_PASSWORD_KEY, CONSTANTS.OAUTH_KEY + ":SessionToken", CONSTANTS.OAUTH_KEY + ":Uid", CONSTANTS.OAUTH_KEY + ":AccessToken", CONSTANTS.OAUTH_KEY + ":RefreshToken", "proton:decrypted_token", "proton:encrypted_password"], i = 0; i < whitelist.length; i++)
if (nameStorage.hasOwnProperty(whitelist[i])) {
var item = storage.getItem(whitelist[i]),
nameItem = nameStorage[whitelist[i]];
if (angular.isString(item) && angular.isString(nameItem)) {
try {
item = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(item)), nameItem = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(nameItem))
} catch (e) {
continue
}
if (item.length === nameItem.length) {
for (var xored = new Array(item.length), j = 0; j < item.length; j++) xored[j] = item[j] ^ nameItem[j];
for (var unpaddedLength = item.length; unpaddedLength > 0 && 0 === xored[unpaddedLength - 1];) unpaddedLength--;
data[whitelist[i]] = pmcrypto.arrayToBinaryString(xored.slice(0, unpaddedLength))
}
}
}
storage.clear(), window.name = "", nameStorage = {};
var api = {
getItem: function(key) {
return angular.isString(key) && data.hasOwnProperty(key) ? data[key] : null
},
setItem: function(key, value) {
angular.isString(key) && angular.isString(value) && (data[key] = value)
},
removeItem: function(key) {
angular.isString(key) && data.hasOwnProperty(key) && delete data[key]
},
clear: function() {
data = {}
}
},
flush = function() {
for (var key in data)
if (data.hasOwnProperty(key)) {
for (var _item = pmcrypto.binaryStringToArray(data[key]), paddedLength = 256 * Math.ceil(_item.length / 256), share1 = webcrypto.getRandomValues(new Uint8Array(paddedLength)), share2 = new Uint8Array(share1), _i = 0; _i < _item.length; _i++) share2[_i] ^= _item[_i];
nameStorage[key] = pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(share1)), storage.setItem(key, pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(share2)))
}
_.isEmpty(nameStorage) || (window.name = JSON.stringify(nameStorage))
};
if (window.addEventListener) window.addEventListener("unload", flush, !1);
else {
if (!window.attachEvent) throw new Error("No method for adding event listeners!");
window.attachEvent("onunload", flush)
}
return api
}), angular.module("proton.commons").factory("webcrypto", function() {
return window.crypto && window.crypto.getRandomValues ? window.crypto : window.msCrypto && window.msCrypto.getRandomValues ? window.msCrypto : {
getRandomValues: function() {
throw new Error("No cryptographic randomness!")
}
}
}), angular.module("proton.composer").constant("ComposerRequestStatus", {
SUCCESS: 1e3,
DRAFT_NOT_EXIST: 15033,
MESSAGE_ALREADY_SEND: 15034
}), angular.module("proton.composer").controller("ComposeMessageController", function($filter, $rootScope, $scope, $state, $stateParams, $timeout, gettextCatalog, authentication, cache, confirmModal, CONSTANTS, hotkeys, messageModel, embedded, networkActivityTracker, composerRequestModel, messageBuilder, notification, AppModel, outsidersMap, encryptMessage, extractDataURI, messageRequest, validateMessage, postMessage, sendMessage, eventManager) {
function checkComposerNumber() {
var limit = $scope.messages.length >= CONSTANTS.MAX_NUMBER_COMPOSER || 1 === $scope.messages.length && AppModel.is("mobile");
return limit && notification.error(gettextCatalog.getString("Maximum composer reached", null, "Notify the user when he try to open more than " + CONSTANTS.MAX_NUMBER_COMPOSER + " composer")), limit
}
function bindFrom(_ref11) {
var AddressID = _ref11.AddressID,
addresses = _.chain(authentication.user.Addresses).where({
Status: 1,
Receive: 1
}).sortBy("Order").value();
if (AddressID) {
var adr = _.findWhere(addresses, {
ID: AddressID
});
return {
From: adr || addresses[0],
AddressID: adr ? AddressID : addresses[0].ID
}
}
return {
From: addresses[0],
AddressID: addresses[0].ID
}
}
function initMessage(message) {
1 === authentication.user.ComposerMode && (message.maximized = !0, AppModel.set("maximizedComposer", !0)), message.attachmentsToggle = message.Attachments.length - message.NumEmbedded > 0 && message.Attachments.length > message.NumEmbedded, message.ccbcc = !1, message.autocompletesFocussed = !1, message.uid = $scope.uid++, message.pendingAttachements = [], message.askEmbedding = !1, delete message.asEmbedded, message.uploading = 0, message.sending = !1;
var _bindFrom = bindFrom(message),
From = _bindFrom.From,
AddressID = _bindFrom.AddressID;
message.From = From, message.AddressID = AddressID, $scope.$applyAsync(function() {
var size = $scope.messages.unshift(message);
postMessage(message).then(function() {
$rootScope.$emit("composer.update", {
type: "loaded",
data: {
size: size,
message: message
}
})
}).catch(function() {
var _$scope$messages = _toArray($scope.messages),
list = _$scope$messages.slice(1);
$scope.messages = list
})
})
}
function dispatchMessageAction(message) {
$rootScope.$emit("actionMessage", message)
}
function removeMessage(list, message) {
return list.filter(function(item) {
return message.ID !== item.ID
})
}
function closeComposer(msg, discard, save) {
var _this = this,
message = messageModel(msg),
process = function() {
$scope.messages = removeMessage($scope.messages, message), composerRequestModel.clear(message), outsidersMap.remove(message.ID), commitComposer(message, !0), $(".tooltip").not(_this).hide(), $rootScope.$emit("composer.update", {
type: "close",
data: {
size: $scope.messages.length,
message: message
}
})
};
if (!0 === discard) {
var ids = [message.ID];
$rootScope.$emit("messageActions", {
action: "delete",
data: {
ids: ids
}
})
}
$timeout.cancel(message.defferredSaveLater), !0 === save ? postMessage(message, {
autosaving: !0
}).then(process) : process()
}
var unsubscribe = [],
unicodeTagView = $filter("unicodeTagView");
$scope.messages = [], $scope.uid = 1;
var commitComposer = function(_ref, clear) {
var ID = _ref.ID,
ConversationID = _ref.ConversationID,
list = AppModel.get("composerList") || [];
if (!clear) return AppModel.store("composerList", (list.push({
ID: ID,
ConversationID: ConversationID
}), list));
AppModel.store("composerList", list.filter(function(item) {
return item.ID !== ID
}))
};
unsubscribe.push($scope.$watch("messages.length", function() {
$scope.messages.length > 0 ? (AppModel.set("activeComposer", !0), window.onbeforeunload = function() {
return gettextCatalog.getString("By leaving now, you will lose what you have written in this email. You can save a draft if you want to come back to it later on.", null)
}, hotkeys.unbind(), hotkeys.bind(["meta+s"])) : (AppModel.set("activeComposer", !1), window.onbeforeunload = void 0, 1 === authentication.user.Hotkeys ? hotkeys.bind() : hotkeys.unbind())
})), unsubscribe.push($scope.$on("updateUser", function() {
$scope.addresses = authentication.user.Addresses
})), unsubscribe.push($scope.$on("onDrag", function() {
_.each($scope.messages, function(message) {
$scope.togglePanel(message, "attachments")
})
})), unsubscribe.push($scope.$on("deleteConversation", function(event, ID) {
_.each($scope.messages, function(message) {
ID === message.ID && $scope.close(message, !1, !1)
})
}));
var isSent = function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
Type = _ref2.Type;
return Type === CONSTANTS.INBOX_AND_SENT || Type === CONSTANTS.SENT
};
unsubscribe.push($rootScope.$on("app.event", function(event, _ref3) {
var type = _ref3.type,
data = _ref3.data;
switch (type) {
case "activeMessages":
var removed = $scope.messages.filter(function(_ref4) {
var _ref4$ID = _ref4.ID,
ID = void 0 === _ref4$ID ? "" : _ref4$ID,
msg = _.findWhere(data.messages, {
ID: ID
});
return msg && isSent(msg)
});
removed.length && removed.forEach(function(message) {
closeComposer(message), !isSent(message) && notification.info(gettextCatalog.getString("Email was already sent", null, "Info"))
})
}
})), unsubscribe.push($rootScope.$on("message.refresh", function(event, messageIDs) {
$scope.messages.forEach(function(message) {
var ID = message.ID;
if (messageIDs.indexOf(ID) > -1) {
var messageCached = cache.getMessageCached(ID);
messageCached && (message.Time = messageCached.Time, message.ConversationID = messageCached.ConversationID)
}
})
})), unsubscribe.push($rootScope.$on("composer.new", function(e, _ref5) {
var type = _ref5.type,
_ref5$data = _ref5.data,
data = void 0 === _ref5$data ? {} : _ref5$data;
!checkComposerNumber() && AppModel.is("onLine") && validateMessage.canWrite() && initMessage(messageBuilder.create(type, data.message))
})), unsubscribe.push($rootScope.$on("composer.load", function(event, _ref6) {
var ID = _ref6.ID,
found = _.findWhere($scope.messages, {
ID: ID
}),
limitReached = checkComposerNumber();
found || limitReached || cache.queryMessage(ID).then(function(message) {
message.clearTextBody().then(function() {
return initMessage(message)
}).then(function() {
return commitComposer(message)
}).catch(notification.error)
})
})), unsubscribe.push($rootScope.$on("composer.update", function(e, _ref7) {
var type = _ref7.type,
data = _ref7.data;
switch (type) {
case "loaded":
commitComposer(data.message);
break;
case "key.autosave":
$scope.$applyAsync(function() {
postMessage(_.find($scope.messages, {
focussed: !0
}), {
autosaving: !0
})
});
break;
case "editor.focus":
var message = data.message;
data.isMessage && $scope.$applyAsync(function() {
message.autocompletesFocussed = !1, message.attachmentsToggle = !1, message.ccbcc = !1
});
break;
case "send.message":
$scope.send(data.message);
break;
case "send.success":
case "close.message":
$scope.close(data.message, !1, !1);
break;
case "close.panel":
$scope.closePanel(data.message)
}
})), unsubscribe.push($rootScope.$on("message.updated", function(e, _ref8) {
var message = _ref8.message;
postMessage(message, {
autosaving: !0
})
})), unsubscribe.push($rootScope.$on("squire.editor", function(e, _ref9) {
var type = _ref9.type,
data = _ref9.data;
"input" === type && $scope.saveLater(data.message)
})), unsubscribe.push($rootScope.$on("attachment.upload", function(e, _ref10) {
var type = _ref10.type,
data = _ref10.data;
"remove.success" === type && "text/plain" !== data.message.MIMEType && postMessage(data.message, {
autosaving: !0
})
}));
var onResize = _.debounce(function() {
$rootScope.$emit("composer.update", {
type: "refresh",
data: {
size: $scope.messages.length
}
})
}, 1e3);
$(window).on("resize", onResize), $scope.$on("$destroy", function() {
$(window).off("resize", onResize), window.onbeforeunload = void 0, unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
}), $scope.slideDown = function(message) {
message.attachmentsToggle = !message.attachmentsToggle
}, $scope.isEmbedded = function(attachment) {
return embedded.isEmbedded(attachment)
}, $scope.togglePanel = function(message, panelName) {
!0 === message.displayPanel ? $scope.closePanel(message) : $scope.openPanel(message, panelName)
}, $scope.openPanel = function(message, panelName) {
message.displayPanel = !0, message.panelName = panelName, "encrypt" === panelName && $timeout(function() {
angular.element("#uid" + message.uid + ' input[name="outsidePw"]').focus()
}, 100, !1)
}, $scope.closePanel = function(message) {
message.displayPanel = !1, message.panelName = ""
}, $scope.saveLater = function(message) {
return !message.sending && postMessage(message, {
autosaving: !0,
loader: !1
})
}, $scope.save = function(message) {
var notification = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
autosaving = arguments.length > 2 && void 0 !== arguments[2] && arguments[2],
msg = messageModel(message);
return embedded.parser(msg, {
direction: "cid"
}).then(function(result) {
return msg.Body = result, postMessage(msg, {
notification: notification,
autosaving: autosaving
})
})
}, $scope.subject = function(message) {
return message.Subject || gettextCatalog.getString("New message", null, "Title")
}, $scope.send = function() {
var _ref12 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(msg) {
var message, setStateSending, promise;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return message = messageModel(msg), setStateSending = function(is) {
return message.sending = is, msg.sending = is
}, message.Password = message.Password || "", message.PasswordHint = message.PasswordHint || "", _context.prev = 4, _context.next = 7, validateMessage.checkSubject(message);
case 7:
_context.next = 12;
break;
case 9:
return _context.prev = 9, _context.t0 = _context.catch(4), _context.abrupt("return");
case 12:
setStateSending(!0), dispatchMessageAction(message), promise = validateMessage.validate(message).then(eventManager.stop).then(function() {
return extractDataURI(message)
}).then(function() {
return postMessage(message)
}).then(function(messageSaved) {
return message.ID = messageSaved.ID, message
}).then(function(msg) {
return sendMessage(msg)
}).then(eventManager.start).catch(function(e) {
throw setStateSending(!1), message.encrypting = !1, dispatchMessageAction(message), eventManager.start(), new Error(e.raw ? e.message : unicodeTagView(e.message))
}), networkActivityTracker.track(promise);
case 16:
case "end":
return _context.stop()
}
}, _callee, void 0, [
[4, 9]
])
}));
return function(_x4) {
return _ref12.apply(this, arguments)
}
}(), $scope.focusFirstComposer = function(message) {
$rootScope.$emit("composer.update", {
type: "focus.first",
data: {
message: message
}
})
}, $scope.minimize = function(message) {
message.minimized = !0, message.previousMaximized = message.maximized, message.maximized = !1, message.ccbcc = !1, AppModel.set("maximizedComposer", !1), $(".tooltip").not(void 0).hide(), $scope.focusFirstComposer(message)
}, $scope.unminimize = function(message) {
message.minimized = !1, message.maximized = message.previousMaximized, $(".tooltip").not(void 0).hide()
}, $scope.maximize = function(message) {
message.maximized = !0, AppModel.set("maximizedComposer", !0)
}, $scope.normalize = function(message) {
var width = window.innerWidth,
height = window.innerHeight,
isSmall = width <= 640 || height <= 500;
message.minimized = !1, message.maximized = isSmall, AppModel.set("maximizedComposer", isSmall)
}, $scope.openCloseModal = function(message) {
var discard = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
$scope.close(message, discard, !discard)
}, $scope.close = closeComposer, $scope.discard = function(message) {
var title = gettextCatalog.getString("Delete", null),
question = gettextCatalog.getString("Permanently delete this draft?", null);
confirmModal.activate({
params: {
title: title,
message: question,
confirm: function() {
$scope.openCloseModal(message, !0), notification.success(gettextCatalog.getString("Message discarded", null)), confirmModal.deactivate()
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}
}), angular.module("proton.composer").directive("actionCompose", function($rootScope) {
return {
scope: {
model: "=actionCompose"
},
link: function(scope, element, _ref) {
function onClick(e) {
if (e.preventDefault(), /addFile|addEmbedded/.test(actionComposeType)) return $rootScope.$emit("addFile", {
asEmbedded: "addEmbedded" === actionComposeType,
message: scope.model
});
$rootScope.$emit("composer.new", {
type: actionComposeType,
data: {
message: scope.model
}
})
}
var actionComposeType = _ref.actionComposeType;
element[0].addEventListener("click", onClick), scope.$on("$destroy", function() {
element[0].removeEventListener("click", onClick)
})
}
}
}), angular.module("proton.composer").directive("btnSendMessage", function($rootScope, gettextCatalog) {
var getLabel = function(msg) {
var label = void 0;
switch (!!msg) {
case !0 === msg.encryptingAttachment:
label = gettextCatalog.getString("Encrypting attachments", null, "Action");
break;
case msg.uploading > 0:
label = gettextCatalog.getString("Uploading", null, "Action");
break;
case !0 === msg.encrypting:
label = gettextCatalog.getString("Encrypting", null, "Action");
break;
case !0 === msg.saving && !1 === msg.autosaving:
label = gettextCatalog.getString("Saving", null, "Action");
break;
case !0 === msg.sending:
label = gettextCatalog.getString("Sending", null, "Action");
break;
case msg.disableSend && msg.disableSend():
default:
label = gettextCatalog.getString("Send", null, "Action")
}
return label
};
return {
replace: !0,
scope: {
model: "=message"
},
template: '<button class="btnSendMessage-btn-action"></button>',
link: function(scope, el) {
var isCurrentMsg = function(msg) {
return msg.ID === scope.model.ID
};
el[0].textContent = getLabel(scope.model);
var onClick = function() {
$rootScope.$emit("composer.update", {
type: "send.message",
data: {
message: scope.model
}
})
},
unsubscribe = $rootScope.$on("actionMessage", function(e, message) {
isCurrentMsg(message) && (el[0].textContent = getLabel(message), message.disableSend && (el[0].disabled = message.disableSend()))
});
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.composer").directive("composer", function(AppModel, $rootScope, embedded, attachmentFileFormat, authentication) {
var addDragenterClassName = function(el) {
var className = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "composer-draggable";
return el.classList.add(className)
},
addDragleaveClassName = function(el) {
el.classList.remove("composer-draggable"), el.classList.remove("composer-draggable-editor")
},
isMessage = function(_ref, _ref2) {
var ID = _ref.ID,
_ref2$message = _ref2.message,
message = void 0 === _ref2$message ? {} : _ref2$message;
return ID === _ref2.messageID || ID === message.ID
},
onAction = function(scope, el) {
return function(e, _ref3) {
var type = _ref3.type,
data = _ref3.data;
if (isMessage(scope.message, data)) switch (type) {
case "dragenter":
attachmentFileFormat.isUploadAbleType(data.event) && addDragenterClassName(el);
break;
case "drop":
if ("attachment.upload" === e.name && data.queue.files.length && data.queue.hasEmbedded) return addDragenterClassName(el, "composer-draggable-editor");
addDragleaveClassName(el);
break;
case "upload":
addDragleaveClassName(el);
break;
case "upload.success":
_rAF(function() {
return addDragleaveClassName(el)
})
}
}
};
return {
replace: !0,
templateUrl: "templates/directives/composer/composer.tpl.html",
link: function(scope, el) {
var onClick = function(_ref4) {
var target = _ref4.target;
/composerHeader-btn/.test(target.classList.toString()) || $rootScope.$emit("composer.update", {
type: "focus.click",
data: {
message: scope.message,
composer: el,
index: +el[0].getAttribute("data-index")
}
}), /squireToolbar/.test(target.classList.toString()) && scope.$applyAsync(function() {
scope.message.ccbcc = !1
})
},
onDragLeave = _.debounce(function(e) {
var target = e.target;
(target.classList.contains("composer-dropzone") || target.classList.contains("composer-dropzone-wrapper")) && addDragleaveClassName(el[0])
}, 500),
onDragEnter = function(_ref5) {
var originalEvent = _ref5.originalEvent;
attachmentFileFormat.isUploadAbleType(originalEvent) && addDragenterClassName(el[0])
},
onKeydown = function(_ref6) {
if (27 === _ref6.keyCode) {
if (document.activeElement && document.activeElement.classList.contains("autocompleteEmails-input")) return;
1 === authentication.user.Hotkeys && $rootScope.$emit("composer.update", {
type: "close.message",
data: {
message: scope.message
}
})
}
};
el.on("dragenter", onDragEnter), el.on("dragleave", onDragLeave), el.on("click", onClick), el.on("keydown", onKeydown);
var unsubscribeEditor = $rootScope.$on("editor.draggable", onAction(scope, el[0])),
unsubscribeAtt = $rootScope.$on("attachment.upload", onAction(scope, el[0]));
scope.$on("$destroy", function() {
el.off("dragenter", onDragEnter), el.off("dragleave", onDragLeave), el.off("click", onClick), el.off("keydown", onKeydown), unsubscribeEditor(), unsubscribeAtt(), AppModel.set("activeComposer", !1), AppModel.set("maximizedComposer", !1), scope.selected = void 0
})
}
}
}), angular.module("proton.composer").directive("composerAskEmbedded", function($rootScope, gettextCatalog) {
var buildTitle = function(node, pending) {
var counterTranslateKey = gettextCatalog.getPlural(pending, "image detected", "images detected", {}, "Composer, message drag and drop images");
node.textContent = pending + " " + counterTranslateKey
};
return {
replace: !0,
templateUrl: "templates/directives/composer/composerAskEmbedded.tpl.html",
link: function(scope, el, _ref) {
var _ref$action = _ref.action,
action = void 0 === _ref$action ? "" : _ref$action,
key = ["attachment.upload", action].filter(Boolean).join("."),
dispatch = function(data) {
return $rootScope.$emit(key, {
type: "upload",
data: data
})
},
$title = el[0].querySelector(".composerAskEmbdded-title"),
unsubscribe = $rootScope.$on(key, function(e, _ref2) {
var type = _ref2.type,
data = _ref2.data;
"drop" === type && buildTitle($title, data.queue.files.filter(function(_ref3) {
return _ref3.isEmbedded
}).length)
}),
onClick = function(_ref4) {
var target = _ref4.target;
"BUTTON" === target.nodeName && dispatch({
messageID: scope.message.ID,
message: scope.message,
action: target.getAttribute("data-action")
})
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.composer").directive("composerAttachments", function($rootScope, gettextCatalog) {
var CLASS_HIDDEN = "composerAttachments-hidden",
labelHeader = {
show: gettextCatalog.getString("Show", null, "Action"),
hide: gettextCatalog.getString("Hide", null, "Action")
},
togglePanel = function(scope, el) {
var doAction = function(action, label) {
return function() {
"remove" === action && el.classList.remove(CLASS_HIDDEN), el.classList[action]("composerAttachments-close"), scope.$applyAsync(function() {
return scope.labelHeader = labelHeader[label]
})
}
},
open = doAction("remove", "hide"),
close = doAction("add", "show"),
show = function() {
return el.classList.remove(CLASS_HIDDEN)
},
hide = function() {
return el.classList.add(CLASS_HIDDEN)
},
isOpened = function() {
return !el.classList.contains("composerAttachments-close")
};
return {
open: open,
close: close,
isOpened: isOpened,
hide: hide,
show: show,
toggle: function() {
return isOpened() ? close() : open()
}
}
},
formatAttachments = function(scope) {
return (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []).map(function(_ref) {
var ID = _ref.ID,
_ref$Headers = _ref.Headers,
Headers = void 0 === _ref$Headers ? {} : _ref$Headers;
return {
id: ID,
packet: {
filename: _ref.Name,
uploading: !1,
Size: _ref.Size,
Inline: +("inline" === Headers["content-disposition"])
},
messageID: scope.message.ID,
message: scope.message
}
})
},
isMessage = function(_ref2, _ref3) {
var ID = _ref2.ID,
_ref3$message = _ref3.message,
message = void 0 === _ref3$message ? {} : _ref3$message;
return ID === _ref3.messageID || ID === message.ID
},
onAction = function(scope, actionsPanel) {
return function(e, _ref4) {
var type = _ref4.type,
data = _ref4.data,
status = data.status,
packet = data.packet,
id = data.id,
messageID = data.messageID,
REQUEST_ID = data.REQUEST_ID,
isStart = data.isStart;
if (isMessage(scope.message, data)) switch (type) {
case "upload":
if ("cancel" !== data.action) return;
if (scope.message.Attachments.length) return actionsPanel.close();
actionsPanel.hide();
break;
case "cancel":
case "remove.success":
scope.$applyAsync(function() {
scope.list = scope.list.filter(function(o) {
return o.id !== id
}).filter(function(o) {
return o.id !== REQUEST_ID
}), !scope.list.length && actionsPanel.hide()
});
break;
case "uploading":
status && isStart && (actionsPanel.open(), scope.$applyAsync(function() {
scope.list.push({
id: id,
packet: packet,
messageID: messageID,
message: scope.message
})
}));
break;
case "error":
scope.$applyAsync(function() {
scope.list = scope.list.filter(function(item) {
return item.id !== id && item.message.ID !== scope.message.ID
}), actionsPanel.close(), !scope.list.length && actionsPanel.hide()
});
break;
case "upload.success":
actionsPanel.close()
}
}
};
return {
replace: !0,
scope: {
message: "=model"
},
templateUrl: "templates/directives/composer/composerAttachments.tpl.html",
link: function(scope, el) {
scope.list = formatAttachments(scope, scope.message.Attachments), scope.labelHeader = labelHeader.show;
var actionsPanel = togglePanel(scope, el[0]),
$header = angular.element(el[0].querySelector(".composerAttachments-header"));
!scope.list.length && actionsPanel.hide();
var onClick = function() {
return actionsPanel.toggle()
};
$header.on("click", onClick);
var unsubscribe = $rootScope.$on("attachment.upload", onAction(scope, actionsPanel));
scope.$on("$destroy", function() {
$header.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.composer").directive("composerAttachmentsItem", function($rootScope, gettextCatalog, attachmentDownloader) {
var getTitle = function(name) {
return gettextCatalog.getString("Download the attachment " + name)
},
dispatcher = function(isOutside) {
return function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
event = ("attachment.upload" + (isOutside ? ".outside" : "")).trim();
$rootScope.$emit(event, {
type: type,
data: data
})
}
};
return {
replace: !0,
template: '<a class="composerAttachmentsItem-container"><progress-upload data-model="attachment"></progress-upload></a>',
link: function(scope, el, _ref) {
var _ref$isOutside = _ref.isOutside,
isOutside = void 0 !== _ref$isOutside && _ref$isOutside,
dispatch = dispatcher(isOutside);
el[0].title = getTitle(scope.attachment.packet.filename);
var onClick = function(e) {
attachmentDownloader.isNotSupported(e) || dispatch("download.composer", scope.attachment)
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick)
})
}
}
}), angular.module("proton.composer").directive("composerContainer", function($rootScope, composerRender, composerLoader) {
return {
link: function(scope, el) {
var focusMessage = composerLoader(scope),
renderList = function(data) {
var $list = [].slice.call(el[0].querySelectorAll(".composer-container"));
_rAF(function() {
return composerRender.render($list, data)
})
},
openClose = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
scope.$applyAsync(function() {
if (scope.messages.length) {
var message = "close" === type ? scope.messages[0] : data.message;
message.focussed = !1;
var _composerRender$findC = composerRender.findComposer(el[0], message),
index = _composerRender$findC.index,
composer = _composerRender$findC.composer,
position = index - 1 >= 0 ? index - 1 : index,
state = angular.extend({}, data, {
message: message,
composer: composer,
index: position,
size: scope.messages.length,
keepState: !1
});
focusMessage(state);
var id = setTimeout(function() {
return renderList(state), clearTimeout(id)
}, 160)
}
})
},
onOrientationChange = function() {
return openClose("close")
};
window.addEventListener("orientationchange", onOrientationChange, !1);
var unsubscribe = $rootScope.$on("composer.update", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
switch (type) {
case "focus.click":
scope.$applyAsync(function() {
return focusMessage(data)
});
break;
case "focus.first":
var notMinimized = _.findWhere(scope.messages, {
minimized: !1
});
notMinimized && openClose(type, {
message: notMinimized
});
break;
case "close":
openClose(type, data);
break;
case "editor.loaded":
case "editor.focus":
var message = data.message,
editor = data.editor;
if (!data.isMessage) break;
if (message.focussed) {
scope.$applyAsync(function() {
return message.autocompletesFocussed = !1
});
break
}
scope.$applyAsync(function() {
var _composerRender$findC2 = composerRender.findComposer(el[0], message),
index = _composerRender$findC2.index,
composer = _composerRender$findC2.composer,
state = angular.extend({}, data, {
composer: composer,
index: index,
keepState: !1,
focusEditor: "editor.focus" === type,
size: scope.messages.length
});
focusMessage(state, editor), "editor.loaded" === type && renderList(state)
})
}
});
scope.$on("$destroy", function() {
window.removeEventListener("orientationchange", onOrientationChange, !1), unsubscribe()
})
}
}
}), angular.module("proton.composer").directive("composerDropzone", function($rootScope, attachmentFileFormat, tools, attachmentModel, notification, gettextCatalog, CONSTANTS, $state) {
function getDropFileConfigMessage(message, file) {
return {
currentSize: message.attachmentsSize() + (message.queuedFilesSize || 0) + file.size,
numberFiles: (message.Attachments || []).length + (message.queuedFiles || 0)
}
}
function buildQueue(message, dropzone) {
return function(queue, file) {
var _getDropFileConfigMes = getDropFileConfigMessage(message, file),
currentSize = _getDropFileConfigMes.currentSize;
if (_getDropFileConfigMes.numberFiles === ATTACHMENT_NUMBER_LIMIT) {
var msg = dropMessages[ATTACHMENT_NUMBER_LIMIT];
return dropzone.removeFile(file), notification.error(msg), queue
}
if (currentSize >= ATTACHMENT_MAX_SIZE) {
var _msg = dropMessages[ATTACHMENT_MAX_SIZE](currentSize);
return dropzone.removeFile(file), notification.error(_msg), queue
}
if (0 === currentSize) {
var _msg2 = dropMessages[0];
return dropzone.removeFile(file), notification.error(_msg2), queue
}
return queue.files.push({
file: file,
isEmbedded: attachmentFileFormat.isEmbedded(file.type)
}), queue.size += file.size, queue
}
}
var _dropMessages;
Dropzone.autoDiscover = !1;
var BASE_SIZE = CONSTANTS.BASE_SIZE,
ATTACHMENT_SIZE_LIMIT = CONSTANTS.ATTACHMENT_SIZE_LIMIT,
ATTACHMENT_NUMBER_LIMIT = CONSTANTS.ATTACHMENT_NUMBER_LIMIT,
ATTACHMENT_MAX_SIZE = ATTACHMENT_SIZE_LIMIT * BASE_SIZE * BASE_SIZE,
isEO = $state.includes("eo.*"),
dropMessages = (_dropMessages = {
0: gettextCatalog.getString("Empty attachment", null, "Composer")
}, _defineProperty(_dropMessages, ATTACHMENT_NUMBER_LIMIT, gettextCatalog.getString("Messages are limited to " + ATTACHMENT_NUMBER_LIMIT + " attachments", null, "Composer")), _defineProperty(_dropMessages, ATTACHMENT_SIZE_LIMIT, gettextCatalog.getString("Attachments are limited to " + ATTACHMENT_SIZE_LIMIT + " MB.", null, "Composer")), _defineProperty(_dropMessages, ATTACHMENT_MAX_SIZE, function(bytes) {
var total = Math.round(10 * bytes / BASE_SIZE / BASE_SIZE) / 10;
return gettextCatalog.getString("Attachments are limited to " + ATTACHMENT_SIZE_LIMIT + " MB. Total attached would be: " + total + " MB.", null, "Composer")
}), _dropMessages),
ERROR_EO_NUMBER_ATT = gettextCatalog.getString("Maximum number of attachments (10) exceeded.", null, "Composer"),
dictDefaultMessage = gettextCatalog.getString("Drop a file here to upload", null, "Info"),
canUploadList = function(message) {
var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
_ref = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
_ref$size = _ref.size,
size = void 0 === _ref$size ? 0 : _ref$size,
listSize = [].slice.call(list).reduce(function(acc, file) {
return acc + file.size
}, 0);
return message.attachmentsSize() + size + listSize <= ATTACHMENT_MAX_SIZE
},
getConfig = function(message, dispatchAction) {
return {
addRemoveLinks: !1,
dictDefaultMessage: dictDefaultMessage,
url: "/file/post",
autoProcessQueue: !1,
paramName: "file",
previewTemplate: '<div style="display:none"></div>',
init: function() {
var _this = this;
_.forEach(message.Attachments, function(_ref2) {
var Name = _ref2.Name,
Size = _ref2.Size,
MIMEType = _ref2.MIMEType,
ID = _ref2.ID,
mockFile = {
name: Name,
size: Size,
type: MIMEType,
ID: ID
};
_this.options.addedfile.call(_this, mockFile)
}, this), this.on("addedfiles", function(list) {
if (!canUploadList(message, list, attachmentModel.getCurrentQueue(message))) {
_this.removeAllFiles();
var id = void 0;
return id = setTimeout(function() {
notification.error(dropMessages[ATTACHMENT_SIZE_LIMIT]), dispatchAction(message, {
size: 0,
files: []
}), clearTimeout(id)
}, 100)
}
var queue = [].slice.call(list).reduce(buildQueue(message, _this), {
files: [],
size: 0
});
if (_this.removeAllFiles(), queue.hasEmbedded = queue.files.every(function(_ref3) {
return _ref3.isEmbedded && "text/plain" !== message.MIMEType
}), isEO && queue.files.length + message.Attachments.length > 10) return dispatchAction(message, queue, "attachments.limit.error"), notification.error(ERROR_EO_NUMBER_ATT);
dispatchAction(message, queue)
})
}
}
};
return {
link: function(scope, el, _ref4) {
var _ref4$action = _ref4.action,
action = void 0 === _ref4$action ? "" : _ref4$action,
key = ["attachment.upload", action].filter(Boolean).join("."),
dispatchAction = function(message) {
var queue = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
type = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "drop";
$rootScope.$emit(key, {
type: type,
data: {
messageID: message.ID,
message: message,
queue: queue
}
})
},
dropzone = new Dropzone(el[0], getConfig(scope.message, dispatchAction)),
unsubscribe = $rootScope.$on("addFile", function(e, _ref5) {
var asEmbedded = _ref5.asEmbedded;
_ref5.message.ID === scope.message.ID && (scope.message.asEmbedded = asEmbedded, dropzone.element.click())
});
scope.$on("$destroy", function() {
dropzone.off("dragover"), dropzone.off("addedfiles"), dropzone.destroy(), unsubscribe()
})
}
}
}), angular.module("proton.composer").directive("composerEncrypt", function(notification, gettextCatalog, $rootScope) {
var MESSAGES = {
noPassword: gettextCatalog.getString("Please enter a password for this email.", null, "Error"),
noMatchPassword: gettextCatalog.getString("Message passwords do not match.", null, "Error")
},
dispatch = function(type, message) {
return $rootScope.$emit("composer.update", {
type: type,
data: {
message: message,
type: "encryption"
}
})
};
return {
replace: !0,
scope: {
message: "="
},
templateUrl: "templates/composer/composerEncrypt.tpl.html",
link: function(scope, el) {
var $cancel = el.find(".composerEncrypt-btn-cancel");
scope.model = {
password: "",
confirm: "",
hint: ""
};
var onSubmit = function(e) {
return e.stopPropagation(), scope.model.password.length ? scope.model.password !== scope.model.confirm ? notification.error(MESSAGES.noMatchPassword) : void scope.$applyAsync(function() {
scope.message.IsEncrypted = 1, scope.message.Password = scope.model.password, scope.message.PasswordHint = scope.model.hint, dispatch("close.panel", scope.message)
}) : notification.error(MESSAGES.noPassword)
},
onCancel = function() {
scope.$applyAsync(function() {
scope.model.password = "", scope.model.confirm = "", scope.model.hint = "", scope.encryptForm.$setUntouched(), delete scope.message.PasswordHint, scope.message.IsEncrypted = 0, dispatch("close.panel", scope.message)
})
};
el.on("submit", onSubmit), $cancel.on("click", onCancel), scope.$on("$destroy", function() {
el.off("submit", onSubmit), $cancel.off("click", onCancel)
})
}
}
}), angular.module("proton.composer").directive("composerExpiration", function(notification, gettextCatalog, $rootScope, CONSTANTS) {
var MESSAGES = {
maxEpiration: gettextCatalog.getString("The maximum expiration is 4 weeks.", null, "Error"),
invalid: gettextCatalog.getString("Invalid expiration time.", null, "Error")
},
dispatch = function(type, message) {
return $rootScope.$emit("composer.update", {
type: type,
data: {
message: message,
type: "expiration"
}
})
},
formatOption = function(size) {
return _.range(size).map(function(value) {
return {
label: "" + value,
value: value
}
})
},
OPTIONS = {
week: formatOption(5),
day: formatOption(7),
hour: formatOption(24)
},
initModel = function(message) {
if (angular.isDefined(message.ExpirationTime)) {
var deltaHours = message.ExpirationTime / 3600,
deltaDays = Math.floor(deltaHours / 24);
return {
weeks: angular.copy(_.findWhere(OPTIONS.week, {
value: Math.floor(deltaDays / 7)
})),
days: angular.copy(_.findWhere(OPTIONS.day, {
value: deltaDays % 7
})),
hours: angular.copy(_.findWhere(OPTIONS.hour, {
value: deltaHours % 24
}))
}
}
return {
days: 0,
hours: 0,
weeks: 0
}
},
computeHours = function(_ref) {
var days = _ref.days,
hours = _ref.hours,
weeks = _ref.weeks;
return hours.value + 24 * (days.value + 7 * weeks.value)
};
return {
replace: !0,
scope: {
message: "="
},
templateUrl: "templates/composer/composerExpiration.tpl.html",
link: function(scope, el) {
var $cancel = el.find(".composerExpiration-btn-cancel");
scope.model = initModel(scope.message), scope.options = OPTIONS;
var onSubmit = function(e) {
e.stopPropagation();
var hours = computeHours(scope.model);
return parseInt(hours, 10) > CONSTANTS.MAX_EXPIRATION_TIME ? notification.error(MESSAGES.maxEpiration) : isNaN(hours) ? notification.error(MESSAGES.invalid) : void scope.$applyAsync(function() {
scope.message.ExpirationTime = 3600 * hours, dispatch("close.panel", scope.message)
})
},
onCancel = function() {
scope.$applyAsync(function() {
delete scope.message.ExpirationTime, scope.expirationForm.$setUntouched(), dispatch("close.panel", scope.message)
})
};
el.on("submit", onSubmit), $cancel.on("click", onCancel), scope.$on("$destroy", function() {
el.off("submit", onSubmit), $cancel.off("click", onCancel)
})
}
}
}), angular.module("proton.composer").directive("composerHeader", function() {
return {
replace: !0,
templateUrl: "templates/directives/composer/composer-header.tpl.html"
}
}), angular.module("proton.composer").directive("composerInputMeta", function() {
var containsInvalid = function(_ref) {
var _ref$ToList = _ref.ToList,
ToList = void 0 === _ref$ToList ? [] : _ref$ToList,
_ref$CCList = _ref.CCList,
CCList = void 0 === _ref$CCList ? [] : _ref$CCList,
_ref$BCCList = _ref.BCCList,
BCCList = void 0 === _ref$BCCList ? [] : _ref$BCCList;
return _.some([].concat(_toConsumableArray(ToList), _toConsumableArray(CCList), _toConsumableArray(BCCList)), {
invalid: !0
})
},
containsRecipient = function(scope) {
return function() {
var _scope$message = scope.message,
_scope$message$ToList = _scope$message.ToList,
ToList = void 0 === _scope$message$ToList ? [] : _scope$message$ToList,
_scope$message$CCList = _scope$message.CCList,
CCList = void 0 === _scope$message$CCList ? [] : _scope$message$CCList,
_scope$message$BCCLis = _scope$message.BCCList,
BCCList = void 0 === _scope$message$BCCLis ? [] : _scope$message$BCCLis;
return !containsInvalid(scope.message) && (ToList.length || CCList.length || BCCList.length)
}
},
containsBCC = function(_ref2) {
var _ref2$CCList = _ref2.CCList,
CCList = void 0 === _ref2$CCList ? [] : _ref2$CCList,
_ref2$BCCList = _ref2.BCCList,
BCCList = void 0 === _ref2$BCCList ? [] : _ref2$BCCList;
return CCList.length || BCCList.length
},
getNameAutocomplete = function(label) {
return "composerAutocomplete" + label + Math.random().toString(32).slice(2, 12)
};
return {
replace: !0,
templateUrl: "templates/directives/composer/composerInputMeta.tpl.html",
compile: function(element, _ref3) {
var label = _ref3.label,
key = _ref3.key,
$label = element[0].querySelector(".composerInputMeta-label"),
$input = element[0].querySelector(".composerInputMeta-autocomplete");
return $label && ($label.textContent = label), $input && ($input.setAttribute("data-name", getNameAutocomplete(label)), $input.setAttribute("data-emails", "message." + key)),
function(scope, el) {
var isCurrentMsg = function() {
return scope.message.ID === scope.selected.ID
},
$btn = el[0].querySelector(".composerInputMeta-overlay-button");
scope.containsRecipient = containsRecipient(scope), scope.containsInvalid = containsInvalid;
var onClick = function(_ref4) {
_ref4.target.classList.contains("autocompleteEmails-label") || scope.$applyAsync(function() {
scope.selected.autocompletesFocussed = !0, containsBCC(scope.selected) && (scope.message.ccbcc = !0, scope.message.attachmentsToggle = !0), _rAF(function() {
return el.find("input").focus()
})
})
},
onClickBtn = function(e) {
e.stopPropagation(), isCurrentMsg() && scope.$applyAsync(function() {
scope.message.ccbcc = !scope.message.ccbcc, scope.message.autocompletesFocussed = !0, scope.message.attachmentsToggle = !1
})
};
$btn.addEventListener("click", onClickBtn, !1), el.on("click", onClick), scope.$on("$destroy", function() {
$btn.removeEventListener("click", onClickBtn, !1), el.off("click", onClick)
})
}
}
}
}), angular.module("proton.composer").directive("composerMessage", function() {
return {
replace: !0,
scope: {},
templateUrl: "templates/partials/composer.tpl.html",
controller: "ComposeMessageController"
}
}), angular.module("proton.composer").directive("composerSelectFrom", function(notification, authentication, editorModel, aboutClient, gettextCatalog) {
var I18N = {
ATTACHMENT_SEND_CHANGE: gettextCatalog.getString("Attachments and inline images must be removed first before changing sender", null, "Compose message")
},
listAddress = function() {
return _.chain(authentication.user.Addresses).where({
Status: 1,
Receive: 1
}).sortBy("Order").value()
};
return {
scope: {
message: "=model"
},
replace: !0,
templateUrl: "templates/directives/composer/composerSelectFrom.tpl.html",
link: function(scope, el) {
var $select = el.find("select");
scope.addresses = listAddress();
var onClick = function(e) {
if (scope.message.Attachments.length) return e.preventDefault(), notification.error(I18N.ATTACHMENT_SEND_CHANGE)
},
onChange = function() {
scope.$applyAsync(function() {
scope.message.AddressID = scope.message.From.ID, editorModel.find(scope.message).editor.fireEvent("refresh", {
action: "message.changeFrom"
})
})
},
onMouseDown = function() {
return $select.focus()
};
aboutClient.isIE11() && $select.on("mousedown", onMouseDown), el.on("click", onClick), el.on("change", onChange), scope.$on("$destroy", function() {
aboutClient.isIE11() && $select.off("mousedown", onMouseDown), el.off("click", onClick), el.off("change", onChange)
})
}
}
}), angular.module("proton.composer").directive("composerSubject", function(editorModel) {
return {
replace: !0,
templateUrl: "templates/directives/composer/composerSubject.tpl.html",
link: function(scope, el) {
var $input = el[0].querySelector("input"),
onFocus = function() {
scope.$applyAsync(function() {
scope.message.autocompletesFocussed = !1, scope.message.ccbcc = !1, scope.message.attachmentsToggle = !1
})
},
onKeydown = _.throttle(function(e) {
if (9 === e.which) {
if ("text/plain" === scope.message.MIMEType) return e.preventDefault(), el.parents(".composer").find("textarea").focus();
var _editorModel$find = editorModel.find(scope.message),
editor = _editorModel$find.editor;
editor && "text/plain" !== scope.message.MIMEType && (e.preventDefault(), editor.focus())
}
}, 150),
onBlur = function() {
scope.$applyAsync(function() {
return scope.saveLater(scope.message)
})
};
$input.addEventListener("focus", onFocus, !0), $input.addEventListener("keydown", onKeydown, !1), $input.addEventListener("blur", onBlur, !1), scope.$on("$destroy", function() {
$input.removeEventListener("focus", onFocus, !0), $input.removeEventListener("keydown", onKeydown, !1), $input.removeEventListener("blur", onBlur, !1)
})
}
}
}), angular.module("proton.composer").directive("composerTime", function($rootScope, gettextCatalog) {
var getTime = function(_ref) {
var Time = _ref.Time;
return moment.unix(Time).format("LT")
},
I18N = {
saveAt: gettextCatalog.getString("Saved at", null, "Info display in the composer footer"),
saving: gettextCatalog.getString("Saving", null, "Info display in the composer footer")
};
return {
restrict: "E",
replace: !0,
template: '<time class="composerTime-container"></time>',
link: function(scope, element) {
var update = function(message) {
if (message.saving) return void(element[0].textContent = I18N.saving);
message.Time && (element[0].textContent = I18N.saveAt + " " + getTime(message))
},
unsubscribe = $rootScope.$on("actionMessage", function(event, message) {
scope.message.ID === message.ID && update(message)
});
update(scope.message), scope.$on("$destroy", unsubscribe)
}
}
}), angular.module("proton.composer").directive("responsiveComposer", function($rootScope, authentication) {
var latestState = {},
computeType = function(scope) {
return function() {
var width = window.innerWidth,
height = window.innerHeight,
isSmall = width <= 640 || height <= 600;
scope.message.maximized && !latestState.isSmall || scope.message.minimized || (latestState.isSmall = isSmall, scope.$applyAsync(function() {
$rootScope.small = height < 700 && height >= 600, $rootScope.mini = height < 600, isSmall && scope.maximize(scope.message), !isSmall && 0 === authentication.user.ComposerMode && scope.normalize(scope.message)
}))
}
};
return {
restrict: "A",
link: function(scope) {
var resizable = computeType(scope),
onResize = _.debounce(resizable, 100),
id = setTimeout(function() {
resizable(), clearTimeout(id)
}, 100);
window.addEventListener("resize", onResize), scope.$on("$destroy", function() {
window.removeEventListener("resize", onResize)
})
}
}
}), angular.module("proton.composer").factory("composerLoader", function(editorModel, $rootScope) {
function customFocus(el, scope, message) {
if (el[0] && (!el[0].contains(document.activeElement) || el[0] === document.activeElement)) var id = setTimeout(function() {
clearTimeout(id);
var _scope$selected = scope.selected,
_scope$selected$ToLis = _scope$selected.ToList,
ToList = void 0 === _scope$selected$ToLis ? [] : _scope$selected$ToLis,
_scope$selected$CCLis = _scope$selected.CCList,
CCList = void 0 === _scope$selected$CCLis ? [] : _scope$selected$CCLis,
_scope$selected$BCCLi = _scope$selected.BCCList;
if (![].concat(ToList, CCList, void 0 === _scope$selected$BCCLi ? [] : _scope$selected$BCCLi).length) {
var input = el.find(".toRow").find("input").eq(0);
if (input.get(0)) return scope.$applyAsync(function() {
scope.selected.autocompletesFocussed = !0, _rAF(function() {
return input.focus()
})
})
}
if (!scope.selected.Subject.length) return el.find(".subject").focus();
if ("text/plain" === message.MIMEType) return el.find(".plaintext-editor").focus();
var _editorModel$find = editorModel.find(message),
editor = _editorModel$find.editor;
if (editor) return _rAF(function() {
return editor.focus()
});
var unsubscribe = $rootScope.$on("composer.update", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
"editor.loaded" === type && message.ID === data.message.ID && (data.editor.focus(), unsubscribe())
})
}, 300)
}
function focusMessage(scope) {
return function(_ref2) {
var composer = _ref2.composer,
index = _ref2.index,
message = _ref2.message,
focusEditor = _ref2.focusEditor,
_ref2$keepState = _ref2.keepState,
keepState = void 0 === _ref2$keepState || _ref2$keepState;
if (!message.focussed) {
var messagesLength = scope.messages.length;
if (_.each(scope.messages, function(msg, iteratee) {
msg.focussed = !1, msg.zIndex = iteratee > index ? 100 * (messagesLength - (iteratee - index)) : 100 * messagesLength
}), message.focussed = !0, scope.selected = message, !keepState && (scope.selected.autocompletesFocussed = !1), focusEditor) {
return editorModel.find(message).editor.focus()
}!keepState && customFocus(composer, scope, message)
}
}
}
return focusMessage
}), angular.module("proton.composer").factory("composerRender", function() {
function sizes(element, count) {
var width = element.offsetWidth,
margin = document.documentElement.classList.contains("ua-windows_nt") ? 40 : 20,
windowWidth = document.body.offsetWidth,
overlap = 0;
return windowWidth / count < width && (overlap = (windowWidth - width - margin) / (count - 1)), {
width: width,
margin: margin,
windowWidth: windowWidth,
overlap: overlap
}
}
function getPositionRight(_ref, index) {
var width = _ref.width,
margin = _ref.margin,
overlap = _ref.overlap,
right = overlap ? index * overlap : index * (width + margin) + margin;
return parseInt(right, 10) || margin
}
function bindStyles(element, styles) {
Object.keys(styles).forEach(function(key) {
return element.style[key] = styles[key]
})
}
function render($list) {
var _ref2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref2$size = _ref2.size,
size = void 0 === _ref2$size ? 1 : _ref2$size;
$list.forEach(function(node, index) {
var config = sizes(node, size),
styles = {
visibility: "visible"
};
styles.transform = "translateX(-" + getPositionRight(config, index) + "px)", bindStyles(node, styles)
})
}
function findComposer(node, _ref3) {
var ID = _ref3.ID,
composer = node.querySelector('[data-composer-id="' + ID + '"]');
return composer ? {
composer: angular.element(composer),
index: +composer.getAttribute("data-index")
} : {
composer: angular.element(node.querySelector(".composer")),
index: 0
}
}
return {
render: render,
findComposer: findComposer
}
}), angular.module("proton.composer").factory("composerRequestModel", function($q) {
var MAP_REQUEST = {},
read = function(key) {
return MAP_REQUEST["key." + key] || []
},
clear = function(_ref) {
var uid = _ref.uid;
delete MAP_REQUEST["key." + uid]
};
return {
save: function(message, promise) {
var key = "key." + message.uid;
MAP_REQUEST[key] = MAP_REQUEST[key] || [], MAP_REQUEST[key].push(promise)
},
clear: clear,
chain: function(_ref2) {
var uid = _ref2.uid,
list = read(uid).map(function(_ref3) {
return _ref3.promise
});
return $q.all(list)
}
}
}), angular.module("proton.composer").factory("outsidersMap", function() {
var MAP = {},
set = function(key, value) {
return MAP[key] = value
},
get = function(key) {
return MAP[key]
},
remove = function(key) {
return delete MAP[key]
};
return {
set: set,
get: get,
clear: function() {
return MAP = {}
},
remove: remove
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.composer").factory("encryptMessage", function($rootScope, pmcw, srp, ComposerRequestStatus, outsidersMap, CONSTANTS, gettextCatalog) {
var encryptFromPublicKeys = function() {
var _ref17 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(message, emails, publicKeys) {
var _ref18, sessionKey, dataPacket, _parseRecipients, promises, cleartext, packageSet;
return regeneratorRuntime.wrap(function(_context7) {
for (;;) switch (_context7.prev = _context7.next) {
case 0:
return _context7.next = 2, message.cleartextBodyPackets();
case 2:
return _ref18 = _context7.sent, sessionKey = _ref18.sessionKey, dataPacket = _ref18.dataPacket, _parseRecipients = parseRecipients(message, emails, {
sessionKey: sessionKey,
dataPacket: dataPacket,
publicKeys: publicKeys
}), promises = _parseRecipients.promises, cleartext = _parseRecipients.cleartext, packageSet = _parseRecipients.packageSet, outsidersMap.set(message.ID, cleartext), _context7.abrupt("return", {
cleartext: cleartext,
encrypt: function() {
return Promise.all(promises).then(function() {
return [packageSet]
})
}
});
case 8:
case "end":
return _context7.stop()
}
}, _callee7, this)
}));
return function(_x7, _x8, _x9) {
return _ref17.apply(this, arguments)
}
}(),
encryptFromEmails = function() {
var _ref19 = _asyncToGenerator(regeneratorRuntime.mark(function _callee8(message, emails) {
var uniqueEmails, _ref20, data;
return regeneratorRuntime.wrap(function(_context8) {
for (;;) switch (_context8.prev = _context8.next) {
case 0:
return _context8.prev = 0, uniqueEmails = _.uniq(emails), _context8.next = 4, message.getPublicKeys(uniqueEmails);
case 4:
if (_ref20 = _context8.sent, data = _ref20.data, data.Code === ComposerRequestStatus.SUCCESS) {
_context8.next = 8;
break
}
throw new Error(data.Error || ERROR_REQUEST_KEYS);
case 8:
return _context8.abrupt("return", encryptFromPublicKeys(message, uniqueEmails, data));
case 11:
throw _context8.prev = 11, _context8.t0 = _context8.catch(0), console.error("Cannot encrypt message", _context8.t0), message.encrypting = !1, dispatchMessageAction(message), _context8.t0;
case 17:
case "end":
return _context8.stop()
}
}, _callee8, this, [
[0, 11]
])
}));
return function(_x10, _x11) {
return _ref19.apply(this, arguments)
}
}(),
SEND_TYPES = CONSTANTS.SEND_TYPES,
ERROR_REQUEST_KEYS = gettextCatalog.getString("Cannot get public keys", null, "Encrypt message"),
dispatchMessageAction = function(message) {
return $rootScope.$emit("actionMessage", message)
},
cleartextUser = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", {
Type: SEND_TYPES.SEND_CLEAR,
Signature: 0
});
case 1:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function() {
return _ref.apply(this, arguments)
}
}(),
getCleartextBodyKeyPacket = function(_ref2) {
var data = _ref2.data;
return _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt("return", pmcw.encode_base64(pmcw.arrayToBinaryString(data)));
case 1:
case "end":
return _context2.stop()
}
}, _callee2, void 0)
}))
},
encryptBodyKeyPacket = function() {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(_ref5) {
var _ref6, message, _ref5$sessionKey = _ref5.sessionKey,
sessionKey = void 0 === _ref5$sessionKey ? {} : _ref5$sessionKey,
_ref5$publicKeys = _ref5.publicKeys,
publicKeys = void 0 === _ref5$publicKeys ? [] : _ref5$publicKeys,
_ref5$passwords = _ref5.passwords,
passwords = void 0 === _ref5$passwords ? [] : _ref5$passwords;
return regeneratorRuntime.wrap(function(_context3) {
for (;;) switch (_context3.prev = _context3.next) {
case 0:
return _context3.next = 2, pmcw.encryptSessionKey({
data: sessionKey.data,
algorithm: sessionKey.algorithm,
publicKeys: publicKeys.length > 0 ? pmcw.getKeys(publicKeys) : [],
passwords: passwords
});
case 2:
return _ref6 = _context3.sent, message = _ref6.message, _context3.abrupt("return", pmcw.encode_base64(pmcw.arrayToBinaryString(message.packets.write())));
case 5:
case "end":
return _context3.stop()
}
}, _callee3, void 0)
}));
return function(_x) {
return _ref4.apply(this, arguments)
}
}(),
insideUser = function() {
var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(message, publicKey, sessionKey) {
var _ref8, _ref9, BodyKeyPacket, AttachmentKeyPackets;
return regeneratorRuntime.wrap(function(_context4) {
for (;;) switch (_context4.prev = _context4.next) {
case 0:
return _context4.next = 2, Promise.all([encryptBodyKeyPacket({
sessionKey: sessionKey,
publicKeys: publicKey
}), message.encryptAttachmentKeyPackets(publicKey)]);
case 2:
return _ref8 = _context4.sent, _ref9 = _slicedToArray(_ref8, 2), BodyKeyPacket = _ref9[0], AttachmentKeyPackets = _ref9[1], _context4.abrupt("return", {
Type: CONSTANTS.SEND_TYPES.SEND_PM,
BodyKeyPacket: BodyKeyPacket,
AttachmentKeyPackets: AttachmentKeyPackets,
Signature: 0
});
case 7:
case "end":
return _context4.stop()
}
}, _callee4, void 0)
}));
return function(_x2, _x3, _x4) {
return _ref7.apply(this, arguments)
}
}(),
encryptedOutsideUser = function() {
var _ref10 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(message, sessionKey) {
var Token, _ref11, _ref12, EncToken, BodyKeyPacket, AttachmentKeyPackets, verifier;
return regeneratorRuntime.wrap(function(_context5) {
for (;;) switch (_context5.prev = _context5.next) {
case 0:
return _context5.prev = 0, Token = message.generateReplyToken(), _context5.next = 4, Promise.all([pmcw.encryptMessage({
data: Token,
publicKeys: [],
passwords: [message.Password]
}), encryptBodyKeyPacket({
passwords: message.Password,
sessionKey: sessionKey
}), message.encryptAttachmentKeyPackets([], [message.Password]), srp.randomVerifier(message.Password)]);
case 4:
return _ref11 = _context5.sent, _ref12 = _slicedToArray(_ref11, 4), EncToken = _ref12[0].data, BodyKeyPacket = _ref12[1], AttachmentKeyPackets = _ref12[2], verifier = _ref12[3], _context5.abrupt("return", {
Auth: verifier.Auth,
Type: SEND_TYPES.SEND_EO,
PasswordHint: message.PasswordHint,
Token: Token,
EncToken: EncToken,
BodyKeyPacket: BodyKeyPacket,
AttachmentKeyPackets: AttachmentKeyPackets,
Signature: 0
});
case 13:
throw _context5.prev = 13, _context5.t0 = _context5.catch(0), message.encrypting = !1, dispatchMessageAction(message), console.error(_context5.t0), _context5.t0;
case 19:
case "end":
return _context5.stop()
}
}, _callee5, void 0, [
[0, 13]
])
}));
return function(_x5, _x6) {
return _ref10.apply(this, arguments)
}
}(),
parseRecipients = function(message, emails, _ref13) {
var publicKeys = _ref13.publicKeys,
sessionKey = _ref13.sessionKey,
dataPacket = _ref13.dataPacket,
packageSet = {
Type: 0,
Addresses: {},
MIMEType: message.MIMEType || "text/html",
Body: pmcw.encode_base64(pmcw.arrayToBinaryString(dataPacket[0]))
},
cleartextBodyKeyPacket = getCleartextBodyKeyPacket(sessionKey),
bindPackageSet = function(promise, email) {
return promise.then(function(pkg) {
packageSet.Addresses[email] = pkg, packageSet.Type |= pkg.Type
})
},
_emails$reduce = emails.reduce(function(acc, email) {
return publicKeys[email] && publicKeys[email].length > 0 ? (acc.promises.push(bindPackageSet(insideUser(message, publicKeys[email], sessionKey), email)), acc) : 1 === message.IsEncrypted ? (acc.promises.push(bindPackageSet(encryptedOutsideUser(message, sessionKey), email)), acc) : (acc.cleartext = !0, acc.promises.push(bindPackageSet(cleartextUser(), email)), acc)
}, {
cleartext: !1,
promises: []
}),
promises = _emails$reduce.promises,
cleartext = _emails$reduce.cleartext;
if (cleartext) {
var cleartextBodyAttachments = function() {
var _ref14 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6() {
var _ref15, _ref16, bodyKey, attachmentKeys;
return regeneratorRuntime.wrap(function(_context6) {
for (;;) switch (_context6.prev = _context6.next) {
case 0:
return _context6.next = 2, Promise.all([cleartextBodyKeyPacket(), message.cleartextAttachmentKeyPackets()]);
case 2:
_ref15 = _context6.sent, _ref16 = _slicedToArray(_ref15, 2), bodyKey = _ref16[0], attachmentKeys = _ref16[1], packageSet.BodyKey = bodyKey, packageSet.AttachmentKeys = attachmentKeys;
case 8:
case "end":
return _context6.stop()
}
}, _callee6, void 0)
}));
return function() {
return _ref14.apply(this, arguments)
}
}();
promises.push(cleartextBodyAttachments())
}
return {
promises: promises,
cleartext: cleartext,
packageSet: packageSet
}
};
return encryptFromEmails
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.composer").factory("extractDataURI", function(attachmentModel, embedded) {
function dataURItoBlob() {
for (var dataURI = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", _dataURI$split = dataURI.split(","), _dataURI$split2 = _slicedToArray(_dataURI$split, 2), _dataURI$split2$ = _dataURI$split2[0], mime = void 0 === _dataURI$split2$ ? "" : _dataURI$split2$, _dataURI$split2$2 = _dataURI$split2[1], byte = void 0 === _dataURI$split2$2 ? "" : _dataURI$split2$2, byteString = atob(byte), mimeString = mime.split(":")[1].split(";")[0], ab = new ArrayBuffer(byteString.length), dw = new DataView(ab), i = 0; i < byteString.length; i++) dw.setUint8(i, byteString.charCodeAt(i));
return new Blob([ab], {
type: mimeString
})
}
return function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message) {
var content, testDiv, images, promises;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
if ("text/plain" !== message.MIMEType) {
_context.next = 2;
break
}
return _context.abrupt("return", message);
case 2:
return content = message.getDecryptedBody(), testDiv = document.createElement("DIV"), testDiv.innerHTML = content, images = testDiv.querySelectorAll("img"), promises = _.chain([].slice.call(images)).filter(function(_ref2) {
return /data:image/.test(_ref2.src)
}).filter(function(_ref3) {
return _ref3.src.includes(",")
}).map(function(image) {
var cid = embedded.generateCid(image.src, message.From.Email),
setEmbeddedImg = function() {
return image.setAttribute("data-embedded-img", cid), Promise.resolve()
};
if (embedded.exist(message, cid)) return setEmbeddedImg();
var file = dataURItoBlob(image.src);
return file.name = image.alt || "image" + Date.now(), file.inline = 1, attachmentModel.create(file, message, !0, cid).then(setEmbeddedImg)
}).value(), _context.next = 9, Promise.all(promises);
case 9:
return message.setDecryptedBody(testDiv.innerHTML), _context.abrupt("return", message);
case 11:
case "end":
return _context.stop()
}
}, _callee, this)
}));
return function(_x2) {
return _ref.apply(this, arguments)
}
}()
}), angular.module("proton.composer").factory("messageRequest", function($rootScope, messageApi, ComposerRequestStatus, CONSTANTS, gettextCatalog) {
function getSendError(data) {
return _.has(data, "data") ? getSendError(data.data) : data.ErrorDescription ? new Error(data.Error + ": " + data.ErrorDescription) : new Error(data.Error || I18N.ERROR_SENDING)
}
var draft = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(parameters, message, type) {
var _ref2, data;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.next = 2, getEditPromise(type, parameters);
case 2:
if (_ref2 = _context.sent, data = _ref2.data, data.Code !== ComposerRequestStatus.SUCCESS && data.Code !== ComposerRequestStatus.DRAFT_NOT_EXIST) {
_context.next = 6;
break
}
return _context.abrupt("return", data);
case 6:
if (data.Code !== ComposerRequestStatus.MESSAGE_ALREADY_SEND) {
_context.next = 8;
break
}
return _context.abrupt("return", dispatch("close.message", {
message: message
}));
case 8:
throw new Error(data.Error || I18N.ERROR_REQUEST_DRAFT);
case 9:
case "end":
return _context.stop()
}
}, _callee, this)
}));
return function(_x3, _x4, _x5) {
return _ref.apply(this, arguments)
}
}(),
send = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(parameters) {
var _ref4, _ref4$data, data, err;
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return _context2.prev = 0, _context2.next = 3, messageApi.send(parameters);
case 3:
return _ref4 = _context2.sent, _ref4$data = _ref4.data, data = void 0 === _ref4$data ? {} : _ref4$data, _context2.abrupt("return", data);
case 9:
throw _context2.prev = 9, _context2.t0 = _context2.catch(0), err = getSendError(_context2.t0), err.code = _context2.t0.Code, err;
case 14:
case "end":
return _context2.stop()
}
}, _callee2, this, [
[0, 9]
])
}));
return function(_x6) {
return _ref3.apply(this, arguments)
}
}(),
STATUS = CONSTANTS.STATUS,
I18N = {
ERROR_REQUEST_DRAFT: gettextCatalog.getString("Saving draft failed, please try again", null, "Error"),
ERROR_SENDING: gettextCatalog.getString("Cannot send message", null, "Error")
},
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("composer.update", {
type: type,
data: data
})
},
getEditPromise = function() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : STATUS.CREATE,
parameters = arguments[1];
return type === STATUS.UPDATE ? messageApi.updateDraft(parameters) : messageApi.createDraft(parameters)
};
return {
draft: draft,
send: send
}
}), angular.module("proton.composer").factory("onCurrentMessage", function($rootScope) {
var isCurrent = function(_ref) {
var _ref$message = _ref.message,
message = void 0 === _ref$message ? {} : _ref$message,
_ref2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref2$ID = _ref2.ID;
return (void 0 === _ref2$ID ? "editor" : _ref2$ID) === (message.ID || "editor")
},
onCurrentMessage = function(scope, cb) {
return function(e, _ref3) {
var type = _ref3.type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
isCurrent(scope, data.message) && cb(type, data)
}
};
return function(event, scope, cb) {
return $rootScope.$on(event, onCurrentMessage(scope, cb))
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.composer").factory("postMessage", function(CONSTANTS, $rootScope, messageRequest, ComposerRequestStatus, cache, notify, gettextCatalog, messageApi, composerRequestModel, embedded, outsidersMap, networkActivityTracker, $filter) {
function syncAttachmentsRemote(collection, list) {
var map = collection.reduce(function(acc, att) {
return acc[att.ID] = att, att.AttachmentID && (acc[att.AttachmentID] = att), acc
}, {});
return list.reduce(function(acc) {
var att = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return acc.push(_.extend({}, map[att.ID], att)), acc
}, [])
}
var STATUS = CONSTANTS.STATUS,
I18N = {
SAVE_MESSAGE_SUCCESS: gettextCatalog.getString("Message saved", null, "Record message")
},
unicodeTagView = $filter("unicodeTagView"),
dispatchMessageAction = function(message) {
return $rootScope.$emit("actionMessage", message)
},
makeParams = function(message, autosaving) {
var parameters = {
Message: _.pick(message, "ToList", "CCList", "BCCList", "Subject", "IsRead", "MIMEType")
};
return parameters.Message.Subject = parameters.Message.Subject || "", message.saving = !0, message.autosaving = autosaving, dispatchMessageAction(message), angular.isString(parameters.Message.ToList) && (parameters.Message.ToList = []), angular.isString(parameters.Message.CCList) && (parameters.Message.CCList = []), angular.isString(parameters.Message.BCCList) && (parameters.Message.BCCList = []), angular.isDefined(message.ParentID) && (parameters.ParentID = message.ParentID, parameters.Action = message.Action), angular.isDefined(message.ID) ? parameters.id = message.ID : parameters.Message.IsRead = 1, !1 === autosaving && (parameters.Message.IsRead = 1), parameters.Message.AddressID = message.AddressID, parameters
},
saveDraft = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message, _ref2) {
var data, Message, Code, conversation, contextNumUnread, numMessages, firstConversation, events, _ref3, _ref3$data, _data, actionType = _ref2.actionType,
parameters = _ref2.parameters,
notification = _ref2.notification;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.next = 2, messageRequest.draft(parameters, message, actionType);
case 2:
if (data = _context.sent, Message = data.Message, Code = data.Code, Code !== ComposerRequestStatus.SUCCESS) {
_context.next = 25;
break
}
return conversation = cache.getConversationCached(Message.ConversationID) || {}, contextNumUnread = conversation.ContextNumUnread || 0, numMessages = void 0, actionType === STATUS.CREATE ? (numMessages = (conversation.NumMessages || 0) + 1, message.ID = Message.ID) : actionType === STATUS.UPDATE && (numMessages = conversation.NumMessages || 0), message.IsRead = Message.IsRead, message.Time = Message.Time, message.Type = Message.Type, message.LabelIDs = Message.LabelIDs, Message.Attachments.length > 0 && (message.Attachments = syncAttachmentsRemote(message.Attachments, Message.Attachments)), Message.Senders = [Message.Sender], Message.Recipients = _.uniq(Message.ToList.concat(Message.CCList, Message.BCCList)), firstConversation = {
Recipients: Message.Recipients,
Senders: Message.Senders,
Subject: Message.Subject
}, events = [{
Action: actionType,
ID: Message.ID,
Message: Message
}], events.push({
Action: STATUS.UPDATE_FLAGS,
ID: Message.ConversationID,
Conversation: angular.extend({
NumAttachments: Message.Attachments.length,
NumMessages: numMessages,
ContextNumUnread: contextNumUnread,
ID: Message.ConversationID,
LabelIDsAdded: [CONSTANTS.MAILBOX_IDENTIFIERS.allDrafts, CONSTANTS.MAILBOX_IDENTIFIERS.drafts]
}, 1 === numMessages ? firstConversation : {})
}), cache.events(events), !0 === notification && notify({
message: I18N.SAVE_MESSAGE_SUCCESS,
classes: "notification-success"
}), message.saving = !1, message.autosaving = !1, dispatchMessageAction(message), _context.abrupt("return", Message);
case 25:
if (Code !== ComposerRequestStatus.DRAFT_NOT_EXIST) {
_context.next = 33;
break
}
return delete parameters.id, _context.next = 29, messageApi.createDraft(parameters);
case 29:
return _ref3 = _context.sent, _ref3$data = _ref3.data, _data = void 0 === _ref3$data ? {} : _ref3$data, _context.abrupt("return", _data.Message);
case 33:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x2, _x3) {
return _ref.apply(this, arguments)
}
}(),
save = function() {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(message, _ref5) {
var parameters, _ref6, _ref7, _ref7$, ID, body, encryptedBody, actionType, notification = _ref5.notification,
autosaving = _ref5.autosaving;
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return _context2.prev = 0, parameters = makeParams(message, autosaving), _context2.next = 4, composerRequestModel.chain(message);
case 4:
return _ref6 = _context2.sent, _ref7 = _slicedToArray(_ref6, 1), _ref7$ = _ref7[0], _ref7$ = void 0 === _ref7$ ? {} : _ref7$, ID = _ref7$.ID, ID && (message.ID = ID, parameters.id = ID), _context2.next = 12, embedded.parser(message, {
direction: "cid",
isOutside: outsidersMap.get(message.ID)
});
case 12:
return body = _context2.sent, message.setDecryptedBody(body, !message.isPlainText()), _context2.next = 16, message.encryptBody(message.From.Keys[0].PublicKey);
case 16:
return encryptedBody = _context2.sent, actionType = message.ID ? STATUS.UPDATE : STATUS.CREATE, parameters.Message.Body = encryptedBody, _context2.next = 21, saveDraft(message, {
actionType: actionType,
parameters: parameters,
notification: notification
});
case 21:
return _context2.abrupt("return", _context2.sent);
case 24:
throw _context2.prev = 24, _context2.t0 = _context2.catch(0), message.saving = !1, message.autosaving = !1, dispatchMessageAction(message), composerRequestModel.clear(message), _context2.t0;
case 31:
case "end":
return _context2.stop()
}
}, _callee2, void 0, [
[0, 24]
])
}));
return function(_x4, _x5) {
return _ref4.apply(this, arguments)
}
}();
return function() {
var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(message) {
var promise, _message, _ref9 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
_ref9$notification = _ref9.notification,
notification = void 0 !== _ref9$notification && _ref9$notification,
_ref9$autosaving = _ref9.autosaving,
autosaving = void 0 !== _ref9$autosaving && _ref9$autosaving,
_ref9$loader = _ref9.loader,
loader = void 0 === _ref9$loader || _ref9$loader;
return regeneratorRuntime.wrap(function(_context3) {
for (;;) switch (_context3.prev = _context3.next) {
case 0:
return _context3.prev = 0, promise = save(message, {
notification: notification,
autosaving: autosaving
}), (!1 === autosaving || loader) && networkActivityTracker.track(promise), composerRequestModel.save(message, promise), _context3.next = 6, promise;
case 6:
return _context3.abrupt("return", _context3.sent);
case 9:
if (_context3.prev = 9, _context3.t0 = _context3.catch(0), _message = unicodeTagView(_context3.t0.message), !autosaving) {
_context3.next = 14;
break
}
return _context3.abrupt("return", notify({
message: _message,
classes: "notification-danger"
}));
case 14:
throw new Error(_message);
case 15:
case "end":
return _context3.stop()
}
}, _callee3, void 0, [
[0, 9]
])
}));
return function(_x6) {
return _ref8.apply(this, arguments)
}
}()
}), angular.module("proton.composer").factory("sendMessage", function(CONSTANTS, messageModel, gettextCatalog, encryptMessage, messageRequest, notification, cache, $rootScope) {
var STATUS = CONSTANTS.STATUS,
I18N = {
SEND_SUCCESS: gettextCatalog.getString("Message sent", null, "Send message"),
EXPIRE_ERROR: gettextCatalog.getString("Expiring emails to non-ProtonMail recipients require a message password to be set. For more information, {{link}}click here", {
link: '<a href="https://protonmail.com/support/knowledge-base/expiration/" target="_blank">'
}, "Send message")
},
dispatchMessageAction = function(message) {
return $rootScope.$emit("actionMessage", message)
},
prepare = function(message, parameters) {
return message.encrypting = !0, dispatchMessageAction(message), parameters.id = message.ID, parameters.ExpirationTime = message.ExpirationTime, message.emailsToString()
},
send = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message, parameters) {
var emails, _ref2, encrypt, cleartext, error, packages;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return emails = prepare(message, parameters), _context.next = 3, encryptMessage(message, emails);
case 3:
if (_ref2 = _context.sent, encrypt = _ref2.encrypt, !(cleartext = _ref2.cleartext) || message.Password.length || !message.ExpirationTime) {
_context.next = 10;
break
}
throw error = new Error(I18N.EXPIRE_ERROR + "</a>."), error.raw = !0, error;
case 10:
return _context.next = 12, encrypt();
case 12:
return packages = _context.sent, parameters.Packages = packages, message.encrypting = !1, dispatchMessageAction(message), _context.abrupt("return", messageRequest.send(parameters));
case 17:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x, _x2) {
return _ref.apply(this, arguments)
}
}();
return function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(message) {
var _ref4, Parent, _ref4$Sent, Sent, conversation, NumMessages, ContextNumUnread, events, parameters = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return _context2.next = 2, send(message, parameters);
case 2:
_ref4 = _context2.sent, Parent = _ref4.Parent, _ref4$Sent = _ref4.Sent, Sent = void 0 === _ref4$Sent ? {} : _ref4$Sent, $rootScope.$emit("composer.update", {
type: "send.success",
data: {
message: message,
discard: !1,
save: !1
}
}), conversation = cache.getConversationCached(Sent.ConversationID), NumMessages = angular.isDefined(conversation) ? conversation.NumMessages : 1, ContextNumUnread = angular.isDefined(conversation) ? conversation.ContextNumUnread : 0, Sent.Senders = [Sent.Sender], Sent.Recipients = _.uniq(message.ToList.concat(message.CCList, message.BCCList)), events = [{
Action: STATUS.UPDATE_FLAGS,
ID: Sent.ID,
Message: Sent
}], Parent && events.push({
Action: STATUS.UPDATE_FLAGS,
ID: Parent.ID,
Message: Parent
}), events.push({
Action: STATUS.UPDATE_FLAGS,
ID: Sent.ConversationID,
Conversation: {
NumMessages: NumMessages,
ContextNumUnread: ContextNumUnread,
Recipients: Sent.Recipients,
Senders: Sent.Senders,
Subject: Sent.Subject,
ID: Sent.ConversationID,
LabelIDsAdded: [CONSTANTS.MAILBOX_IDENTIFIERS.allSent, CONSTANTS.MAILBOX_IDENTIFIERS.sent],
LabelIDsRemoved: [CONSTANTS.MAILBOX_IDENTIFIERS.allDrafts, CONSTANTS.MAILBOX_IDENTIFIERS.drafts]
}
}), notification.success(I18N.SEND_SUCCESS), cache.events(events, !1, !0), _.delay(function() {
$rootScope.$emit("message.open", {
type: "save.success",
data: {
message: messageModel(Sent)
}
})
}, 500);
case 18:
case "end":
return _context2.stop()
}
}, _callee2, void 0)
}));
return function(_x3) {
return _ref3.apply(this, arguments)
}
}()
}), angular.module("proton.composer").factory("validateMessage", function(gettextCatalog, tools, regexEmail, CONSTANTS, confirmModal, authentication, notification, addressWithoutKeys) {
function canWrite() {
return authentication.user.Delinquent >= UNPAID_STATE.DELINQUENT ? notification.error(I18N.ERROR_DELINQUENT) : !addressWithoutKeys.allDirty() || notification.error(I18N.ERROR_ADDRESSES + "<br>" + getErrorInfo())
}
var validate = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message) {
var emailStats;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
if ("text/plain" !== message.MIMEType && message.setDecryptedBody(tools.fixImages(message.getDecryptedBody())), !(message.uploading > 0)) {
_context.next = 3;
break
}
throw new Error(I18N.STILL_UPLOADING);
case 3:
if (cleanEmails(message), emailStats = message.ToList.concat(message.CCList, message.BCCList).reduce(function(acc, _ref2) {
var _ref2$Address = _ref2.Address,
Address = void 0 === _ref2$Address ? "" : _ref2$Address;
return acc.all.push(Address), !regexEmail.test(Address) && acc.invalid.push(Address), acc.total++, acc
}, {
all: [],
invalid: [],
total: 0
}), !emailStats.invalid.length) {
_context.next = 7;
break
}
throw new Error(I18N.invalidEmails(emailStats.invalid.join(",")));
case 7:
if (!(emailStats.total > 25)) {
_context.next = 9;
break
}
throw new Error(I18N.maxRecipients(emailStats.total));
case 9:
if (emailStats.total) {
_context.next = 11;
break
}
throw new Error(I18N.NO_RECIPIENT);
case 11:
if (!(message.Subject && message.Subject.length > MAX_TITLE_LENGTH)) {
_context.next = 13;
break
}
throw new Error(I18N.MAX_SUBJECT_LENGTH);
case 13:
if (!(message.getDecryptedBody().length > 16e6)) {
_context.next = 15;
break
}
throw new Error(I18N.MAX_BODY_LENGTH);
case 15:
case "end":
return _context.stop()
}
}, _callee, this)
}));
return function(_x) {
return _ref.apply(this, arguments)
}
}(),
checkSubject = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(_ref4) {
var Subject = _ref4.Subject;
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
if (!Subject) {
_context2.next = 2;
break
}
return _context2.abrupt("return");
case 2:
return _context2.abrupt("return", new Promise(function(resolve, reject) {
confirmModal.activate({
params: {
title: I18N.NO_SUBJECT_TITLE,
message: I18N.NO_SUBJECT_MESSAGE,
confirm: function() {
confirmModal.deactivate(), resolve()
},
cancel: function() {
confirmModal.deactivate(), reject()
}
}
})
}));
case 3:
case "end":
return _context2.stop()
}
}, _callee2, this)
}));
return function(_x2) {
return _ref3.apply(this, arguments)
}
}(),
MAX_TITLE_LENGTH = CONSTANTS.MAX_TITLE_LENGTH,
UNPAID_STATE = CONSTANTS.UNPAID_STATE,
I18N = {
STILL_UPLOADING: gettextCatalog.getString("Wait for attachment to finish uploading or cancel upload.", null, "Error"),
invalidEmails: function(total) {
return gettextCatalog.getString("Invalid email(s): " + total + ".", null, "Error")
},
MAX_BODY_LENGTH: gettextCatalog.getString("The maximum length of the message body is 16,000,000 characters.", null, "Error"),
NO_RECIPIENT: gettextCatalog.getString("Please enter at least one recipient.", null, "Error"),
MAX_SUBJECT_LENGTH: gettextCatalog.getString("The maximum length of the subject is " + MAX_TITLE_LENGTH + ".", null, "Error"),
maxRecipients: function(total) {
return gettextCatalog.getString("The maximum number (" + total + ") of Recipients is 25.", null, "Error")
},
NO_SUBJECT_TITLE: gettextCatalog.getString("No subject", null, "Title"),
NO_SUBJECT_MESSAGE: gettextCatalog.getString("No subject, send anyway?", null, "Info"),
ERROR_ADDRESSES_INFO_PRIVATE: gettextCatalog.getString("You can generate your keys here", null, "Error"),
ERROR_ADDRESSES: gettextCatalog.getString("No address with keys available to compose a message.", null, "Error"),
MEMBER: gettextCatalog.getString("Addresses / Users", null, "Title"),
ERROR_ADDRESSES_INFO: gettextCatalog.getString("Contact your organization’s administrator to resolve this.", null, "Error"),
ERROR_DELINQUENT: gettextCatalog.getString("Your account currently has an overdue invoice. Please pay all unpaid invoices.", null, "Info")
},
cleanEmails = function(message) {
message.ToList.concat(message.CCList, message.BCCList).forEach(function(item) {
item.Address = item.Address.trim()
})
},
getErrorInfo = function() {
return authentication.user.Private ? I18N.ERROR_ADDRESSES_INFO_PRIVATE + ' <a href="/members">' + I18N.MEMBER + "</a>" : I18N.ERROR_ADDRESSES_INFO
};
return {
checkSubject: checkSubject,
validate: validate,
canWrite: canWrite
}
}), angular.module("proton.config", []).constant("CONFIG", {
app_version: "3.12.13",
api_version: "2",
date_version: "Wed Dec 06 2017",
year: 2017,
clientID: "Web",
clientSecret: "4957cc9a2e0a2a49d02475c9d013478d",
articleLink: "https://protonmail.com/blog/protonmail-v3-12-release-notes/",
translations: ["de_DE", "en_US", "es_ES", "fr_FR", "it_IT", "nl_NL", "pl_PL", "pt_BR", "ru_RU", "tr_TR", "uk_UA"],
debug: !1,
apiUrl: "/api",
statsConfig: {
isEnabled: !0,
statsHost: "stats.protonmail.ch",
domains: ["*.protonmail.com", "*.mail.protonmail.com"],
cookieDomain: "*.protonmail.com",
siteId: 5,
abSiteId: 8
}
}), angular.module("proton.constants", []).constant("regexEmail", /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/i).constant("CONSTANTS", {
GIFT_CODE_LENGTH: 16,
BLACK_FRIDAY_INTERVAL: 6e5,
PLANS: {
PLAN: {
PLUS: "plus",
PROFESSIONAL: "professional",
VISIONARY: "visionary",
VPN_BASIC: "vpnbasic",
VPN_PLUS: "vpnplus"
},
ADDON: {
ADDRESS: "5address",
MEMBER: "1member",
DOMAIN: "1domain",
SPACE: "1gb",
VPN: "1vpn"
}
},
PLANS_TYPE: {
PLAN: 1,
ADDON: 0
},
CONTACTS_LIMIT_ENCRYPTION: 20,
CONTACTS_LIMIT_UPLOAD: 50,
VCARD_VERSION: "4.0",
VCARD_KEYS: ["email", "adr", "tel", "note", "kind", "source", "xml", "nickname", "photo", "bday", "anniversary", "gender", "impp", "lang", "tz", "geo", "title", "role", "logo", "org", "member", "related", "categories", "rev", "sound", "uid", "clientpidmap", "url", "key", "fburl", "caladruri", "caluri"],
VCARD_TYPES: ["work", "home", "text", "voice", "fax", "cell", "video", "pager", "textphone", "iana-token", "x-name", "contact", "acquaintance", "friend", "met", "co-worker", "colleague", "co-resident", "neighbor", "child", "parent", "sibling", "spouse", "kin", "muse", "crush", "date", "sweetheart", "me", "agent", "emergency"],
CONTACT_MODE: {
ENCRYPTED_AND_SIGNED: 3,
SIGNED: 2,
ENCRYPTED: 1,
CLEAR_TEXT: 0
},
CONTACT_ERROR: {
TYPE3_CONTACT_VERIFICATION: 3,
TYPE3_CONTACT_DECRYPTION: 2,
TYPE2_CONTACT: 1,
TYPE1_CONTACT: 0
},
CONTACT_EMAILS_LIMIT: 1e3,
CONTACTS_LIMIT: 1e3,
EXPORT_CONTACTS_LIMIT: 50,
MAX_VPN: 100,
MAX_MEMBER: 100,
AWESOMEPLETE_MAX_ITEMS: 20,
MAIN_KEY: "0",
TIMEOUT: 3e4,
BASE_SIZE: 1024,
PM_SIGNATURE: 'Sent with <a href="https://protonmail.com" target="_blank">ProtonMail</a> Secure Email.',
KEY_PHASE: 5,
KEY_VERSION: 3,
MAX_OUTSIDE_REPLY: 4,
MAILBOX_PASSWORD_KEY: "proton:mailbox_pwd",
OAUTH_KEY: "proton:oauth",
WHITELIST: ["[email protected]"],
INVITE_MAIL: 1,
INVITE_VPN: 2,
FREE_USER_ROLE: 0,
PAID_MEMBER_ROLE: 1,
PAID_ADMIN_ROLE: 2,
UNPAID_STATE: {
NOT: 0,
AVAILABLE: 1,
OVERDUE: 2,
DELINQUENT: 3,
NO_RECEIVE: 4
},
INBOX: 0,
DRAFT: 1,
SENT: 2,
INBOX_AND_SENT: 3,
PM_ADDRESS: 1,
PM_ALIAS: 2,
CUSTOM_DOMAIN_ADDRESS: 3,
REPLY: 0,
REPLY_ALL: 1,
FORWARD: 2,
FILTER_VERSION: 1,
ROW_MODE: 1,
COLUMN_MODE: 0,
ATTACHMENT_SIZE_LIMIT: 25,
ATTACHMENT_NUMBER_LIMIT: 100,
MAX_TITLE_LENGTH: 255,
MAX_NUMBER_COMPOSER: 3,
MESSAGE_VIEW_MODE: 1,
CONVERSATION_VIEW_MODE: 0,
MESSAGE_LIMIT: 100,
CONVERSATION_LIMIT: 100,
ENCRYPTED_STATUS: {
NONE: 0,
INTERNAL: 1,
EXTERNAL: 2,
OUT_ENC: 3,
OUT_PLAIN: 4,
STORED_ENC: 5,
AUTOREPLY: 10
},
INTERVAL_EVENT_TIMER: 3e4,
TIMEOUT_PRELOAD_MESSAGE: 500,
UPLOAD_GRADIENT_DARK: "147, 145, 209",
UPLOAD_GRADIENT_LIGHT: "255, 255, 255",
ENC_OUT_ENC_REPLY: 6,
SAVE_TIMEOUT_TIME: 3e3,
SAVE_THROTTLE_TIME: 1e4,
MAX_EXPIRATION_TIME: 672,
ELEMENTS_PER_PAGE: 50,
CONTACTS_PER_PAGE: 1e3,
HD_BREAKPOINT: 1920,
DESKTOP_BREAKPOINT: 1200,
ROW_BREAKPOINT: 960,
MOBILE_BREAKPOINT: 800,
WIZARD_ENABLED: !0,
MAILBOX_IDENTIFIERS: {
inbox: "0",
allDrafts: "1",
allSent: "2",
trash: "3",
spam: "4",
allmail: "5",
starred: "10",
archive: "6",
sent: "7",
drafts: "8",
search: "search",
label: "label"
},
EMAIL_FORMATING: {
OPEN_TAG_AUTOCOMPLETE: "‹",
CLOSE_TAG_AUTOCOMPLETE: "›",
OPEN_TAG_AUTOCOMPLETE_RAW: "<",
CLOSE_TAG_AUTOCOMPLETE_RAW: ">"
},
STATUS: {
DELETE: 0,
CREATE: 1,
UPDATE: 2,
UPDATE_DRAFT: 2,
UPDATE_FLAGS: 3
},
DEFAULT_SQUIRE_VALUE: {
LINK: "",
IMAGE: "",
HEADER_CLASS: "h4",
IFRAMECLASSNAME: "angular-squire-iframe"
},
URL_INFO: "https://mail.protonmail.com/assets/host.png",
MIN_PAYPAL_AMOUNT: 500,
MAX_PAYPAL_AMOUNT: 99999900,
MIN_BITCOIN_AMOUNT: 500,
BTC_DONATION_ADDRESS: "1Q1nhq1NbxPYAbw1BppwKbCqg58ZqMb9A8",
CURRENCIES: ["USD", "EUR", "CHF"],
BILLING_CYCLE: [1, 12, 24],
CYCLE: {
MONTHLY: 1,
YEARLY: 12,
TWO_YEARS: 24
},
IFRAME_SECURE_ORIGIN: "https://secure.protonmail.com",
INVITE_URL: "https://protonmail.com/invite",
DEFAULT_CURRENCY: "EUR",
DEFAULT_CYCLE: 12,
TRACKER_ROUTE: "proton.php",
PIWIK_SCRIPT: "proton.js",
METRIC_GOALS: {
SIGNUP_ALL: 2,
SIGNUP_FREE: 4,
SIGNUP_PAID: 3,
SIGNUP_PLUS: 6,
SIGNUP_VISIONARY: 5
},
SEND_TYPES: {
SEND_PM: 1,
SEND_EO: 2,
SEND_CLEAR: 4,
SEND_PGP_INLINE: 8,
SEND_PGP_MIME: 16,
SEND_MIME: 32
},
AUTOCOMPLETE_DOMAINS: ["protonmail.com", "protonmail.ch", "gmail.com", "hotmail.com", "live.com", "yahoo.com", "outlook.com"],
FONT_SIZE: {
small: 8,
normal: 14,
large: 20,
huge: 26
},
COMPOSER_COLOR: {
COLOR: "#222222",
BACKGROUND: "#FFFFFF"
},
FONT_COLOR: {
white: ["#FFFFFF", "#DADADA", "#B5B5B5", "#909090", "#6B6B6B", "#464646", "#222222"],
magenta: ["#F6CBCB", "#EC9798", "#E36667", "#ED4139", "#CF3932", "#9A2B25", "#681D19"],
blue: ["#CDE1F2", "#9CC3E5", "#6CA6D9", "#3B83C2", "#2A47F6", "#145390", "#0F3A62"],
green: ["#D7EAD3", "#B3D6A9", "#8FC380", "#77F241", "#66A657", "#3A762B", "#29501F"],
yellow: ["#FFF2CD", "#FEE59C", "#FCD86F", "#FDF84E", "#F2C246", "#BE8F35", "#7F6124"]
},
CANCEL_REQUEST: "CANCEL_REQUEST",
ENCRYPTION_DEFAULT: 2048
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.contact").directive("contactAddressInput", function() {
var FIELD = "contactAddressInput-field",
FOCUSSED = "contactAddressInput-focussed",
DELAY = 200;
return {
restrict: "E",
replace: !0,
scope: {
value: "=",
form: "=",
focused: "="
},
templateUrl: "templates/contact/contactAddressInput.tpl.html",
link: function(scope, element) {
function onFocus() {
element.addClass(FOCUSSED), setTimeout(function() {
return element.find(".contactAddressInput-street").focus()
}, DELAY), scope.$applyAsync(function() {
return scope.focused = !0
})
}
function onBlur() {
setTimeout(function() {
element.find("." + FIELD + ":focus").length || (element.removeClass(FOCUSSED), scope.$applyAsync(function() {
return scope.focused = !1
}))
}, DELAY)
}
function onChange() {
scope.$applyAsync(function() {
var _scope$model = scope.model,
postBox = _scope$model.postBox,
extended = _scope$model.extended,
street = _scope$model.street,
locality = _scope$model.locality,
region = _scope$model.region,
postalCode = _scope$model.postalCode,
country = _scope$model.country;
scope.value = [postBox, extended, street, locality, region, postalCode, country], scope.model.default = formatDefaultValue()
})
}
var defaultInput = element.find(".contactAddressInput-default"),
defaultValue = Array.isArray(scope.value) && scope.value.length > 1 ? scope.value : ["", "", scope.value],
_defaultValue = _slicedToArray(defaultValue, 7),
_defaultValue$ = _defaultValue[0],
postBoxValue = void 0 === _defaultValue$ ? "" : _defaultValue$,
_defaultValue$2 = _defaultValue[1],
extendedValue = void 0 === _defaultValue$2 ? "" : _defaultValue$2,
_defaultValue$3 = _defaultValue[2],
streetValue = void 0 === _defaultValue$3 ? "" : _defaultValue$3,
_defaultValue$4 = _defaultValue[3],
localityValue = void 0 === _defaultValue$4 ? "" : _defaultValue$4,
_defaultValue$5 = _defaultValue[4],
regionValue = void 0 === _defaultValue$5 ? "" : _defaultValue$5,
_defaultValue$6 = _defaultValue[5],
postalCodeValue = void 0 === _defaultValue$6 ? "" : _defaultValue$6,
_defaultValue$7 = _defaultValue[6],
countryValue = void 0 === _defaultValue$7 ? "" : _defaultValue$7,
fields = element.find("." + FIELD),
formatDefaultValue = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : scope.value).filter(function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").trim()
}).join("\n")
};
scope.model = {
default: formatDefaultValue(defaultValue),
postBox: postBoxValue,
extended: extendedValue,
street: streetValue,
locality: localityValue,
region: regionValue,
postalCode: postalCodeValue,
country: countryValue
}, postBoxValue.length && element.addClass("contactAddressInput-show-post-box"), extendedValue.length && element.addClass("contactAddressInput-show-extended"), defaultInput.on("focus", onFocus), fields.on("change", onChange), fields.on("blur", onBlur), scope.$on("$destroy", function() {
defaultInput.off("focus", onFocus), fields.off("change", onChange), fields.off("blur", onBlur)
})
}
}
}), angular.module("proton.contact").directive("contactClear", function() {
return {
replace: !0,
templateUrl: "templates/contact/contactClear.tpl.html"
}
}), angular.module("proton.contact").directive("contactDetails", function($state, CONSTANTS, contactDetailsModel, contactBeforeToLeaveModal, gettextCatalog, notification, subscriptionModel, memberModel, dispatchers, vcard) {
var MAP_FIELDS = {
Name: "FN",
Emails: "EMAIL",
Tels: "TEL",
Adrs: "ADR",
Notes: "NOTE"
},
MAP_EVENT = {
deleteContact: function(_ref) {
return {
type: "deleteContacts",
data: {
contactIDs: [_ref.ID]
}
}
},
downloadContact: function(_ref2) {
return {
type: "exportContacts",
data: {
contactID: _ref2.ID
}
}
}
},
I18N = {
invalidForm: gettextCatalog.getString("This form is invalid", null, "Error displays when the user try to leave an unsaved and invalid contact details")
},
getFieldKey = function() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return MAP_FIELDS[type] || type.toUpperCase()
};
return {
restrict: "E",
replace: !0,
scope: {
contact: "=",
modal: "="
},
templateUrl: "templates/contact/contactDetails.tpl.html",
link: function(scope, element) {
function saveBeforeToLeave(toState, toParams) {
contactBeforeToLeaveModal.activate({
params: {
save: function() {
contactBeforeToLeaveModal.deactivate(), saveContact() && $state.go(toState.name, toParams)
},
discard: function() {
contactBeforeToLeaveModal.deactivate(), scope.contactForm.$setPristine(!0), $state.go(toState.name, toParams)
},
cancel: function() {
contactBeforeToLeaveModal.deactivate()
}
}
})
}
function onClick(_ref5) {
var target = _ref5.target,
action = target.getAttribute("data-action");
action && ("back" === action && $state.go("secured.contacts"), dispatch(action, scope.contact))
}
function isValidForm() {
return !scope.contactForm.$invalid && _.chain(scope.model).values().reduce(function(acc) {
var child = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [];
return acc.concat(child.filter(function(_ref6) {
var _ref6$value = _ref6.value;
return void 0 === _ref6$value ? "" : _ref6$value
}))
}, []).value().length
}
function saveContact() {
if (!isValidForm()) return notification.error(I18N.invalidForm), !1;
var contact = contactDetailsModel.prepare(scope);
return scope.contact.ID ? (contact.ID = scope.contact.ID, dispatch("updateContact", {
contact: contact
})) : dispatch("createContact", {
contacts: [contact]
}), scope.contactForm.$setSubmitted(!0), scope.contactForm.$setPristine(!0), !0
}
var _dispatchers = dispatchers(["contacts", "$stateChangeStart"]),
on = _dispatchers.on,
unsubscribe = _dispatchers.unsubscribe,
dispatcher = _dispatchers.dispatcher,
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
opt = (MAP_EVENT[type] || _.noop)(data) || {
type: type,
data: data
};
dispatcher.contacts(opt.type, opt.data)
},
updateType = function() {
var types = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.contains(types, CONSTANTS.CONTACT_MODE.ENCRYPTED_AND_SIGNED) && element.addClass("contactDetails-encrypted-and-signed")
},
onSubmit = function() {
return saveContact()
},
isFree = !subscriptionModel.hasPaid("mail") && !memberModel.isMember(),
properties = vcard.extractProperties(scope.contact.vCard),
hasEmail = _.filter(properties, function(property) {
return "email" === property.getField()
}).length;
scope.model = {}, scope.state = {
encrypting: !1,
ID: scope.contact.ID,
hasEmail: hasEmail,
isFree: isFree
}, on("contacts", function(event, _ref3) {
var _ref3$type = _ref3.type,
type = void 0 === _ref3$type ? "" : _ref3$type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
scope.modal && "submitContactForm" === type && onSubmit(), "contactUpdated" === type && data.contact.ID === scope.contact.ID && updateType(data.cards.map(function(_ref4) {
return _ref4.Type
}))
}), on("$stateChangeStart", function(event, toState, toParams) {
!scope.modal && scope.contactForm.$dirty && (event.preventDefault(), saveBeforeToLeave(toState, toParams))
}), updateType(scope.contact.types), scope.contact.errors && (-1 !== scope.contact.errors.indexOf(3) && element.addClass("contactDetails-encrypted-verification-error"), -1 !== scope.contact.errors.indexOf(2) && element.addClass("contactDetails-encrypted-error"), -1 !== scope.contact.errors.indexOf(1) && element.addClass("contactDetails-verification-error")), element.on("click", onClick), element.on("submit", onSubmit), scope.get = function(type) {
if (type) return contactDetailsModel.extract({
vcard: scope.contact.vCard,
field: getFieldKey(type)
})
}, scope.$on("$destroy", function() {
element.off("click", onClick), element.off("submit", onSubmit), unsubscribe()
})
}
}
}), angular.module("proton.contact").directive("contactEncrypted", function(gettextCatalog) {
var SHOW_CLASS = "contactDetails-show-custom-fields",
I18N = {
SHOW: gettextCatalog.getString("Show custom fields", null, "Action in contact details"),
HIDE: gettextCatalog.getString("Hide custom fields", null, "Action in contact details")
};
return {
restrict: "E",
replace: !0,
templateUrl: "templates/contact/contactEncrypted.tpl.html",
link: function(scope, el) {
var button = el.find(".contactDetails-toggle-custom-fields"),
updateText = function() {
var key = el[0].classList.contains(SHOW_CLASS) ? "HIDE" : "SHOW";
button[0].textContent = I18N[key]
},
onClick = function() {
return el[0].classList.toggle(SHOW_CLASS), updateText()
};
button.on("click", onClick), updateText(), scope.$on("$destroy", function() {
button.off("click", onClick)
})
}
}
}), angular.module("proton.contact").directive("contactError", function() {
return {
replace: !0,
templateUrl: "templates/contact/contactError.tpl.html"
}
}), angular.module("proton.contact").directive("contactItem", function($rootScope, contactTransformLabel, contactUI, messageModel) {
var AS_SORTABLE_DISABLED = "as-sortable-disabled",
addX = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return value.startsWith("x") ? value : "X-" + value
};
return {
restrict: "E",
require: "^form",
templateUrl: "templates/directives/contact/contactItem.tpl.html",
scope: {
form: "=",
model: "=",
state: "=",
getDatas: "&datas",
type: "@type"
},
link: function(scope, element, attr, ngFormController) {
function onClick(e) {
e.stopPropagation();
var action = e.target.getAttribute("data-action"),
index = parseInt(e.target.getAttribute("data-index"), 10);
switch (action) {
case "add":
add();
break;
case "composeTo":
composeTo(e.target.getAttribute("data-email"));
break;
case "remove":
remove(scope.UI.items[index]);
break;
case "toggleSortable":
scope.$applyAsync(function() {
scope.UI.sortableState = !scope.UI.sortableState, list.toggleClass(AS_SORTABLE_DISABLED)
})
}
}
function add() {
var populated = contactUI.populate(scope.UI, type);
ngFormController.$setDirty(), scope.$applyAsync(function() {
contactUI.add(scope.UI, populated.key, populated.type, ""), setTimeout(function() {
return element.find(".contactItem-field").focus()
}, 100)
})
}
function remove(item) {
$(".tooltip").not(this).hide(), contactUI.remove(scope.UI, item), ngFormController.$setDirty(), scope.change()
}
function composeTo(Address) {
var message = messageModel();
message.ToList = [{
Address: Address,
Name: Address
}], $rootScope.$emit("composer.new", {
data: {
message: message
},
type: "new"
})
}
var datas = scope.getDatas(),
type = scope.type,
state = scope.state,
list = element.find(".contactItem-container");
scope.config = {
isFocusedAddress: !1
}, list.addClass("contactItem-container-" + scope.type), list.addClass(AS_SORTABLE_DISABLED), scope.itemContactDragControlListeners = {
containment: ".contactDetails-container",
containerPositioning: "relative",
accept: function(sourceItemHandleScope, destSortableScope) {
return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id
},
dragStart: function() {
scope.itemMoved = !0
},
dragEnd: function() {
scope.itemMoved = !1
},
orderChanged: function() {
ngFormController.$setDirty()
}
}, scope.UI = contactUI.initialize(datas, type, state), scope.getAddressValue = function(item) {
var itemValue = item.value;
return angular.isArray(itemValue) ? itemValue.join(" ") : angular.isString(itemValue) ? itemValue : ""
}, scope.change = function() {
return scope.$applyAsync(function() {
return scope.model[type] = scope.UI.items
})
}, scope.visibleItems = function() {
return scope.UI.items.filter(function(_ref) {
return !_ref.hide
})
}, scope.onFocus = function(item) {
return item.displaySelector = !0
}, scope.onBlur = function(item) {
return item.displaySelector = !1
}, scope.toggleSelector = function(event, item) {
item.displaySelector = !item.displaySelector, event.preventDefault(), event.stopPropagation()
}, scope.setLabel = function() {
var item = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
value = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
item.label = value || item.label, "Customs" === type && (item.type = addX(item.label)), "Personals" === type && (item.type = contactTransformLabel.toVCard(item.label)), ngFormController.$setDirty(), scope.change()
}, scope.change(), element.on("click", onClick), scope.$on("$destroy", function() {
element.off("click", onClick)
})
}
}
}), angular.module("proton.contact").directive("contactList", function($filter, dispatchers, $state, $stateParams, contactCache) {
var ITEM_CLASS = "contactList-item",
ACTIVE_CLASS = "contactList-item-activeContact";
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/contact/contactList.tpl.html",
link: function(scope, element) {
function updateContacts() {
var filteredContacts = contactCache.paginate(contactCache.get("filtered"));
scope.$applyAsync(function() {
scope.contacts = filteredContacts, _.defer(function() {
activeContact(isLoadedContact), isLoadedContact = !1
}, 1e3)
})
}
function activeContact() {
var scroll = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
if (element.find("." + ITEM_CLASS).removeClass(ACTIVE_CLASS), $stateParams.id) {
var $row = element.find("." + ITEM_CLASS + '[data-contact-id="' + unescape($stateParams.id) + '"]');
$row.addClass(ACTIVE_CLASS), scroll && $row[0] && element.animate({
scrollTop: $row.offset().top - 120
}, 1e3)
}
}
function onClick(e) {
var target = e.target,
shiftKey = e.shiftKey;
/customCheckbox/.test(target.className) && (e.stopPropagation(), setContactSelection(target.dataset.contactId, target.checked, shiftKey));
var action = target.getAttribute("data-action");
if ("showContact" === action && $state.go("secured.contacts.details", {
id: target.dataset.contactId
}), "toggleSort" === action) {
var sort = target.getAttribute("data-sort"),
prefix = ($stateParams.sort || "").startsWith("-") ? "" : "-";
$state.go("secured.contacts", {
sort: "" + prefix + sort
})
}
}
var _dispatchers = dispatchers(["contacts", "$stateChangeSuccess"]),
dispatcher = _dispatchers.dispatcher,
on = _dispatchers.on,
unsubscribe = _dispatchers.unsubscribe,
lastChecked = null,
isLoadedContact = !!$stateParams.id;
scope.contacts = [], scope.showContact = function(contactID) {
return $state.go("secured.contacts.details", {
id: contactID
})
};
var selectContact = function(contact, isChecked, shiftKey) {
var contactIDs = [contact.ID];
if (lastChecked) {
if (shiftKey) {
var start = scope.contacts.indexOf(contact),
end = _.findIndex(scope.contacts, {
ID: lastChecked.ID
}),
col = scope.contacts.slice(Math.min(start, end), Math.max(start, end) + 1);
contactIDs.push.apply(contactIDs, _toConsumableArray(_.pluck(col, "ID")))
}
lastChecked = contact
} else lastChecked = contact;
dispatcher.contacts("selectContacts", {
contactIDs: contactIDs,
isChecked: isChecked
})
},
setContactSelection = function(ID, checked, shiftKey) {
return scope.$applyAsync(function() {
var contact = _.findWhere(scope.contacts, {
ID: ID
});
selectContact(contact, checked, shiftKey)
})
};
on("contacts", function(event, _ref) {
var _ref$type = _ref.type;
"contactsUpdated" === (void 0 === _ref$type ? "" : _ref$type) && scope.$applyAsync(function() {
return updateContacts()
})
}), on("$stateChangeSuccess", function() {
scope.$applyAsync(function() {
return activeContact()
})
}), element.on("click", onClick), contactCache.hydrate(), scope.$on("$destroy", function() {
element.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.contact").directive("contactNoResult", function($rootScope) {
function onClick(event) {
var action = event.target.getAttribute("data-action");
MAP[action] && $rootScope.$emit("contacts", {
type: MAP[action]
})
}
var MAP = {
add: "addContact",
import: "importContacts"
};
return {
replace: !0,
templateUrl: "templates/contact/contactNoResult.tpl.html",
link: function(scope, element) {
element.on("click", onClick), scope.$on("$destroy", function() {
element.off("click", onClick)
})
}
}
}), angular.module("proton.contact").directive("contactPlaceholder", function() {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/contact/contactPlaceholder.tpl.html"
}
}), angular.module("proton.contact").directive("contactToolbar", function($rootScope, $state, $stateParams, CONSTANTS, contactCache, gettextCatalog, messageModel, notification, dispatchers) {
function composeSelectedContacts(dispatcher) {
var list = getList().filter(function(_ref) {
var _ref$Emails = _ref.Emails;
return (void 0 === _ref$Emails ? [] : _ref$Emails).length
}).map(function(_ref2) {
var Emails = _ref2.Emails,
Name = _ref2.Name;
return {
Address: Emails[0].Email,
Name: Name
}
});
if (list.length) {
var message = messageModel();
return message.ToList = list, dispatcher["composer.new"]("new", {
message: message
})
}
notification.error(gettextCatalog.getString("Contact does not contain email address", null, "Error"))
}
var getList = function() {
return contactCache.get("selected").length ? contactCache.get("selected") : [contactCache.getItem($stateParams.id)].filter(Boolean)
};
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/contact/contactToolbar.tpl.html",
link: function(scope, element) {
function update() {
var paginatedContacts = contactCache.paginate(contactCache.get("filtered")),
selectedContacts = contactCache.get("selected"),
checkedContacts = _.where(paginatedContacts, {
selected: !0
});
scope.$applyAsync(function() {
scope.totalItems = contactCache.total(), scope.disabled = !paginatedContacts.length, scope.noSelection = !($stateParams.id || selectedContacts.length), scope.checkAll = paginatedContacts.length === checkedContacts.length
})
}
function onClick(_ref3) {
var target = _ref3.target,
type = target.getAttribute("data-action");
return "composeSelectedContacts" === type && composeSelectedContacts(dispatcher), "deleteSelectedContacts" === type ? dispatcher.contacts("deleteContacts", {
contactIDs: _.pluck(getList(), "ID")
}) : "addContact" === type || /^(merge|export|import)Contacts$/.test(type) ? dispatcher.contacts(type) : void 0
}
var _dispatchers = dispatchers(["composer.new", "contacts", "$stateChangeSuccess"]),
on = _dispatchers.on,
unsubscribe = _dispatchers.unsubscribe,
dispatcher = _dispatchers.dispatcher;
scope.numPerPage = CONSTANTS.CONTACTS_PER_PAGE, scope.selectPage = function(page) {
return $state.go($state.$current.name, {
page: page
})
}, scope.currentPage = +($stateParams.page || 1), scope.selectAll = function(event) {
var contactIDs = _.pluck(contactCache.paginate(contactCache.get("filtered")), "ID");
dispatcher.contacts("selectContacts", {
contactIDs: contactIDs,
isChecked: !!event.target.checked
})
}, on("contacts", function(e, _ref4) {
var type = _ref4.type;
("contactsUpdated" === type || "selectContacts" === type) && update()
}), on("$stateChangeSuccess", function(e, state) {
"secured.contacts.details" === state.name && scope.noSelection && update()
}), element.on("click", onClick), update(), scope.$on("$destroy", function() {
element.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.contact").directive("contactView", function($rootScope, $stateParams, contactCache) {
var CONTACTS_EMPTY = "contacts-empty",
CONTACTS_NO_RESULT = "contacts-no-result";
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/views/contacts.tpl.html",
link: function(scope, element) {
function update() {
var contacts = contactCache.paginate(contactCache.get("filtered"));
element[0].classList.remove(CONTACTS_EMPTY, CONTACTS_NO_RESULT), !contacts.length && !$stateParams.keyword && element[0].classList.add(CONTACTS_EMPTY), !contacts.length && $stateParams.keyword && element[0].classList.add(CONTACTS_NO_RESULT)
}
var unsubscribe = $rootScope.$on("contacts", function(event, _ref) {
var _ref$type = _ref.type;
"contactsUpdated" === (void 0 === _ref$type ? "" : _ref$type) && scope.$applyAsync(function() {
return update()
})
});
update(), scope.$on("$destroy", function() {
unsubscribe()
})
}
}
}), angular.module("proton.contact").factory("contactCache", function($filter, $rootScope, $state, $stateParams, networkActivityTracker, CONSTANTS, Contact, contactDownloader, contactEmails, contactImporter) {
function selected() {
var selected = _.chain(get()).filter(function(_ref2) {
return _ref2.selected
}).pluck("ID").value();
return !selected.length && $stateParams.id ? [$stateParams.id] : selected
}
function filter() {
var keyword = $stateParams.keyword || "";
return keyword ? _.pluck(orderBy(search(keyword, get())), "ID") : _.pluck(orderBy(get()), "ID")
}
function get() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "all";
return "all" === key ? angular.copy(CACHE.contacts) : _.map(CACHE.map[key], function(contactID) {
return CACHE.map.all[contactID]
})
}
function hydrate(force) {
if (isHydrated() && !force) return emit(), Promise.resolve();
var promise = Contact.all().then(function() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return CACHE.hydrated = !0, CACHE.contacts = contacts, sync(), get()
}).then(function() {
return emit()
});
return networkActivityTracker.track(promise), promise
}
function load() {
var promise = Contact.load().then(function(_ref3) {
var _ref3$Contacts = _ref3.Contacts,
Contacts = void 0 === _ref3$Contacts ? [] : _ref3$Contacts;
return CACHE.contacts = Contacts, sync(), get()
}).then(function() {
return emit()
});
return networkActivityTracker.track(promise), promise
}
function find(id) {
var promise = Contact.get(id);
return networkActivityTracker.track(promise), promise
}
function sync() {
var emails = contactEmails.fetch();
CACHE.contacts = _.map(get(), function(contact) {
return contact.Emails = _.where(emails, {
ContactID: contact.ID
}), contact.emails = contact.Emails.map(function(_ref4) {
var _ref4$Email = _ref4.Email;
return void 0 === _ref4$Email ? "" : _ref4$Email
}).join(", "), contact
}), CACHE.map = {
all: _.reduce(get(), function(acc, contact) {
return acc[contact.ID] = contact, acc
}, {}),
selected: selected(),
filtered: filter()
}
}
function clear() {
CACHE.contacts.length = 0, CACHE.hydrated = !1
}
function create(contact) {
CACHE.contacts.push(contact), CACHE.map.all[contact.ID] = contact
}
function update(contact, index) {
CACHE.contacts[index] = contact, CACHE.map.all[contact.ID] = contact
}
function deleteContactEmail(EmailID) {
var contact = _.find(get(), function(contact) {
return _.some(contact.Emails, {
ID: EmailID
})
});
contact && updateContact({
ID: contact.ID,
contact: contact
})
}
function updateContact(_ref5) {
var ID = _ref5.ID,
contact = _ref5.contact,
index = findIndex(ID); - 1 !== index ? update(contact, index) : create(contact), emit()
}
function refreshContactEmails(_ref6) {
var ID = _ref6.ID,
index = findIndex(ID);
if (-1 !== index) {
updateContact({
ID: ID,
contact: CACHE.contacts[index]
})
}
}
function paginate() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
currentPage = $stateParams.page || 1,
begin = (currentPage - 1) * CONTACTS_PER_PAGE,
end = begin + CONTACTS_PER_PAGE;
return contacts.slice(begin, end)
}
function deletedContactEmail(_ref7) {
var ID = _ref7.ID;
CACHE.contacts.length > 0 && deleteContactEmail(ID)
}
function resetContacts() {
clear(), hydrate()
}
function search() {
var keyword = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
contacts = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
value = lowerCase(keyword);
return _.filter(contacts, function(_ref8) {
var _ref8$Name = _ref8.Name,
Name = void 0 === _ref8$Name ? "" : _ref8$Name,
_ref8$Emails = _ref8.Emails,
Emails = void 0 === _ref8$Emails ? [] : _ref8$Emails;
return lowerCase(Name).indexOf(value) > -1 || filterEmails(Emails, value).length
})
}
function searchingContact() {
CACHE.map.filtered = filter(), emit()
}
function selectContacts(_ref9) {
var _ref9$contactIDs = _ref9.contactIDs,
contactIDs = void 0 === _ref9$contactIDs ? [] : _ref9$contactIDs,
isChecked = _ref9.isChecked;
CACHE.contacts = _.map(get(), function(contact) {
return contactIDs.indexOf(contact.ID) > -1 && (contact.selected = isChecked), contact
}), sync(), emit()
}
function contactEvents(_ref10) {
var _ref10$events = _ref10.events,
events = void 0 === _ref10$events ? [] : _ref10$events,
todo = events.reduce(function(acc, _ref11) {
var ID = _ref11.ID,
_ref11$Contact = _ref11.Contact,
Contact = void 0 === _ref11$Contact ? {} : _ref11$Contact,
Action = _ref11.Action,
action = ACTIONS[Action];
return "create" === action ? (acc[action].push(Contact), acc) : (acc[action][ID] = Contact, acc)
}, {
update: {},
create: [],
remove: {}
});
CACHE.contacts = _.chain(get()).map(function(contact) {
return todo.update[contact.ID] || contact
}).filter(function(_ref12) {
var ID = _ref12.ID;
return !todo.remove[ID]
}).value().concat(todo.create), sync(), emit()
}
var _ACTIONS, CACHE = {
hydrated: !1,
contacts: [],
map: {
all: {},
selected: [],
filtered: []
}
},
CONTACTS_PER_PAGE = CONSTANTS.CONTACTS_PER_PAGE,
ACTIONS = (_ACTIONS = {}, _defineProperty(_ACTIONS, CONSTANTS.STATUS.DELETE, "remove"), _defineProperty(_ACTIONS, CONSTANTS.STATUS.CREATE, "create"), _defineProperty(_ACTIONS, CONSTANTS.STATUS.UPDATE, "update"), _ACTIONS),
getItem = function(ID) {
return _.findWhere(CACHE.contacts, {
ID: ID
})
},
findIndex = function(ID) {
return _.findIndex(CACHE.contacts, {
ID: ID
})
},
emit = function() {
return $rootScope.$emit("contacts", {
type: "contactsUpdated",
data: {
all: get()
}
})
},
orderBy = function() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $filter("orderBy")(contacts, $stateParams.sort || "Name")
},
lowerCase = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").toLowerCase()
},
filterEmails = function() {
var emails = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
value = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return _.filter(emails, function(_ref) {
var _ref$Email = _ref.Email;
return lowerCase(void 0 === _ref$Email ? "" : _ref$Email).indexOf(value) > -1
})
},
total = function() {
return $stateParams.keyword ? CACHE.map.filtered.length : CACHE.contacts.length
},
isHydrated = function() {
return CACHE.hydrated
};
return $rootScope.$on("contacts", function(event, _ref13) {
var type = _ref13.type,
_ref13$data = _ref13.data,
data = void 0 === _ref13$data ? {} : _ref13$data;
"contactEvents" === type && contactEvents(data), "refreshContactEmails" === type && refreshContactEmails(data), "deletedContactEmail" === type && deletedContactEmail(data), "resetContacts" === type && resetContacts(), "importContacts" === type && contactImporter(data.contactID), "exportContacts" === type && contactDownloader(data.contactID), "selectContacts" === type && selectContacts(data), "searchingContact" === type && searchingContact()
}), {
hydrate: hydrate,
isHydrated: isHydrated,
clear: clear,
get: get,
total: total,
paginate: paginate,
load: load,
find: find,
getItem: getItem
}
}), angular.module("proton.contact").factory("contactDetailsModel", function(contactTransformLabel, CONSTANTS, contactSchema, gettextCatalog) {
function getKeys() {
var field = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
vcard = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return "CUSTOMS" === field ? _.difference(Object.keys(vcard.data), [].concat(FIELDS.AVOID, FIELDS.FN, FIELDS.EMAIL, FIELDS.TEL, FIELDS.ADR, FIELDS.NOTE, FIELDS.PERSONALS)) : FIELDS[field]
}
function getType(property) {
var type = property.getType();
return Array.isArray(type) ? type[0] : type
}
function getParams() {
var item = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
pref = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0,
params = item.params || {};
return item.label && MAP_KEYS[item.type] !== item.label && (params.type = contactTransformLabel.toVCard(item.label)), pref && (params.pref = pref), params
}
function prepare(scope) {
var params = angular.copy(contactSchema.contactAPI);
Object.keys(scope.model).forEach(function(key) {
var child = scope.model[key];
switch (key) {
case "Emails":
case "Tels":
case "Adrs":
child.forEach(function(item, index) {
item.value && params.vCard.add(item.type, escapeValue(item.value), getParams(item, child.length > 1 && index + 1))
});
break;
default:
child.forEach(function(item) {
item.value && params.vCard.add(item.type, escapeValue(item.value), getParams(item))
})
}
});
var fnProperty = params.vCard.get("fn");
if (!fnProperty || fnProperty.isEmpty()) {
var value = "",
emailProperty = params.vCard.get("email");
if (emailProperty) {
var emailValue = emailProperty.valueOf();
value = Array.isArray(emailValue) ? emailValue[0].valueOf() : emailValue
}
params.vCard.add("fn", value || I18N.unknown)
}
return params
}
function extract(_ref) {
var _ref$vcard = _ref.vcard,
vcard = void 0 === _ref$vcard ? {} : _ref$vcard,
_ref$field = _ref.field,
field = void 0 === _ref$field ? "" : _ref$field;
return _.reduce(getKeys(field, vcard), function(acc, key) {
var property = vcard.get(key);
if (!checkProperty(property)) return acc;
var value = property.valueOf();
return Array.isArray(value) ? (_.each(orderByPref(value), function(prop) {
return acc.push(buildProperty(prop))
}), acc) : (acc.push(buildProperty(property)), acc)
}, [])
}
function orderByPref() {
var properties = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.sortBy(properties, function(property) {
var _ref2 = property.getParams() || {},
_ref2$pref = _ref2.pref;
return void 0 === _ref2$pref ? 0 : _ref2$pref
})
}
var ESCAPE_REGEX = /:|,|;|"/gi,
UNESCAPE_REGEX = /\\:|\\,|\\;|\\"/gi,
I18N = {
unknown: gettextCatalog.getString("Unknown", null, "Default display name vcard")
},
FIELDS = {
AVOID: ["version", "n", "prodid", "abuid"],
FN: ["fn"],
EMAIL: ["email"],
TEL: ["tel"],
ADR: ["adr"],
NOTE: ["note"],
PERSONALS: ["kind", "source", "xml", "nickname", "photo", "bday", "anniversary", "gender", "impp", "lang", "tz", "geo", "title", "role", "logo", "org", "member", "related", "categories", "rev", "sound", "uid", "clientpidmap", "url", "key", "fburl", "caladruri", "caluri"]
},
MAP_KEYS = CONSTANTS.VCARD_KEYS.reduce(function(acc, key) {
return acc[key] = contactTransformLabel.toLang(key), acc
}, {}),
unescapeValue = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(UNESCAPE_REGEX, function(val) {
return val.substr(1)
})
},
processEscape = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(ESCAPE_REGEX, function(val) {
return "\\" + val
})
},
escapeValue = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return Array.isArray(value) ? value.map(processEscape) : processEscape(value)
},
cleanValue = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
key = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return "adr" === key || "n" === key ? value.split(";").map(unescapeValue) : unescapeValue(value)
},
buildProperty = function() {
var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
key = property.getField();
return {
value: cleanValue(property.valueOf(), key),
type: getType(property),
key: key,
params: property.getParams()
}
},
checkProperty = function(property) {
return !!Array.isArray(property) || property && !property.isEmpty()
};
return {
extract: extract,
prepare: prepare,
unescapeValue: unescapeValue,
escapeValue: escapeValue
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.contact").factory("contactDownloader", function(Contact, contactLoaderModal, contactDetailsModel, downloadFile, vcard) {
var getFileName = function(id, _ref) {
var _ref2 = _slicedToArray(_ref, 1),
card = _ref2[0],
nameProperty = card.get("fn");
return "all" !== id && nameProperty ? contactDetailsModel.unescapeValue(nameProperty.valueOf()) + ".vcf" : "proton.vcf"
},
get = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(id) {
var _ref4, vCard, list;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
if ("all" === id) {
_context.next = 6;
break
}
return _context.next = 3, Contact.get(id);
case 3:
return _ref4 = _context.sent, vCard = _ref4.vCard, _context.abrupt("return", [vCard]);
case 6:
return _context.next = 8, Contact.exportAll();
case 8:
return list = _context.sent, _context.abrupt("return", list.map(function(_ref5) {
return _ref5.vCard
}));
case 10:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x) {
return _ref3.apply(this, arguments)
}
}();
return function() {
var id = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "all",
promise = get(id);
contactLoaderModal.activate({
params: {
mode: "export",
close: function() {
contactLoaderModal.deactivate()
}
}
}), promise.then(function(data) {
var blob = new Blob([vcard.to(data)], {
type: "data:attachment/vcard;"
});
contactLoaderModal.deactivate(), downloadFile(blob, getFileName(id, data))
}).catch(contactLoaderModal.deactivate)
}
}), angular.module("proton.contact").factory("contactEditor", function($rootScope, $state, eventManager, Contact, contactModal, contactEmails, contactCache, contactLoaderModal, contactSchema, confirmModal, gettextCatalog, networkActivityTracker, notification) {
function create(_ref) {
var _ref$contacts = _ref.contacts,
contacts = void 0 === _ref$contacts ? [] : _ref$contacts,
mode = _ref.mode,
promise = Contact.add(contacts).then(function(_ref2) {
var created = _ref2.created,
total = _ref2.total,
errors = _ref2.errors;
return eventManager.call().then(function() {
$rootScope.$emit("contacts", {
type: "contactCreated",
data: {
created: created,
total: total,
errors: errors,
mode: mode
}
})
})
});
return "import" === mode && contactLoaderModal.activate({
params: {
mode: "import",
close: function() {
contactLoaderModal.deactivate()
}
}
}), promise
}
function update(_ref3) {
var _ref3$contact = _ref3.contact,
contact = void 0 === _ref3$contact ? {} : _ref3$contact,
promise = Contact.update(contact).then(function(_ref4) {
var Contact = _ref4.Contact,
cards = _ref4.cards;
return $rootScope.$emit("contacts", {
type: "contactUpdated",
data: {
contact: Contact,
cards: cards
}
}), notification.success(gettextCatalog.getString("Contact edited", null, "Success message")), eventManager.call()
});
return networkActivityTracker.track(promise), promise
}
function remove(_ref5) {
var _ref5$contactIDs = _ref5.contactIDs,
contactIDs = void 0 === _ref5$contactIDs ? [] : _ref5$contactIDs,
_ref5$confirm = _ref5.confirm,
confirm = void 0 === _ref5$confirm || _ref5$confirm,
success = "all" === contactIDs ? gettextCatalog.getString("All contacts deleted", null, "Success") : gettextCatalog.getPlural(contactIDs.length, "Contact deleted", "Contacts deleted", null, "Success"),
process = function() {
requestDeletion(contactIDs).then(function() {
notification.success(success), $state.go("secured.contacts")
})
};
if (confirm) return confirmDeletion(contactIDs, function() {
return process()
});
process()
}
function requestDeletion() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
promise = "all" === IDs ? Contact.clear() : Contact.remove({
IDs: IDs
});
return networkActivityTracker.track(promise), promise.then(function() {
return "all" === IDs && (contactCache.clear(), contactEmails.clear()), eventManager.call()
})
}
function confirmDeletion() {
var contactIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
callback = arguments[1],
message = "all" === contactIDs ? gettextCatalog.getString("Are you sure you want to delete all your contacts?", null, "Info") : gettextCatalog.getPlural(contactIDs.length, "Are you sure you want to delete this contact?", "Are you sure you want to delete the selected contacts?", null, "Info"),
title = "all" === contactIDs ? gettextCatalog.getString("Delete all", null, "Title") : gettextCatalog.getString("Delete", null, "Title");
confirmModal.activate({
params: {
title: title,
message: message,
confirm: function() {
callback(), confirmModal.deactivate()
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}
function add(_ref6) {
var email = _ref6.email,
name = _ref6.name,
contact = angular.copy(contactSchema.contactAPI);
email && contact.vCard.add("email", email), name && contact.vCard.add("fn", name), contactModal.activate({
params: {
contact: contact,
close: function() {
contactModal.deactivate()
}
}
})
}
return $rootScope.$on("contacts", function(event, _ref7) {
var type = _ref7.type,
_ref7$data = _ref7.data,
data = void 0 === _ref7$data ? {} : _ref7$data;
"deleteContacts" === type && remove(data), "updateContact" === type && update(data), "createContact" === type && create(data), "addContact" === type && add(data)
}), {
init: angular.noop,
create: create,
update: update,
remove: remove
}
}), angular.module("proton.contact").factory("contactEmails", function($rootScope, Contact, networkActivityTracker) {
var emails = [],
set = function(data) {
return emails.push.apply(emails, _toConsumableArray(data))
},
fetch = function() {
return emails
},
clear = function() {
return emails.length = 0
},
findIndex = function(ID) {
return _.findIndex(emails, {
ID: ID
})
},
emit = function(contact) {
$rootScope.$emit("contacts", {
type: "refreshContactEmails",
data: {
ID: contact.ContactID
}
})
},
loadCache = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
var list;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.next = 2, Contact.hydrate();
case 2:
return list = _context.sent, set(list), _context.abrupt("return", fetch());
case 5:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function() {
return _ref.apply(this, arguments)
}
}(),
load = function() {
var promise = loadCache();
return networkActivityTracker.track(promise), promise
};
return $rootScope.$on("createContactEmail", function(event, contactEmail) {
emails.push(contactEmail), emit(contactEmail)
}), $rootScope.$on("updateContactEmail", function(event, ID, contactEmail) {
var index = findIndex(ID); - 1 !== index ? emails[index] = contactEmail : emails.push(contactEmail), emit(contactEmail)
}), $rootScope.$on("deleteContactEmail", function(event, ID) {
var index = findIndex(ID); - 1 !== index && (emails.splice(index, 1), $rootScope.$emit("contacts", {
type: "deletedContactEmail",
data: {
ID: ID
}
}))
}), {
set: set,
fetch: fetch,
clear: clear,
findIndex: findIndex,
load: load
}
}), angular.module("proton.contact").factory("contactImporter", function($rootScope, contactSchema, importContactModal, notification, vcard, csv, gettextCatalog, networkActivityTracker) {
var I18N = {
noFiles: gettextCatalog.getString("No files were selected", null, "Error"),
invalid: gettextCatalog.getString("Invalid file type", null, "Error"),
parsingCSV: gettextCatalog.getString("Cannot convert the file", null, "Error")
},
dispatch = function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $rootScope.$emit("contacts", {
type: "createContact",
data: {
contacts: contactSchema.prepare(data),
mode: "import"
}
})
},
importVCF = function() {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(reader) {
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", dispatch(vcard.from(reader.result)));
case 1:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x2) {
return _ref.apply(this, arguments)
}
}(),
importVCard = function(file) {
return csv.csvToVCard(file).then(function() {
var parsed = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return parsed.length && dispatch(parsed)
}).catch(function(e) {
throw console.error(e), new Error(I18N.parsingCSV)
})
},
MAP_SRC = {
".vcf": importVCF,
".csv": importVCard
},
importFiles = function() {
var files = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
if (!files.length) return notification.error(I18N.noFiles);
var reader = new FileReader,
file = files[0],
extension = file.name.slice(-4);
reader.onload = function(e) {
return notification.error(e)
}, reader.onload = function() {
if (!MAP_SRC[extension]) return notification.error(I18N.invalid), importContactModal.deactivate();
var parameter = ".vcf" === extension ? reader : file,
promise = MAP_SRC[extension](parameter).then(function() {
return importContactModal.deactivate()
});
networkActivityTracker.track(promise)
}, reader.readAsText(file, "utf-8")
};
return function() {
importContactModal.activate({
params: {
import: importFiles,
cancel: function() {
importContactModal.deactivate()
}
}
})
}
}), angular.module("proton.contact").factory("contactMerger", function($rootScope, contactMergerModal, contactEditor, contactSchema, Contact, gettextCatalog, networkActivityTracker, notification, vcard) {
function getEmails(_ref) {
var Emails = _ref.Emails,
vCard = _ref.vCard;
return Array.isArray(Emails) ? _.map(Emails, function(_ref2) {
var _ref2$Email = _ref2.Email;
return void 0 === _ref2$Email ? "" : _ref2$Email
}) : _.reduce(vcard.extractProperties(vCard), function(acc, property) {
return "email" === property.getField() && acc.push(property.valueOf()), acc
}, [])
}
function extractDuplicates() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
_$reduce = _.reduce(contacts, function(acc, contact, index) {
var emails = getEmails(contact);
return _.each(emails, function() {
var email = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
acc.map[email] = acc.map[email] || [], acc.map[email].push(index), acc.map[email].length > 1 && acc.duplicate.push(email)
}), acc
}, {
map: {},
duplicate: []
}),
_$reduce$map = _$reduce.map,
map = void 0 === _$reduce$map ? {} : _$reduce$map,
_$reduce$duplicate = _$reduce.duplicate,
duplicate = void 0 === _$reduce$duplicate ? [] : _$reduce$duplicate;
return _.chain(duplicate).uniq().reduce(function(acc, email) {
return acc[email] = [], _.each(map[email], function(index) {
var contact = contacts[index];
contact.selected = !0, acc[email].push(contact)
}), acc
}, {}).value()
}
function confirm(emails) {
contactMergerModal.activate({
params: {
emails: emails,
merge: function() {
_merge(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}), contactMergerModal.deactivate()
},
close: function() {
contactMergerModal.deactivate()
}
}
})
}
function _merge() {
var emails = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_$chain$reduce$value = _.chain(Object.keys(emails)).reduce(function(acc, key) {
var contacts = emails[key],
properties = _.chain(contacts).filter(function(_ref3) {
return _ref3.selected
}).reduce(function(acc2, contact) {
return contact.selected && (acc.toDelete.push(contact.ID), acc2.push(vcard.extractProperties(contact.vCard))), acc2
}, []).value();
if (properties.length) {
var newCard = new vCard;
_.each(properties, function(property) {
return newCard.addProperty(property)
}), acc.toCreate.push(newCard)
}
return acc
}, {
toDelete: [],
toCreate: []
}).value(),
toDelete = _$chain$reduce$value.toDelete,
toCreate = _$chain$reduce$value.toCreate;
contactEditor.remove({
contactIDs: toDelete,
confirm: !1
}), contactEditor.create({
contacts: contactSchema.prepare(toCreate)
})
}
function mergeContacts() {
var promise = Contact.exportAll().then(function(contacts) {
var emails = extractDuplicates(contacts);
Object.keys(emails).length ? confirm(emails) : notification.info(I18N.noDuplicate)
});
return networkActivityTracker.track(promise), promise
}
var I18N = {
mergeContacts: gettextCatalog.getString("Merge contacts", null, "Title"),
noDuplicate: gettextCatalog.getString("You have no duplicate contacts", null, "Info")
};
return $rootScope.$on("contacts", function(event, _ref4) {
"mergeContacts" === _ref4.type && mergeContacts()
}), {
init: angular.noop,
extractDuplicates: extractDuplicates
}
}), angular.module("proton.contact").factory("contactSchema", function(gettextCatalog) {
function getType(property) {
var type = property.getType();
return Array.isArray(type) ? type : [type]
}
var contactAPI = {
vCard: new vCard
},
group = ["Tel", "Adr", "Note"],
personnal = ["Bday", "Title", "Org", "Nickname"],
I18N = {
UNKNOWN: gettextCatalog.getString("Unknown", null, "Default display name vcard")
},
all = group.concat(personnal),
buildEmailProperty = function() {
var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return {
Email: property.valueOf(),
Type: getType(property)
}
},
formatEmails = function() {
var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return Array.isArray(property) ? _.map(property, buildEmailProperty) : [buildEmailProperty(property)]
},
checkProperty = function(property) {
return !!Array.isArray(property) || property && !property.isEmpty() && property.valueOf().trim()
};
return {
contactAPI: contactAPI,
group: group,
personnal: personnal,
custom: function(key) {
return -1 === all.indexOf(key)
},
prepare: function() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.reduce(contacts, function(acc, contact) {
var prepared = {
Emails: [],
vCard: contact
},
nameProperty = contact.get("fn"),
emailProperty = contact.get("email");
if (checkProperty(emailProperty) && (prepared.Emails = formatEmails(emailProperty)), checkProperty(nameProperty)) prepared.Name = nameProperty.valueOf().trim();
else {
var nameValue = prepared.Emails.length ? prepared.Emails[0].Email : I18N.UNKNOWN;
prepared.Name = nameValue, prepared.vCard.set("fn", nameValue)
}
return acc.push(prepared), acc
}, [])
}
}
}), angular.module("proton.contact").factory("contactTransformLabel", function(gettextCatalog) {
var MAP = {
adr: gettextCatalog.getString("Address", null, "VCard key name"),
anniversary: gettextCatalog.getString("Anniversary", null, "VCard key name"),
caladruri: gettextCatalog.getString("Calendar user address", null, "VCard key name"),
caluri: gettextCatalog.getString("URI for a calendar", null, "VCard key name"),
bday: gettextCatalog.getString("Birthday", null, "VCard key name"),
categories: gettextCatalog.getString("Categories", null, "VCard key name"),
cell: gettextCatalog.getString("Cell", null, "VCard key name"),
custom: gettextCatalog.getString("Custom", null, "VCard key name"),
email: gettextCatalog.getString("Email", null, "VCard key name"),
fax: gettextCatalog.getString("Fax", null, "VCard key name"),
fburl: gettextCatalog.getString("Free or busy URL", null, "VCard key name"),
fn: gettextCatalog.getString("Name", null, "VCard key name"),
gender: gettextCatalog.getString("Gender", null, "VCard key name"),
geo: gettextCatalog.getString("Geolocation", null, "VCard key name"),
home: gettextCatalog.getString("Personal", null, "VCard key name"),
impp: gettextCatalog.getString("Impp", null, "VCard key name"),
key: gettextCatalog.getString("Key", null, "VCard key name"),
lang: gettextCatalog.getString("Language", null, "VCard key name"),
logo: gettextCatalog.getString("Logo", null, "VCard key name"),
member: gettextCatalog.getString("Member", null, "VCard key name"),
nickname: gettextCatalog.getString("Nickname", null, "VCard key name"),
note: gettextCatalog.getString("Note", null, "VCard key name"),
office: gettextCatalog.getString("Office", null, "VCard key name"),
org: gettextCatalog.getString("Organization", null, "VCard key name"),
photo: gettextCatalog.getString("Photo", null, "VCard key name"),
private: gettextCatalog.getString("Private", null, "VCard key name"),
prodid: gettextCatalog.getString("Software", null, "VCard key name"),
related: gettextCatalog.getString("Related", null, "VCard key name"),
rev: gettextCatalog.getString("Revision", null, "VCard key name"),
role: gettextCatalog.getString("Role", null, "VCard key name"),
sound: gettextCatalog.getString("Sound", null, "VCard key name"),
tel: gettextCatalog.getString("Phone", null, "VCard key name"),
title: gettextCatalog.getString("Title", null, "VCard key name"),
tz: gettextCatalog.getString("Timezone", null, "VCard key name"),
uid: "UID",
url: "URL",
work: gettextCatalog.getString("Work", null, "VCard key name")
};
return {
toLang: function() {
var label = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return MAP[label.toLowerCase()] || "" + label.charAt(0).toUpperCase() + label.slice(1)
},
toVCard: function() {
var label = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return Object.keys(MAP).find(function(key) {
return label === MAP[key]
}) || label
}
}
}), angular.module("proton.contact").factory("contactUI", function(gettextCatalog, tools, contactTransformLabel) {
function removeX() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return value.toLowerCase().startsWith("x-") ? value.substring(2) : value.toLowerCase().startsWith("x") ? value.substring(1) : value
}
function initialize() {
var datas = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
type = arguments[1],
UI = {
allowCustom: !1,
allowMultiple: !1,
mode: "singleLine",
infinite: !1,
unique: !1,
sortable: !1,
sortableState: !1,
placeholder: "",
iconClass: "",
labels: [],
items: [],
hide: ["version", "n", "prodid", "abuid", "uid"],
inputType: "text"
};
switch (type) {
case "Name":
UI.unique = !0, UI.placeholder = I18N.name, UI.iconClass = "fa-user";
break;
case "Emails":
UI.infinite = !0, UI.sortable = !0, UI.inputType = "email", UI.placeholder = I18N.emailAddress, UI.iconClass = "fa-envelope", UI.labels = EMAIL_TYPE.map(function(label) {
return contactTransformLabel.toLang(label)
});
break;
case "Tels":
UI.inputType = "tel", UI.placeholder = I18N.phoneNumber, UI.iconClass = "fa-phone", UI.labels = TEL_TYPE.map(function(label) {
return contactTransformLabel.toLang(label)
});
break;
case "Adrs":
UI.placeholder = I18N.address, UI.iconClass = "fa-home", UI.mode = "address", UI.labels = ADR_TYPE.map(function(label) {
return contactTransformLabel.toLang(label)
});
break;
case "Personals":
UI.placeholder = I18N.information, UI.iconClass = "fa-address-card", UI.labels = PERSONAL_TYPE.map(function(label) {
return contactTransformLabel.toLang(label)
});
break;
case "Notes":
UI.placeholder = I18N.note, UI.iconClass = "fa-sticky-note", UI.mode = "multiLine", UI.unique = !0;
break;
case "Customs":
UI.infinite = !0, UI.placeholder = I18N.customField, UI.iconClass = "fa-asterisk", UI.labels = [I18N.custom], UI.allowCustom = !0
}
if (UI.selectable = UI.labels.length > 1, datas.length && (UI.allowMultiple = !0, datas.forEach(function(data) {
(data.value || UI.unique) && add(UI, data.key, removeX(data.type) || removeX(data.key), data.value)
})), !datas.length || 1 === datas.length && _.contains(UI.hide, datas[0].key)) {
var populated = populate(UI, type);
add(UI, populated.key, populated.type, "")
}
return UI.inputName = "name_" + UI.placeholder.replace(/\W+|_/g, ""), UI
}
function populate(UI, type) {
switch (type) {
case "Name":
return {
key: "fn",
type: "fn"
};
case "Emails":
return {
key: "email",
type: "email"
};
case "Tels":
return {
key: "tel",
type: "tel"
};
case "Adrs":
return {
key: "adr",
type: "adr"
};
case "Personals":
var key = findKey(UI);
return {
key: key,
type: key
};
case "Customs":
return {
key: "x-custom",
type: "custom"
};
case "Notes":
return {
key: "note",
type: "note"
}
}
}
function findKey(_ref) {
var _ref$items = _ref.items,
items = void 0 === _ref$items ? [] : _ref$items,
types = _.pluck(items, "type");
return _.find(PERSONAL_TYPE, function(type) {
return -1 === types.indexOf(type)
}) || PERSONAL_TYPE[_.random(PERSONAL_TYPE.length - 1)]
}
function add(UI, type, label) {
var value = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "",
params = arguments[4],
hide = _.contains(UI.hide, type);
UI.items.push({
type: type,
label: contactTransformLabel.toLang(label),
value: value,
hide: hide,
params: params
})
}
var EMAIL_TYPE = ["email", "home", "work", "other"],
TEL_TYPE = ["tel", "mobile", "work", "fax", "other"],
ADR_TYPE = ["adr", "home", "work", "other"],
PERSONAL_TYPE = ["org", "anniversary", "bday", "gender", "nickname", "role", "title", "url"],
I18N = {
name: gettextCatalog.getString("Name", null, "Placeholder"),
emailAddress: gettextCatalog.getString("Email address", null, "Placeholder"),
phoneNumber: gettextCatalog.getString("Phone number", null, "Placeholder"),
information: gettextCatalog.getString("Information", null, "Placeholder"),
note: gettextCatalog.getString("A note", null, "Placeholder"),
address: gettextCatalog.getString("Address", null, "Placeholder"),
custom: gettextCatalog.getString("Custom", null),
customField: gettextCatalog.getString("Custom field", null, "Placeholder")
};
return {
remove: function(UI, item) {
return UI.items.splice(UI.items.indexOf(item), 1)
},
add: add,
initialize: initialize,
populate: populate
}
}), angular.module("proton.contact").filter("contact", function(gettextCatalog, authentication) {
var getContact = function(Email) {
return _.findWhere(authentication.user.Contacts, {
Email: Email
}) || {}
},
getContactFromUser = function(nameContact, Address) {
var _getContact = getContact(Address),
_getContact$Name = _getContact.Name,
Name = void 0 === _getContact$Name ? "" : _getContact$Name,
Email = _getContact.Email;
return Name && Name !== Email ? Name : nameContact || Address
},
fillContact = function(Name, Address) {
var contact = getContact(Address);
return Address !== Name && Name ? angular.isString(contact.Name) && contact.Name ? contact.Name + " <" + Address + ">" : void 0 : Address
};
return function(sender, parameter) {
var _ref = sender || {},
_ref$Name = _ref.Name,
Name = void 0 === _ref$Name ? "" : _ref$Name,
_ref$Address = _ref.Address,
Address = void 0 === _ref$Address ? "" : _ref$Address;
return "Address" === parameter ? "<" + Address + ">" : "Name" === parameter ? getContactFromUser(Name, Address) : fillContact(Name, Address) || Name + " <" + Address + ">"
}
}), angular.module("proton.contact").filter("spam", function() {
return function() {
var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
input = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return input ? _.filter(contacts, function(contact) {
return contact.Email.indexOf(input) > -1
}) : contacts
}
}), angular.module("proton.contact").factory("contactBeforeToLeaveModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/contact/contactBeforeToLeaveModal.tpl.html",
controller: function(params) {
this.save = params.save, this.discard = params.discard, this.cancel = params.cancel
}
})
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.contact").factory("contactLoaderModal", function($rootScope, gettextCatalog, pmModal) {
var I18N = {
encrypting: function(progress) {
return gettextCatalog.getString("Encrypting contacts: {{progress}}%", {
progress: progress
}, "Label for the progress bar displayed during the contact import")
},
decrypting: function(progress) {
return gettextCatalog.getString("Decrypting contacts: {{progress}}%", {
progress: progress
}, "Label for the progress bar displayed during the contact export")
},
upload: function(progress) {
return gettextCatalog.getString("Upload: {{progress}}%", {
progress: progress
}, "Label for the progress bar displayed during the contact import")
},
importComplete: gettextCatalog.getString("Importing contacts complete!", null, "Import complete"),
contactImported: gettextCatalog.getString("contacts successfully imported.", null, "1 of 2 contacts successfully imported."),
exportTitle: gettextCatalog.getString("Exporting Contacts", null, "Title for the contacts exporter modal"),
importTitle: gettextCatalog.getString("Importing Contacts", null, "Title for the contacts exporter modal"),
exportInfo: gettextCatalog.getString("Exporting contacts, this may take a few minutes. When the progress is completed, this modal will close and let you download the file.", null, "Information for the contacts exporter modal"),
importInfo: gettextCatalog.getString("Importing contacts, this may take a few minutes.", null, "Information for the contacts importer modal"),
importFail: function(number) {
return gettextCatalog.getString("{{number}} failed to import.", {
number: number
}, "Number of failed contact during the contact import")
},
totalFailure: gettextCatalog.getString("Import failed. Please check the import file or try again.", null, "Error during importation")
},
getTitle = function(mode) {
return "export" === mode ? I18N.exportTitle : I18N.importTitle
},
getInfo = function(mode) {
return "export" === mode ? I18N.exportInfo : I18N.importInfo
},
getLabel = function() {
var mode = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
progress = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
return "export" === mode ? I18N.decrypting(progress) : "import" === mode ? progress > 50 ? I18N.upload(progress) : I18N.encrypting(progress) : ""
},
getRows = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).map(function(_ref) {
return '<li class="contactLoaderModal-log">- ' + _ref.error + "</li>"
}).join("")
},
getSuccess = function(_ref2) {
var _ref2$created = _ref2.created,
created = void 0 === _ref2$created ? [] : _ref2$created,
_ref2$total = _ref2.total,
total = void 0 === _ref2$total ? 0 : _ref2$total,
_ref2$errors = _ref2.errors,
errors = void 0 === _ref2$errors ? [] : _ref2$errors;
if (!created.length) {
var _errors = _slicedToArray(errors, 1),
_errors$ = _errors[0];
_errors$ = void 0 === _errors$ ? {} : _errors$;
var _errors$$error = _errors$.error;
return '<p class="alert alert-danger">' + (void 0 === _errors$$error ? I18N.totalFailure : _errors$$error) + "</p>"
}
var failure = errors.length ? "<p>" + I18N.importFail(errors.length) + "</p>" : "",
logs = errors.length ? '<ul class="contactLoaderModal-logs">' + getRows(errors) + "</ul>" : "";
return "\n <p>" + I18N.importComplete + '</p>\n <div class="contactLoaderModal-frame">\n <h1>' + created.length + " of " + total + "</h1>\n <strong>" + I18N.contactImported + "</strong>\n </div>\n " + failure + "\n " + logs + "\n "
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/contact/contactLoaderModal.tpl.html",
controller: function(params) {
var unsubscribe = [];
unsubscribe.push($rootScope.$on("contacts", function(event, _ref3) {
var _ref3$type = _ref3.type,
type = void 0 === _ref3$type ? "" : _ref3$type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
"contactCreated" === type && (document.querySelector(".contactLoaderModal-container").classList.add("contactLoaderModal-imported"), document.querySelector(".contactLoaderModal-success").innerHTML = getSuccess(data))
})), unsubscribe.push($rootScope.$on("progressBar", function(event, _ref4) {
var _ref4$type = _ref4.type,
type = void 0 === _ref4$type ? "" : _ref4$type,
_ref4$data = _ref4.data,
data = void 0 === _ref4$data ? {} : _ref4$data,
$label = document.querySelector(".contactLoaderModal-label");
$label && "contactsProgressBar" === type && ($label.textContent = getLabel(params.mode, data.progress))
})), this.title = getTitle(params.mode), this.info = getInfo(params.mode), this.close = params.close, this.$onDestroy = function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
}
}
})
}), angular.module("proton.contact").factory("contactMergerModal", function(gettextCatalog, pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/contact/contactMergerModal.tpl.html",
controller: function(params) {
var _this = this;
this.title = gettextCatalog.getPlural(Object.keys(params.emails).length, "1 Duplicate found", "{{$count}} Duplicates found", {}), this.emails = params.emails, this.cancel = function() {
return params.close()
}, this.merge = function() {
return params.merge(_this.emails)
}
}
})
}), angular.module("proton.contact").factory("contactModal", function($rootScope, $state, gettextCatalog, notification, pmModal) {
var I18N = {
contactAdded: gettextCatalog.getString("Contact added", null, "Success message for the contact modal"),
contactError: gettextCatalog.getString("Error with the request", null, "Default error for the contact modal")
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/contact/contactModal.tpl.html",
controller: function(params) {
var processing = !1,
unsubscribe = $rootScope.$on("contacts", function(event, _ref) {
var _ref$type = _ref.type,
type = void 0 === _ref$type ? "" : _ref$type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if ("contactCreated" === type) {
var _data$created = data.created,
created = void 0 === _data$created ? [] : _data$created,
_data$errors = data.errors,
errors = void 0 === _data$errors ? [] : _data$errors;
processing = !1, errors.length && errors.forEach(function(_ref2) {
var _ref2$error = _ref2.error,
error = void 0 === _ref2$error ? I18N.contactError : _ref2$error;
return notification.error(error)
}), created.length && (notification.success(I18N.contactAdded), $state.go("secured.contacts.details", {
id: created[0].ID
}), params.close())
}
});
this.contact = params.contact, this.cancel = params.close, this.$onDestroy = function() {
return unsubscribe()
}, this.submit = function() {
processing || (processing = !0, $rootScope.$emit("contacts", {
type: "submitContactForm"
}))
}
}
})
}), angular.module("proton.contact").factory("importContactModal", function(pmModal, notification, gettextCatalog) {
var I18N = {
invalidType: gettextCatalog.getString("Invalid file type")
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/contact/importContactModal.tpl.html",
controller: function(params, notify, $timeout, $scope) {
var _this = this,
files = [],
extension = void 0;
this.import = function() {
return params.import(files)
}, this.cancel = params.cancel;
var initialization = function() {
var drop = document.getElementById("dropzone"),
$selectFile = $("#selectedFile");
drop.ondrop = function(e) {
e.preventDefault();
var file = e.dataTransfer.files[0];
if (".csv" !== (extension = file.name.substr(file.name.length - 4)) && ".vcf" !== extension) return _this.hover = !1, notification.error(I18N.invalidType);
files = e.dataTransfer.files, $scope.$applyAsync(function() {
_this.fileDropped = files[0].name, _this.hover = !1
})
}, drop.ondragover = function(event) {
event.preventDefault(), _this.hover = !0
}, drop.ondragleave = function(event) {
event.preventDefault(), _this.hover = !1
}, $("#dropzone").on("click", function() {
$selectFile.trigger("click")
}), $selectFile.change(function() {
var listFiles = $selectFile[0].files,
file = listFiles[0].name;
if (".csv" !== (extension = file.substr(file.length - 4)) && ".vcf" !== extension) return notification.error(I18N.invalidType);
files = listFiles, $scope.$applyAsync(function() {
_this.fileDropped = file, _this.hover = !1
})
})
};
_.defer(initialization, 100)
}
})
}), angular.module("proton.conversation").directive("conversation", function($filter, $rootScope, $state, $stateParams, actionConversation, conversationListeners, messageActions, authentication, messageScroll, cache, CONSTANTS, tools, hotkeys, labelsModel, findExpendableMessage, dispatchers) {
var getScrollToPosition = function() {
var container = document.getElementById("pm_thread"),
getDelta = function(node, type) {
if ("UP" === type) {
if (!node.previousElementSibling) return 0;
return node.previousElementSibling.classList.contains("open") ? node.previousElementSibling.offsetHeight + 42 : 42
}
return node.nextElementSibling && node.nextElementSibling.classList.contains("open") ? node.nextElementSibling.offsetHeight + 42 : 42
};
return function(index, max) {
var type = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "UP",
$item = container.querySelector(".message.marked");
if ($item) {
var delta = getDelta($item, type);
if (0 === index) return container.scrollTop = 0;
"UP" === type && (container.scrollTop -= delta), "DOWN" === type && (container.scrollTop = $item.offsetTop + delta - container.offsetHeight / 2)
}
}
};
return {
restrict: "E",
replace: !0,
scope: {
conversation: "="
},
templateUrl: "templates/partials/conversation.tpl.html",
link: function(scope) {
function back() {
var route = $state.$current.name.replace(".element", "");
$state.go(route, {
id: null
})
}
function expandMessage() {
var messages = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
message = findExpendableMessage.find(messages);
return messages.length && (message.openMe = !0), messages
}
function refreshConversation() {
var conversation = cache.getConversationCached($stateParams.id),
messages = cache.queryMessagesCached($stateParams.id),
labelID = tools.currentLocation();
return messagesCached = messages, scope.trashed = messagesCached.some(function(_ref4) {
var _ref4$LabelIDs = _ref4.LabelIDs,
LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs;
return _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash)
}), scope.nonTrashed = messagesCached.some(function(_ref5) {
var _ref5$LabelIDs = _ref5.LabelIDs,
LabelIDs = void 0 === _ref5$LabelIDs ? [] : _ref5$LabelIDs;
return !_.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash)
}), conversation && (_.findWhere(conversation.Labels, {
ID: labelID
}) || $state.includes("secured.search.**")) ? (_.extend(scope.conversation, conversation), void(Array.isArray(messages) && messages.length > 0 ? function() {
for (var toAdd = [], toRemove = [], list = cache.orderMessage($filter("filterMessages")(messages, scope.showTrashed, scope.showNonTrashed), !1), index = 0; index < list.length; index++) ! function(index) {
scope.messages.some(function(_ref6) {
return _ref6.ID === list[index].ID
}) || toAdd.push({
index: index,
message: list[index]
})
}(index);
for (var index = 0; index < toAdd.length; index++) {
var ref = toAdd[index];
scope.messages.splice(ref.index, 0, ref.message)
}
for (var _index = 0; _index < scope.messages.length; _index++) ! function(_index) {
list.some(function(_ref7) {
return _ref7.ID === scope.messages[_index].ID
}) || toRemove.push({
index: _index
})
}(_index);
for (var _index2 = toRemove.length - 1; _index2 >= 0; _index2--) scope.messages.splice(toRemove[_index2].index, 1)
}() : back())) : back()
}
var messagesCached = [],
_dispatchers = dispatchers(["message.open", "refreshConversation", "message.expiration", "unmarkMessages", "toggleStar", "elements"]),
on = _dispatchers.on,
unsubscribe = _dispatchers.unsubscribe,
dispatcher = _dispatchers.dispatcher,
scrollToPosition = getScrollToPosition(),
unsubscribeActions = angular.noop;
scope.messages = [], scope.mailbox = tools.currentMailbox(), scope.labels = labelsModel.get(), scope.showTrashed = !1, scope.showNonTrashed = !1, $rootScope.numberElementSelected = 1, $rootScope.showWelcome = !1, scope.inTrash = $state.includes("secured.trash.**"), scope.inSpam = $state.includes("secured.spam.**"), scope.getElements = function() {
return [scope.conversation]
};
var openMarked = function(message) {
return function() {
var msg = message || scope.markedMessage;
if (msg) return msg.Type === CONSTANTS.DRAFT ? $rootScope.$emit("composer.load", msg) : void dispatcher["message.open"]("toggle", {
action: "openMarked",
message: msg
})
}
};
on("refreshConversation", function(event, conversationIDs) {
conversationIDs.indexOf(scope.conversation.ID) > -1 && refreshConversation()
}), on("message.expiration", function() {
scope.$applyAsync(function() {
return refreshConversation()
})
}), on("message.open", function(event, _ref) {
var type = _ref.type,
data = _ref.data;
if ("toggle" === type && (unsubscribeActions(), unsubscribeActions = conversationListeners(data.message), hotkeys.unbind(["down", "up"]), scope.markedMessage = void 0), "render" === type) return messageScroll.to(data)
}), on("unmarkMessages", function() {
scope.markedMessage = void 0, unsubscribeActions()
}), scope.$on("move", function(e, mailbox) {
unsubscribeActions();
var labelID = CONSTANTS.MAILBOX_IDENTIFIERS[mailbox];
if (scope.markedMessage) return $rootScope.$emit("messageActions", {
action: "move",
data: {
ids: [scope.markedMessage.ID],
labelID: labelID
}
});
actionConversation.move([scope.conversation.ID], labelID)
});
var onNextPrevElement = function(type) {
return function() {
var index = _.findIndex(scope.messages, {
expand: !0
}),
pos = "DOWN" === type ? index + 1 : index - 1,
message = scope.messages[pos];
"DOWN" === type && pos === scope.messages.length || ("UP" !== type || index) && scope.$applyAsync(function() {
scope.messages[index].expand = !1, scrollToPosition(pos, scope.messages.length, type), unsubscribeActions = conversationListeners(message), openMarked(message)()
})
}
};
scope.$on("nextElement", onNextPrevElement("DOWN")), scope.$on("previousElement", onNextPrevElement("UP")), scope.$on("markPrevious", function() {
if (unsubscribeActions(), scope.markedMessage) {
var index = scope.messages.indexOf(scope.markedMessage);
if (index > 0) {
var pos = index - 1;
scope.$applyAsync(function() {
scope.markedMessage = scope.messages[pos], scrollToPosition(pos, scope.messages.length, "UP"), unsubscribeActions = conversationListeners(scope.markedMessage)
})
}
}
}), scope.$on("markNext", function() {
if (unsubscribeActions(), scope.markedMessage) {
var index = scope.messages.indexOf(scope.markedMessage);
if (index < scope.messages.length - 1) {
var pos = index + 1;
scope.$applyAsync(function() {
scope.markedMessage = scope.messages[pos], scrollToPosition(pos, scope.messages.length, "DOWN"), unsubscribeActions = conversationListeners(scope.markedMessage)
})
}
}
}), on("toggleStar", function() {
var data = {
model: scope.conversation,
type: "conversation"
};
scope.markedMessage && (data.model = scope.markedMessage, data.type = "message"), dispatcher.elements("toggleStar", data)
}), hotkeys.unbind(["down", "up"]), scope.$on("left", function() {
return hotkeys.bind(["down", "up"])
}), scope.$on("openMarked", openMarked()), scope.$on("right", function() {
unsubscribeActions(), !scope.markedMessage && scope.$applyAsync(function() {
scope.markedMessage = _.last(scope.messages), unsubscribeActions = conversationListeners(scope.markedMessage), messageScroll.toID(scope.markedMessage.ID, scope.messages), hotkeys.bind(["down", "up"])
})
}), scope.$on("escape", function() {
back()
}), scope.toggleOption = function(option) {
scope[option] = !scope[option], refreshConversation()
}, scope.showNotifier = function(folder) {
var filtered = _.filter(messagesCached, function(message) {
return _.contains(message.LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS[folder])
});
return filtered.length < messagesCached.length && filtered.length > 0
}, scope.getMessages = function() {
return scope.messages
}, scope.read = function() {
return actionConversation.read([scope.conversation.ID])
}, scope.unread = function() {
actionConversation.unread([scope.conversation.ID]), back()
}, scope.delete = function() {
return actionConversation.remove([scope.conversation.ID])
}, scope.saveLabels = function(labels, alsoArchive) {
actionConversation.label([scope.conversation.ID], labels, alsoArchive)
},
function() {
var messages = [];
if (messagesCached = cache.queryMessagesCached($stateParams.id), scope.trashed = _.some(messagesCached, function(_ref2) {
var LabelIDs = _ref2.LabelIDs;
return _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash)
}), scope.nonTrashed = _.some(messagesCached, function(_ref3) {
var LabelIDs = _ref3.LabelIDs;
return !_.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash)
}), messages = $filter("filterMessages")(messagesCached, scope.showTrashed, scope.showNonTrashed), messages.length > 0) {
var list = _.map(cache.orderMessage(messages, !1), function(msg) {
return delete msg.expand, delete msg.openMe, msg
});
scope.messages = expandMessage(list), unsubscribeActions = conversationListeners(_.last(scope.messages)), authentication.user.ViewLayout === CONSTANTS.ROW_MODE && (scope.markedMessage = $rootScope.expandMessage), dispatcher.elements("mark", {
id: $stateParams.id
})
} else back()
}(), scope.$on("$destroy", function() {
unsubscribe(), unsubscribeActions(), hotkeys.unbind(["down", "up"]), hotkeys.bind(["down", "up"]), dispatcher.elements("close", {
element: scope.conversation
})
})
}
}
}), angular.module("proton.conversation").directive("conversationPlaceholder", function() {
return {
replace: !0,
templateUrl: "templates/partials/conversation-placeholder.tpl.html"
}
}), angular.module("proton.conversation").directive("conversationView", function($state, $stateParams, cache, tools) {
return {
restrict: "E",
replace: !0,
template: '<div class="conversationView-container"><conversation ng-if="conversation" data-conversation="conversation"></conversation></div>',
link: function(scope) {
function back() {
var route = $state.$current.name.replace(".element", "");
$state.go(route, {
id: null
})
}
var conversationID = $stateParams.id,
ID = tools.currentLocation();
cache.getConversation(conversationID).then(function(conversation) {
return _.findWhere(conversation.Labels, {
ID: ID
}) || $state.includes("secured.search.**") ? scope.conversation = conversation : back()
})
}
}
}), angular.module("proton.conversation").directive("listColumns", function() {
return {
replace: !0,
templateUrl: "templates/partials/conversation-list-columns.tpl.html"
}
}), angular.module("proton.conversation").directive("listMobile", function() {
return {
replace: !0,
templateUrl: "templates/partials/conversation-list-mobile.tpl.html"
}
}), angular.module("proton.conversation").directive("listRows", function() {
return {
replace: !0,
templateUrl: "templates/partials/conversation-list-rows.tpl.html"
}
}), angular.module("proton.conversation").directive("statesConversation", function() {
return {
restrict: "E",
replace: !0,
template: "\n <i class=\"fa\" ng-class=\"{\n 'fa-mail-reply': conversation.IsReplied,\n 'fa-mail-reply-all': conversation.IsRepliedAll,\n 'fa-mail-forward': conversation.IsForwarded\n }\"></i>\n "
}
}), angular.module("proton.conversation").factory("actionConversation", function($rootScope, authentication, cache, CONSTANTS, conversationApi, eventManager, gettextCatalog, networkActivityTracker, notification, tools, labelsModel, $filter) {
function getFolderNameTranslated() {
var labelID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
_ref = labelsModel.read(labelID, "folders") || {},
Name = _ref.Name;
return mailboxes[labelID] || Name
}
function remove() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
labelID = arguments[1],
promise = conversationApi.delete(ids, labelID);
if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() {
return eventManager.call()
}), networkActivityTracker.track(promise);
var events = ids.reduce(function(acc, ID) {
var messages = cache.queryMessagesCached(ID);
return $rootScope.$broadcast("deleteConversation", ID), _.each(messages, function(_ref2) {
var ID = _ref2.ID;
return acc.push({
Action: 0,
ID: ID
})
}), acc.push({
Action: 0,
ID: ID
}), acc
}, []);
return cache.events(events), promise
}
function unread() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
currentLocation = tools.currentLocation(),
promise = conversationApi.unread(ids, currentLocation);
cache.addToDispatcher(promise), tools.cacheContext() || (promise.then(function() {
return eventManager.call()
}), networkActivityTracker.track(promise));
var events = ids.reduce(function(acc, ID) {
var messages = cache.queryMessagesCached(ID),
_ref3 = cache.getConversationCached(ID) || {},
_ref3$Labels = _ref3.Labels,
Labels = void 0 === _ref3$Labels ? [] : _ref3$Labels;
if (messages.length) {
var _$chain$filter$sortBy = _.chain(messages).filter(function(_ref4) {
var _ref4$LabelIDs = _ref4.LabelIDs,
LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs;
return _.contains(LabelIDs, currentLocation)
}).sortBy(function(_ref5) {
return _ref5.Time
}).last().value(),
_ID = _$chain$filter$sortBy.ID;
acc.push({
ID: _ID,
Action: 3,
Message: {
ID: _ID,
IsRead: 0
}
})
}
return acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
Labels: _.map(Labels, function(label) {
return label.ID === currentLocation && label.ContextNumUnread++, label
})
}
}), acc
}, []);
cache.events(events)
}
function read() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
currentLocation = tools.currentLocation(),
promise = conversationApi.read(ids);
cache.addToDispatcher(promise), tools.cacheContext() || (promise.then(function() {
return eventManager.call()
}), networkActivityTracker.track(promise));
var events = ids.reduce(function(acc, ID) {
var _ref6 = cache.getConversationCached(ID) || {},
_ref6$Labels = _ref6.Labels,
Labels = void 0 === _ref6$Labels ? [] : _ref6$Labels;
return _.each(cache.queryMessagesCached(ID), function(_ref7) {
var ID = _ref7.ID;
acc.push({
ID: ID,
Action: 3,
Message: {
ID: ID,
IsRead: 1
}
})
}), acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
Labels: _.map(Labels, function(label) {
return label.ID === currentLocation && (label.ContextNumUnread = 0), label
})
}
}), acc
}, []);
cache.events(events)
}
function unstar() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
promise = conversationApi.unstar(ids),
LabelIDsRemoved = [MAILBOX_IDENTIFIERS.starred];
if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() {
return eventManager.call()
}), networkActivityTracker.track(promise);
var events = _.chain(ids).map(function(id) {
return cache.getConversationCached(id)
}).filter(Boolean).reduce(function(acc, _ref8) {
var ID = _ref8.ID,
ContextNumUnread = _ref8.ContextNumUnread,
messages = cache.queryMessagesCached(ID);
return _.each(messages, function(message) {
acc.push({
Action: 3,
ID: message.ID,
Message: {
ID: message.ID,
IsRead: message.IsRead,
LabelIDsRemoved: LabelIDsRemoved
}
})
}), acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
ContextNumUnread: ContextNumUnread,
LabelIDsRemoved: LabelIDsRemoved
}
}), acc
}, []).value();
cache.events(events)
}
function star() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
promise = conversationApi.star(ids),
LabelIDsAdded = [MAILBOX_IDENTIFIERS.starred];
if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() {
return eventManager.call()
}), networkActivityTracker.track(promise);
var events = _.chain(ids).map(function(id) {
return cache.getConversationCached(id)
}).filter(Boolean).reduce(function(acc, _ref9) {
var ID = _ref9.ID,
ContextNumUnread = _ref9.ContextNumUnread,
messages = cache.queryMessagesCached(ID);
return _.each(messages, function(message) {
acc.push({
Action: 3,
ID: message.ID,
Message: {
ID: message.ID,
IsRead: message.IsRead,
LabelIDsAdded: LabelIDsAdded
}
})
}), acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
ContextNumUnread: ContextNumUnread,
LabelIDsAdded: LabelIDsAdded
}
}), acc
}, []).value();
cache.events(events)
}
function label(ids, labels, alsoArchive) {
var currentLocation = tools.currentLocation(),
isStateAllowedRemove = _.contains(basicFolders, currentLocation) || labelsModel.contains(currentLocation, "folders"),
current = tools.currentLocation(),
process = function(events) {
cache.events(events), !0 === alsoArchive && conversationApi.archive(ids)
},
getLabelsId = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
cb = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : angular.noop;
return _.chain(list).filter(cb).map(function(_ref10) {
return _ref10.ID
}).value() || []
},
toApplyLabels = getLabelsId(labels, function(_ref11) {
return !0 === _ref11.Selected
}),
toRemoveLabels = getLabelsId(labels, function(_ref12) {
return !1 === _ref12.Selected
}),
toApply = [].concat(toApplyLabels),
toRemove = [].concat(toRemoveLabels);
!0 === alsoArchive && (toApply.push(MAILBOX_IDENTIFIERS.archive), isStateAllowedRemove && toRemove.push(current));
var events = _.chain(ids).map(function(id) {
return cache.getConversationCached(id)
}).filter(Boolean).reduce(function(acc, _ref13) {
var ID = _ref13.ID,
ContextNumUnread = _ref13.ContextNumUnread,
messages = cache.queryMessagesCached(ID);
return _.each(messages, function(message) {
var toApply = [].concat(toApplyLabels),
toRemove = [].concat(toRemoveLabels);
!0 === alsoArchive && (toApply.push(MAILBOX_IDENTIFIERS.archive), isStateAllowedRemove && toRemove.push(current)), acc.push({
Action: 3,
ID: message.ID,
Message: {
ID: message.ID,
IsRead: message.IsRead,
LabelIDsAdded: toApply,
LabelIDsRemoved: toRemove
}
})
}), acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
ContextNumUnread: ContextNumUnread,
Selected: !1,
LabelIDsAdded: toApply,
LabelIDsRemoved: toRemove
}
}), acc
}, []).value(),
getPromises = function(list) {
var starter = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
flag = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1;
return _.reduce(list, function(acc, id) {
return acc.push(conversationApi.labels(id, flag, ids)), acc
}, starter)
},
promise = Promise.all(getPromises(toRemove, getPromises(toApply), 0));
if (cache.addToDispatcher(promise), tools.cacheContext()) return process(events);
promise.then(function() {
return process(events)
}), networkActivityTracker.track(promise)
}
function move() {
var conversationIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
labelID = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
folders = labelsModel.ids("folders"),
labels = labelsModel.ids("labels"),
toTrash = labelID === MAILBOX_IDENTIFIERS.trash,
toSpam = labelID === MAILBOX_IDENTIFIERS.spam,
toInbox = labelID === MAILBOX_IDENTIFIERS.inbox,
promise = conversationApi.labels(labelID, 1, conversationIDs),
folderName = getFolderNameTranslated(labelID),
successMessage = gettextCatalog.getPlural(conversationIDs.length, "Conversation moved to", "Conversations moved to", {}),
displaySuccess = function() {
return notification.success(successMessage + " " + unicodeTagView(folderName))
},
folderIDs = basicFolders.concat(folders).concat(toSpam || toTrash ? labels : []);
if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() {
return eventManager.call()
}).then(function() {
return displaySuccess()
}), networkActivityTracker.track(promise);
var labelIDsAdded = [labelID],
events = _.reduce(conversationIDs, function(acc, ID) {
var messages = cache.queryMessagesCached(ID);
_.each(messages, function(_ref14) {
var Type = _ref14.Type,
_ref14$LabelIDs = _ref14.LabelIDs,
LabelIDs = void 0 === _ref14$LabelIDs ? [] : _ref14$LabelIDs,
ID = _ref14.ID,
IsRead = _ref14.IsRead,
copyLabelIDsAdded = labelIDsAdded.slice(),
copyLabelIDsRemoved = _.filter(LabelIDs, function(labelID) {
return _.contains(folderIDs, labelID)
});
if (toInbox) switch (Type) {
case 1:
var index = copyLabelIDsAdded.indexOf(MAILBOX_IDENTIFIERS.inbox);
copyLabelIDsAdded.splice(index, 1), copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allDrafts);
break;
case 2:
var _index = copyLabelIDsAdded.indexOf(MAILBOX_IDENTIFIERS.inbox);
copyLabelIDsAdded.splice(_index, 1), copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allSent);
break;
case 3:
copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allSent)
}
acc.push({
ID: ID,
Action: 3,
Message: {
ID: ID,
IsRead: toTrash ? 1 : IsRead,
LabelIDsRemoved: copyLabelIDsRemoved,
LabelIDsAdded: copyLabelIDsAdded
}
})
});
var conversation = cache.getConversationCached(ID);
if (conversation) {
var labelIDsRemoved = _.chain(conversation.Labels).filter(function(_ref15) {
var ID = _ref15.ID;
return _.contains(folderIDs, ID)
}).map(function(_ref16) {
return _ref16.ID
}).value();
acc.push({
Action: 3,
ID: ID,
Conversation: {
ID: ID,
Selected: !1,
ContextNumUnread: toTrash ? 0 : conversation.ContextNumUnread,
LabelIDsRemoved: labelIDsRemoved,
LabelIDsAdded: labelIDsAdded
}
})
}
return acc
}, []);
cache.events(events), displaySuccess()
}
var _mailboxes, unicodeTagView = $filter("unicodeTagView"),
MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS,
basicFolders = [MAILBOX_IDENTIFIERS.inbox, MAILBOX_IDENTIFIERS.trash, MAILBOX_IDENTIFIERS.spam, MAILBOX_IDENTIFIERS.archive, MAILBOX_IDENTIFIERS.sent, MAILBOX_IDENTIFIERS.drafts],
mailboxes = (_mailboxes = {}, _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.inbox, gettextCatalog.getString("Inbox", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.spam, gettextCatalog.getString("Spam", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.drafts, gettextCatalog.getString("Drafts", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.allDrafts, gettextCatalog.getString("Drafts", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.sent, gettextCatalog.getString("Sent", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.allSent, gettextCatalog.getString("Sent", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.trash, gettextCatalog.getString("Trash", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.archive, gettextCatalog.getString("Archive", null)), _mailboxes);
return {
remove: remove,
unread: unread,
read: read,
unstar: unstar,
star: star,
label: label,
move: move
}
}), angular.module("proton.conversation").factory("conversationApi", function($http, url) {
var requestURL = url.build("conversations");
return {
query: function() {
var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $http({
url: requestURL(),
method: "GET",
params: params
})
},
get: function() {
var ConversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return $http.get(requestURL(ConversationID))
},
count: function() {
return $http.get(requestURL("count"))
},
star: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("star"), {
IDs: IDs
})
},
unstar: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("unstar"), {
IDs: IDs
})
},
read: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("read"), {
IDs: IDs
})
},
unread: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
LabelID = arguments[1];
return $http.put(requestURL("unread"), {
IDs: IDs,
LabelID: LabelID
})
},
trash: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("trash"), {
IDs: IDs
})
},
inbox: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("inbox"), {
IDs: IDs
})
},
spam: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("spam"), {
IDs: IDs
})
},
archive: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return $http.put(requestURL("archive"), {
IDs: IDs
})
},
delete: function() {
var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
LabelID = arguments[1];
return $http.put(requestURL("delete"), {
IDs: IDs,
LabelID: LabelID
})
},
labels: function() {
var LabelID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
Action = arguments[1],
ConversationIDs = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : [];
return $http.put(requestURL("label"), {
LabelID: LabelID,
Action: Action,
ConversationIDs: ConversationIDs
})
}
}
}), angular.module("proton.conversation").factory("conversationListeners", function($rootScope, CONSTANTS) {
function watch(message) {
var listeners = Object.keys(composerMapActions).map(function(key) {
return $rootScope.$on(key, openComposer(key, message))
});
return function() {
listeners.forEach(function(cb) {
return cb()
}), listeners.length = 0
}
}
var composerMapActions = {
replyConversation: "reply",
replyAllConversation: "replyall",
forwardConversation: "forward"
},
isDraft = function(_ref) {
return _ref.Type === CONSTANTS.DRAFT
},
isDecrypted = function(_ref2) {
return !_ref2.failedDecryption
},
openComposer = function(key) {
var message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return function() {
if (!isDraft(message) && isDecrypted(message)) {
var type = composerMapActions[key];
$rootScope.$emit("composer.new", {
type: type,
data: {
message: message
}
})
}
}
};
return watch
}), angular.module("proton.conversation").factory("mailboxIdentifersTemplate", function($rootScope, CONSTANTS, labelsModel) {
var CLEANER = document.createElement("div"),
contains = function(key, labels) {
return _.contains(labels, CONSTANTS.MAILBOX_IDENTIFIERS[key])
},
stripHTML = function(s) {
return CLEANER.innerText = s || "", CLEANER.innerHTML
},
templateTag = function(className, tooltip) {
return '<i class="' + className + '" translate>' + tooltip + "</i>"
},
templateLabel = function() {
var className = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
tooltip = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
color = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "",
ptTooltip = stripHTML(tooltip).replace(/"|'/g, "");
return color ? '<i class="fa ' + className + '" pt-tooltip="' + ptTooltip + '" style="color: ' + color + '"></i>' : '<i class="fa ' + className + '" pt-tooltip="' + ptTooltip + '"></i>'
},
getFolder = function() {
var labelIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
id = _.find(labelIDs, function(id) {
return labelsModel.contains(id, "folders")
});
return labelsModel.read(id, "folders") || {}
},
icon = function(_ref, templateMaker) {
var _ref$className = _ref.className,
className = void 0 === _ref$className ? "" : _ref$className,
_ref$tooltip = _ref.tooltip,
tooltip = void 0 === _ref$tooltip ? "" : _ref$tooltip,
_ref$color = _ref.color,
color = void 0 === _ref$color ? "" : _ref$color;
return className && tooltip ? templateMaker ? templateMaker(className, tooltip, color) : templateLabel(className, tooltip, color) : ""
},
escapeTooltip = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(/^{{/g, "{​{")
};
return function(_ref2) {
var MAP_LABELS = _ref2.MAP_LABELS,
MAP_TYPES = _ref2.MAP_TYPES;
return {
getTemplateLabels: function(labels) {
return Object.keys(MAP_LABELS).reduce(function(acc, key) {
if ("folder" === key) {
var _getFolder = getFolder(labels),
color = _getFolder.Color,
tooltip = _getFolder.Name;
return acc + icon(_.extend({}, MAP_LABELS[key], {
tooltip: escapeTooltip(tooltip),
color: color
}))
}
return contains(key, labels) ? acc + icon(MAP_LABELS[key]) : acc
}, "")
},
getTemplateType: function(type) {
return 2 === type || 3 === type ? icon(MAP_TYPES.sent, templateTag) : 1 === type ? icon(MAP_TYPES.drafts, templateTag) : ""
}
}
}
}), angular.module("proton.conversation").factory("conversationsInterceptor", function($q, $injector) {
return {
responseError: function() {
var rep = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
if (/\/conversations\//.test((rep.config || {}).url)) {
var cache = $injector.get("cache"),
cacheCounters = $injector.get("cacheCounters"),
eventManager = $injector.get("eventManager");
cache.reset(), cacheCounters.reset(), eventManager.call()
}
return $q.reject(rep)
}
}
}), angular.module("proton.conversation").factory("markedScroll", function() {
var CACHE = {},
getMarked = function() {
return CACHE.wrapper.querySelector(".conversation.marked")
};
return {
follow: function() {
CACHE.wrapper || (CACHE.wrapper = document.body.querySelector(".conversation-wrapper")), _rAF(function() {
var $marked = getMarked();
CACHE.wrapper.scrollTop = $marked.offsetTop - CACHE.wrapper.offsetHeight / 2
})
},
clear: function() {
return CACHE.wrapper = null
}
}
}), angular.module("proton.conversation").factory("messageScroll", function() {
function scroll(index, nodeMessage) {
var $header = document.getElementById("conversationHeader"),
$thread = document.getElementById("pm_thread");
if (0 === index) return $($thread).animate({
scrollTop: 0
}, 200);
var node = nodeMessage || document.getElementById("message" + index),
previous = document.getElementById("message" + (index - 1)),
headerOffset = $header ? $header.getBoundingClientRect().top + $header.offsetHeight : 0,
amountScrolled = $thread ? $thread.scrollTop : 0,
paddingTop = ~~$thread.style.paddingTop.replace("px", ""),
summaryHeight = document.getElementsByClassName("summary")[0].getBoundingClientRect().height,
scrollTop = node ? node.getBoundingClientRect().top + amountScrolled - headerOffset - paddingTop : 0;
scrollTop -= 1 === index || previous.classList.contains("open") ? summaryHeight / 2 + 10 : 1.5 * summaryHeight + 20, $($thread).animate({
scrollTop: scrollTop
}, 200)
}
var toID = function(ID) {
var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [];
return scroll(_.findIndex(list, {
ID: ID
}))
};
return {
to: function(_ref) {
scroll(_ref.index, _ref.node)
},
toID: toID
}
}), angular.module("proton.core").controller("HeaderController", function($rootScope, $scope, $state, authentication, organizationModel, CONSTANTS) {
var unsubscribes = [];
$scope.params = {}, $scope.user = authentication.user, $scope.organization = organizationModel.get(), $scope.wizardEnabled = CONSTANTS.WIZARD_ENABLED, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE, $scope.ctrl = {}, $scope.starred = 2, unsubscribes.push($rootScope.$on("organizationChange", function(event, newOrganization) {
$scope.organization = newOrganization
})), unsubscribes.push($rootScope.$on("updateUser", function() {
$scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE
})), $scope.$on("$destroy", function() {
unsubscribes.forEach(function(cb) {
return cb()
}), unsubscribes.length = 0
}), $scope.cancel = function() {
angular.isDefined($scope.params.cancel) && angular.isFunction($scope.params.cancel) && $scope.params.cancel()
}, $scope.activeSettings = function() {
return -1 !== ["dashboard", "account", "labels", "filters", "security", "appearance", "domains", "bridge", "signatures", "members", "payments", "keys", "vpn"].indexOf($state.$current.name.replace("secured.", ""))
}
}), angular.module("proton.core").controller("ResetController", function($scope, $rootScope, $state, $log, gettextCatalog, $q, $http, CONSTANTS, authentication, networkActivityTracker, User, Reset, Key, passwords, pmcw, tempStorage, tools, notification) {
$scope.generateKeys = function(mbpw) {
var promises = [],
keySalt = CONSTANTS.KEY_PHASE > 1 ? passwords.generateKeySalt() : null;
return $scope.process.genNewKeys = !0, passwords.computeKeyPassword(mbpw, keySalt).then(function(newMailboxPwd) {
return _.each($scope.addresses, function(address) {
promises.push(pmcw.generateKey({
userIds: [{
name: address.Email,
email: address.Email
}],
passphrase: newMailboxPwd
}).then(function(response) {
return {
AddressID: address.ID,
PrivateKey: response.privateKeyArmored
}
}, function(err) {
return $scope.process.genNewKeys = !1, $log.error(err), $scope.error = err, Promise.reject(err)
}))
}), $q.all(promises).then(function(keys) {
return $scope.process.generatingKeys = !0, {
KeySalt: keySalt,
PrimaryKey: keys[0].PrivateKey,
AddressKeys: keys
}
})
})
}, $scope.resetMailbox = function() {
if (void 0 === $scope.resetMailboxToken) return void notification.error("Missing reset token");
networkActivityTracker.track($scope.generateKeys($scope.account.mailboxPassword).then($scope.newMailbox).then($scope.resetMailboxTokenResponse).then($scope.doLogUserIn).then($scope.doMailboxLogin))
}, $scope.doLogUserIn = function() {
return authentication.loginWithCredentials({
Username: $scope.creds.username,
Password: $scope.creds.password
})
}, $scope.doMailboxLogin = function(_ref) {
var data = _ref.data;
return $scope.creds.authResponse = data, authentication.unlockWithPassword($scope.account.mailboxPassword, $scope.creds.authResponse).then(function() {
return authentication.setAuthCookie($scope.creds.authResponse).then(function() {
$scope.process.redirecting = !0, $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured(), $state.go("secured.inbox")
}, function() {
notification.error("doMailboxLogin: Unable to set authCookie.")
})
}, function() {
notification.error("doMailboxLogin: Unable to unlock mailbox.")
})
}, $scope.verifyResetCode = function() {
angular.isUndefined($scope.account.resetMbCode) || 0 === $scope.account.resetMbCode.length ? notification.info("Verification Code required") : Reset.validateResetToken({
Username: $scope.creds.username,
Token: $scope.account.resetMbCode
}).then(function(response) {
1e3 !== response.data.Code ? notification.error("Invalid Verification Code.") : ($scope.addresses = response.data.Addresses, $scope.resetMailboxToken = $scope.account.resetMbCode, $scope.showForm = !0, $scope.showEmailMessage = !1)
}, function(err) {
$log.error(err), notification.error("Unable to verify Reset Token.")
})
}, $scope.resetMailboxInit = function() {
if ("DANGER" !== $scope.process.danger) return notification.error("Invalid value"), !1;
angular.isDefined($scope.creds) && angular.isDefined($scope.creds.authResponse) && ($http.defaults.headers.common.Authorization = "Bearer " + $scope.creds.authResponse.ResetToken, $http.defaults.headers.common["x-pm-uid"] = $scope.creds.authResponse.Uid);
var tokenResponse = function(response) {
var deferred = $q.defer();
return response.data.Error || 1e3 !== response.data.Code ? (notification.info(response), $log.error(response), deferred.reject(response.data.Error)) : response.data.Token ? ($scope.resetMailboxToken = response.data.Token, Reset.validateResetToken({
Username: $scope.creds.username,
Token: response.data.Token
}).then(function(response) {
1e3 !== response.data.Code ? notification.error("Invalid Verification Code.") : ($scope.addresses = response.data.Addresses, $scope.showForm = !0, $scope.showEmailMessage = !1, deferred.resolve(200))
}, function(err) {
$log.error(err), notification.error("Unable to verify Reset Token.")
})) : ($scope.showEmailMessage = !0, deferred.resolve(200)), deferred.promise
};
networkActivityTracker.track(function() {
return Reset.getMailboxResetToken({})
}().then(tokenResponse))
}, $scope.cancelReset = function() {
tempStorage.setItem("creds", $scope.creds), $state.go("login.unlock")
}, $scope.newMailbox = function(params) {
var resetMBtoken = void 0;
return void 0 !== $scope.resetMailboxToken && (resetMBtoken = $scope.resetMailboxToken), params.Token = resetMBtoken, Key.reset(params)
}, $scope.resetMailboxTokenResponse = function(response) {
var promise = $q.defer();
return response || promise.reject(new Error("Connection error: Unable to save new keys.")), 200 !== response.status ? (notification.error("Error, try again in a few minutes."), $scope.process.savingKeys = !1, promise.reject(new Error("Status Error: Unable to save new keys."))) : response.data.Error ? "" !== response.data.ErrorDescription ? (notification.error(response.data.ErrorDescription), $log.error(response), $scope.process.savingKeys = !1, promise.reject(new Error(response.data.ErrorDescription))) : (notification.error(response.data.Error), $log.error(response), $scope.process.savingKeys = !1, promise.reject(new Error(response.data.Error))) : ($scope.process.savingKeys = !0, promise.resolve(200)), promise
},
function() {
$scope.creds = tempStorage.getItem("creds"), $scope.creds && $scope.creds.authResponse || $state.go("login"), $scope.tools = tools, $scope.resetMailboxToken = void 0, $scope.account = [], $scope.addresses = [], $scope.process = {}, $scope.process.danger = "", $scope.process.generatingKeys = !1, $scope.process.savingKeys = !1, $scope.process.redirecting = !1, $scope.showForm = !1
}()
}), angular.module("proton.core").controller("SecuredController", function($rootScope, $scope, $state, authentication, cacheCounters, contactCache, CONSTANTS, eventManager, hotkeys, AppModel, desktopNotifications, attachSignupSubscription, addressWithoutKeysManager) {
$scope.inboxSidebar = AppModel.is("inboxSidebar"), $scope.showSidebar = AppModel.is("showSidebar"), $scope.settingsSidebar = AppModel.is("settingsSidebar"), $scope.contactSidebar = AppModel.is("contactSidebar"), $scope.mobileMode = AppModel.is("mobile"), $scope.tabletMode = AppModel.is("tablet"), $scope.user = authentication.user, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE, $scope.keyPhase = CONSTANTS.KEY_PHASE, $rootScope.isLoggedIn = !0, $rootScope.isLocked = !1;
var bindAppValue = function(key, _ref) {
var value = _ref.value;
return $scope.$applyAsync(function() {
return $scope[key] = value
})
},
unsubscribe = $rootScope.$on("AppModel", function(e, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"inboxSidebar" === type && bindAppValue(type, data), "mobile" === type && bindAppValue("mobileMode", data), "tablet" === type && bindAppValue("tabletMode", data), "showSidebar" === type && bindAppValue(type, data), "settingsSidebar" === type && bindAppValue(type, data), "contactSidebar" === type && bindAppValue(type, data)
});
desktopNotifications.request(), 1 === authentication.user.Hotkeys ? hotkeys.bind() : hotkeys.unbind(), attachSignupSubscription(), eventManager.start(authentication.user.EventID), cacheCounters.query(), !$state.includes("secured.contacts") && contactCache.load(), addressWithoutKeysManager.manage().catch(_.noop), $scope.$on("updateUser", function() {
$scope.$applyAsync(function() {
$scope.user = authentication.user, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE
})
}), $scope.idDefined = function() {
return $state.params.id && $state.params.id.length > 0
}, $scope.isMobile = function() {
return AppModel.is("mobile")
}, $scope.$on("$destroy", function() {
hotkeys.unbind(), unsubscribe()
})
}), angular.module("proton.core").controller("SetupController", function($http, $location, $log, $q, $rootScope, $scope, $state, Address, authentication, CONSTANTS, confirmModal, domains, gettextCatalog, Key, networkActivityTracker, Payment, passwords, pmcw, Reset, secureSessionStorage, setupKeys, tools, user) {
function setupAddress() {
return $log.debug("setupAddress"), $scope.filling = !1, 0 === user.Addresses.length ? Address.setup({
Domain: $scope.domain.value
}).then(function(result) {
return result.data && 1e3 === result.data.Code ? (user.Addresses = [result.data.Address], user) : result.data && result.data.Error ? $q.reject({
message: result.data.Error
}) : $q.reject({
message: "Something went wrong during address creation"
})
}) : $q.resolve(user)
}
function generateKeys() {
return $log.debug("generateKeys"), $scope.genKeys = !0, setupKeys.generate(user.Addresses, passwordCopy)
}
function installKeys() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $log.debug("installKeys"), $scope.genKeys = !1, $scope.creating = !0, $scope.setupAccount = !0, setupKeys.setup(data, passwordCopy).then(function() {
authentication.savePassword(data.mailboxPassword), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured()
})
}
function doGetUserInfo() {
return $log.debug("getUserInfo"), $scope.getUserInfo = !0, authentication.fetchUserInfo()
}
function finishRedirect() {
if ($log.debug("finishRedirect"), $scope.finishCreation = !0, authentication.user.Delinquent < UNPAID_STATE.DELINQUENT) return $state.go("secured.inbox", {
welcome: WIZARD_ENABLED
});
$state.go("secured.dashboard")
}
var passwordCopy = void 0,
WIZARD_ENABLED = CONSTANTS.WIZARD_ENABLED,
KEY_PHASE = CONSTANTS.KEY_PHASE,
UNPAID_STATE = CONSTANTS.UNPAID_STATE;
$scope.submit = function() {
return passwordCopy = $scope.password, networkActivityTracker.track(setupAddress().then(generateKeys).then(installKeys).then(doGetUserInfo).then(finishRedirect)).catch(function() {
$scope.setupError = !0
})
},
function() {
$scope.keyPhase = KEY_PHASE, $scope.tools = tools, $scope.filling = !0, $scope.creating = !1, $scope.genKeys = !1, $scope.setupAccount = !1, $scope.getUserInfo = !1, $scope.finishCreation = !1, $scope.generating = !1, $scope.domains = [], _.each(domains, function(domain) {
$scope.domains.push({
label: domain,
value: domain
})
}), $scope.username = user.Name, $scope.domain = $scope.domains[0], $scope.chooseDomain = 0 === user.Addresses.length, $scope.password = "", $scope.passwordConfirm = ""
}()
}), angular.module("proton.core").controller("SignupController", function($location, $rootScope, $scope, $state, $stateParams, authentication, domains, gettextCatalog, networkActivityTracker, notification, plans, AppModel, signupModel, signupUserProcess) {
function generateUserKeys() {
$scope.step = 2;
var promise = signupUserProcess.generateNewKeys().then(function() {
if (AppModel.is("preInvited")) return createAccount();
if (plans.length) {
if (signupModel.optionsHumanCheck("payment")) return $scope.step = 4;
$scope.step = 3;
var message = gettextCatalog.getString("It currently isn't possible to subscribe to a Paid ProtonMail plan.", null);
return notification.info(message)
}
$scope.step = 3
});
networkActivityTracker.track(promise)
}
function verify(_ref) {
var Payment = _ref.Payment,
Amount = _ref.Amount,
Currency = _ref.Currency,
GiftCode = _ref.GiftCode,
Credit = _ref.Credit;
signupModel.verify({
Payment: Payment,
Amount: Amount,
Currency: Currency,
GiftCode: GiftCode,
Credit: Credit
}, $scope.plan).then(createAccount)
}
function applyGift(opt) {
signupModel.applyGiftCode(opt).then(function(data) {
return notification.success(I18N.success), data
})
}
var unsubscribe = [],
I18N = {
success: gettextCatalog.getString("Gift code applied", null, "Success")
};
$scope.step = 1, $scope.plans = plans, $scope.domains = _.map(domains, function(value) {
return {
label: value,
value: value
}
}), $scope.isFromInvitation = AppModel.is("preInvited"), $scope.account = {
username: function() {
return $location.search().u || $stateParams.username || ""
}(),
domain: $scope.domains[0],
codeVerification: "",
captcha_token: !1,
smsCodeVerification: "",
emailVerification: ""
}, authentication.logout(!1, authentication.isLoggedIn()), plans.length && ($scope.plan = _.findWhere(plans, {
Name: $stateParams.plan,
Cycle: parseInt($stateParams.billing, 10),
Currency: $stateParams.currency
}));
var createAccount = function() {
return $scope.step = 5, signupUserProcess.createAccount($scope.account)
};
unsubscribe.push($rootScope.$on("payments", function(e, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
if ("create.account" === type && ("humanVerification" !== data.action && createAccount(), "humanVerification" === data.action)) {
var _data$options = data.options;
verify({
Payment: _data$options.Payment,
Amount: _data$options.Amount,
Currency: _data$options.Currency
})
}
}));
var bindStep = function(key, value) {
return $scope.$applyAsync(function() {
return $scope[key] = value
})
};
unsubscribe.push($rootScope.$on("signup", function(e, _ref3) {
var type = _ref3.type,
data = _ref3.data;
if ("chech.humanity" === type && bindStep("step", 3), "creating" === type && bindStep("step", 5), "signup.error" === type && bindStep("signupError", data.value), "goto.step" === type && bindStep("step", data.value), "userform.submit" === type && generateUserKeys(), "humanform.submit" === type && createAccount(), "apply.gift" === type && applyGift(data), "payform.submit" === type) {
var _data$payment = data.payment;
verify({
Payment: _data$payment.method,
Amount: _data$payment.Amount,
Currency: _data$payment.Currency,
GiftCode: _data$payment.GiftCode,
Credit: _data$payment.Credit
})
}
})), $scope.$on("$destroy", function() {
unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
})
}), angular.module("proton.core").controller("SupportController", function($rootScope, $scope, $state, $log, authentication, CONSTANTS, tempStorage, User, tools, notification, gettextCatalog, confirmModal, Reset, setupKeys, Key, networkActivityTracker) {
function resetState() {
$scope.params.resetToken = "", $scope.params.danger = "", $scope.params.password = "", $scope.params.passwordConfirm = "", $scope.resetState = $scope.states.RECOVERY
}
function resetLostPassword() {
$scope.params.username = $scope.params.username;
var promise = Reset.requestResetToken({
Username: $scope.params.username,
NotificationEmail: $scope.params.recoveryEmail
}).then(function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) $scope.resetState = $scope.states.CODE;
else if (data.Error) return Promise.reject(data.Error)
});
networkActivityTracker.track(promise)
}
function doReset() {
return 2 === $scope.passwordMode && $scope.keyPhase < 3 ? Reset.resetPassword($scope.tokenParams, $scope.params.password).then(function() {
var response = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_response$data = response.data,
data = void 0 === _response$data ? {} : _response$data;
return 1e3 === data.Code ? response : Promise.reject({
message: data.Error || "Unable to update password. Please try again"
})
}) : generateKeys().then(installKeys)
}
function generateKeys() {
return $log.debug("generateKeys"), $scope.resetState = $scope.states.GENERATE, setupKeys.generate($scope.addresses, $scope.params.password)
}
function installKeys() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return $log.debug("installKeys"), $scope.resetState = $scope.states.INSTALL, $scope.resetAccount = !0, setupKeys.reset(data, $scope.params.password, $scope.tokenParams)
}
function doLogUserIn() {
return $scope.logUserIn = !0, authentication.loginWithCredentials({
Username: $scope.params.username,
Password: $scope.params.password
}).then(function(_ref3) {
var data = _ref3.data;
return $rootScope.isLoggedIn = !0, data
})
}
function finishRedirect(authResponse) {
$log.debug("finishRedirect"), $scope.finishInstall = !0;
var creds = {
username: $scope.params.username,
password: $scope.params.password,
authResponse: authResponse
};
tempStorage.setItem("creds", creds), $state.go("login.unlock")
}
var GENERIC_MESSAGE = {
title: gettextCatalog.getString("Problem loading your account", null, "Title"),
content: gettextCatalog.getString("ProtonMail encountered a problem loading your account. Please refresh the page and try again later.", null, "Info"),
type: "alert-danger"
};
$scope.keyPhase = CONSTANTS.KEY_PHASE, $scope.states = {
RECOVERY: 1,
CODE: 2,
CHECKING: 3,
DANGER: 4,
PASSWORD: 5,
GENERATE: 6,
INSTALL: 7
}, $scope.tools = tools, $scope.params = {}, $scope.params.recoveryEmail = "", $scope.params.username = "", $scope.passwordMode = 0, resetState(), $scope.resetAccount = !1, $scope.logUserIn = !1, $scope.finishInstall = !1, $scope.getMessageTitle = function() {
return $state.params.data.title || GENERIC_MESSAGE.title
}, $scope.getMessageContent = function() {
return $state.params.data.content || GENERIC_MESSAGE.content
}, $scope.getMessageType = function() {
return $state.params.data.type || GENERIC_MESSAGE.type
}, $scope.confirmResetLostPassword = function() {
var title = gettextCatalog.getString("Confirm Reset Password", null, "Title"),
message = gettextCatalog.getString('Resetting your password means you will no longer be able to read your old emails. <a href="https://protonmail.com/support/knowledge-base/updating-your-login-password/" target="_blank">Click here to learn more</a>. If you have further questions, please email [email protected]. Are you sure you want to reset your password?', null, "Title");
confirmModal.activate({
params: {
title: title,
message: message,
confirm: function() {
confirmModal.deactivate(), resetLostPassword()
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}, $scope.validateToken = function() {
$scope.resetState = $scope.states.CHECKING, $scope.tokenParams = {
Username: $scope.params.username,
Token: $scope.params.resetToken
}, Reset.validateResetToken($scope.tokenParams).then(function(_ref2) {
var _ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
if (1e3 !== data.Code) return Promise.reject({
message: data.Error || "Unable to verify reset token"
});
$scope.passwordMode = data.PasswordMode, $scope.addresses = data.Addresses, $scope.resetState = $scope.states.DANGER, 2 === $scope.passwordMode && $scope.keyPhase < 3 && ($scope.resetState = $scope.states.PASSWORD)
}).catch(function(error) {
resetState(), $log.error(error), notification.error(error.message)
})
}, $scope.confirmReset = function() {
$scope.resetState = $scope.states.PASSWORD
}, $scope.resetPassword = function() {
networkActivityTracker.track(doReset().then(doLogUserIn).then(finishRedirect).catch(function(error) {
$log.error(error), resetState(), notification.error(error.message)
}))
}, $state.is("support.reset-password") && $state.params.username && $state.params.token && ($scope.resetState = $scope.states.CHECKING, $scope.params.username = $state.params.username,
$scope.params.resetToken = $state.params.token, $scope.validateToken())
}), angular.module("proton.core").directive("cardPanel", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/directives/core/cardPanel.tpl.html",
scope: {
card: "="
}
}
}), angular.module("proton.core").directive("hideUpgrade", function(organizationModel, $rootScope) {
var HIDE_UPGRADE_CLASS = "hideUpgrade";
return {
restrict: "A",
link: function(scope, element) {
function update(_ref) {
return "visionary" === _ref.PlanName ? element[0].classList.add(HIDE_UPGRADE_CLASS) : element[0].classList.remove(HIDE_UPGRADE_CLASS)
}
var unsubscribe = $rootScope.$on("organizationChange", function(event, newOrganization) {
return update(newOrganization)
});
update(organizationModel.get()), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.core").directive("paginator", function($rootScope, $stateParams, paginationModel, CONSTANTS) {
var ELEMENTS_PER_PAGE = CONSTANTS.ELEMENTS_PER_PAGE,
buildClassNames = function(scope) {
var className = [],
maxPageNumber = paginationModel.getMaxPage();
return 1 === (~~$stateParams.page || 1) && className.push("paginator-disabled-previous"), (paginationModel.isMax() || 0 === scope.totalItems) && className.push("paginator-disabled-next"), 0 !== maxPageNumber && 1 !== maxPageNumber && 0 !== scope.totalItems || className.push("paginator-disabled-main"), className.join(" ")
},
buildPageList = function() {
var size = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 1;
return _.range(1, size + 1)
},
buildPages = function() {
var size = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ELEMENTS_PER_PAGE,
total = Math.ceil(size / ELEMENTS_PER_PAGE),
value = ~~$stateParams.page > total ? ~~$stateParams.page : total;
return buildPageList(value)
},
onAction = function(key) {
return function(e) {
return e.preventDefault(), paginationModel[key]()
}
};
return {
restrict: "E",
replace: !0,
templateUrl: "templates/directives/paginator.tpl.html",
scope: {
totalItems: "="
},
link: function(scope, el) {
scope.pages = buildPageList(paginationModel.getMaxPage()), scope.page = ~~$stateParams.page || 1;
var rawClassNames = el[0].className;
el[0].className += " " + buildClassNames(scope);
var $next = el[0].querySelector(".paginator-btn-next"),
$previous = el[0].querySelector(".paginator-btn-previous"),
$dropdown = el[0].querySelector(".paginator-dropdown-list"),
onNext = onAction("next"),
onPrevious = onAction("previous"),
onSelect = function(e) {
e.preventDefault();
var target = e.target;
target.classList.contains("paginator-dropdown-item") && paginationModel.to({
page: +target.getAttribute("data-value")
})
};
$next.addEventListener("click", onNext, !1), $previous.addEventListener("click", onPrevious, !1), $dropdown.addEventListener("click", onSelect, !1);
var unsubscribe = $rootScope.$on("app.cacheCounters", function(event, _ref) {
var type = _ref.type,
data = _ref.data;
"refresh.currentState" === type && scope.$applyAsync(function() {
scope.pages = buildPages(data.value), el[0].className = rawClassNames + " " + buildClassNames(scope)
})
});
scope.$on("$destroy", function() {
$next.removeEventListener("click", onNext), $previous.removeEventListener("click", onPrevious), $dropdown.removeEventListener("click", onSelect, !1), unsubscribe()
})
}
}
}), angular.module("proton.core").directive("paginatorScope", function($rootScope) {
return {
restrict: "E",
replace: !0,
templateUrl: "templates/directives/paginatorScope.tpl.html",
scope: {
page: "=",
totalItems: "=",
itemsPerPage: "=",
change: "="
},
link: function(scope, el, attribute) {
scope.pages = [];
var disable = function() {
scope.disableMain = 1 === Math.ceil(scope.totalItems / scope.itemsPerPage) || 0 === scope.totalItems, scope.disableP = 1 === scope.page || 0 === scope.totalItems, scope.disableN = Math.ceil(scope.totalItems / scope.itemsPerPage) === scope.page || 0 === scope.totalItems
},
buildPages = function() {
var pages = void 0,
temp = [];
pages = scope.totalItems % scope.itemsPerPage == 0 ? scope.totalItems / scope.itemsPerPage : Math.floor(scope.totalItems / scope.itemsPerPage) + 1;
for (var i = 1; i <= pages; ++i) temp.push(i);
scope.pages = temp
};
scope.select = function(p) {
scope.change(p), scope.$applyAsync(function() {
return disable()
})
}, scope.next = function() {
return scope.change(scope.page + 1)
}, scope.previous = function() {
return scope.change(scope.page - 1)
}, scope.$watch("totalItems", function() {
disable(), buildPages()
});
var unsubscribe = $rootScope.$on("paginatorScope", function(e, _ref) {
var type = _ref.type,
page = _ref.page;
type === attribute.type && (scope.page = page, disable())
});
scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.core").directive("placeholderProgress", function(authentication, $filter) {
var humanSize = $filter("humanSize"),
percentage = $filter("percentage"),
percentageValue = function() {
return percentage(authentication.user.UsedSpace, authentication.user.MaxSpace)
};
return {
templateUrl: "templates/directives/core/placeholderProgress.tpl.html",
replace: !0,
link: function(scope) {
scope.storageStyle = function() {
return {
width: percentageValue() + "%"
}
}, scope.usedSpace = humanSize(authentication.user.UsedSpace), scope.maxSpace = humanSize(authentication.user.MaxSpace)
}
}
}), angular.module("proton.core").factory("alertModal", function(pmModal) {
return pmModal({
controller: function(params) {
this.title = params.title, this.message = params.message, this.alert = params.alert || "alert-info", this.ok = function() {
params.ok()
}
},
controllerAs: "ctrl",
templateUrl: "templates/modals/alert.tpl.html"
})
}), angular.module("proton.core").factory("browserFingerprint", function() {
function get() {
return new Promise(function(resolve, reject) {
try {
(new window.Fingerprint2).get(function(fingerprint, components) {
resolve({
fingerprint: fingerprint,
components: components
})
})
} catch (error) {
reject(error)
}
})
}
return {
get: get
}
}), angular.module("proton.core").factory("bugModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/bug.tpl.html",
controller: function(params) {
var _this = this;
this.form = params.form, this.form.attachScreenshot = !1, this.submit = function() {
params.submit && params.submit(_this.form)
}, this.cancel = function() {
params.cancel && params.cancel()
}
}
})
}), angular.module("proton.core").factory("cardModal", function(pmModal, Payment, gettextCatalog, cardModel, networkActivityTracker, paymentModel) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/card.tpl.html",
controller: function(params) {
var self = this;
self.card = {}, params.method ? (self.text = gettextCatalog.getString("Update your credit card information.", null, "Credit card modal"), self.mode = "display", self.panel = {
fullname: params.method.Details.Name,
number: "•••• •••• •••• " + params.method.Details.Last4,
month: params.method.Details.ExpMonth,
year: params.method.Details.ExpYear,
cvc: "•••",
zip: params.method.Details.ZIP,
country: params.method.Details.Country
}) : (self.text = gettextCatalog.getString("Add a credit card.", null, "Credit card modal"), self.mode = "edition");
var method = function() {
if ("edition" === self.mode) {
var card = cardModel(self.card);
return Payment.updateMethod({
Type: "card",
Details: card.details()
}).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data.PaymentMethod
}).catch(function(_ref2) {
var _ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
throw Error(data.Error)
})
}
return Promise.resolve()
};
self.edit = function() {
self.card.fullname = self.panel.fullname, self.mode = "edition"
}, self.submit = function() {
var promise = method().then(function(method) {
return paymentModel.getMethods(!0).then(function(methods) {
return {
method: method,
methods: methods
}
})
}).then(params.close);
networkActivityTracker.track(promise)
}, self.cancel = params.close
}
})
}), angular.module("proton.core").factory("checkTypoEmails", function() {
var addresses = ["prontonmail.", "prtonmail.", "protomail.", "protonmai.", "protonmsil.", "ptotonmail."].reduce(function(previousValue, currentValue) {
return previousValue.concat([currentValue + "ch", currentValue + "com"])
}, []).concat(["gmail.co", "yahoo.co"]);
return function() {
var email = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
splitter = email.split("@");
if (splitter.length) {
var domain = splitter[1];
return addresses.indexOf(domain) > -1
}
return !1
}
}), angular.module("proton.core").factory("confirmModal", function(pmModal, gettextCatalog) {
var I18N = {
confirm: gettextCatalog.getString("Confirm", null, "Default text for the confirm button in the confirm modal"),
cancel: gettextCatalog.getString("Cancel", null, "Default text for the cancel button in the confirm modal")
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/confirm.tpl.html",
controller: function(params, hotkeys) {
hotkeys.unbind(["enter"]), this.title = params.title, this.message = params.message, this.confirmText = params.confirmText || I18N.confirm, this.cancelText = params.cancelText || I18N.cancel, this.confirm = function() {
return hotkeys.bind(["enter"]), params.confirm()
}, this.cancel = function() {
return hotkeys.bind(["enter"]), params.cancel()
}, setTimeout(function() {
return angular.element("#confirmModalBtn").focus()
}, 100)
}
})
}), angular.module("proton.core").factory("consoleMessage", function($log) {
var styles = {
span: "color: #505061; font-size: 14px;",
strong: "color: #505061; font-size: 14px; font-weight: bold;",
alert: "color: #FF5956; font-size: 18px; font-weight: bold;",
alertSpan: "color: #FF5956; font-size: 14px;",
link: "color: #9397cd; font-size: 14px;"
};
return function() {
$log.info("%cFind a %csecurity bug?%c🐛 [email protected]", styles.span, styles.strong, styles.link), $log.info("%cWe're %chiring!â›° %chttps://protonmail.com/careers", styles.span, styles.strong, styles.link)
}
}), angular.module("proton.core").factory("csv", function(csvFormat) {
var properties = csvFormat.getAllProperties(),
toVCard = function(contact) {
return _.reduce(properties, function(acc) {
var key = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
props = csvFormat[key](contact);
return props.length && _.each(props, function(_ref) {
var _ref$value = _ref.value,
value = void 0 === _ref$value ? "" : _ref$value,
_ref$parameter = _ref.parameter,
parameter = void 0 === _ref$parameter ? "" : _ref$parameter,
params = {};
parameter && (params.type = parameter), acc.add(key, value, params)
}), acc
}, new vCard)
};
return {
csvToVCard: function(file) {
return new Promise(function(resolve, reject) {
var onComplete = function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref2$data = _ref2.data;
return resolve((void 0 === _ref2$data ? [] : _ref2$data).map(toVCard))
};
Papa.parse(file, {
header: !0,
dynamicTyping: !0,
complete: onComplete,
error: reject,
skipEmptyLines: !0
})
})
}
}
}), angular.module("proton.core").factory("csvFormat", function() {
var PROPERTIES = {
adr: [],
anniversary: ["Anniversary"],
bday: ["Birthday"],
email: ["E-mail Address", "E-mail 2 Address", "E-mail 3 Address", "Email", "Alternate Email 1", "Alternate Email 2", "Primary Email", "Secondary Email"],
fn: [],
gender: ["Gender"],
geo: ["Geolocation", "Location"],
impp: ["Impp"],
lang: ["Language"],
logo: ["Logo"],
member: ["Membmer", "Group Membership"],
nickname: ["Nickname", "Display Name", "Screen Name"],
note: ["Notes", "Note"],
org: ["Company", "Organization", "Department"],
photo: ["Photo", "Avatar"],
prodid: ["Software"],
rev: ["Revision"],
role: ["Role"],
sound: ["Sound"],
tel: ["Primary Phone", "Other Phone", "Radio Phone", "Other", "Yahoo Phone"],
title: ["Title", "Job Title", "JobTitle"],
tz: ["Timezone", "TimeZone"],
uid: ["UID"],
url: ["URL", "Web Page", "Personal Website", "Business Website", "Website", "Web Page 1", "Web Page 2", "Personal Web Page"]
},
PHONES = {
Home: ["Home Phone", "Home Phone 2"],
Work: ["Work Phone", "Company Main Phone", "Business Phone", "Business Phone 2"],
Mobile: ["Mobile", "Mobile Number", "Mobile Phone"],
Fax: ["Fax", "Fax Number", "Home Fax", "Business Fax", "Other Fax", "Telex"],
Pager: ["Pager", "Pager Number"],
Car: ["Car Phone"]
},
parameters = {
Fax: ["Fax"],
Home: ["Home"],
Work: ["Work", "Business"],
Mobile: ["Mobile"],
Personal: ["Personal", "Perso", "Main", "Primary"]
},
getParameter = function() {
var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return _.chain(Object.keys(parameters)).filter(function(param) {
return parameters[param].filter(function(value) {
return key.indexOf(value) > -1
}).length > 0
}).first().value()
},
extractKeys = function() {
var keys = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
contact = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return keys.reduce(function(acc, key) {
var value = contact[key];
if (value) {
var property = {
value: value.toString()
},
parameter = getParameter(key);
parameter && (property.parameter = parameter), acc.push(property)
}
return acc
}, [])
},
extractAddress = function(contact, type) {
var address = contact[type + " Address"] || contact[type + " Street"] || "",
address2 = contact[type + " Address 2"] || contact[type + " Street 2"] || "",
city = contact[type + " City"] || "",
state = contact[type + " State"] || "",
zipCode = contact[type + " ZipCode"] || contact[type + " Postal Code"] || contact[type + " ZIP"] || "",
country = contact[type + " Country"] || contact[type + " Country/Region"] || "",
value = ["", address2, address, city, state, zipCode, country];
return value.join("").trim().length ? value.join(";").trim() : ""
},
getAllProperties = function() {
return Object.keys(PROPERTIES)
},
anniversary = function(contact) {
return extractKeys(PROPERTIES.anniversary, contact)
},
gender = function(contact) {
return extractKeys(PROPERTIES.gender, contact)
},
geo = function(contact) {
return extractKeys(PROPERTIES.geo, contact)
},
impp = function(contact) {
return extractKeys(PROPERTIES.impp, contact)
},
lang = function(contact) {
return extractKeys(PROPERTIES.lang, contact)
},
logo = function(contact) {
return extractKeys(PROPERTIES.logo, contact)
},
member = function(contact) {
return extractKeys(PROPERTIES.member, contact)
},
nickname = function(contact) {
return extractKeys(PROPERTIES.nickname, contact)
},
note = function(contact) {
return extractKeys(PROPERTIES.note, contact)
},
org = function(contact) {
return extractKeys(PROPERTIES.org, contact)
},
photo = function(contact) {
return extractKeys(PROPERTIES.photo, contact)
},
prodid = function(contact) {
return extractKeys(PROPERTIES.prodid, contact)
},
rev = function(contact) {
return extractKeys(PROPERTIES.csv, contact)
},
role = function(contact) {
return extractKeys(PROPERTIES.role, contact)
},
sound = function(contact) {
return extractKeys(PROPERTIES.sound, contact)
},
title = function(contact) {
return extractKeys(PROPERTIES.title, contact)
},
tz = function(contact) {
return extractKeys(PROPERTIES.tz, contact)
},
uid = function(contact) {
return extractKeys(PROPERTIES.uid, contact)
},
url = function(contact) {
return extractKeys(PROPERTIES.url, contact)
};
return {
getAllProperties: getAllProperties,
adr: function(contact) {
var addresses = [];
if (_.each(["Home", "Work", "Business", "Other"], function(type) {
var value = extractAddress(contact, type);
value && addresses.push({
value: value,
type: type
})
}), contact["Address 1 - Formatted"]) {
var address = {
value: contact["Address 1 - Formatted"]
};
contact["Address 2 - Type"] && (address.parameter = contact["Address 1 - Type"]), addresses.push(address)
}
if (contact["Address 2 - Formatted"]) {
var _address = {
value: contact["Address 2 - Formatted"]
};
contact["Address 2 - Type"] && (_address.parameter = contact["Address 2 - Type"]), addresses.push(_address)
}
if (contact["Address 3 - Formatted"]) {
var _address2 = {
value: contact["Address 3 - Formatted"]
};
contact["Address 3 - Type"] && (_address2.parameter = contact["Address 3 - Type"]), addresses.push(_address2)
}
return addresses
},
anniversary: anniversary,
bday: function(contact) {
var bdays = extractKeys(PROPERTIES.bday, contact),
year = contact["Birth Year"],
month = contact["Birth Month"],
day = contact["Birth Day"];
return year && month && day && bdays.push(year + "-" + month + "-" + day), bdays
},
email: function(contact) {
var emails = extractKeys(PROPERTIES.email, contact);
if (contact["E-mail 1 - Value"]) {
var _email = {
value: contact["E-mail 1 - Value"]
};
contact["E-mail 1 - Type"] && (_email.parameter = contact["E-mail 1 - Type"]), emails.push(_email)
}
if (contact["E-mail 2 - Value"]) {
var _email2 = {
value: contact["E-mail 2 - Value"]
};
contact["E-mail 2 - Type"] && (_email2.parameter = contact["E-mail 2 - Type"]), emails.push(_email2)
}
if (contact["E-mail 3 - Value"]) {
var _email3 = {
value: contact["E-mail 3 - Value"]
};
contact["E-mail 3 - Type"] && (_email3.parameter = contact["E-mail 3 - Type"]), emails.push(_email3)
}
return emails
},
fn: function(contact) {
var fullnames = [],
name = [];
return contact.First && name.push(contact.First), contact.Name && name.push(contact.Name), contact.Middle && name.push(contact.Middle), contact.Last && name.push(contact.Last), contact["First Name"] && name.push(contact["First Name"]), contact["Middle Name"] && name.push(contact["Middle Name"]), contact["Last Name"] && name.push(contact["Last Name"]), name.length && fullnames.push({
value: name.join(" ")
}), fullnames
},
gender: gender,
geo: geo,
impp: impp,
lang: lang,
logo: logo,
member: member,
nickname: nickname,
note: note,
org: org,
photo: photo,
prodid: prodid,
rev: rev,
role: role,
sound: sound,
tel: function(contact) {
var tels = extractKeys(PROPERTIES.tel, contact);
if (Object.keys(PHONES).forEach(function(parameter) {
PHONES[parameter].forEach(function(key) {
var value = contact[key];
value && tels.push({
value: value,
parameter: parameter
})
})
}), contact["Phone 1 - Value"]) {
var _tel = {
value: contact["Phone 1 - Value"]
};
contact["Phone 1 - Type"] && (_tel.parameter = contact["Phone 1 - Type"]), tels.push(_tel)
}
if (contact["Phone 2 - Value"]) {
var _tel2 = {
value: contact["Phone 2 - Value"]
};
contact["Phone 2 - Type"] && (_tel2.parameter = contact["Phone 2 - Type"]), tels.push(_tel2)
}
if (contact["Phone 3 - Value"]) {
var _tel3 = {
value: contact["Phone 3 - Value"]
};
contact["Phone 3 - Type"] && (_tel3.parameter = contact["Phone 3 - Type"]), tels.push(_tel3)
}
return tels
},
title: title,
tz: tz,
uid: uid,
url: url
}
}), angular.module("proton.core").factory("customizeInvoiceModal", function(eventManager, pmModal, settingsApi, notification, authentication, networkActivityTracker) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/customizeInvoice.tpl.html",
controller: function(params) {
var self = this;
self.text = authentication.user.InvoiceText || "", self.cancel = function() {
return params.cancel()
}, self.submit = function() {
var promise = settingsApi.invoiceText({
InvoiceText: self.text
}).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (data.Error) throw new Error(data.Error);
return data
}).then(function() {
return eventManager.call()
}).then(function() {
notification.success("Invoice customized"), params.cancel()
});
networkActivityTracker.track(promise)
}
}
})
}), angular.module("proton.core").factory("deleteAccountModal", function(pmModal, Bug, User, networkActivityTracker, authentication, $state, CONSTANTS, gettextCatalog, notification) {
function report(params, isAdmin) {
return isAdmin ? Bug.report(params) : Promise.resolve()
}
function deleteUser(params) {
return User.delete(params).then(function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data;
throw new Error(data.Error)
})
}
var I18N = {
invalidForm: gettextCatalog.getString("Invalid email address or password", null, "Error reported when the delete account form is invalid")
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/deleteAccount.tpl.html",
controller: function(params, $scope) {
var self = this;
self.hasTwoFactor = authentication.user.TwoFactor, self.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, self.email = "", self.feedback = "", self.password = "", self.twoFactorCode = "", self.submit = function() {
if ($scope.deleteForm.$invalid) return void notification.error(I18N.invalidForm);
var username = authentication.user.Name,
params = {
OS: "--",
OSVersion: "--",
Browser: "--",
BrowserVersion: "--",
BrowserExtensions: "--",
Client: "--",
ClientVersion: "--",
Title: "[DELETION FEEDBACK] " + username,
Username: username,
Email: self.email || authentication.user.Addresses[0].Email,
Description: self.feedback
},
promise = report(params, self.isAdmin).then(function() {
return deleteUser({
Password: self.password,
TwoFactorCode: self.twoFactorCode
})
}).then(function() {
return $state.go("login")
});
networkActivityTracker.track(promise)
}, self.cancel = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("dkimModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/dkim.tpl.html",
controller: function(params) {
this.domain = params.domain, this.step = params.step, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.next = function() {
params.next()
}, this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("dmarcModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/dmarc.tpl.html",
controller: function(params) {
this.domain = params.domain, this.step = params.step, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.verify = function() {
params.verify()
}, this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("domainModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/domain.tpl.html",
controller: function(params) {
var self = this;
self.step = params.step, self.domain = params.domain, self.name = "", self.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, self.submit = function() {
angular.isDefined(params.submit) && angular.isFunction(params.submit) && params.submit(self.name)
}, self.next = function() {
angular.isDefined(params.next) && angular.isFunction(params.next) && params.next()
}, self.cancel = function() {
angular.isDefined(params.cancel) && angular.isFunction(params.cancel) && params.cancel()
}, self.beginsWith = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
_self$name = self.name;
return (void 0 === _self$name ? "" : _self$name).substring(0, value.length) === value
}
}
})
}), angular.module("proton.core").factory("donateModal", function($rootScope, pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/donate.tpl.html",
controller: function(params) {
this.typeOfModal = params.type, this.close = params.close;
var unsubscribe = $rootScope.$on("payments", function(e, _ref) {
/^(donation|topUp)\.request\.success/.test(_ref.type) && params.close()
});
this.$onDestroy = function() {
return unsubscribe()
}
}
})
}), angular.module("proton.core").factory("downloadFile", function(gettextCatalog, notification, aboutClient) {
var newerBrowser = gettextCatalog.getString("Download requires a newer browser.", null, "Error"),
learnMore = gettextCatalog.getString("Learn more.", null, "Info");
return function(blob, filename) {
try {
if (!aboutClient.isFileSaverSupported()) throw new Error(newerBrowser);
window.saveAs(blob, filename)
} catch (error) {
notification.error(newerBrowser + ' <a href="https://protonmail.com/support/knowledge-base/problems-with-attachments/" target="_blank">' + learnMore + "</a>"), console.error(error)
}
}
}), angular.module("proton.core").factory("$exceptionHandler", function($injector) {
var nReports = 0,
MAP_ERROR_SILENT = {
"loginPassword:cancel": !0
},
getError = function(exception) {
if (exception instanceof Error) return {
message: exception.message,
stack: exception.stack
};
if (angular.isString(exception)) return exception;
try {
var json = angular.toJson(exception);
return $.isEmptyObject(json) ? exception.toString() : exception
} catch (err) {
return err.message
}
},
isLoggable = function(err) {
return !(MAP_ERROR_SILENT[err] || MAP_ERROR_SILENT[(err || {}).message])
};
return function(exception) {
if (nReports++, console.error(exception), nReports < 6) {
var error = getError(exception);
if (!isLoggable(error)) return Promise.resolve();
try {
return $injector.get("bugReportApi").crash(error)
} catch (e) {
console.error(e)
}
}
return Promise.resolve()
}
}), angular.module("proton.core").factory("feedbackModal", function(pmModal, Bug, notification, networkActivityTracker, gettextCatalog) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/feedback.tpl.html",
controller: function(params) {
var _this = this;
this.fdbckTxt = "", this.submit = function() {
var description = _this.fdbckTxt,
data = {
OS: "--",
OSVersion: "--",
Browser: "--",
BrowserVersion: "--",
BrowserExtensions: "--",
Client: "--",
ClientVersion: "--",
Title: "[FEEDBACK v3]",
Username: "--",
Email: "--",
Description: description
},
feedbackPromise = Bug.report(data);
feedbackPromise.then(function() {
notification.success(gettextCatalog.getString("Thanks for your feedback!", null, "Success message when sending feedback")), params.close()
}), networkActivityTracker.track(feedbackPromise)
}, this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("hotkeyModal", function(pmModal, authentication, CONSTANTS) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/hotkey.tpl.html",
controller: function(params) {
this.isMac = -1 !== navigator.userAgent.indexOf("Mac OS X"), authentication.user.ViewLayout === CONSTANTS.ROW_MODE ? this.mode = "row" : authentication.user.ViewLayout === CONSTANTS.COLUMN_MODE && (this.mode = "column"), this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("humanVerificationModal", function($http, $rootScope, pmModal, User, networkActivityTracker) {
function handleResult(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
return 1e3 === data.Code ? Promise.resolve(data) : data.Error ? Promise.reject(data.Error) : Promise.reject("Error")
}
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/humanVerification.tpl.html",
controller: function(params, $scope) {
var self = this,
unsubscribe = [];
self.tokens = {
captcha: ""
};
var promise = User.human().then(handleResult).then(function(_ref2) {
var VerifyMethods = _ref2.VerifyMethods,
Token = _ref2.Token;
self.token = Token, self.methods = VerifyMethods, self.showCaptcha = _.contains(VerifyMethods, "captcha"), self.verificator = "captcha"
});
networkActivityTracker.track(promise), self.submit = function() {
var promise = User.check({
Token: self.tokens[self.verificator],
TokenType: self.verificator
}).then(handleResult).then(function() {
params.close(!0)
}).catch(function() {
params.close(!0)
});
networkActivityTracker.track(promise)
}, self.cancel = function() {
return params.close(!1)
}, unsubscribe.push($rootScope.$on("captcha.token", function(event, token) {
$scope.$applyAsync(function() {
self.tokens.captcha = token
})
})), self.$onDestroy = function() {
unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
}
}
})
}), angular.module("proton.core").factory("logoutManager", function($rootScope, authentication, eventManager, cache, cacheCounters, contactCache, paymentModel) {
return $rootScope.$on("$stateChangeSuccess", function(e, state) {
var currentState = state.name,
specialStates = ["login.setup"]; - 1 === currentState.indexOf("secured") && -1 === specialStates.indexOf(currentState) && (eventManager.stop(), cache.reset(), cacheCounters.reset(), contactCache.clear(), paymentModel.clear(), authentication.isLoggedIn() && authentication.logout(), $rootScope.$emit("logout"))
}), {}
}), angular.module("proton.core").factory("mxModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/mx.tpl.html",
controller: function(params) {
this.domain = params.domain, this.step = params.step, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.next = function() {
params.next()
}, this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("reactivateModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/reactivate.tpl.html",
controller: function(params) {
this.loginPassword = "", this.keyPassword = "", this.submit = function() {
params.submit && params.submit(this.loginPassword, this.keyPassword)
}.bind(this), this.cancel = function() {
params.cancel && params.cancel()
}
}
})
}), angular.module("proton.core").factory("recoveryCodeModal", function(pmModal, downloadFile) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/twofactor/recoveryCode.tpl.html",
controller: function(params) {
this.recoveryCodesFirstHalf = params.recoveryCodes.slice(0, 8), this.recoveryCodesSecondHalf = params.recoveryCodes.slice(8, 16), this.download = function() {
var blob = new Blob([params.recoveryCodes.join("\r\n")], {
type: "text/plain;charset=utf-8;"
});
downloadFile(blob, "protonmail_recovery_codes.txt")
}, this.done = function() {
params.close()
}, this.cancel = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("sharedSecretModal", function(authentication, pmModal, $timeout, webcrypto) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/twofactor/sharedSecret.tpl.html",
controller: function(params) {
var self = this,
randomBytes = webcrypto.getRandomValues(new Uint8Array(20)),
sharedSecret = base32.encode(randomBytes),
primaryAddress = _.find(authentication.user.Addresses, function(_ref) {
return _ref.Keys
}),
identifier = primaryAddress ? primaryAddress.Email : authentication.user.Name + "@protonmail",
qrURI = "otpauth://totp/" + identifier + "?secret=" + sharedSecret + "&issuer=ProtonMail&algorithm=SHA1&digits=6&period=30";
self.sharedSecret = params.sharedSecret || sharedSecret, self.qrURI = params.qrURI || qrURI, self.manual = !1, self.next = function() {
return params.next(self.sharedSecret, self.qrURI)
}, self.cancel = function() {
return params.cancel()
}, self.displayManual = function() {
self.manual = !self.manual
}, self.makeCode = function() {
new QRCode(document.getElementById("qrcode"), self.qrURI)
}
}
})
}), angular.module("proton.core").factory("signatureModal", function(pmModal, authentication) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/signature.tpl.html",
controller: function(params) {
this.defaultDisplayName = authentication.user.DisplayName, this.defaultSignature = authentication.user.Signature, this.address = params.address, this.address.DisplayName = this.address.DisplayName || authentication.user.DisplayName, this.address.Signature = this.address.Signature || authentication.user.Signature, this.address.custom = !0, this.confirm = function() {
params.confirm(this.address)
}, this.cancel = function() {
params.cancel()
}
}
})
}), angular.module("proton.core").factory("spfModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/spf.tpl.html",
controller: function(params) {
this.domain = params.domain, this.step = params.step, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.next = function() {
params.next()
}, this.close = function() {
params.close()
}
}
})
}), angular.module("proton.core").factory("supportModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/support.tpl.html",
controller: function(params) {
this.cancel = function() {
params.cancel && params.cancel()
}
}
})
}), angular.module("proton.core").factory("switchPasswordModeModal", function(authentication, pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/switchPasswordMode.tpl.html",
controller: function(params) {
var self = this;
self.currentPasswordMode = authentication.user.PasswordMode, self.save = function() {}, self.cancel = params.cancel
}
})
}), angular.module("proton.core").factory("twoFAIntroModal", function(pmModal) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/twofactor/twoFAIntroModal.tpl.html",
controller: function(params) {
var self = this;
self.next = function() {
return params.next()
}, self.cancel = function() {
return params.cancel()
}
}
})
}), angular.module("proton.core").factory("vcard", function(CONSTANTS, notification, sanitize) {
function isValidType() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return !type.length || _.contains(VCARD_TYPES, type.toLowerCase())
}
function clean() {
var vcard = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : new vCard,
properties = extractProperties(vcard);
return _.reduce(properties, function(acc, property) {
var type = property.getType(),
typeValue = type && (Array.isArray(type) ? type.map(function(t) {
return cleanType(t)
}).filter(function(t) {
return t
}) : cleanType(type)),
key = property.getField(),
value = property.valueOf(),
params = property.getParams();
return delete params.type, typeValue && typeValue.length && (params.type = typeValue), acc.add(key, sanitize.input(cleanValue(value)), params), acc
}, new vCard)
}
function cleanType() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return "x-INTERNET" === type ? "" : isValidType(type) ? type : type.toLowerCase().startsWith("x") ? type : "x-" + type
}
function cleanValue() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
matches = value.match(/_\$!<(.*)>!\$_/);
return Array.isArray(matches) ? matches[1] : value
}
function extractProperties() {
var vcard = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : new vCard;
return _.reduce(Object.keys(vcard.data), function(acc, key) {
var value = vcard.get(key),
props = Array.isArray(value) ? value : [value];
return acc.concat(props)
}, [])
}
function build() {
var properties = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
target = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : new vCard;
return _.each(properties, function(property) {
return target.addProperty(property)
}), target
}
var VCARD_VERSION = CONSTANTS.VCARD_VERSION,
VCARD_TYPES = CONSTANTS.VCARD_TYPES,
merge = function() {
var vcards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.reduce(vcards, function(acc) {
return build(extractProperties(arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}), acc)
}, new vCard)
},
to = function() {
var vcards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return _.reduce(vcards, function(acc, vCard) {
return acc + clean(vCard).toString(VCARD_VERSION) + "\r\n"
}, "")
};
return {
from: function() {
var vcfString = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
try {
return vCard.parse(vcfString).map(function(vcard) {
return clean(vcard)
})
} catch (e) {
notification.error(e)
}
},
to: to,
extractProperties: extractProperties,
merge: merge,
build: build,
isValidType: isValidType
}
}), angular.module("proton.core").factory("verificationModal", function(pmModal, $rootScope) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/domain/verification.tpl.html",
controller: function(params) {
this.domain = params.domain, this.step = params.step, this.open = function(name) {
$rootScope.$broadcast(name, params.domain)
}, this.submit = function() {
angular.isDefined(params.close) && angular.isFunction(params.close) && params.submit()
}, this.next = function() {
angular.isDefined(params.close) && angular.isFunction(params.close) && (params.close(), params.next())
}, this.close = function() {
angular.isDefined(params.close) && angular.isFunction(params.close) && params.close()
}
}
})
}), angular.module("proton.core").factory("welcomeModal", function(pmModal, settingsApi, authentication, networkActivityTracker) {
function saveDisplayName(DisplayName) {
var promise = settingsApi.display({
DisplayName: DisplayName
});
authentication.user.DisplayName = DisplayName, networkActivityTracker.track(promise)
}
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/modals/welcome.tpl.html",
controller: function(params) {
var _this = this;
this.displayName = authentication.user.DisplayName, this.cancel = params.cancel, this.next = function() {
_this.displayName.length && saveDisplayName(_this.displayName), params.next()
}
}
})
}), angular.module("proton.core").factory("formatResponseInterceptor", function($q) {
return {
responseError: function(rejection) {
return rejection.data = rejection.data || {}, $q.reject(rejection)
}
}
}), angular.module("proton.core").service("cache", function($interval, $q, $rootScope, $state, $stateParams, CONSTANTS, conversationApi, firstLoad, gettextCatalog, messageModel, messageApi, cacheCounters, networkActivityTracker, tools, labelsModel, cachePages) {
function storeConversations() {
(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).forEach(updateConversation)
}
function getPages(_ref) {
var _ref$Page = _ref.Page,
Page = void 0 === _ref$Page ? 0 : _ref$Page,
_ref$Limit = _ref.Limit,
Limit = void 0 === _ref$Limit ? CONSTANTS.CONVERSATION_LIMIT : _ref$Limit;
return _.range(Page, Page + Limit / CONSTANTS.ELEMENTS_PER_PAGE, 1)
}
function storeMessages() {
(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).forEach(updateMessage)
}
function storeTime(conversationId, loc, time) {
timeCached[conversationId] = timeCached[conversationId] || {}, timeCached[conversationId][loc] = time
}
function updateMessage(message, isSend) {
_.findWhere(messagesCached, {
ID: message.ID
}) ? messagesCached = _.map(messagesCached, function(msg) {
if (isSend && msg.ID === message.ID) return message;
if (msg.ID === message.ID) {
var m = _.extend({}, msg, message);
return m.Type = message.Type, m
}
return msg
}) : messagesCached.push(message), manageTimes(message.ConversationID), $rootScope.$emit("labelsElement." + message.ID, message), $rootScope.$emit("foldersMessage." + message.ID, message), $rootScope.$emit("foldersElement." + message.ID, message)
}
function extractContextDatas(oldElement, newElement) {
var _newElement$Labels = newElement.Labels,
Labels = void 0 === _newElement$Labels ? [] : _newElement$Labels,
ID = tools.currentLocation(),
_ref2 = Labels.length ? _.findWhere(Labels, {
ID: ID
}) || {} : newElement,
_ref2$ContextNumUnrea = _ref2.ContextNumUnread,
ContextNumUnread = void 0 === _ref2$ContextNumUnrea ? oldElement.ContextNumUnread : _ref2$ContextNumUnrea,
_ref2$ContextNumAttac = _ref2.ContextNumAttachments,
ContextNumAttachments = void 0 === _ref2$ContextNumAttac ? oldElement.ContextNumAttachments : _ref2$ContextNumAttac,
_ref2$ContextSize = _ref2.ContextSize,
ContextSize = void 0 === _ref2$ContextSize ? oldElement.ContextSize : _ref2$ContextSize,
_ref2$ContextTime = _ref2.ContextTime;
return {
ContextNumUnread: ContextNumUnread,
ContextNumAttachments: ContextNumAttachments,
ContextSize: ContextSize,
ContextTime: void 0 === _ref2$ContextTime ? oldElement.ContextTime : _ref2$ContextTime
}
}
function updateConversation(conversation) {
var current = _.findWhere(conversationsCached, {
ID: conversation.ID
});
if (current) return _.extend(current, conversation, {
Labels: getLabels(current, conversation),
Senders: filterSenderConversation(current.Senders, conversation.Senders)
}, extractContextDatas(current, conversation)), delete current.LabelIDsAdded, delete current.LabelIDsRemoved, manageTimes(current.ID), $rootScope.$emit("labelsElement." + current.ID, current), void $rootScope.$emit("foldersElement." + current.ID, current);
_.extend(conversation, extractContextDatas(conversation, conversation)), conversationsCached.push(conversation), manageTimes(conversation.ID), $rootScope.$emit("labelsElement." + conversation.ID, conversation), $rootScope.$emit("foldersElement." + conversation.ID, conversation)
}
function vector(_ref3, unread, type) {
var _ref3$LabelIDs = _ref3.LabelIDs,
LabelIDs = void 0 === _ref3$LabelIDs ? [] : _ref3$LabelIDs,
_ref3$Labels = _ref3.Labels,
Labels = void 0 === _ref3$Labels ? [] : _ref3$Labels,
IsRead = _ref3.IsRead,
toInt = function(value) {
return +!!value
},
locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids());
return _.reduce(locs, function(acc, loc) {
if ("message" === type) {
var test = _.contains(LabelIDs, loc);
acc[loc] = toInt(unread ? test && 0 === IsRead : test)
}
if ("conversation" === type) {
var label = _.findWhere(Labels, {
ID: loc
});
acc[loc] = toInt(unread ? label && label.ContextNumUnread > 0 : label)
}
return acc
}, {})
}
function manageTimes(conversationID) {
if (conversationID) {
var _ref4 = api.getConversationCached(conversationID) || {},
_ref4$Labels = _ref4.Labels,
Labels = void 0 === _ref4$Labels ? [] : _ref4$Labels,
messages = api.queryMessagesCached(conversationID);
messages.length && Labels.forEach(function(_ref5) {
var ID = _ref5.ID,
_ref6 = _.chain(messages).filter(function(_ref7) {
var _ref7$LabelIDs = _ref7.LabelIDs,
LabelIDs = void 0 === _ref7$LabelIDs ? [] : _ref7$LabelIDs;
return _.contains(LabelIDs, ID)
}).first().value() || {},
Time = _ref6.Time;
Time && storeTime(conversationID, ID, Time)
})
}
}
function manageCounters(oldElement, newElement, type) {
var oldUnreadVector = vector(oldElement, !0, type),
newUnreadVector = vector(newElement, !0, type),
newTotalVector = vector(newElement, !1, type),
oldTotalVector = vector(oldElement, !1, type),
locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids());
_.each(locs, function(loc) {
var deltaUnread = newUnreadVector[loc] - oldUnreadVector[loc],
deltaTotal = newTotalVector[loc] - oldTotalVector[loc],
currentUnread = void 0,
currentTotal = void 0;
"message" === type ? (currentUnread = cacheCounters.unreadMessage(loc), currentTotal = cacheCounters.totalMessage(loc), cacheCounters.updateMessage(loc, currentTotal + deltaTotal, currentUnread + deltaUnread)) : "conversation" === type && (currentUnread = cacheCounters.unreadConversation(loc), currentTotal = cacheCounters.totalConversation(loc), cacheCounters.updateConversation(loc, currentTotal + deltaTotal, currentUnread + deltaUnread))
})
}
function queryConversations(request) {
var loc = getLocation(request),
context = tools.cacheContext();
request.Limit = request.Limit || CONSTANTS.CONVERSATION_LIMIT;
var promise = api.getDispatcher().then(function() {
return conversationApi.query(request)
}).then(function() {
var _ref9 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref9$data = _ref9.data,
data = void 0 === _ref9$data ? {} : _ref9$data;
if (1e3 === data.Code) {
if (cacheCounters.currentState(data.Limit), $rootScope.$emit("elements", {
type: "setLimit",
data: {
limit: data.Limit,
total: data.Total
}
}), _.each(data.Conversations, function(conversation) {
conversation.loaded = !0, storeTime(conversation.ID, loc, conversation.ContextTime)
}), context) {
var total = data.Limit,
unread = 0 === total ? 0 : data.Unread,
pages = getPages(request);
return cacheCounters.updateConversation(loc, total, unread), storeConversations(data.Conversations), pages.forEach(function(page) {
return !cachePages.inside(page) && cachePages.add(page)
}), api.clearDispatcher(), api.orderConversation(data.Conversations.slice(0, CONSTANTS.ELEMENTS_PER_PAGE), loc)
}
return api.clearDispatcher(), data.Conversations.slice(0, CONSTANTS.ELEMENTS_PER_PAGE)
}
if (api.clearDispatcher(), $rootScope.$emit("elements", {
type: "error",
data: {
code: data.Code,
error: data.Error
}
}), data.Code === INVALID_SEARCH_ERROR_CODE) return [];
throw new Error(data.Error || I18N.errorConversations)
});
return networkActivityTracker.track(promise), promise
}
function queryMessages(request) {
var loc = getLocation(request),
context = tools.cacheContext();
request.Limit = request.Limit || CONSTANTS.MESSAGE_LIMIT;
var promise = api.getDispatcher().then(function() {
return messageApi.query(request)
}).then(function() {
var _ref10 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref10$data = _ref10.data,
data = void 0 === _ref10$data ? {} : _ref10$data;
if (1e3 === data.Code) {
var _data$Messages = data.Messages,
Messages = void 0 === _data$Messages ? [] : _data$Messages,
_data$Total = data.Total,
Total = void 0 === _data$Total ? 0 : _data$Total,
_data$Limit = data.Limit,
Limit = void 0 === _data$Limit ? 0 : _data$Limit;
if (cacheCounters.currentState(Limit), $rootScope.$emit("elements", {
type: "setLimit",
data: {
limit: Limit,
total: Total
}
}), _.each(Messages, function(message) {
var _message$ToList = message.ToList,
ToList = void 0 === _message$ToList ? [] : _message$ToList,
_message$CCList = message.CCList,
CCList = void 0 === _message$CCList ? [] : _message$CCList,
_message$BCCList = message.BCCList,
BCCList = void 0 === _message$BCCList ? [] : _message$BCCList;
message.loaded = !0, message.Senders = [message.Sender], message.Recipients = _.uniq([].concat(ToList, CCList, BCCList))
}), storeMessages(Messages), context) {
var pages = getPages(request);
return cacheCounters.updateMessage(loc, Limit), pages.forEach(function(page) {
return !cachePages.inside(page) && cachePages.add(page)
}), api.clearDispatcher(), api.orderMessage(Messages.slice(0, CONSTANTS.ELEMENTS_PER_PAGE))
}
return api.clearDispatcher(), Messages.slice(0, CONSTANTS.ELEMENTS_PER_PAGE)
}
if (api.clearDispatcher(), $rootScope.$emit("elements", {
type: "error",
data: {
code: data.Code,
error: data.Error
}
}), data.Code === INVALID_SEARCH_ERROR_CODE) return [];
throw new Error(data.Error || I18N.errorMessages)
});
return networkActivityTracker.track(promise), promise
}
function getConversation() {
var conversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
promise = conversationApi.get(conversationID).then(function() {
var _ref11 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref11$data = _ref11.data,
data = void 0 === _ref11$data ? {} : _ref11$data,
Code = data.Code,
Conversation = data.Conversation,
Messages = data.Messages;
if (1e3 === Code) {
var conversation = Conversation,
messages = Messages,
message = _.max(messages, function(_ref12) {
return _ref12.Time
});
return messages.forEach(function(message) {
return message.loaded = !0
}), conversation.loaded = !0, conversation.Time = message.Time, storeConversations([conversation]), storeMessages(messages), angular.copy(conversation)
}
throw new Error(data.Error)
});
return networkActivityTracker.track(promise), promise
}
function getMessage() {
var messageID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
promise = messageApi.get(messageID).then(function() {
var _ref13 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref13$data = _ref13.data,
data = void 0 === _ref13$data ? {} : _ref13$data;
if (1e3 === data.Code) {
var message = data.Message;
return message.loaded = !0, storeMessages([message]), messageModel(message)
}
throw new Error(data.Error)
});
return networkActivityTracker.track(promise), promise
}
function reverse() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, item) {
return acc.unshift(item), acc
}, [])
}
function getLabelsId() {
var oldElement = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
newElement = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
labelIDs = newElement.LabelIDs || oldElement.LabelIDs || [];
return Array.isArray(newElement.LabelIDsRemoved) && (labelIDs = _.difference(labelIDs, newElement.LabelIDsRemoved)), Array.isArray(newElement.LabelIDsAdded) && (labelIDs = _.uniq(labelIDs.concat(newElement.LabelIDsAdded))), labelIDs
}
function getLabels(old, _ref22) {
var _ref22$Labels = _ref22.Labels,
Labels = void 0 === _ref22$Labels ? [] : _ref22$Labels,
_ref22$LabelIDsRemove = _ref22.LabelIDsRemoved,
LabelIDsRemoved = void 0 === _ref22$LabelIDsRemove ? [] : _ref22$LabelIDsRemove,
_ref22$LabelIDsAdded = _ref22.LabelIDsAdded,
LabelIDsAdded = void 0 === _ref22$LabelIDsAdded ? [] : _ref22$LabelIDsAdded,
_ref22$ContextNumUnre = _ref22.ContextNumUnread,
ContextNumUnread = void 0 === _ref22$ContextNumUnre ? 0 : _ref22$ContextNumUnre;
if (LabelIDsAdded.length || LabelIDsRemoved.length) {
var toAdd = _.map(LabelIDsAdded, function(ID) {
return {
ID: ID,
ContextNumUnread: ContextNumUnread
}
}),
filtered = _.filter(old.Labels, function(_ref23) {
var ID = _ref23.ID;
return !_.contains(LabelIDsRemoved, ID)
});
return _.uniq(filtered.concat(toAdd), function(_ref24) {
return _ref24.ID
})
}
return Labels.length ? _.map(Labels, function(label) {
var oldLabel = _.findWhere(old.Labels || [], {
ID: label.ID
});
return oldLabel ? _.extend({}, oldLabel, label) : label
}) : old.Labels || []
}
function handleCounters() {
var events = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
_.chain(events).filter(function(event) {
return event.Message
}).map(function(event) {
return angular.copy(event.Message)
}).each(function(newMessage) {
var oldMessage = _.findWhere(messagesCached, {
ID: newMessage.ID
});
oldMessage && (newMessage.LabelIDs = getLabelsId(oldMessage, newMessage), manageCounters(oldMessage, newMessage, "message"))
}), _.chain(events).filter(function(event) {
return event.Conversation
}).map(function(event) {
return angular.copy(event.Conversation)
}).each(function(newConversation) {
var oldConversation = _.findWhere(conversationsCached, {
ID: newConversation.ID
});
oldConversation && (newConversation.Labels = getLabels(oldConversation, newConversation), manageCounters(oldConversation, newConversation, "conversation"))
}), cacheCounters.status()
}
function expiration() {
var now = moment().unix(),
_messagesCached$reduc = messagesCached.reduce(function(acc) {
var message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {},
ExpirationTime = message.ExpirationTime;
return acc[0 !== ExpirationTime && ExpirationTime < now ? "removeList" : "list"].push(message), acc
}, {
list: [],
removeList: []
}),
list = _messagesCached$reduc.list,
removeList = _messagesCached$reduc.removeList;
messagesCached = list, removeList.length && $rootScope.$emit("message.expiration", removeList)
}
var api = {},
messagesCached = [],
conversationsCached = [],
dispatcher = [],
timeCached = {},
INVALID_SEARCH_ERROR_CODE = 15225,
_CONSTANTS$STATUS = CONSTANTS.STATUS,
DELETE = _CONSTANTS$STATUS.DELETE,
CREATE = _CONSTANTS$STATUS.CREATE,
UPDATE_DRAFT = _CONSTANTS$STATUS.UPDATE_DRAFT,
UPDATE_FLAGS = _CONSTANTS$STATUS.UPDATE_FLAGS,
_CONSTANTS$MAILBOX_ID = CONSTANTS.MAILBOX_IDENTIFIERS,
inbox = _CONSTANTS$MAILBOX_ID.inbox,
allDrafts = _CONSTANTS$MAILBOX_ID.allDrafts,
drafts = _CONSTANTS$MAILBOX_ID.drafts,
allSent = _CONSTANTS$MAILBOX_ID.allSent,
sent = _CONSTANTS$MAILBOX_ID.sent,
trash = _CONSTANTS$MAILBOX_ID.trash,
spam = _CONSTANTS$MAILBOX_ID.spam,
allmail = _CONSTANTS$MAILBOX_ID.allmail,
archive = _CONSTANTS$MAILBOX_ID.archive,
starred = _CONSTANTS$MAILBOX_ID.starred,
I18N = {
errorMessages: gettextCatalog.getString("No messages available", null, "Error"),
errorConversations: gettextCatalog.getString("No conversations available", null, "Error")
},
dispatchElements = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("elements", {
type: type,
data: data
})
};
api.addToDispatcher = function(action) {
return dispatcher.push(action)
}, api.clearDispatcher = function() {
return dispatcher.length = 0
}, api.getDispatcher = function() {
return Promise.all(dispatcher)
}, $interval(expiration, 1e3, 0, !1);
var filterSenderConversation = function() {
var previous = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []).concat(previous).reduce(function(acc, sender) {
return acc.map[sender.Address] || (acc.list.push(sender), acc.map[sender.Address] = !0), acc
}, {
list: [],
map: {}
}).list
},
getLocation = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).Label
};
api.empty = function(labelID) {
messagesCached = _.filter(messagesCached, function(_ref14) {
var _ref14$LabelIDs = _ref14.LabelIDs;
return -1 === (void 0 === _ref14$LabelIDs ? [] : _ref14$LabelIDs).indexOf(labelID)
}), cacheCounters.updateMessage(labelID, 0), _.each(conversationsCached, function(conversation) {
conversation.Labels = _.filter(conversation.Labels, function(_ref15) {
return _ref15.ID !== labelID
})
}), cacheCounters.updateConversation(labelID, 0), dispatchElements("refresh")
}, api.orderConversation = function() {
var conversations = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
loc = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return reverse(conversations.sort(function(a, b) {
return api.getTime(a.ID, loc) < api.getTime(b.ID, loc) ? -1 : api.getTime(a.ID, loc) > api.getTime(b.ID, loc) ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0
}))
}, api.orderMessage = function() {
var messages = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
doReverse = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1],
list = messages.sort(function(a, b) {
return a.Time < b.Time ? -1 : a.Time > b.Time ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0
});
return doReverse ? reverse(list) : list
}, api.orderElements = function() {
var elements = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
type = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "message",
doReverse = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2],
loc = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "",
list = elements.sort(function(a, b) {
var timeA = "message" === type ? a.Time : api.getTime(a.ID, loc),
timeB = "message" === type ? b.Time : api.getTime(b.ID, loc);
return timeA < timeB ? -1 : timeA > timeB ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0
});
return doReverse ? reverse(list) : list
}, api.getTime = function(conversationId, loc) {
return timeCached[conversationId] && angular.isNumber(timeCached[conversationId][loc]) ? timeCached[conversationId][loc] : (api.getConversationCached(conversationId) || {}).ContextTime || ""
}, api.queryMessages = function(request) {
var loc = getLocation(request),
context = tools.cacheContext(),
page = request.Page || 0;
if (context && !firstLoad.get() && cachePages.consecutive(page)) {
var start = page * CONSTANTS.ELEMENTS_PER_PAGE,
end = start + CONSTANTS.ELEMENTS_PER_PAGE,
total = void 0,
number = void 0,
mailbox = tools.currentMailbox(),
messages = _.chain(messagesCached).filter(function(_ref16) {
var _ref16$LabelIDs = _ref16.LabelIDs;
return -1 !== (void 0 === _ref16$LabelIDs ? [] : _ref16$LabelIDs).indexOf(loc)
}).map(function(message) {
return messageModel(message)
}).value();
switch (messages = api.orderMessage(messages), mailbox) {
case "label":
total = cacheCounters.totalMessage($stateParams.label);
break;
default:
total = cacheCounters.totalMessage(CONSTANTS.MAILBOX_IDENTIFIERS[mailbox])
}
if (angular.isDefined(total) && (number = 0 === total ? 0 : total % CONSTANTS.ELEMENTS_PER_PAGE == 0 ? CONSTANTS.ELEMENTS_PER_PAGE : Math.ceil(total / CONSTANTS.ELEMENTS_PER_PAGE) - 1 === page ? total % CONSTANTS.ELEMENTS_PER_PAGE : CONSTANTS.ELEMENTS_PER_PAGE, cacheCounters.currentState(total), messages = messages.slice(start, end), messages.length === number)) return Promise.resolve(messages)
}
return queryMessages(request)
}, api.queryConversations = function(request) {
var loc = getLocation(request),
context = tools.cacheContext(),
page = request.Page || 0;
if (context && !firstLoad.get() && cachePages.consecutive(page)) {
var start = page * CONSTANTS.ELEMENTS_PER_PAGE,
end = start + CONSTANTS.ELEMENTS_PER_PAGE,
total = void 0,
number = void 0,
mailbox = tools.currentMailbox(),
conversations = _.filter(conversationsCached, function(_ref17) {
var _ref17$Labels = _ref17.Labels,
Labels = void 0 === _ref17$Labels ? [] : _ref17$Labels,
ID = _ref17.ID;
return _.findWhere(Labels, {
ID: loc
}) && api.getTime(ID, loc)
});
switch (conversations = api.orderConversation(conversations, loc), mailbox) {
case "label":
total = cacheCounters.totalConversation($stateParams.label);
break;
default:
total = cacheCounters.totalConversation(CONSTANTS.MAILBOX_IDENTIFIERS[mailbox])
}
if (angular.isDefined(total) && (number = 0 === total ? 0 : total % CONSTANTS.ELEMENTS_PER_PAGE == 0 ? CONSTANTS.ELEMENTS_PER_PAGE : Math.ceil(total / CONSTANTS.ELEMENTS_PER_PAGE) - 1 === page ? total % CONSTANTS.ELEMENTS_PER_PAGE : CONSTANTS.ELEMENTS_PER_PAGE, cacheCounters.currentState(total), conversations = conversations.slice(start, end), conversations.length === number)) return Promise.resolve(conversations)
}
return queryConversations(request)
}, api.queryMessagesCached = function() {
var ConversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return api.orderMessage(_.where(messagesCached, {
ConversationID: ConversationID
})).map(messageModel)
}, api.getConversationCached = function(ID) {
return angular.copy(_.findWhere(conversationsCached, {
ID: ID
}))
}, api.getMessageCached = function(ID) {
return messageModel(_.findWhere(messagesCached, {
ID: ID
}))
}, api.getConversation = function(ID) {
var conversation = _.findWhere(conversationsCached, {
ID: ID
}) || {},
messages = api.queryMessagesCached(ID);
return !0 === conversation.loaded && messages.length === conversation.NumMessages ? Promise.resolve(angular.copy(conversation)) : getConversation(ID)
}, api.getMessage = function() {
var ID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
message = _.findWhere(messagesCached, {
ID: ID
}) || {};
return new Promise(function(resolve) {
resolve(message.Body ? messageModel(message) : api.queryMessage(ID))
})
}, api.queryMessage = getMessage, api.delete = function(event) {
return messagesCached = messagesCached.filter(function(_ref18) {
return _ref18.ID !== event.ID
}), conversationsCached = conversationsCached.filter(function(_ref19) {
return _ref19.ID !== event.ID
}), Promise.resolve()
}, api.createMessage = function(event) {
return updateMessage(event.Message), Promise.resolve()
}, api.updateMessage = updateMessage, api.createConversation = function(_ref20) {
var Conversation = _ref20.Conversation;
return Conversation.loaded = !0, updateConversation(Conversation), Promise.resolve()
}, api.updateDraftConversation = function(event) {
return updateConversation(event.Conversation), Promise.resolve()
}, api.updateFlagMessage = function(event, isSend) {
var current = _.findWhere(messagesCached, {
ID: event.ID
});
if (!current) return Promise.resolve();
var message = _.extend({}, current, event.Message);
return message.LabelIDs = getLabelsId(current, event.Message), delete message.LabelIDsRemoved, delete message.LabelIDsAdded, Promise.resolve(updateMessage(message, isSend))
}, api.updateFlagConversation = function() {
var event = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return (_.findWhere(conversationsCached, {
ID: event.ID
}) || {}).loaded ? (updateConversation(event.Conversation), Promise.resolve()) : getConversation(event.ID).then(function(conversation) {
conversation.LabelIDsAdded = event.Conversation.LabelIDsAdded, conversation.LabelIDsRemoved = event.Conversation.LabelIDsRemoved, updateConversation(conversation)
})
};
var formatCreate = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return Promise.all(list.map(function(_ref25) {
var event = _ref25.event,
type = _ref25.type;
return api["create" + type](event)
}))
},
formatUpdate = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
promise = list.map(function(_ref26) {
var event = _ref26.event,
type = _ref26.type,
isSend = _ref26.isSend,
item = _ref26.item;
return api["Message" === type ? "updateFlagMessage" : "update" + item + type](event, isSend)
});
return Promise.all(promise)
},
formatDelete = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return Promise.all(list.map(api.delete))
},
eventProcess = function() {
var events = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
fromBackend = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
isSend = arguments[2];
console.log("[events] from the " + (fromBackend ? "back" : "front") + "-end", events), !fromBackend && handleCounters(events);
var _$chain$reduce$value = _.chain(events).reduce(function(acc, event) {
var hasType = event.Message || event.Conversation,
type = event.Message ? "Message" : "Conversation";
return hasType && (event[type].ID = event.ID, fromBackend && event.Action === UPDATE_DRAFT && (event[type].loaded = !1), acc[type + "IDs"].push(event.ID), event.Action === CREATE && acc.flow[type].create.push({
event: event,
type: type
}), event.Action === UPDATE_DRAFT && acc.flow[type].update.push({
event: event,
type: type,
isSend: isSend,
item: "Draft"
}), event.Action === UPDATE_FLAGS && acc.flow[type].update.push({
event: event,
type: type,
isSend: isSend,
item: "Flag"
})), event.Action === DELETE && acc.flow.delete.push(event), acc
}, {
flow: {
Message: {
create: [],
update: []
},
Conversation: {
create: [],
update: []
},
delete: []
},
MessageIDs: [],
ConversationIDs: []
}).value(),
flow = _$chain$reduce$value.flow,
MessageIDs = _$chain$reduce$value.MessageIDs,
ConversationIDs = _$chain$reduce$value.ConversationIDs;
return formatCreate(flow.Message.create).then(function() {
return formatUpdate(flow.Message.update)
}).then(function() {
return formatCreate(flow.Conversation.create)
}).then(function() {
return formatUpdate(flow.Conversation.update)
}).then(function() {
return formatDelete(flow.delete)
}).then(function() {
return api.callRefresh(MessageIDs, ConversationIDs)
})
};
return api.events = eventProcess, api.callRefresh = function() {
var messageIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
conversationIDs = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [];
dispatchElements("refresh"), $rootScope.$emit("updatePageName"), $rootScope.$emit("refreshConversation", conversationIDs), $rootScope.$emit("message.refresh", messageIDs), dispatchElements("refresh.time")
}, api.reset = function() {
conversationsCached.length = 0, messagesCached.length = 0
}, api.more = function(elementID, elementTime, action) {
var type = tools.getTypeList(),
elementsCached = "conversation" === type ? conversationsCached : messagesCached,
loc = tools.currentLocation(),
elements = elementsCached.filter(function(_ref27) {
var _ref27$LabelIDs = _ref27.LabelIDs;
return (void 0 === _ref27$LabelIDs ? [] : _ref27$LabelIDs).indexOf(loc) > -1
}),
elementsOrdered = api.orderElements(elements, type, !0, loc);
if (_.findWhere(elementsOrdered, {
ID: elementID
})) {
var currentIndex = _.findIndex(elementsOrdered, {
ID: elementID
});
if ("previous" === action && elementsOrdered[currentIndex + 1]) return Promise.resolve(elementsOrdered[currentIndex + 1]);
if ("next" === action && elementsOrdered[currentIndex - 1]) return Promise.resolve(elementsOrdered[currentIndex - 1])
}
return function() {
var Label = loc,
request = {
Label: Label
};
return "next" === action ? (request.BeginID = elementID, request.Begin = elementTime) : "previous" === action && (request.EndID = elementID, request.End = elementTime), ("conversation" === type ? queryConversations(request) : queryMessages(request)).then(function() {
var elements = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
if (elements.length) return elements["next" === action ? elements.length - 1 : 0];
throw new Error("No elements found")
})
}()
}, api
}), angular.module("proton.core").service("cacheCounters", function(messageApi, CONSTANTS, conversationApi, $q, $rootScope, authentication, labelsModel) {
var api = {},
counters = {},
_CONSTANTS$MAILBOX_ID = CONSTANTS.MAILBOX_IDENTIFIERS,
inbox = _CONSTANTS$MAILBOX_ID.inbox,
allDrafts = _CONSTANTS$MAILBOX_ID.allDrafts,
drafts = _CONSTANTS$MAILBOX_ID.drafts,
allSent = _CONSTANTS$MAILBOX_ID.allSent,
sent = _CONSTANTS$MAILBOX_ID.sent,
trash = _CONSTANTS$MAILBOX_ID.trash,
spam = _CONSTANTS$MAILBOX_ID.spam,
allmail = _CONSTANTS$MAILBOX_ID.allmail,
archive = _CONSTANTS$MAILBOX_ID.archive,
starred = _CONSTANTS$MAILBOX_ID.starred,
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("app.cacheCounters", {
type: type,
data: data
})
},
exist = function(loc) {
angular.isUndefined(counters[loc]) && (counters[loc] = {
message: {
total: 0,
unread: 0
},
conversation: {
total: 0,
unread: 0
}
})
};
return $rootScope.$on("labelsModel", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
"cache.update" === type && (data.create.forEach(function(_ref2) {
var ID = _ref2.ID;
return exist(ID)
}), Object.keys(data.remove).forEach(function(ID) {
delete counters[ID]
}))
}), api.query = function() {
var locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids());
return $q.all({
message: messageApi.count(),
conversation: conversationApi.count()
}).then(function() {
var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref3$message = _ref3.message,
message = void 0 === _ref3$message ? {} : _ref3$message,
_ref3$conversation = _ref3.conversation,
conversation = void 0 === _ref3$conversation ? {} : _ref3$conversation;
return locs.forEach(exist), _.chain(message.data.Counts).filter(function(_ref4) {
var LabelID = _ref4.LabelID;
return counters[LabelID]
}).each(function(_ref5) {
var LabelID = _ref5.LabelID,
_ref5$Total = _ref5.Total,
Total = void 0 === _ref5$Total ? 0 : _ref5$Total,
_ref5$Unread = _ref5.Unread,
Unread = void 0 === _ref5$Unread ? 0 : _ref5$Unread;
counters[LabelID].message.total = Total, counters[LabelID].message.unread = Unread
}), _.chain(conversation.data.Counts).filter(function(_ref6) {
var LabelID = _ref6.LabelID;
return counters[LabelID]
}).each(function(_ref7) {
var LabelID = _ref7.LabelID,
_ref7$Total = _ref7.Total,
Total = void 0 === _ref7$Total ? 0 : _ref7$Total,
_ref7$Unread = _ref7.Unread,
Unread = void 0 === _ref7$Unread ? 0 : _ref7$Unread;
counters[LabelID].conversation.total = Total, counters[LabelID].conversation.unread = Unread
}), dispatch("load"), Promise.resolve()
}, Promise.reject)
}, api.add = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return exist(loc)
}, api.status = function() {
return dispatch("update.counters", {
counters: counters
})
}, api.updateMessage = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
total = arguments[1],
unread = arguments[2];
exist(loc), angular.isDefined(total) && (counters[loc].message.total = total), angular.isDefined(unread) && (counters[loc].message.unread = unread)
}, api.updateConversation = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
total = arguments[1],
unread = arguments[2];
exist(loc), angular.isDefined(total) && (counters[loc].conversation.total = total), angular.isDefined(unread) && (counters[loc].conversation.unread = unread)
}, api.totalMessage = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return counters[loc] && counters[loc].message && counters[loc].message.total
}, api.totalConversation = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return counters[loc] && counters[loc].conversation && counters[loc].conversation.total
}, api.unreadMessage = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return counters[loc] && counters[loc].message && counters[loc].message.unread
}, api.unreadConversation = function() {
var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return counters[loc] && counters[loc].conversation && counters[loc].conversation.unread
}, api.reset = function() {
counters = {}
}, api.currentState = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0;
counters.CURRENT_STATE_VALUE = value, dispatch("refresh.currentState", {
value: value
})
}, api.getCurrentState = function() {
return counters.CURRENT_STATE_VALUE || 0
}, api.getCounter = function(location) {
return counters[location]
}, api
}), angular.module("proton.core").factory("cachePages", function($rootScope, tools) {
var pages = [],
inside = function(page) {
return pages.indexOf(page) > -1
},
add = function(page) {
return pages.push(page)
},
clear = function() {
return pages.length = 0
},
consecutive = function(page) {
for (var i = page; i >= 0; i--)
if (-1 === pages.indexOf(i)) return !1;
return !0
};
return $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState) {
tools.filteredState(fromState.name) !== tools.filteredState(toState.name) && clear()
}), {
init: angular.noop,
add: add,
inside: inside,
clear: clear,
consecutive: consecutive
}
}), angular.module("proton.core").factory("paginationModel", function(CONSTANTS, cacheCounters, $rootScope, $state, $stateParams, authentication, tools) {
var ELEMENTS_PER_PAGE = CONSTANTS.ELEMENTS_PER_PAGE,
MESSAGE_VIEW_MODE = CONSTANTS.MESSAGE_VIEW_MODE,
currentState = "";
$rootScope.$on("$stateChangeSuccess", function(e, state) {
currentState = state.name.replace(".element", "")
});
var getLayout = function() {
return authentication.user.ViewMode === MESSAGE_VIEW_MODE ? "message" : "conversation"
},
getMaxPage = function() {
var counter = cacheCounters.getCounter(tools.currentLocation());
if (tools.cacheContext() && counter) {
var key = "unread" === $stateParams.filter ? "unread" : "total";
return Math.ceil(counter[getLayout()][key] / ELEMENTS_PER_PAGE)
}
return Math.ceil(cacheCounters.getCurrentState() / ELEMENTS_PER_PAGE)
},
switchPage = function() {
var opts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
$state.go(currentState, _.extend({
id: null
}, opts))
},
previous = function() {
var pos = ~~$stateParams.page || 0;
if (pos) {
var page = pos - 1;
switchPage({
page: page <= 1 ? void 0 : page
})
}
},
next = function() {
var pos = ~~$stateParams.page || 1,
page = pos + 1;
page <= getMaxPage() && switchPage({
page: page
})
},
isMax = function() {
return (~~$stateParams.page || 1) >= getMaxPage()
};
return {
init: angular.noop,
next: next,
previous: previous,
getMaxPage: getMaxPage,
isMax: isMax,
to: switchPage
}
}), angular.module("proton.dashboard").directive("activePlan", function($rootScope, CONSTANTS, subscriptionModel) {
var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN,
PLUS = _CONSTANTS$PLANS$PLAN.PLUS,
PROFESSIONAL = _CONSTANTS$PLANS$PLAN.PROFESSIONAL,
VISIONARY = _CONSTANTS$PLANS$PLAN.VISIONARY,
PLANS = _.reduce(["free", PLUS, PROFESSIONAL, VISIONARY], function(acc, plan) {
return acc + " " + plan + "-active"
}, "");
return {
restrict: "A",
link: function(scope, element) {
var update = function() {
return element.removeClass(PLANS).addClass(subscriptionModel.name() + "-active")
},
unsubscribe = $rootScope.$on("subscription", function(event, _ref) {
"update" === _ref.type && update()
});
update(), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("addVpn", function($rootScope, gettextCatalog) {
return {
restrict: "E",
replace: !0,
scope: {},
template: '<button class="addVpn-button" type="button">\n <div class="addVpn-button-wrapper">\n <i class="addVpn-button-sign"></i>\n <span class="addVpn-button-txt">' + gettextCatalog.getString("+ Add ProtonVPN", null, "Button") + "</span>\n </div>\n </button>",
link: function(scope, element, _ref) {
var plan = _ref.plan,
value = "free" === plan ? "vpnbasic" : "vpnplus",
onClick = function() {
$rootScope.$emit("dashboard", {
type: "change.addon",
data: {
addon: "vpn",
plan: "free",
value: value
}
}), $rootScope.$emit("dashboard", {
type: "change.addon",
data: {
addon: "vpn",
plan: "plus",
value: value
}
}), $rootScope.$emit("dashboard", {
type: "change.addon",
data: {
addon: "vpn",
plan: "professional",
value: value
}
})
};
element.on("click", onClick), scope.$on("$destroy", function() {
return element.off("click", onClick)
})
}
}
}), angular.module("proton.dashboard").directive("addonRow", function($filter, $rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, dashboardOptions, gettextCatalog, subscriptionModel, customProPlanModel) {
customProPlanModel.init();
var _CONSTANTS$PLANS$ADDO = CONSTANTS.PLANS.ADDON,
MEMBER = _CONSTANTS$PLANS$ADDO.MEMBER,
ADDRESS = _CONSTANTS$PLANS$ADDO.ADDRESS,
DOMAIN = _CONSTANTS$PLANS$ADDO.DOMAIN,
SPACE = _CONSTANTS$PLANS$ADDO.SPACE,
MAP_ADDONS = {
member: MEMBER,
address: ADDRESS,
domain: DOMAIN,
space: SPACE
},
filter = function(amount) {
return $filter("currency")(amount / 100 / dashboardConfiguration.cycle(), dashboardConfiguration.currency())
},
initValue = function(addon) {
return "" + subscriptionModel.count(addon)
},
getPrice = function(_ref) {
var addon = _ref.addon,
value = _ref.value;
if (!value || "none" === value) return "";
var amounts = dashboardModel.amounts();
return "+ " + filter(amounts[MAP_ADDONS[addon]] * value) + "/mo"
};
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/addonRow.tpl.html",
compile: function(element, _ref2) {
function buildOptions() {
var options = _.reduce(dashboardOptions.get(plan, addon), function(acc, _ref3) {
var label = _ref3.label,
value = _ref3.value;
return acc + '<option value="' + value + '">' + label + " " + getPrice({
addon: addon,
value: value
}) + "</option>"
}, "");
$select.html(options)
}
var addon = _ref2.addon,
plan = _ref2.plan,
$select = element.find(".addonRow-select"),
set = function() {
var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : initValue(addon);
return $select.val(value)
};
return buildOptions(),
function(scope) {
var onChange = function() {
return $rootScope.$emit("dashboard", {
type: "change.addon",
data: {
addon: addon,
plan: plan,
value: +$select.val()
}
})
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref4) {
var type = _ref4.type,
_ref4$data = _ref4.data,
data = void 0 === _ref4$data ? {} : _ref4$data;
if ("addon.updated" === type && data.addon === addon && data.plan === plan && (buildOptions(), set(data.value)), "currency.updated" === type || "cycle.updated" === type) {
var value = $select.val();
buildOptions(), set(value)
}
});
$select.on("change", onChange), set(), onChange(), scope.$on("$destroy", function() {
unsubscribe(), $select.off("change", onChange)
})
}
}
}
}), angular.module("proton.dashboard").directive("currencySelector", function($rootScope, dashboardConfiguration) {
var ACTIVE_BUTTON_CLASS = "active";
return {
restrict: "E",
replace: !0,
templateUrl: "templates/dashboard/currencySelector.tpl.html",
link: function(scope, element) {
function onClick(event) {
var currency = event.target.getAttribute("value");
$rootScope.$emit("dashboard", {
type: "change.currency",
data: {
currency: currency
}
}), active(currency)
}
function active(currency) {
_.each($buttons, function(button) {
button.value === currency ? button.classList.add(ACTIVE_BUTTON_CLASS) : button.classList.remove(ACTIVE_BUTTON_CLASS)
})
}
var currency = dashboardConfiguration.currency(),
$buttons = element.find(".currencySelector-button");
element.on("click", onClick);
var unsubscribe = $rootScope.$on("subscription", function(event, _ref) {
var type = _ref.type,
data = _ref.data;
"update" === type && active(data.subscription.Currency)
});
active(currency), scope.$on("$destroy", function() {
unsubscribe(), element.off("click", onClick)
})
}
}
}), angular.module("proton.dashboard").directive("freeColumn", function($rootScope, dashboardConfiguration) {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/freeColumn.tpl.html",
link: function(scope, element) {
var update = function() {
var _dashboardConfigurati = dashboardConfiguration.get(),
free = _dashboardConfigurati.free,
action = free.vpnplus || free.vpnbasic ? "add" : "remove";
element[0].classList[action]("freeColumn-show-vpn")
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref) {
"vpn.updated" === _ref.type && update()
});
update(), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("overviewSection", function($rootScope, authentication, organizationModel, subscriptionModel) {
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/dashboard/overviewSection.tpl.html",
link: function(scope, element) {
function updateUser() {
scope.$applyAsync(function() {
scope.user = angular.copy(authentication.user)
})
}
function updateOrganization(organization) {
scope.$applyAsync(function() {
scope.organization = angular.copy(organization)
})
}
function updateSubscription(subscription) {
scope.$applyAsync(function() {
scope.subscription = angular.copy(subscription)
})
}
function onClick() {
$(".settings").animate({
scrollTop: $("#plans").offset().top
}, 1e3)
}
var unsubscribe = [],
$buttons = element.find(".scroll");
$buttons.on("click", onClick);
var refreshUser = function() {
authentication.fetchUserInfo().then(function(data) {
return scope.user = data
})
};
unsubscribe.push($rootScope.$on("updateUser", function() {
updateUser()
})), unsubscribe.push($rootScope.$on("organizationChange", function(e, organization) {
updateOrganization(organization)
})), unsubscribe.push($rootScope.$on("subscription", function(e, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
"update" === type && updateSubscription(data.subscription)
})), unsubscribe.push($rootScope.$on("payments", function(e, _ref2) {
"topUp.request.success" === _ref2.type && refreshUser()
})), updateUser(), updateOrganization(organizationModel.get()), updateSubscription(subscriptionModel.get()), scope.$on("$destroy", function() {
$buttons.off("click", onClick), _.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.dashboard").directive("planPrice", function($filter, $rootScope, dashboardConfiguration, dashboardModel, gettextCatalog) {
var types = ["cycle.updated", "currency.updated"],
I18N = {
user: gettextCatalog.getString("user", null, "Label"),
month: gettextCatalog.getString("month", null, "Delay")
},
amount = function(plan, cycle, currency) {
var amounts = dashboardModel.amounts(cycle),
month = "/" + I18N.month,
user = "professional" === plan ? "/" + I18N.user : "";
return "" + $filter("currency")(amounts[plan] / 100 / cycle, currency) + month + user
};
return {
restrict: "E",
replace: !0,
scope: {},
template: '<strong class="planPrice"></strong>',
link: function(scope, element, _ref) {
function update() {
scope.$applyAsync(function() {
element.text(amount(plan, dashboardConfiguration.cycle(), dashboardConfiguration.currency()))
})
}
var plan = _ref.plan,
unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) {
var type = _ref2.type;
types.indexOf(type) > -1 && update()
});
update(), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("plusColumn", function() {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/plusColumn.tpl.html"
}
}), angular.module("proton.dashboard").directive("professionalColumn", function(customProPlanModal) {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/professionalColumn.tpl.html",
link: function(scope, element) {
function onClick() {
customProPlanModal.activate({
params: {
close: function() {
customProPlanModal.deactivate()
}
}
})
}
var $buttons = element.find(".professionalColumn-customize");
$buttons.on("click", onClick), scope.$on("$destroy", function() {
$buttons.off("click", onClick)
})
}
}
}), angular.module("proton.dashboard").directive("selectPlan", function($rootScope, gettextCatalog, subscriptionModel) {
var ACTIVE_BUTTON_CLASS = "primary",
I18N = {
downgradeToFree: gettextCatalog.getString("Downgrade to Free", null, "Button to select plan on the dashboard"),
downgradeToPlus: gettextCatalog.getString("Downgrade to Plus", null, "Button to select plan on the dashboard"),
downgradeToProfessional: gettextCatalog.getString("Switch to Professional", null, "Button to select plan on the dashboard"),
updateFree: gettextCatalog.getString("Update Free", null, "Button to select plan on the dashboard"),
updatePlus: gettextCatalog.getString("Update Plus", null, "Button to select plan on the dashboard"),
updateProfessional: gettextCatalog.getString("Update Professional", null, "Button to select plan on the dashboard"),
updateVisionary: gettextCatalog.getString("Update Visionary", null, "Button to select plan on the dashboard"),
upgradeToPlus: gettextCatalog.getString("Upgrade to Plus", null, "Button to select plan on the dashboard"),
upgradeToProfessional: gettextCatalog.getString("Upgrade to Professional", null, "Button to select plan on the dashboard"),
upgradeToVisionary: gettextCatalog.getString("Switch to Visionary", null, "Button to select plan on the dashboard")
},
MAP = {
free: {
free: I18N.updateFree,
plus: I18N.upgradeToPlus,
professional: I18N.upgradeToProfessional,
visionary: I18N.upgradeToVisionary
},
plus: {
free: I18N.downgradeToFree,
plus: I18N.updatePlus,
professional: I18N.upgradeToProfessional,
visionary: I18N.upgradeToVisionary
},
professional: {
free: I18N.downgradeToFree,
plus: I18N.downgradeToPlus,
professional: I18N.updateProfessional,
visionary: I18N.upgradeToVisionary
},
visionary: {
free: I18N.downgradeToFree,
plus: I18N.downgradeToPlus,
professional: I18N.downgradeToProfessional,
visionary: I18N.updateVisionary
}
};
return {
restrict: "E",
replace: !0,
scope: {},
template: '<button class="selectPlan-button pm_button large" type="button"></button>',
link: function(scope, element, _ref) {
function update() {
var currentPlanName = subscriptionModel.name();
element.text(MAP[currentPlanName][plan]), element.addClass(ACTIVE_BUTTON_CLASS), currentPlanName === plan && element.removeClass(ACTIVE_BUTTON_CLASS)
}
var plan = _ref.plan,
onClick = function() {
return $rootScope.$emit("dashboard", {
type: "select.plan",
data: {
plan: plan
}
})
},
unsubscribe = $rootScope.$on("subscription", function(event, _ref2) {
"update" === _ref2.type && update()
});
element.on("click", onClick), update(), scope.$on("$destroy", function() {
element.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("subscriptionSection", function($rootScope, CONSTANTS, subscriptionModel, gettextCatalog) {
function formatTitle() {
var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
switch (plan.Name) {
case "1vpn":
plan.Title = "+ " + plan.time * plan.MaxVPN + " " + I18N.vpn;
break;
case "1gb":
plan.Title = "+ " + plan.time * fromBase(plan.MaxSpace) + " GB";
break;
case "5address":
plan.Title = "+ " + plan.time * plan.MaxAddresses + " " + I18N.addresses;
break;
case "1domain":
plan.Title = "+ " + plan.time * plan.MaxDomains + " " + (plan.time > 1 ? I18N.domains : I18N.domain);
break;
case "1member":
plan.Title = "+ " + plan.time * plan.MaxMembers + " " + (plan.time > 1 ? I18N.members : I18N.member)
}
}
function extractAddons() {
var plans = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
vpn = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
return _.chain(plans).where({
Type: 0
}).reduce(function(acc, plan) {
return vpn === plan.Name.indexOf("vpn") > -1 && (acc[plan.Name] ? (acc[plan.Name].Amount += plan.Amount, acc[plan.Name].time++) : (acc[plan.Name] = plan, acc[plan.Name].time = 1)), acc
}, {}).each(function(plan) {
return formatTitle(plan)
}).value()
}
var _cycles, _CONSTANTS$CYCLE = CONSTANTS.CYCLE,
MONTHLY = _CONSTANTS$CYCLE.MONTHLY,
YEARLY = _CONSTANTS$CYCLE.YEARLY,
TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS,
I18N = {
vpn: gettextCatalog.getString("VPN connections", null),
addresses: gettextCatalog.getString("addresses", null),
domain: gettextCatalog.getString("domain", null),
domains: gettextCatalog.getString("domains", null),
member: gettextCatalog.getString("user", null),
members: gettextCatalog.getString("users", null),
cycles: (_cycles = {}, _defineProperty(_cycles, MONTHLY, gettextCatalog.getString("Monthly", null)), _defineProperty(_cycles, YEARLY, gettextCatalog.getString("Annually", null)), _defineProperty(_cycles, TWO_YEARS, gettextCatalog.getString("2-years", null)), _cycles),
methods: {
card: gettextCatalog.getString("Credit card", null),
paypal: "Paypal"
}
},
formatSubscription = function() {
var sub = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
return sub.cycle = I18N.cycles[sub.Cycle], sub.plans = _.reduce(sub.Plans, function(acc, plan) {
return plan.Type === CONSTANTS.PLANS_TYPE.PLAN && (plan.addons = extractAddons(sub.Plans, plan.Name.indexOf("vpn") > -1), acc.push(plan)), acc
}, []), sub
},
getFirstMethodType = function() {
var methods = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [];
return methods.length ? I18N.methods[methods[0].Type] : "None"
},
fromBase = function(value) {
return value / Math.pow(CONSTANTS.BASE_SIZE, 3)
};
return {
scope: {
methods: "="
},
restrict: "E",
replace: !0,
templateUrl: "templates/dashboard/subscriptionSection.tpl.html",
link: function(scope) {
var subscription = subscriptionModel.get(),
unsubscribe = $rootScope.$on("subscription", function(event, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
"update" === type && scope.$applyAsync(function() {
scope.subscription = formatSubscription(data.subscription)
})
});
scope.subscription = formatSubscription(subscription), scope.method = getFirstMethodType(scope.methods), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("totalPlan", function($filter, $rootScope, dashboardConfiguration, dashboardModel, gettextCatalog) {
var amount = function(plan, cycle, currency) {
return $filter("currency")(dashboardModel.total(plan, cycle) / 100 / cycle, currency)
},
types = ["addon.updated", "cycle.updated", "currency.updated", "vpn.updated"],
month = gettextCatalog.getString("month", null);
return {
restrict: "E",
replace: !0,
scope: {},
template: '<strong class="totalPlan"></strong>',
link: function(scope, element, _ref) {
function update() {
scope.$applyAsync(function() {
element.text(amount(plan, dashboardConfiguration.cycle(), dashboardConfiguration.currency()) + "/" + month)
})
}
var plan = _ref.plan,
unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) {
var type = _ref2.type;
types.indexOf(type) > -1 && update()
});
update(), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("totalRows", function($filter, $rootScope, blackFridayModel, CONSTANTS, dashboardConfiguration, dashboardModel, gettextCatalog, subscriptionModel) {
var _CONSTANTS$CYCLE = CONSTANTS.CYCLE,
MONTHLY = _CONSTANTS$CYCLE.MONTHLY,
YEARLY = _CONSTANTS$CYCLE.YEARLY,
TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS,
I18N = {
billedAs: function(amount, cycle) {
return cycle === YEARLY ? gettextCatalog.getString("Billed as {{amount}} /yr", {
amount: amount
}, "Info") : cycle === TWO_YEARS ? gettextCatalog.getString("Billed as {{amount}} /2-yr", {
amount: amount
}, "Info") : ""
}
},
types = ["addon.updated", "cycle.updated", "currency.updated", "vpn.updated"],
amount = function(plan, cycle, currency, division) {
return $filter("currency")(dashboardModel.total(plan, cycle) / 100 / division, currency)
};
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/totalRows.tpl.html",
link: function(scope, element, _ref) {
function bindClass() {
var action = subscriptionModel.cycle() === TWO_YEARS || blackFridayModel.isBlackFridayPeriod(!0) ? "add" : "remove";
element[0].classList[action]("totalRows-has-2-years")
}
function update() {
scope.$applyAsync(function() {
monthly.text(amount(plan, MONTHLY, dashboardConfiguration.currency(), MONTHLY)), yearly.text(amount(plan, YEARLY, dashboardConfiguration.currency(), YEARLY)), twoYears.text(amount(plan, TWO_YEARS, dashboardConfiguration.currency(), TWO_YEARS)), yearlyBilled.text(I18N.billedAs(amount(plan, YEARLY, dashboardConfiguration.currency(), MONTHLY), YEARLY)), twoYearsBilled.text(I18N.billedAs(amount(plan, TWO_YEARS, dashboardConfiguration.currency(), MONTHLY), TWO_YEARS)), scope.cycle = dashboardConfiguration.cycle()
})
}
var plan = _ref.plan,
unsubscribe = [],
monthly = element.find(".totalRows-monthly-price"),
yearly = element.find(".totalRows-yearly-price"),
yearlyBilled = element.find(".totalRows-yearly-billed-price"),
twoYears = element.find(".totalRows-2-years-price"),
twoYearsBilled = element.find(".totalRows-2-years-billed-price");
scope.onChange = function() {
return $rootScope.$emit("dashboard", {
type: "change.cycle",
data: {
cycle: scope.cycle
}
})
}, unsubscribe.push($rootScope.$on("dashboard", function(event, _ref2) {
var _ref2$type = _ref2.type,
type = void 0 === _ref2$type ? "" : _ref2$type;
types.indexOf(type) > -1 && update()
})), unsubscribe.push($rootScope.$on("blackFriday", function(event, _ref3) {
var _ref3$type = _ref3.type;
"tictac" === (void 0 === _ref3$type ? "" : _ref3$type) && bindClass()
})), update(), bindClass(), scope.$on("$destroy", function() {
unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.dashboard").directive("visionaryColumn", function() {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/visionaryColumn.tpl.html"
}
}), angular.module("proton.dashboard").directive("vpnColumns", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, customVpnModel) {
function onClick(event) {
switch (event.target.getAttribute("data-action")) {
case "vpnbasic":
customVpnModel.set("vpnbasic", 1), customVpnModel.set("vpnplus", 0), customVpnModel.set("vpn", 0);
break;
case "vpnplus":
customVpnModel.set("vpnbasic", 0), customVpnModel.set("vpnplus", 1)
}
}
var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN,
VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC,
VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS;
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/vpnColumns.tpl.html",
link: function(scope, element) {
var amounts = dashboardModel.amounts(),
update = function() {
element.removeClass("vpnColumns-vpnbasic-selected vpnColumns-vpnplus-selected"), customVpnModel.get("vpnbasic") && element.addClass("vpnColumns-vpnbasic-selected"), customVpnModel.get("vpnplus") && element.addClass("vpnColumns-vpnplus-selected")
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref) {
"vpn.modal.updated" === _ref.type && update()
});
scope.vpnbasicAmount = dashboardModel.filter(amounts[VPN_BASIC]) + "/mo", scope.vpnplusAmount = dashboardModel.filter(amounts[VPN_PLUS]) + "/mo", element.on("click", onClick), scope.$on("$destroy", function() {
element.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("vpnDiscountPanel", function() {
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/vpnDiscountPanel.tpl.html"
}
}), angular.module("proton.dashboard").directive("vpnRow", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, gettextCatalog, subscriptionModel, customVpnModal) {
var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN,
VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC,
VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS,
VPN = CONSTANTS.PLANS.ADDON.VPN,
getName = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).vpnplus ? "ProtonVPN Plus" : "ProtonVPN Basic"
},
getClass = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).vpnplus ? "vpnRow-vpnplus" : "vpnRow-vpnbasic"
},
initVpn = function(plan) {
return $rootScope.$emit("dashboard", {
type: "init.vpn",
data: {
plan: plan
}
})
},
I18N = {
with: gettextCatalog.getString("with", null, "ProtonVPN with X connections"),
connections: gettextCatalog.getString("connections", null, "ProtonVPN with X connections")
},
openModal = function(plan) {
customVpnModal.activate({
params: {
plan: plan,
close: function() {
customVpnModal.deactivate()
}
}
})
};
return {
restrict: "E",
replace: !0,
scope: {},
templateUrl: "templates/dashboard/vpnRow.tpl.html",
link: function(scope, element, _ref) {
var plan = _ref.plan,
getAmount = function() {
var vpnbasic = dashboardModel.amount({
plan: plan,
addon: "vpnbasic"
}),
vpnplus = dashboardModel.amount({
plan: plan,
addon: "vpnplus"
}),
vpn = dashboardModel.amount({
plan: plan,
addon: "vpn"
}),
amount = vpnbasic + vpnplus + ("professional" === plan ? vpn : 0);
return "+ " + dashboardModel.filter(amount) + "/mo"
},
getConnections = function(config) {
var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()),
addons = _dashboardModel$get.addons,
connections = function(key) {
return addons[key].MaxVPN
},
vpnbasic = config.vpnbasic * connections(VPN_BASIC),
vpnplus = config.vpnplus * connections(VPN_PLUS),
vpn = config.vpn * connections(VPN);
return vpnbasic + vpnplus + ("professional" === plan ? vpn : 0) + " " + I18N.connections
},
$info = element.find(".vpnRow-info"),
buildString = function(config) {
return $info.html('\n <div class="vpnRow-left">\n <b class="' + getClass(config) + '">' + getName(config) + "</b> " + I18N.with + ' <button type="button" class="vpnRow-edit" data-action="open-vpn-modal">' + getConnections(config) + '</button>\n </div>\n <div class="vpnRow-right">\n <strong>' + getAmount() + "</strong>\n </div>\n ")
},
update = function() {
var config = dashboardConfiguration.get()[plan];
config.vpnplus || config.vpnbasic ? (element.addClass("vpnRow-has-vpn"), buildString(config)) : element.removeClass("vpnRow-has-vpn")
},
onClick = function(event) {
"open-vpn-modal" === event.target.getAttribute("data-action") && openModal(plan)
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) {
var type = _ref2.type;
"currency.updated" !== type && "cycle.updated" !== type || update(), "vpn.updated" === type && update()
});
element.on("click", onClick), initVpn(plan), scope.$on("$destroy", function() {
unsubscribe(), element.off("click", onClick)
})
}
}
}), angular.module("proton.dashboard").directive("vpnSlider", function($rootScope, CONSTANTS, customVpnModel, dashboardConfiguration, dashboardModel) {
var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN,
VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS,
VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC,
onClick = function(event) {
switch (event.target.getAttribute("data-action")) {
case "vpnplus":
customVpnModel.set("vpnbasic", 0), customVpnModel.set("vpnplus", 1)
}
};
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/dashboard/vpnSlider.tpl.html",
link: function(scope, element) {
var $count = element.find(".vpnSlider-count"),
_dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()),
addons = _dashboardModel$get.addons,
vpnbasic = addons[VPN_BASIC],
vpnplus = addons[VPN_PLUS],
_customVpnModel$param = customVpnModel.parameters(),
value = _customVpnModel$param.value,
options = _customVpnModel$param.options,
updateCount = function() {
customVpnModel.get("vpnbasic") && $count.text("" + vpnbasic.MaxVPN), customVpnModel.get("vpnplus") && $count.text("" + (vpnplus.MaxVPN + customVpnModel.get("vpn")))
},
updateSlider = function() {
customVpnModel.get("vpnplus") && scope.$applyAsync(function() {
return scope.value = customVpnModel.get("vpnplus") * vpnplus.MaxVPN + customVpnModel.get("vpn")
})
},
updateClass = function() {
element[0].classList.toggle("vpnSlider-vpnplus-selected", customVpnModel.get("vpnplus")), element[0].classList.toggle("vpnSlider-vpnbasic-selected", customVpnModel.get("vpnbasic"))
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref) {
var _ref$type = _ref.type;
"vpn.modal.updated" === (void 0 === _ref$type ? "" : _ref$type) && (updateCount(), updateSlider(), updateClass())
});
scope.value = value, scope.options = options, element.on("click", onClick), scope.$on("$destroy", function() {
element.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.dashboard").directive("vpnTotal", function($rootScope, CONSTANTS, customVpnModel, dashboardConfiguration, dashboardModel) {
return {
replace: !0,
restrict: "E",
scope: {},
templateUrl: "templates/dashboard/vpnTotal.tpl.html",
link: function(scope, element) {
var $amount = element.find(".vpnTotal-amount"),
updateAmount = function() {
var amount = customVpnModel.amount();
$amount.text(dashboardModel.filter(amount) + "/mo")
},
unsubscribe = $rootScope.$on("dashboard", function(event, _ref) {
var _ref$type = _ref.type;
"vpn.modal.updated" === (void 0 === _ref$type ? "" : _ref$type) && updateAmount()
});
scope.$on("$destroy", function() {
unsubscribe()
})
}
}
}), angular.module("proton.dashboard").factory("customProPlanModel", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel) {
function getSliders() {
return _.reduce(["members", "storage", "addresses"], function(acc, type) {
return acc[type] = getSliderParameters(type), acc
}, {})
}
function getEquivalentOptions() {
var _dashboardModel$get2 = dashboardModel.get(dashboardConfiguration.cycle()),
plan = _dashboardModel$get2.plan,
addons = _dashboardModel$get2.addons,
professionalPlan = plan[PROFESSIONAL],
memberAddon = addons[MEMBER];
return _.range(0, MAX_MEMBER).map(function(value) {
return {
members: value * memberAddon.MaxMembers + professionalPlan.MaxMembers,
storage: value * fromBase(memberAddon.MaxSpace) + fromBase(professionalPlan.MaxSpace),
addresses: value * memberAddon.MaxAddresses + professionalPlan.MaxAddresses
}
})
}
function getSliderParameters(type) {
var _dashboardModel$get3 = dashboardModel.get(dashboardConfiguration.cycle()),
addons = _dashboardModel$get3.addons,
plan = _dashboardModel$get3.plan,
memberAddon = addons[MEMBER],
professionalPlan = plan[PROFESSIONAL],
_dashboardConfigurati = dashboardConfiguration.get(),
professional = _dashboardConfigurati.professional,
options = getEquivalentOptions(),
option = _.findWhere(options, {
members: Number(professional.member) + professionalPlan.MaxMembers
}),
step = void 0,
start = void 0,
min = void 0,
max = void 0;
switch (type) {
case "members":
step = memberAddon.MaxMembers, start = option.members, min = _.first(options).members, max = _.last(options).members;
break;
case "storage":
step = fromBase(memberAddon.MaxSpace), start = option.storage, min = _.first(options).storage, max = _.last(options).storage;
break;
case "addresses":
step = memberAddon.MaxAddresses, start = option.addresses, min = _.first(options).addresses, max = _.last(options).addresses
}
return {
value: start,
options: {
type: type,
animate: !1,
tooltips: !0,
connect: [!0, !1],
start: start,
step: step,
range: {
min: min,
max: max
},
pips: {
mode: "values",
values: [min, max],
density: 4
},
format: {
to: function(value) {
return "" + Number(value).toFixed()
},
from: function(value) {
return value
}
}
}
}
}
var PLANS = CONSTANTS.PLANS,
BASE_SIZE = CONSTANTS.BASE_SIZE,
MAX_MEMBER = CONSTANTS.MAX_MEMBER,
PLAN = PLANS.PLAN,
ADDON = PLANS.ADDON,
MEMBER = ADDON.MEMBER,
PROFESSIONAL = PLAN.PROFESSIONAL,
fromBase = function(value) {
return value / Math.pow(BASE_SIZE, 3)
},
CACHE = {},
refreshSlider = function(type) {
return $rootScope.$emit("refresh.slider", {
type: type,
data: {
value: CACHE[type]
}
})
},
send = function() {
var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()),
plan = _dashboardModel$get.plan,
professionalPlan = plan[PROFESSIONAL];
$rootScope.$emit("dashboard", {
type: "change.addon",
data: {
plan: "professional",
addon: "member",
value: CACHE.members - professionalPlan.MaxMembers
}
})
};
return $rootScope.$on("slider.updated", function(event, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (_.contains(["members", "storage", "addresses"], type)) {
var options = getEquivalentOptions(),
_$findWhere = _.findWhere(options, _defineProperty({}, type, data.value)),
members = _$findWhere.members,
storage = _$findWhere.storage,
addresses = _$findWhere.addresses;
CACHE.members = members, CACHE.storage = storage, CACHE.addresses = addresses, refreshSlider("members"), refreshSlider("storage"), refreshSlider("addresses")
}
}), {
init: angular.noop,
getSliders: getSliders,
send: send
}
}), angular.module("proton.dashboard").factory("customVpnModel", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel) {
var MAX_VPN = CONSTANTS.MAX_VPN,
PLANS = CONSTANTS.PLANS,
PLAN = PLANS.PLAN,
ADDON = PLANS.ADDON,
VPN = ADDON.VPN,
VPN_BASIC = PLAN.VPN_BASIC,
VPN_PLUS = PLAN.VPN_PLUS,
CACHE = {},
dispatch = function() {
return $rootScope.$emit("dashboard", {
type: "vpn.modal.updated"
})
},
set = function(key, value) {
CACHE[key] = value, dispatch()
},
get = function(key) {
return key ? CACHE[key] : angular.copy(CACHE)
},
parameters = function() {
var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()),
addons = _dashboardModel$get.addons,
vpn = addons[VPN],
vpnplus = addons[VPN_PLUS],
step = vpn.MaxVPN,
min = vpnplus.MaxVPN,
start = CACHE.vpn + vpnplus.MaxVPN,
max = MAX_VPN;
return {
value: start,
options: {
type: "vpn",
animate: !1,
tooltips: !0,
connect: [!0, !1],
start: start,
step: step,
range: {
min: min,
max: max
},
pips: {
mode: "values",
values: [min, max],
density: 4
},
format: {
to: function(value) {
return "" + Number(value).toFixed()
},
from: function(value) {
return value
}
}
}
}
},
init = function(plan) {
var config = dashboardConfiguration.get(),
_config$plan = config[plan],
_config$plan$vpnbasic = _config$plan.vpnbasic,
vpnbasic = void 0 === _config$plan$vpnbasic ? 0 : _config$plan$vpnbasic,
_config$plan$vpnplus = _config$plan.vpnplus,
vpnplus = void 0 === _config$plan$vpnplus ? 0 : _config$plan$vpnplus,
_config$plan$vpn = _config$plan.vpn,
vpn = void 0 === _config$plan$vpn ? 0 : _config$plan$vpn;
CACHE.vpnbasic = vpnbasic, CACHE.vpnplus = vpnbasic || vpnplus ? vpnplus : 1, CACHE.vpn = vpn, dispatch()
},
amount = function() {
var amounts = dashboardModel.amounts(),
result = 0;
return CACHE.vpnbasic && (result += amounts[VPN_BASIC]), CACHE.vpnplus && (result += amounts[VPN_PLUS]), CACHE.vpn && (result += CACHE.vpn * amounts[VPN]), result
};
return $rootScope.$on("slider.updated", function(event, _ref) {
var _ref$type = _ref.type,
type = void 0 === _ref$type ? "" : _ref$type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if ("vpn" === type) {
var _dashboardModel$get2 = dashboardModel.get(dashboardConfiguration.cycle()),
addons = _dashboardModel$get2.addons,
vpnplus = addons[VPN_PLUS];
CACHE.vpn = data.value - vpnplus.MaxVPN, dispatch()
}
}), {
init: init,
set: set,
get: get,
parameters: parameters,
amount: amount
}
}), angular.module("proton.dashboard").factory("dashboardConfiguration", function() {
var CONFIGURATION = {
free: {},
plus: {},
professional: {}
};
return {
cycle: function() {
return CONFIGURATION.cycle
},
currency: function() {
return CONFIGURATION.currency
},
get: function() {
return angular.copy(CONFIGURATION)
},
set: function(key, value) {
return CONFIGURATION[key] = value
},
addon: function(plan, _addon, value) {
return CONFIGURATION[plan][_addon] = value
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.dashboard").factory("dashboardModel", function($filter, $rootScope, confirmModal, CONSTANTS, dashboardConfiguration, downgrade, gettextCatalog, Payment, paymentModal, subscriptionModel, networkActivityTracker, paymentModel) {
var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN,
PLUS = _CONSTANTS$PLANS$PLAN.PLUS,
PROFESSIONAL = _CONSTANTS$PLANS$PLAN.PROFESSIONAL,
VISIONARY = _CONSTANTS$PLANS$PLAN.VISIONARY,
VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC,
VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS,
MAIL_PLANS = ["free", PLUS, PROFESSIONAL, VISIONARY],
_CONSTANTS$PLANS$ADDO = CONSTANTS.PLANS.ADDON,
ADDRESS = _CONSTANTS$PLANS$ADDO.ADDRESS,
MEMBER = _CONSTANTS$PLANS$ADDO.MEMBER,
DOMAIN = _CONSTANTS$PLANS$ADDO.DOMAIN,
SPACE = _CONSTANTS$PLANS$ADDO.SPACE,
VPN = _CONSTANTS$PLANS$ADDO.VPN,
_CONSTANTS$CYCLE = CONSTANTS.CYCLE,
MONTHLY = _CONSTANTS$CYCLE.MONTHLY,
YEARLY = _CONSTANTS$CYCLE.YEARLY,
TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS,
CACHE_PLAN = {},
CACHE_API = {},
filter = function(amount) {
return $filter("currency")(amount / 100 / dashboardConfiguration.cycle(), dashboardConfiguration.currency())
},
get = function(key) {
var cache = angular.copy(CACHE_PLAN);
return key ? cache[key] : cache
},
changeAddon = function(plan, addon, value) {
dashboardConfiguration.addon(plan, addon, value), $rootScope.$emit("dashboard", {
type: "addon.updated",
data: {
plan: plan,
addon: addon,
value: value
}
})
},
selectVpn = function() {
var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
vpn = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
dashboardConfiguration.addon("free", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("free", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("plus", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("plus", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("professional", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("professional", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("professional", "vpn", vpn), $rootScope.$emit("dashboard", {
type: "vpn.updated"
})
},
removeVpn = function() {
dashboardConfiguration.addon("free", "vpnbasic", 0), dashboardConfiguration.addon("free", "vpnplus", 0), dashboardConfiguration.addon("plus", "vpnbasic", 0), dashboardConfiguration.addon("plus", "vpnplus", 0), dashboardConfiguration.addon("professional", "vpnbasic", 0), dashboardConfiguration.addon("professional", "vpnplus", 0), dashboardConfiguration.addon("professional", "vpn", 0), $rootScope.$emit("dashboard", {
type: "vpn.updated"
})
},
updateVpn = function() {
var vpnbasic = +subscriptionModel.hasPaid("vpnbasic"),
vpnplus = +subscriptionModel.hasPaid("vpnplus"),
vpn = subscriptionModel.count("vpn");
dashboardConfiguration.addon("free", "vpnbasic", vpnbasic), dashboardConfiguration.addon("free", "vpnplus", vpnplus), dashboardConfiguration.addon("plus", "vpnbasic", vpnbasic), dashboardConfiguration.addon("plus", "vpnplus", vpnplus), dashboardConfiguration.addon("professional", "vpnbasic", vpnbasic), dashboardConfiguration.addon("professional", "vpnplus", vpnplus), dashboardConfiguration.addon("professional", "vpn", vpn), $rootScope.$emit("dashboard", {
type: "vpn.updated"
})
},
initVpn = function() {
var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
dashboardConfiguration.addon(plan, "vpnbasic", +subscriptionModel.hasPaid("vpnbasic")), dashboardConfiguration.addon(plan, "vpnplus", +subscriptionModel.hasPaid("vpnplus")), "professional" === plan && dashboardConfiguration.addon(plan, "vpn", subscriptionModel.count("vpn")), $rootScope.$emit("dashboard", {
type: "vpn.updated",
data: {
plan: plan
}
})
},
query = function() {
var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "USD",
cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY,
key = "plans-" + currency + "-" + cycle,
_ref = CACHE_API[key] || {},
_ref$Plans = _ref.Plans;
return void 0 === _ref$Plans ? [] : _ref$Plans
},
collectPlans = function(plan) {
var plans = [],
cache = CACHE_PLAN[dashboardConfiguration.cycle()],
config = dashboardConfiguration.get();
switch (plan) {
case "free":
config.free.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.free.vpnplus && plans.push(cache.addons[VPN_PLUS]);
break;
case "plus":
plans.push(cache.plan[PLUS]), config.plus.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.plus.vpnplus && plans.push(cache.addons[VPN_PLUS]), _.times(config.plus.space, function() {
return plans.push(cache.addons[SPACE])
}), _.times(config.plus.address, function() {
return plans.push(cache.addons[ADDRESS])
}), _.times(config.plus.domain, function() {
return plans.push(cache.addons[DOMAIN])
});
break;
case "professional":
plans.push(cache.plan[PROFESSIONAL]), config.professional.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.professional.vpnplus && plans.push(cache.addons[VPN_PLUS]), _.times(config.professional.member, function() {
return plans.push(cache.addons[MEMBER])
}), _.times(config.professional.domain, function() {
return plans.push(cache.addons[DOMAIN])
}), _.times(config.professional.vpn, function() {
return plans.push(cache.addons[VPN])
});
break;
case "visionary":
plans.push(cache.plan[VISIONARY])
}
return plans
},
selectPlan = function(plan, choice) {
var plans = collectPlans(plan);
if ("free" === plan && !plans.length) return downgrade();
var PlanIDs = _.pluck(plans, "ID"),
promise = Payment.valid({
Cycle: dashboardConfiguration.cycle(),
Currency: dashboardConfiguration.currency(),
PlanIDs: PlanIDs,
Coupon: subscriptionModel.coupon()
}).then(function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref2$data = _ref2.data,
valid = void 0 === _ref2$data ? {} : _ref2$data;
paymentModal.activate({
params: {
planIDs: PlanIDs,
valid: valid,
choice: choice,
plan: plan,
cancel: function() {
paymentModal.deactivate()
}
}
})
}).catch(function() {
var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
throw Error(data.Error)
});
networkActivityTracker.track(promise)
},
fetchPlans = function() {
var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "USD",
cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY,
key = "plans-" + currency + "-" + cycle;
return CACHE_API[key] ? Promise.resolve(CACHE_API[key]) : Payment.plans(currency, cycle).then(function(_ref4) {
var _ref4$data = _ref4.data,
data = void 0 === _ref4$data ? {} : _ref4$data;
return CACHE_API[key] = data, data
}).catch(function() {
var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref5$data = _ref5.data;
throw (void 0 === _ref5$data ? {} : _ref5$data).Error
})
},
loadPlanCycle = function(currency) {
var cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY;
return fetchPlans(currency, cycle).then(function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_reduce = (data.Plans || []).reduce(function(acc, plan) {
return acc.amounts[plan.Name] = plan.Amount, _.contains(MAIL_PLANS, plan.Name) ? (acc.plan[plan.Name] = plan, acc.list.push(plan), acc) : (acc.addons[plan.Name] = plan, acc)
}, {
addons: {},
plan: {},
list: [],
amounts: {}
});
return {
list: _reduce.list,
addons: _reduce.addons,
plan: _reduce.plan,
amounts: _reduce.amounts
}
})
},
loadPlans = function() {
var Currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : dashboardConfiguration.currency(),
promise = Promise.all([loadPlanCycle(Currency), loadPlanCycle(Currency, MONTHLY), loadPlanCycle(Currency, TWO_YEARS)]).then(function(_ref6) {
var _ref7 = _slicedToArray(_ref6, 3),
yearly = _ref7[0],
monthly = _ref7[1],
twoYears = _ref7[2];
return CACHE_PLAN[YEARLY] = angular.copy(yearly), CACHE_PLAN[MONTHLY] = angular.copy(monthly), CACHE_PLAN[TWO_YEARS] = angular.copy(twoYears), angular.copy(CACHE_PLAN)
});
return networkActivityTracker.track(promise), promise
},
changeCurrency = function(currency) {
loadPlans(currency).then(function(data) {
dashboardConfiguration.set("currency", currency), $rootScope.$emit("dashboard", {
type: "currency.updated",
data: _.extend(data, {
currency: currency
})
})
})
},
amounts = function() {
var cycle = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : dashboardConfiguration.cycle();
return angular.copy(CACHE_PLAN[cycle].amounts)
},
amount = function(_ref8) {
var _ref8$config = _ref8.config,
config = void 0 === _ref8$config ? dashboardConfiguration.get() : _ref8$config,
plan = _ref8.plan,
addon = _ref8.addon,
_ref8$cycle = _ref8.cycle,
cycle = void 0 === _ref8$cycle ? dashboardConfiguration.cycle() : _ref8$cycle;
switch (addon) {
case "vpn":
return CACHE_PLAN[cycle].amounts[VPN] * config[plan].vpn;
case "address":
return CACHE_PLAN[cycle].amounts[ADDRESS] * config[plan].address;
case "space":
return CACHE_PLAN[cycle].amounts[SPACE] * config[plan].space;
case "domain":
return CACHE_PLAN[cycle].amounts[DOMAIN] * config[plan].domain;
case "member":
return CACHE_PLAN[cycle].amounts[MEMBER] * config[plan].member;
case "vpnbasic":
return CACHE_PLAN[cycle].amounts[VPN_BASIC] * config[plan].vpnbasic;
case "vpnplus":
return CACHE_PLAN[cycle].amounts[VPN_PLUS] * config[plan].vpnplus
}
switch (plan) {
case "plus":
case "professional":
case "visionary":
return CACHE_PLAN[cycle].amounts[plan];
default:
return 0
}
},
total = function(plan, cycle) {
var config = dashboardConfiguration.get(),
result = 0;
switch (plan) {
case "free":
result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_BASIC
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_PLUS
});
break;
case "plus":
result += amount({
config: config,
plan: plan,
cycle: cycle
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "address"
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "space"
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "domain"
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_BASIC
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_PLUS
}), result *= config[plan].vpnbasic || config[plan].vpnplus ? .8 : 1;
break;
case "professional":
result += amount({
config: config,
plan: plan,
cycle: cycle
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "member"
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "domain"
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_BASIC
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: VPN_PLUS
}), result += amount({
config: config,
plan: plan,
cycle: cycle,
addon: "vpn"
}), result *= config[plan].vpnbasic || config[plan].vpnplus ? .8 : 1;
break;
case "visionary":
result += amount({
config: config,
plan: plan,
cycle: cycle
})
}
return result
},
changeCycle = function(cycle) {
dashboardConfiguration.set("cycle", cycle), $rootScope.$emit("dashboard", {
type: "cycle.updated",
data: {
cycle: cycle
}
})
};
return $rootScope.$on("subscription", function(event, _ref9) {
var _ref9$type = _ref9.type;
"update" === (void 0 === _ref9$type ? "" : _ref9$type) && (updateVpn(), changeCycle(subscriptionModel.cycle()), changeCurrency(subscriptionModel.currency()))
}), $rootScope.$on("dashboard", function(event, _ref10) {
var type = _ref10.type,
_ref10$data = _ref10.data,
data = void 0 === _ref10$data ? {} : _ref10$data;
"change.cycle" === type && changeCycle(data.cycle), "change.currency" === type && changeCurrency(data.currency), "change.addon" === type && changeAddon(data.plan, data.addon, data.value), "select.plan" === type && selectPlan(data.plan), "select.vpn" === type && selectVpn(data.plan, data.vpn), "remove.vpn" === type && removeVpn(), "init.vpn" === type && initVpn(data.plan)
}), $rootScope.$on("modal.payment", function(e, _ref11) {
var type = _ref11.type,
data = _ref11.data;
if ("process.success" === type) {
var promise = Promise.all([subscriptionModel.fetch(), paymentModel.getMethods(!0)]);
networkActivityTracker.track(promise)
}
if ("switch" === type) {
var Cycle = data.Cycle,
Currency = data.Currency,
plan = data.plan;
paymentModal.deactivate(), dashboardConfiguration.set("currency", Currency), dashboardConfiguration.set("cycle", Cycle), loadPlanCycle(Currency, Cycle).then(function() {
selectPlan(plan, "paypal")
})
}
}), {
init: angular.noop,
loadPlans: loadPlans,
fetchPlans: fetchPlans,
get: get,
query: query,
amount: amount,
amounts: amounts,
total: total,
filter: filter
}
}), angular.module("proton.dashboard").factory("dashboardOptions", function(gettextCatalog, CONSTANTS) {
var MAX_MEMBER = CONSTANTS.MAX_MEMBER,
ADDRESS_OPTIONS = _.range(5, 51, 5).map(function(value, index) {
return {
label: gettextCatalog.getString("{{value}} Addresses", {
value: value
}, "dashboard options select"),
value: index
}
}),
SPACE_OPTIONS = _.range(5, 21).map(function(value, index) {
return {
label: gettextCatalog.getPlural(value, "1 GB Storage", "{{$count}} GB Storage", {}, "dashboard options select"),
value: index
}
}),
MEMBER_OPTIONS = _.range(1, MAX_MEMBER + 1).map(function(value, index) {
return {
label: gettextCatalog.getPlural(value, "1 User", "{{$count}} Users", {}, "dashboard options select"),
value: index
}
}),
generateDomains = function(start, end) {
return _.range(start, end).map(function(value, index) {
return {
label: gettextCatalog.getPlural(value, "1 Custom Domain", "{{$count}} Custom Domains", {}, "dashboard options select"),
value: index
}
})
},
VPN_OPTIONS = [{
label: "----------",
value: "none"
}, {
label: "Basic",
value: "vpnbasic"
}, {
label: "Plus",
value: "vpnplus"
}],
options = {
free: {
vpn: VPN_OPTIONS
},
plus: {
vpn: VPN_OPTIONS,
address: ADDRESS_OPTIONS,
space: SPACE_OPTIONS,
domain: generateDomains(1, 11)
},
professional: {
vpn: VPN_OPTIONS,
member: MEMBER_OPTIONS,
domain: generateDomains(2, 11)
}
};
return {
get: function(plan, addon) {
return angular.copy(options[plan][addon])
}
}
}), angular.module("proton.dashboard").factory("downgrade", function($rootScope, confirmModal, eventManager, gettextCatalog, networkActivityTracker, notification, Payment, subscriptionModel) {
function unsubscribe() {
return Payment.delete().then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data
}).then(function() {
return eventManager.call()
}).then(function() {
return subscriptionModel.set(FREE_PLAN)
}).catch(function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
throw Error(data.Error)
})
}
var FREE_PLAN = {
Type: 1,
Name: "free"
},
I18N = {
downgradeTitle: gettextCatalog.getString("Confirm downgrade", null, "Title"),
downgradeMessage: gettextCatalog.getString("This will downgrade your account to a free account. ProtonMail is free software that is supported by donations and paid accounts. Please consider making a donation so we can continue to offer the service for free.<br /><br />Note: Additional addresses, custom domains, and users must be removed/disabled before performing this action.", null, "Info"),
successMessage: gettextCatalog.getString("You have successfully unsubscribed", null, "Downgrade account")
};
return function() {
confirmModal.activate({
params: {
title: I18N.downgradeTitle,
message: I18N.downgradeMessage,
confirm: function() {
var promise = unsubscribe().then(function() {
confirmModal.deactivate(), notification.success(I18N.successMessage)
});
networkActivityTracker.track(promise)
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}
}), angular.module("proton.dashboard").factory("customProPlanModal", function(customProPlanModel, gettextCatalog, pmModal) {
var I18N = {
members: function(value) {
return gettextCatalog.getPlural(value, "1 user", "{{$count}} users", {}, "Custom pro plan dashboard")
},
storage: function(value) {
return gettextCatalog.getString("{{value}} GB storage", {
value: value
}, "Custom pro plan dashboard")
},
addresses: function(value) {
return gettextCatalog.getString("{{value}} addresses", {
value: value
}, "Custom pro plan dashboard")
}
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/dashboard/customProPlanModal.tpl.html",
controller: function(params) {
var _this = this;
this.sliders = customProPlanModel.getSliders(), this.format = function(type) {
return I18N[type](_this.sliders[type].value)
}, this.close = function() {
return params.close()
}, this.submit = function() {
customProPlanModel.send(), params.close()
}
}
})
}), angular.module("proton.dashboard").factory("customVpnModal", function($rootScope, dashboardConfiguration, pmModal, customVpnModel) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/dashboard/customVpnModal.tpl.html",
controller: function(params) {
var config = dashboardConfiguration.get(),
plan = params.plan;
customVpnModel.init(plan), this.fromPlan = "customVpnModal-from-" + plan, this.hasVpn = config[plan].vpnbasic || config[plan].vpnplus, this.close = function() {
return params.close()
}, this.remove = function() {
return $rootScope.$emit("dashboard", {
type: "remove.vpn"
}), params.close()
}, this.submit = function() {
var vpnplus = customVpnModel.get("vpnplus"),
vpn = customVpnModel.get("vpn");
$rootScope.$emit("dashboard", {
type: "select.vpn",
data: {
plan: vpnplus ? "vpnplus" : "vpnbasic",
vpn: vpn
}
}), params.close()
}
}
})
}), angular.module("proton.dnd").constant("PTDNDCONSTANTS", {
CLASSNAME: {
BODY: "ptdnd-dragstart",
DRAG_HOVER: "ptdnd-drag-hover",
DROPZONE: "ptDnd-dropzone-container",
DROPZONE_HOVER: "ptdnd-dropzone-hover",
NOTIF: "ptdnd-notification",
NOTIF_ACTIVE: "ptdnd-notification-active",
NOTIF_FIREFOX: "ptdnd-notification-firefox",
DRAG_IMAGE: "ptdnd-dragimage"
},
DROPZONE_ATTR_ID: "data-pt-drop-id"
}), angular.module("proton.dnd").directive("ptDraggable", function($rootScope, ptDndModel, ptDndUtils, PTDNDCONSTANTS, ptDndNotification) {
var CLASSNAME = PTDNDCONSTANTS.CLASSNAME,
DROPZONE_ATTR_ID = PTDNDCONSTANTS.DROPZONE_ATTR_ID,
getSelected = angular.noop;
return document.addEventListener("dragstart", function(event) {
var target = ptDndUtils.getDragInitiatorNode(event.target);
if (!target) return ptDndModel.draggable.set("currentId", null);
var eventData = event.dataTransfer || event.originalEvent.dataTransfer;
if (document.body.classList.add(CLASSNAME.BODY), eventData.effectAllowed = "move", eventData.setData("Text", JSON.stringify({
id: target.dataset.ptId
})), ptDndModel.draggable.set("currentId", target.dataset.ptId), ptDndModel.draggable.has(target.dataset.ptId)) {
var item = ptDndModel.draggable.get(target.dataset.ptId);
item.hookDragStart(target, event), ptDndNotification.onDragStart(event, eventData, item.type)
}
return !1
}), document.addEventListener("dragenter", function(_ref) {
var target = _ref.target;
1 === target.nodeType && !target.classList.contains(CLASSNAME.DRAG_HOVER) && target.hasAttribute(DROPZONE_ATTR_ID) && (angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER), target.classList.add(CLASSNAME.DRAG_HOVER))
}), document.addEventListener("dragleave", function(_ref2) {
var target = _ref2.target;
1 === target.nodeType && target.classList.contains(CLASSNAME.DRAG_HOVER) && target.classList.remove(CLASSNAME.DRAG_HOVER)
}), document.addEventListener("dragend", function() {
document.body.classList.remove(CLASSNAME.BODY), angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER), ptDndModel.draggable.set("currentId", null)
}), {
link: function(scope, el) {
getSelected = scope.getElements;
var id = ptDndUtils.generateUniqId();
el[0].setAttribute("draggable", !0), el[0].setAttribute("data-pt-id", id), ptDndModel.draggable.set(id, {
model: scope.conversation,
type: scope.conversation.ConversationID ? "message" : "conversation",
hookDragStart: function(target, event) {
var _this = this,
value = $rootScope.numberElementChecked;
if (scope.conversation.Selected) return scope.$applyAsync(function() {
scope.conversation.Selected = !0, $rootScope.numberElementChecked = value, _this.onDragStart(target, event, getSelected())
});
$rootScope.$emit("dnd", {
type: "hook.dragstart",
data: {
before: {
number: value,
ids: _.pluck(getSelected(), "ID")
}
}
}), scope.$applyAsync(function() {
scope.conversation.Selected = !0, $rootScope.numberElementChecked = 1, _this.onDragStart(target, event, [scope.conversation])
})
}
})
}
}
}), angular.module("proton.dnd").directive("ptDropzone", function($rootScope, ptDndUtils, ptDndModel, PTDNDCONSTANTS) {
var CLASSNAME = PTDNDCONSTANTS.CLASSNAME,
DROPZONE_ATTR_ID = PTDNDCONSTANTS.DROPZONE_ATTR_ID;
return document.addEventListener("dragenter", function(_ref) {
var target = _ref.target;
1 === target.nodeType && target.hasAttribute(DROPZONE_ATTR_ID) && (angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), target.classList.add(CLASSNAME.DROPZONE_HOVER))
}), document.addEventListener("dragover", function(e) {
if (e.preventDefault(), e.target.hasAttribute(DROPZONE_ATTR_ID)) {
var dragItemId = e.target.getAttribute(DROPZONE_ATTR_ID);
return ptDndModel.dropzone.get(dragItemId).onDragOver(e.target, e), (e.dataTransfer || e.originalEvent.dataTransfer).dropEffect = "move", !1
}
}), document.addEventListener("drop", function(e) {
if (e.preventDefault(), document.body.classList.remove(CLASSNAME.BODY), e.target.hasAttribute(DROPZONE_ATTR_ID) && ptDndModel.draggable.has("currentId")) {
var dragElmId = e.target.getAttribute(DROPZONE_ATTR_ID),
_JSON$parse = JSON.parse((e.dataTransfer || e.originalEvent.dataTransfer).getData("Text")),
id = _JSON$parse.id;
ptDndModel.dropzone.get(dragElmId).onDropSuccess(e, id), ptDndModel.draggable.get(id).onDropItem(e), angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER)
}
}), {
type: "A",
link: function(scope, el) {
var unsubscribe = [],
refresh = function() {
ptDndModel.dropzone.reset(), [].slice.call(el[0].querySelectorAll("[data-pt-dropzone-item]")).forEach(function(node) {
var id = ptDndUtils.generateUniqId("drop");
node.classList.add("ptDnd-dropzone-container"), node.setAttribute(DROPZONE_ATTR_ID, id), ptDndModel.dropzone.set(id, {
value: node.dataset.ptDropzoneItem,
type: node.dataset.ptDropzoneItemType
})
})
},
id = setTimeout(function() {
return refresh(), clearTimeout(id)
}, 1e3);
unsubscribe.push($rootScope.$on("labelsModel", function(e, _ref2) {
var type = _ref2.type;
"cache.refesh" !== type && "cache.update" !== type || refresh()
})), unsubscribe.push($rootScope.$on("$stateChangeSuccess", function() {
_rAF(refresh)
})), scope.$on("$destroy", function() {
unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.dnd").factory("ptDndModel", function($rootScope) {
var CACHE = {},
reset = function(type) {
return function() {
return CACHE[type] = {}
}
},
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("ptDnd", {
type: type,
data: data
})
};
$rootScope.$on("$stateChangeStart", function() {
reset("draggable")
});
var make = function(type) {
var has = function(id) {
return !!(CACHE[type] || {})[id]
},
get = function(id) {
return (CACHE[type] || {})[id]
};
return {
has: has,
set: function(id, value) {
CACHE[type] = CACHE[type] || {}, "draggable" === type && "currentId" !== id && (CACHE[type][id] = _.extend({
selectedList: [],
onDragStart: function(target, event) {
var selectedList = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : [];
CACHE[type][id].selectedList = selectedList, dispatch("dragstart", {
id: id,
target: target,
event: event,
selectedList: selectedList,
model: CACHE[type][id].model,
type: CACHE[type][id].type
})
},
onDropItem: function(event) {
dispatch("drop", {
event: event,
selectedList: CACHE[type][id].selectedList,
model: CACHE[type][id].model,
type: CACHE[type][id].type
})
}
}, value)), "draggable" === type && "currentId" === id && (CACHE[type][id] = value), "dropzone" === type && (CACHE[type][id] = _.extend({
onDragOver: function(target, event) {
dispatch("dragover", {
id: id,
target: target,
event: event,
value: CACHE[type][id].value,
type: CACHE[type][id].type
})
},
onDropSuccess: function(event, itemId) {
_rAF(function() {
dispatch("dropsuccess", {
itemId: itemId,
event: event,
value: CACHE[type][id].value,
type: CACHE[type][id].type
})
})
}
}, value))
},
get: get,
reset: reset(type)
}
};
return {
draggable: make("draggable"),
dropzone: make("dropzone")
}
}), angular.module("proton.dnd").factory("ptDndNotification", function(PTDNDCONSTANTS, gettextCatalog, $rootScope, aboutClient) {
var CLASSNAME = PTDNDCONSTANTS.CLASSNAME,
getMessage = function(total, item) {
var message = gettextCatalog.getPlural(total, "message", "messages", {}),
conversation = gettextCatalog.getPlural(total, "conversation", "conversations", {});
return gettextCatalog.getString("Move {{total}} {{type}}", {
type: "conversation" === item ? conversation : message,
total: total
}, "notification drag and drop")
},
isIE11 = aboutClient.isIE11(),
isEdge = aboutClient.isEdge(),
isFirefox = aboutClient.isFirefox(),
suffix = isEdge ? "!important" : "",
$notif = function() {
var $notif = document.createElement("SPAN");
return $notif.className = CLASSNAME.NOTIF, document.body.appendChild($notif), $notif
}();
isFirefox && $notif.classList.add(CLASSNAME.NOTIF_FIREFOX);
var show = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : $notif).classList.add(CLASSNAME.NOTIF_ACTIVE)
},
hide = function() {
return $notif.classList.remove(CLASSNAME.NOTIF_ACTIVE)
};
!isFirefox && document.addEventListener("drag", function(e) {
_rAF(function() {
$notif.style.transform = ("translate(" + e.clientX + "px, " + e.clientY + "px) " + suffix).trim()
})
}), document.addEventListener("dragend", function() {
hide()
});
var onDragStart = function(e, eventData, type) {
if ($notif.textContent = getMessage($rootScope.numberElementChecked || 1, type), !isIE11 && !isEdge && !isFirefox) {
var img = new Image;
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", eventData.setDragImage(img, 0, 0)
}
isFirefox && eventData.setDragImage($notif, 0, 0), !isIE11 && !isEdge && show()
};
return {
init: angular.noop,
show: show,
hide: hide,
onDragStart: onDragStart
}
}), angular.module("proton.dnd").factory("actionDnd", function($rootScope, $state, CONSTANTS, ptDndModel, actionConversation, labelsModel, gettextCatalog, notification, ptDndNotification, authentication) {
var NOTIFS = {
APPLY_LABEL: gettextCatalog.getString("Apply label", null, "notification drag and drop"),
star: function(total, type) {
var message = gettextCatalog.getPlural(total, "message", "messages", {}),
conversation = gettextCatalog.getPlural(total, "conversation", "conversations", {});
return gettextCatalog.getString("Star {{total}} {{type}}", {
type: "conversation" === type ? conversation : message,
total: total
}, "notification drag and drop")
}
};
ptDndNotification.init();
var move = function(ids, type, labelID) {
if ("conversation" === type) return actionConversation.move(ids, labelID);
$rootScope.$emit("messageActions", {
action: "move",
data: {
ids: ids,
labelID: labelID
}
})
},
label = function(list, type, labelID) {
var ids = _.pluck(list, "ID"),
label = labelsModel.read(labelID),
labels = [(label.Selected = !0, label)];
if (labelsModel.read(labelID, "folders")) return move(ids, type, labelID);
authentication.user.AlsoArchive && move(ids, type, CONSTANTS.MAILBOX_IDENTIFIERS.archive), "conversation" === type ? actionConversation.label(ids, labels) : $rootScope.$emit("messageActions", {
action: "label",
data: {
messages: list,
labels: labels
}
}), notification.success(NOTIFS.APPLY_LABEL + " " + label.Name)
},
star = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
type = arguments[1];
list.forEach(function(model) {
$rootScope.$emit("elements", {
type: "toggleStar",
data: {
model: model,
type: type
}
})
}), notification.success(NOTIFS.star(list.length, type))
},
selectedList = void 0;
return $rootScope.$on("ptDnd", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
if ("drop" === type && (selectedList = data.selectedList), "dropsuccess" === type) {
var _ptDndModel$draggable = ptDndModel.draggable.get(data.itemId),
model = _ptDndModel$draggable.model,
_type = _ptDndModel$draggable.type,
list = $rootScope.numberElementChecked && selectedList ? selectedList : [model],
ids = _.pluck(list, "ID");
if (selectedList = void 0, "label" === data.type) return label(list, _type, data.value);
if ("starred" === data.value) return star(list, _type);
move(ids, _type, CONSTANTS.MAILBOX_IDENTIFIERS[data.value])
}
}), {
init: angular.noop
}
}), angular.module("proton.dnd").factory("ptDndUtils", function() {
function generateUniqId() {
return "" + (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "drag-") + Math.random().toString(36).substring(7)
}
function getDragInitiatorNode(node) {
for (var currentNode = node; currentNode.parentNode;) {
if ("true" === currentNode.getAttribute("draggable")) return currentNode;
currentNode = currentNode.parentNode
}
return null
}
return {
generateUniqId: generateUniqId,
getDragInitiatorNode: getDragInitiatorNode
}
}), angular.module("proton.domains").directive("domainsMenuStep", function() {
return {
replace: !0,
templateUrl: "templates/domains/domainsMenuStep.tpl.html"
}
}), angular.module("proton.domains").factory("domainApi", function($http, url) {
var requestURL = url.build("domains"),
create = function(params) {
return $http.post(requestURL(), params)
},
query = function() {
return $http.get(requestURL())
},
available = function() {
return $http.get(requestURL("available"))
},
catchall = function(domainID, params) {
return $http.put(requestURL(domainID, "catchall"), params)
},
get = function(id) {
return $http.get(requestURL(id))
};
return {
delete: function(id) {
return $http.delete(requestURL(id))
},
create: create,
query: query,
available: available,
get: get,
catchall: catchall
}
}), angular.module("proton.domains").factory("domainModel", function($rootScope, domainApi, gettextCatalog) {
function set(newDomains) {
domains = newDomains
}
function catchall(ID, AddressID) {
return domainApi.catchall(ID, {
AddressID: AddressID
}).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) {
return _.findWhere(domains, {
ID: ID
}).CatchAll = AddressID, data
}
throw new Error(data.Error || errorMessage)
})
}
function fetch() {
return domainApi.query().then(function() {
var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
if (1e3 === data.Code) return domains = data.Domains, data.Domains;
throw new Error(data.Error || errorMessage)
})
}
function clear() {
domains.length = 0
}
var domains = [],
errorMessage = gettextCatalog.getString("Domain request failed", null, "Error"),
query = function() {
return angular.copy(domains)
},
get = function(ID) {
return _.findWhere(query(), {
ID: ID
})
};
return $rootScope.$on("deleteDomain", function(event, ID) {
var index = _.findIndex(domains, {
ID: ID
});
index > -1 && (domains.splice(index, 1), $rootScope.$emit("domainsChange", domains))
}), $rootScope.$on("createDomain", function(event, ID, member) {
var index = _.findIndex(domains, {
ID: ID
}); - 1 === index ? domains.push(member) : _.extend(domains[index], member), $rootScope.$emit("domainsChange", domains)
}), $rootScope.$on("updateDomain", function(event, ID, member) {
var index = _.findIndex(domains, {
ID: ID
}); - 1 === index ? domains.push(member) : _.extend(domains[index], member), $rootScope.$emit("domainsChange", domains)
}), {
query: query,
get: get,
set: set,
fetch: fetch,
clear: clear,
catchall: catchall
}
}), angular.module("proton.domains").factory("pmDomainModel", function(domainApi, gettextCatalog) {
function get() {
return domains
}
function fetch() {
return domainApi.available().then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return clear(), domains.push.apply(domains, _toConsumableArray(data.Domains)), domains;
throw new Error(data.Error || errorMessage)
})
}
function clear() {
domains.length = 0
}
var errorMessage = gettextCatalog.getString("Domain request failed", null, "Error"),
domains = [];
return {
get: get,
fetch: fetch,
clear: clear
}
}), angular.module("proton.elements").controller("ElementsController", function($filter, $log, $q, $rootScope, $scope, $state, $stateParams, $window, actionConversation, AttachmentLoader, authentication, labelsModel, limitElementsModel, cache, cacheCounters, confirmModal, CONSTANTS, embedded, eventManager, firstLoad, gettextCatalog, Label, networkActivityTracker, paginationModel, messageActions, settingsApi, AppModel, markedScroll, removeElement, tools) {
function watchElements() {
angular.isDefined(unbindWatcherElements) && unbindWatcherElements(), unbindWatcherElements = $scope.$watch("conversations", function() {
$rootScope.numberElementSelected = getElementsSelected().length, $rootScope.numberElementUnread = cacheCounters.unreadConversation(tools.currentLocation())
}, !0)
}
function getWildCard() {
return angular.isDefined($stateParams.wildcard) ? $stateParams.wildcard : authentication.user.AutoWildcardSearch
}
function forgeRequestParameters(mailbox) {
var params = {
Page: (~~$stateParams.page || 1) - 1
};
if (angular.isDefined($stateParams.filter) && (params.Unread = +("unread" === $stateParams.filter)), angular.isDefined($stateParams.sort)) {
var sort = $stateParams.sort,
desc = "-" === sort.charAt(0);
!0 === desc && (sort = sort.slice(1)), params.Sort = $filter("capitalize")(sort), params.Desc = +desc
}
return "search" === mailbox ? (params.Address = $stateParams.address, params.Label = $stateParams.label, params.Keyword = $stateParams.keyword, params.To = $stateParams.to, params.From = $stateParams.from, params.Subject = $stateParams.subject, params.Begin = $stateParams.begin, params.End = $stateParams.end, params.Attachments = $stateParams.attachments, params.AutoWildcard = getWildCard()) : params.Label = "label" === mailbox ? $stateParams.label : CONSTANTS.MAILBOX_IDENTIFIERS[mailbox], params
}
function isStarred(_ref5) {
var _ref5$LabelIDs = _ref5.LabelIDs,
LabelIDs = void 0 === _ref5$LabelIDs ? [] : _ref5$LabelIDs,
_ref5$Labels = _ref5.Labels,
Labels = void 0 === _ref5$Labels ? [] : _ref5$Labels;
return Labels.length ? _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.starred) : !!_.findWhere(Labels, {
ID: CONSTANTS.MAILBOX_IDENTIFIERS.starred
})
}
function getElementsSelected() {
var includeMarked = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0],
_$scope$conversations = $scope.conversations,
conversations = void 0 === _$scope$conversations ? [] : _$scope$conversations,
elements = _.where(conversations, {
Selected: !0
});
return $state.params.id && authentication.user.ViewLayout === CONSTANTS.ROW_MODE ? _.filter(conversations, function(_ref6) {
var ID = _ref6.ID,
ConversationID = _ref6.ConversationID;
return ID === $state.params.id || ConversationID === $state.params.id
}) : !elements.length && $scope.markedElement && includeMarked ? _.filter(conversations, function(_ref7) {
var ID = _ref7.ID,
ConversationID = _ref7.ConversationID;
return ID === $scope.markedElement.ID || ConversationID === $scope.markedElement.ID
}) : elements
}
function idsSelected() {
return _.pluck(getElementsSelected(), "ID")
}
function getTypeSelected() {
var elementsSelected = getElementsSelected();
return elementsSelected.length ? elementsSelected[0].ConversationID ? "message" : "conversation" : tools.getTypeList()
}
function redirectUser() {
var name = $state.$current.name,
route = name.replace(".element", "");
$state.go(route, {
id: ""
})
}
function goToPage() {
var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "to";
$stateParams.page && $scope.selectElements("all", !1), $scope.page = ~~$stateParams.page || 1, paginationModel[type]()
}
function openElement(element) {
if (element) {
var params = {},
sameView = $state.params.id && $state.params.id === element.ConversationID;
if ("conversation" === tools.typeView() && "message" === tools.getTypeList() ? (params.id = element.ConversationID, params.messageID = element.ID) : (params.id = element.ID, params.messageID = null), $scope.selectElements("all", !1), embedded.deallocator(element), AttachmentLoader.flushCache(), $scope.markedElement = element, sameView) return $rootScope.$emit("message.open", {
type: "toggle",
data: {
message: element,
action: "openElement"
}
});
var route = $state.$current.name.replace(".element", "");
$state.go(route + ".element", params)
}
}
var unsubscribes = [],
unbindWatcherElements = void 0,
id = setInterval(function() {
$rootScope.$emit("elements", {
type: "refresh.time"
})
}, 6e4);
$scope.elementsLoaded = !1, $scope.limitReached = !1, $scope.conversations = [], $scope.$on("$stateChangeSuccess", function() {
$scope.elementsLoaded = !1, $scope.limitReached = !1
}), $scope.senders = function(element) {
return angular.isDefined(element.Senders) ? element.Senders : [element.Sender]
}, $scope.recipients = function(element) {
if (angular.isDefined(element.Recipients)) return element.Recipients;
var recipients = [];
return element.ToList && (recipients = recipients.concat(element.ToList)), element.CCList && (recipients = recipients.concat(element.CCList)), element.BCCList && (recipients = recipients.concat(element.BCCList)), recipients
};
var displayType = function(type) {
var test = !1,
isColumnsMode = authentication.user.ViewLayout === CONSTANTS.COLUMN_MODE,
isRowsMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE;
switch (type) {
case "rows":
test = !AppModel.is("mobile") && isRowsMode && !$scope.idDefined();
break;
case "columns":
test = isColumnsMode && !AppModel.is("mobile");
break;
case "placeholder":
var idDefined = $scope.idDefined();
test = isColumnsMode && (!idDefined || idDefined && $rootScope.numberElementChecked > 0) && !AppModel.is("mobile");
break;
case "mobile":
test = !$scope.idDefined() && AppModel.is("mobile")
}
return test
};
$scope.displayType = displayType, $scope.startWatchingEvent = function() {
function toggleStar() {
var type = getTypeSelected();
getElementsSelected().forEach(function(model) {
$rootScope.$emit("elements", {
type: "toggleStar",
data: {
type: type,
model: model
}
})
})
}
function nextElement() {
var elementID = $state.params.id;
if (!elementID) return markNext();
var isRowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE,
current = $state.$current.name,
elementTime = $scope.markedElement.Time,
conversationMode = authentication.user.ViewMode === CONSTANTS.CONVERSATION_VIEW_MODE;
cache.more(elementID, elementTime, "previous").then(function(element) {
var id = conversationMode ? element.ConversationID || element.ID : element.ID;
$state.go(current, {
id: id
}), $scope.markedElement = element, $rootScope.$emit("elements", {
type: "switchTo.next.success",
data: element
}), !isRowMode && markedScroll.follow()
}).catch(function(data) {
$rootScope.$emit("elements", {
type: "switchTo.next.error",
data: data
})
})
}
function previousElement() {
var elementID = $state.params.id;
if (!elementID) return markPrevious();
var isRowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE,
current = $state.$current.name,
elementTime = $scope.markedElement.Time,
conversationMode = authentication.user.ViewMode === CONSTANTS.CONVERSATION_VIEW_MODE;
cache.more(elementID, elementTime, "next").then(function(element) {
var id = conversationMode ? element.ConversationID || element.ID : element.ID;
$state.go(current, {
id: id
}), $scope.markedElement = element, $rootScope.$emit("elements", {
type: "switchTo.previous.success",
data: element
}), !isRowMode && markedScroll.follow()
}).catch(function(data) {
$rootScope.$emit("elements", {
type: "switchTo.previous.error",
data: data
})
})
}
var isOpened = !!$state.params.id,
onElement = function(cb) {
var value = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1];
return function() {
isOpened || (cb.apply(void 0, arguments), "conversation" === tools.typeView() && (isOpened = value))
}
};
unsubscribes.push($rootScope.$on("elements", function(e, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
switch (type) {
case "mark":
var thisElement = _.findWhere($scope.conversations, {
ID: data.id
});
thisElement && $scope.markedElement !== thisElement && $scope.$applyAsync(function() {
$scope.markedElement = thisElement
});
break;
case "open":
isOpened = !0, $scope.$applyAsync(function() {
return openElement(data.element)
});
break;
case "close":
isOpened = !1;
break;
case "refresh":
$scope.refreshElements();
break;
case "switchTo.next":
nextElement();
break;
case "switchTo.previous":
previousElement()
}
})), $scope.$on("openMarked", onElement(function() {
openElement($scope.markedElement)
})), $scope.$on("left", function() {
redirectUser(), isOpened = !1
}), $scope.$on("right", onElement(function() {
openElement($scope.markedElement)
})), $scope.$on("selectMark", function() {
$scope.markedElement && $scope.$applyAsync(function() {
$scope.markedElement.Selected = !$scope.markedElement.Selected, $rootScope.numberElementChecked = _.where($scope.conversations, {
Selected: !0
}).length
})
}), unsubscribes.push($rootScope.$on("selectElements", function(event, _ref2) {
var value = _ref2.value,
isChecked = _ref2.isChecked;
$scope.$applyAsync(function() {
$scope.selectElements(value, isChecked)
})
})), $scope.$on("applyLabels", function(event, LabelID) {
$scope.applyLabels(LabelID)
}), $scope.$on("move", function(event, mailbox) {
!isOpened && $scope.move(mailbox)
}), $scope.$on("read", function() {
$scope.read()
}), $scope.$on("unread", function() {
$scope.unread()
}), unsubscribes.push($rootScope.$on("toggleStar", function() {
!isOpened && toggleStar()
}));
var markPrevious = onElement(function() {
if ($scope.conversations) {
var index = $scope.conversations.indexOf($scope.markedElement);
if (index > 0) return $scope.$applyAsync(function() {
$scope.markedElement = $scope.conversations[index - 1]
}), markedScroll.follow(!0);
goToPage("previous")
}
}, !1),
markNext = onElement(function() {
if ($scope.conversations) {
var index = $scope.conversations.indexOf($scope.markedElement);
if (index < $scope.conversations.length - 1) return $scope.$applyAsync(function() {
$scope.markedElement = $scope.conversations[index + 1]
}), markedScroll.follow();
goToPage("next")
}
}, !1);
$scope.$on("markPrevious", markPrevious), $scope.$on("markNext", markNext), $scope.$on("nextElement", function() {
nextElement()
}), $scope.$on("previousElement", function() {
previousElement()
}), $scope.$on("$destroy", function() {
unsubscribes.forEach(function(callback) {
return callback()
}), unsubscribes.length = 0, clearInterval(id), markedScroll.clear()
})
}, $scope.refreshElements = function() {
var request = forgeRequestParameters($scope.mailbox);
return ("message" === tools.getTypeList() ? cache.queryMessages(request) : cache.queryConversations(request)).then(function(elements) {
firstLoad.set(!1);
var page = ~~$stateParams.page || 0,
selectedMap = $scope.conversations.reduce(function(map, element) {
return element.Selected && (map[element.ID] = element), map
}, {});
return $scope.$applyAsync(function() {
var previousConversations = angular.copy($scope.conversations);
if ($scope.elementsLoaded = !0, $scope.conversations = elements.map(function(element) {
return element.Selected = void 0 !== selectedMap[element.ID], element
}), watchElements(), $scope.limitReached = limitElementsModel.isReached() && paginationModel.isMax(), 0 === $scope.conversations.length && page > 0) return $scope.back();
if ($scope.conversations.length > 0) {
var element = void 0;
if ($scope.markedElement) {
var found = _.findWhere($scope.conversations, {
ID: $scope.markedElement.ID
});
if (found) element = found;
else {
var previousIndexMarked = _.findIndex(previousConversations, {
ID: $scope.markedElement.ID
}) || 0;
element = $scope.conversations[previousIndexMarked] || _.first($scope.conversations)
}
} else element = $state.params.id ? _.find($scope.conversations, function(_ref3) {
var ID = _ref3.ID,
ConversationID = _ref3.ConversationID;
return $state.params.id === ConversationID || $state.params.id === ID
}) : _.first($scope.conversations);
$scope.markedElement = element
}
}), elements
}, function() {
$scope.elementsLoaded = !0, $scope.conversations = []
})
}, $scope.active = function(element) {
return !(0 !== $rootScope.numberElementChecked || !angular.isDefined($state.params.id)) && ($state.params.id === element.ConversationID || $state.params.id === element.ID)
}, $scope.hasLabels = function(_ref4) {
var _ref4$LabelIDs = _ref4.LabelIDs,
LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs,
_ref4$Labels = _ref4.Labels,
Labels = void 0 === _ref4$Labels ? [] : _ref4$Labels;
return LabelIDs.length || Labels.length
}, $scope.hasAttachments = function(element) {
return element.ConversationID ? element.NumAttachments > 0 : element.ContextNumAttachments > 0
}, $scope.isRead = function(element) {
return element.ConversationID ? 1 === element.IsRead : 0 === element.ContextNumUnread
}, $scope.size = function(element) {
return element.ConversationID ? element.Size : element.ContextSize
}, $scope.isDisabled = function() {
return !$scope.markedElement && (!$rootScope.numberElementChecked && !angular.isDefined($state.params.id))
}, $scope.isCacheContext = function() {
return tools.cacheContext()
}, $scope.selectElements = function(value, isChecked) {
var actions = {
all: function(element) {
element.Selected = isChecked
},
read: function(element) {
element.Selected = (0 === element.ContextNumUnread || 1 === element.IsRead) && isChecked
},
unread: function(element) {
element.Selected = (element.ContextNumUnread > 0 || 0 === element.IsRead) && isChecked
},
starred: function(element) {
element.Selected = isStarred(element) && isChecked
},
unstarred: function(element) {
element.Selected = !isStarred(element) && isChecked
}
};
_.each($scope.conversations, function(element) {
return actions[value](element)
}), $rootScope.numberElementChecked = _.where($scope.conversations, {
Selected: !0
}).length
}, $scope.read = function() {
var type = getTypeSelected(),
ids = idsSelected();
"conversation" === type ? actionConversation.read(ids) : "message" === type && $rootScope.$emit("messageActions", {
action: "read",
data: {
ids: ids
}
})
}, $scope.unread = function() {
var type = getTypeSelected(),
ids = idsSelected();
"conversation" === type ? actionConversation.unread(ids) : "message" === type && $rootScope.$emit("messageActions", {
action: "unread",
data: {
ids: ids
}
}), angular.isDefined($state.params.id) && $scope.back(!0)
}, $scope.delete = function() {
removeElement({
getElementsSelected: getElementsSelected,
idsSelected: idsSelected,
getTypeSelected: getTypeSelected
})
}, $scope.move = function(mailbox) {
var type = getTypeSelected(),
ids = idsSelected(),
labelID = CONSTANTS.MAILBOX_IDENTIFIERS[mailbox];
0 !== ids.length && ($rootScope.numberElementChecked = 0, "conversation" === type ? actionConversation.move(ids, labelID) : "message" === type && $rootScope.$emit("messageActions", {
action: "move",
data: {
ids: ids,
labelID: labelID
}
}))
}, $scope.getElements = function() {
return getElementsSelected()
}, $scope.saveLabels = function(labels, alsoArchive) {
var type = getTypeSelected(),
ids = idsSelected();
if ("conversation" === type) actionConversation.label(ids, labels, alsoArchive);
else if ("message" === type) {
var messages = getElementsSelected();
$rootScope.$emit("messageActions", {
action: "label",
data: {
messages: messages,
labels: labels,
alsoArchive: alsoArchive
}
})
}
}, $scope.back = function() {
if (arguments.length > 0 && void 0 !== arguments[0] && arguments[0]) {
var opt = _.extend({}, $stateParams, {
id: null
});
return $state.go($state.$current.name.replace(".element", ""), opt)
}
$state.go($state.$current.name.replace(".element", ""), {
id: null,
page: ~~$stateParams.page || 1,
label: $stateParams.label
})
}, $scope.closeLabels = function() {
$(".pm_dropdown").removeClass("active")
}, $scope.displayPaginator = function() {
return !$state.params.id || 0 === authentication.user.ViewLayout
}, $scope.applyLabels = function(labelID) {
var labels = [];
_.each($scope.labels, function(label) {
label.ID === labelID && (label.Selected = !0), labels.push(label)
}), $scope.saveLabels(labels, !0)
}, $scope.goToLabel = function(labelID) {
var params = {
page: void 0,
filter: void 0,
sort: void 0,
label: labelID
};
$state.go("secured.label", params)
},
function() {
$scope.markedElement = void 0, $scope.mailbox = tools.currentMailbox(), $scope.conversationsPerPage = authentication.user.NumMessagePerPage, $scope.labels = labelsModel.get(), $scope.messageButtons = authentication.user.MessageButtons, $scope.selectedFilter = $stateParams.filter, $scope.selectedOrder = $stateParams.sort || "-date", $scope.page = ~~$stateParams.page || 1, $scope.startWatchingEvent(), $scope.refreshElements().then(function() {
$scope.$applyAsync(function() {
$scope.selectElements("all", !1)
})
}, $log.error)
}()
}), angular.module("proton.elements").directive("advancedFilterElement", function($rootScope, $stateParams, CONSTANTS, gettextCatalog, messageApi, confirmModal, labelsModel, networkActivityTracker, cache, notification, eventManager, $state) {
var _BUTTONS_CLASS, getClass = function(name) {
return "advancedFilterElement-" + name
},
MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS,
BUTTONS_CLASS = (_BUTTONS_CLASS = {}, _defineProperty(_BUTTONS_CLASS, getClass("btn-small-to-large"), function() {
return "size" === $stateParams.sort
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-large-to-small"), function() {
return "-size" === $stateParams.sort
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-old-to-new"), function() {
return "date" === $stateParams.sort
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-new-to-old"), function() {
return !$stateParams.sort || "-date" === $stateParams.sort
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-show-all"), function() {
return !($stateParams.sort && "-date" !== $stateParams.sort || $stateParams.filter)
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-unread"), function() {
return "unread" === $stateParams.filter
}), _defineProperty(_BUTTONS_CLASS, getClass("btn-read"), function() {
return "read" === $stateParams.filter
}), _BUTTONS_CLASS),
clearState = function(state) {
return state.replace(".element", "")
},
switchState = function() {
var opt = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
$state.go(clearState($state.$current.name), _.extend({}, $state.params, {
page: void 0,
id: void 0
}, opt))
},
empty = function(mailbox) {
var title = gettextCatalog.getString("Delete all", null, "Title"),
message = gettextCatalog.getString("Are you sure? This cannot be undone.", null, "Info"),
errorMessage = gettextCatalog.getString("Empty request failed", null, "Error shows when the empty folder request failed");
if (-1 !== ["drafts", "spam", "trash", "folder"].indexOf(mailbox)) {
var labelID = $stateParams.label || MAILBOX_IDENTIFIERS[mailbox],
MAP_ACTIONS = {
drafts: "emptyDraft",
spam: "emptySpam",
trash: "emptyTrash",
folder: "emptyLabel"
};
confirmModal.activate({
params: {
title: title,
message: message,
confirm: function() {
var promise = messageApi[MAP_ACTIONS[mailbox]](labelID).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return cache.empty(labelID), confirmModal.deactivate(), notification.success(gettextCatalog.getString("Folder emptied", null)), eventManager.call();
throw new Error(data.Error || errorMessage)
});
networkActivityTracker.track(promise)
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}
},
orderBy = function(sort) {
return switchState({
sort: "-date" === sort ? void 0 : sort
})
},
filterBy = function(filter) {
return switchState({
filter: filter
})
},
clearFilter = function() {
return switchState({
filter: void 0,
sort: void 0
})
},
toggleTrashSpam = function() {
return switchState({
trashspam: angular.isDefined($state.params.trashspam) ? void 0 : 0
})
},
ACTIONS = {
empty: empty,
orderBy: orderBy,
filterBy: filterBy,
clearFilter: clearFilter,
toggleTrashSpam: toggleTrashSpam
};
return {
replace: !0,
templateUrl: "templates/elements/advancedFilterElement.tpl.html",
link: function(scope, el) {
var $btns = el.find("button"),
onClick = function(e) {
e.preventDefault();
var action = e.target.getAttribute("data-action");
action && ACTIONS[action](e.target.getAttribute("data-action-arg"))
};
_.each($btns, function(button) {
var cssClass = button.classList.item(0);
BUTTONS_CLASS[cssClass] && BUTTONS_CLASS[cssClass]() && button.classList.add("active")
});
var bindClass = function() {
var labelID = $stateParams.label,
action = labelID && labelsModel.read(labelID, "folders") ? "add" : "remove";
el[0].classList[action]("advancedFilterElement-state-folder")
},
unsubscribe = $rootScope.$on("$stateChangeSuccess", bindClass);
bindClass(), $btns.on("click", onClick), scope.$on("$destroy", function() {
$btns.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.elements").directive("countElementsSelected", function($rootScope) {
return {
replace: !0,
templateUrl: "templates/elements/countElementsSelected.tpl.html",
link: function(scope, element) {
var $btn = element.find(".countElementsSelected-btn-unselect"),
onClick = function() {
return $rootScope.$emit("selectElements", {
value: "all",
isChecked: !1
})
};
$btn.on("click", onClick), scope.$on("$destroy", function() {
$btn.off("click", onClick)
})
}
}
}), angular.module("proton.elements").directive("elementView", function(tools) {
return {
restrict: "E",
template: "\n <conversation-view ng-if=\"type === 'conversation'\"></conversation-view>\n <message-view ng-if=\"type === 'message'\"></message-view>\n ",
link: function(scope) {
scope.type = tools.typeView()
}
}
}), angular.module("proton.elements").directive("elementsContainer", function($rootScope) {
return {
restrict: "A",
link: function(scope, el) {
var onClick = function(_ref) {
var target = _ref.target;
target && !/ptSelectConversation|customMaskInput/.test(target.className) && $rootScope.$emit("elements", {
type: "open",
data: {
element: scope.conversation
}
})
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick)
})
}
}
}), angular.module("proton.elements").directive("elementsSelector", function($rootScope, authentication, gettextCatalog, dedentTpl) {
var ORDER_FALSY = ["all", "read", "unread", "star", "unstar"],
ORDER_TRUTHY = ["all", "unread", "read", "unstar", "star"],
ACTIONS = {
all: {
label: gettextCatalog.getString("Select All", null, "Action"),
icon: "fa-check-square-o",
action: "all"
},
unread: {
label: gettextCatalog.getString("All Unread", null, "Action"),
icon: "fa-eye-slash",
action: "unread"
},
read: {
label: gettextCatalog.getString("All Read", null, "Action"),
icon: "fa-eye",
action: "read"
},
unstar: {
label: gettextCatalog.getString("All Unstarred", null, "Action"),
icon: "fa-star-o",
action: "unstarred"
},
star: {
label: gettextCatalog.getString("All Starred", null, "Action"),
icon: "fa-star",
action: "starred"
}
},
map = function(list) {
return list.map(function(key) {
return ACTIONS[key]
})
},
orderActions = function() {
var order = +authentication.user.MessageButtons;
return map(order ? ORDER_TRUTHY : ORDER_FALSY)
},
getTemplate = function() {
return orderActions().reduce(function(prev, _ref) {
var label = _ref.label,
icon = _ref.icon,
action = _ref.action;
return prev + dedentTpl('\n <button data-action="' + action + '" class="elementsSelector-btn-action">\n <i class="fa ' + icon + '"></i>\n <span>' + label + "</span>\n </button>\n ")
}, "")
};
return {
replace: !0,
templateUrl: "templates/elements/elementsSelector.tpl.html",
compile: function(element) {
return element[0].querySelector(".pm_dropdown").insertAdjacentHTML("beforeEnd", getTemplate()),
function(scope, el) {
function onClick(_ref2) {
var currentTarget = _ref2.currentTarget,
value = currentTarget.getAttribute("data-action");
$rootScope.$emit("selectElements", {
value: value,
isChecked: !0
}), $rootScope.$emit("closeDropdown")
}
var $btn = el.find(".elementsSelector-btn-action");
$btn.on("click", onClick), scope.checkedSelectorState = function() {
return _.every(scope.conversations, {
Selected: !0
})
}, scope.$on("$destroy", function() {
$btn.off("click", onClick)
})
}
}
}
}), angular.module("proton.elements").directive("foldersElement", function($rootScope, $state, gettextCatalog, $compile, mailboxIdentifersTemplate) {
var allowedStates = ["secured.allSent.**", "secured.sent.**", "secured.allDrafts.**", "secured.drafts.**", "secured.search.**", "secured.starred.**", "secured.allmail.**", "secured.label.**"],
isAllowedState = function() {
return allowedStates.some(function(key) {
return $state.includes(key)
})
},
MAP_LABELS = {
inbox: {
className: "fa-inbox",
tooltip: gettextCatalog.getString("In inbox", null, "Type of label for a message/conversation")
},
sent: {
className: "fa-send",
tooltip: gettextCatalog.getString("In sent", null, "Type of label for a message/conversation")
},
drafts: {
className: "fa-file-text-o",
tooltip: gettextCatalog.getString("In drafts", null, "Type of label for a message/conversation")
},
archive: {
className: "fa-archive",
tooltip: gettextCatalog.getString("In archive", null, "Type of label for a message/conversation")
},
trash: {
className: "fa-trash-o",
tooltip: gettextCatalog.getString("In trash", null, "Type of label for a message/conversation")
},
spam: {
className: "fa-ban",
tooltip: gettextCatalog.getString("In spam", null, "Type of label for a message/conversation")
},
folder: {
className: "fa-folder"
}
},
_mailboxIdentifersTem = mailboxIdentifersTemplate({
MAP_LABELS: MAP_LABELS
}),
getTemplateLabels = _mailboxIdentifersTem.getTemplateLabels;
return {
templateUrl: "templates/elements/foldersElement.tpl.html",
replace: !0,
scope: {
conversation: "="
},
link: function(scope, el) {
var build = function(event, _ref) {
var _ref$LabelIDs = _ref.LabelIDs,
LabelIDs = void 0 === _ref$LabelIDs ? [] : _ref$LabelIDs,
_ref$Labels = _ref.Labels,
Labels = void 0 === _ref$Labels ? [] : _ref$Labels;
if ((LabelIDs.length || Labels.length) && isAllowedState()) {
var labelIDs = Labels.length ? _.map(Labels, function(_ref2) {
return _ref2.ID
}) : LabelIDs,
tpl = $compile(getTemplateLabels(labelIDs))(scope);
el.empty().append(tpl)
}
},
unsubscribe = $rootScope.$on("foldersElement." + scope.conversation.ID, build);
build(0, scope.conversation), scope.$on("$destroy", unsubscribe)
}
}
}), angular.module("proton.elements").directive("labelsElement", function($rootScope, labelsModel, authentication, $state) {
var toLabels = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, id) {
var item = labelsModel.read(id, "labels");
return item && acc.push(item), acc
}, [])
},
moreVisibility = function(node) {
return {
hide: function() {
node.classList.add("labelsElement-hidden")
},
show: function() {
_rAF(function() {
return node.classList.remove("labelsElement-hidden")
})
}
}
};
return {
restrict: "E",
templateUrl: "templates/elements/labelsElement.tpl.html",
replace: !0,
scope: {
element: "="
},
link: function(scope, el, _ref) {
var _ref$limit = _ref.limit,
limit = void 0 === _ref$limit ? 4 : _ref$limit,
moreToggle = moreVisibility(el[0].querySelector(".labelsElement-more")),
build = function(e, _ref2) {
var _ref2$LabelIDs = _ref2.LabelIDs,
LabelIDs = void 0 === _ref2$LabelIDs ? [] : _ref2$LabelIDs,
_ref2$Labels = _ref2.Labels,
Labels = void 0 === _ref2$Labels ? [] : _ref2$Labels;
if (moreToggle.hide(), LabelIDs.length || Labels.length) {
var labelIDs = Labels.length ? _.map(Labels, function(_ref3) {
return _ref3.ID
}) : LabelIDs,
labels = toLabels(labelIDs);
if ("none" !== limit) return scope.labels = labels.length ? angular.copy(labels.slice(0, limit)) : [], void(labels.length > limit && moreToggle.show());
scope.labels = angular.copy(labels)
}
},
onClick = function(e) {
if (e.stopPropagation(), e.target.classList.contains("labelsElement-label")) {
var label = e.target.getAttribute("data-label-id");
$state.go("secured.label", {
label: label
})
}
e.target.classList.contains("labelsElement-btn-remove") && $rootScope.$emit("messageActions", {
action: "unlabel",
data: {
messageID: scope.element.ID,
conversationID: scope.element.ConversationID,
labelID: e.target.getAttribute("data-label-id")
}
})
},
unsubscribe = $rootScope.$on("labelsElement." + scope.element.ID, build);
build(0, scope.element), scope.color = function() {
var _ref4 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref4$Color = _ref4.Color;
return {
color: void 0 === _ref4$Color ? "inherit" : _ref4$Color
}
}, el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick), unsubscribe()
})
}
}
}), angular.module("proton.elements").directive("moveElement", function() {
return {
replace: !0,
templateUrl: "templates/elements/moveElement.tpl.html",
link: function(scope, element) {
function onClick(event) {
if ("BUTTON" === event.target.tagName) {
var action = event.target.getAttribute("data-action");
if ("delete" === action) return scope.delete();
scope.move(action)
}
}
element.on("click", onClick), scope.$on("$destroy", function() {
element.off("click", onClick)
})
}
}
}), angular.module("proton.elements").directive("movedButton", function($state, gettextCatalog, tools) {
var MAP = {
sent: "secured.allSent",
allSent: "secured.sent",
drafts: "secured.allDrafts",
allDrafts: "secured.drafts"
};
return {
restrict: "E",
replace: !0,
scope: {},
template: '\n <button class="movedButton-container">\n <div>\n <i class="movedButton-icon fa fa-share-square-o"></i>\n <span class="movedButton-text">' + gettextCatalog.getString("Include moved messages", null, "Link") + "</span>\n </div>\n </button>\n ",
link: function(scope, element) {
var current = tools.filteredState(),
onClick = function() {
return $state.go(MAP[current], _.extend({}, $state.params, {
page: void 0,
id: void 0
}))
};
"allSent" !== current && "allDrafts" !== current || element.addClass("active"), element.on("click", onClick), scope.$on("$destroy", function() {
return element.off("click", onClick)
})
}
}
}), angular.module("proton.elements").directive("movedSelect", function($rootScope, authentication, gettextCatalog, networkActivityTracker, settingsApi) {
var I18N = {
includeMoved: gettextCatalog.getString("Include Moved", null, "Option"),
hideMoved: gettextCatalog.getString("Hide Moved", null, "Option")
};
return {
restrict: "E",
replace: !0,
scope: {},
template: '\n <span class="movedSelect-container pm_select inline">\n <select class="movedSelect-select">\n <option value="3">' + I18N.includeMoved + '</option>\n <option value="0">' + I18N.hideMoved + '</option>\n </select>\n <i class="fa fa-angle-down"></i>\n </span>\n ',
link: function(scope, element) {
function onChange() {
var Moved = get(),
promise = settingsApi.updateMoved({
Moved: Moved
}).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return authentication.user.Moved = Moved, data;
throw new Error(data.Error)
});
networkActivityTracker.track(promise)
}
var $select = element.find("select"),
set = function(moved) {
return $select.val(+moved)
},
get = function() {
return ~~$select.val()
},
unsubscribe = $rootScope.$on("updateUser", function() {
return set(authentication.user.Moved)
});
set(authentication.user.Moved), $select.on("change", onChange), scope.$on("$destroy", function() {
unsubscribe(), $select.off("change", onChange)
})
}
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.elements").directive("navElements", function($rootScope, $state, authentication, tools, CONSTANTS) {
var SPECIAL_BOXES = ["drafts", "search", "sent", "allDrafts", "allSent"],
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("elements", {
type: type,
data: data
})
},
showNextPrev = function() {
var box = tools.currentMailbox(),
rowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE,
context = tools.cacheContext(),
notSpecial = -1 === SPECIAL_BOXES.indexOf(box);
return $state.params.id && rowMode && context && notSpecial
};
return {
replace: !0,
templateUrl: "templates/elements/navElements.tpl.html",
link: function(scope, el) {
var unsubscribe = [],
toggleClass = function() {
var action = showNextPrev() ? "add" : "remove";
el[0].classList[action]("navElements-displayed")
},
toggleClassError = function(name, type) {
"success" === type && (el[0].classList.remove("navElements-no-previous"), el[0].classList.remove("navElements-no-next")), "error" === type && el[0].classList.add("navElements-no-" + name)
};
toggleClass(), unsubscribe.push($rootScope.$on("$stateChangeSuccess", toggleClass)), unsubscribe.push($rootScope.$on("settings", function(event, _ref) {
"viewLayout.updated" === _ref.type && toggleClass()
})), unsubscribe.push($rootScope.$on("elements", function(e, _ref2) {
var type = _ref2.type;
if (/(previous|next)\.(error|success)$/.test(type)) {
var _type$split = type.split("."),
_type$split2 = _slicedToArray(_type$split, 3),
name = _type$split2[1],
flag = _type$split2[2];
toggleClassError(name, flag)
}
}));
var onClick = function(_ref3) {
var target = _ref3.target;
dispatch("switchTo." + target.getAttribute("data-dest"), {
conversation: scope.conversation,
from: "button"
})
};
el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick), unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}), angular.module("proton.elements").directive("ptSelectElement", function() {
return {
replace: !0,
templateUrl: "templates/elements/ptSelectElement.tpl.html"
}
}), angular.module("proton.elements").directive("ptSelectElements", function($rootScope) {
return {
link: function(scope, el) {
function onChange(_ref) {
var target = _ref.target,
isChecked = target.checked;
$rootScope.$emit("selectElements", {
value: target.value,
isChecked: isChecked
}), _rAF(function() {
return target.blur()
})
}
el.on("change", onChange), scope.$watch("value", function() {
return el.change()
}), scope.$on("$destroy", function() {
el.off("change", onChange)
})
}
}
}), angular.module("proton.elements").directive("ptSelectMultipleElements", function($rootScope) {
function selectConversations(scope) {
return function(previous, from, to) {
_.each(scope.conversations, function(conversation, i) {
if (!(i >= from && i <= to)) return !1;
conversation.Selected = previous.conversation.Selected
}), $rootScope.numberElementChecked = countChecked(scope.conversations)
}
}
var CACHE = {},
countChecked = function(conversations) {
return _.where(conversations, {
Selected: !0
}).length
};
return {
link: function(scope, el) {
function onClick(_ref2) {
var target = _ref2.target,
shiftKey = _ref2.shiftKey,
index = +target.getAttribute("data-index");
if ("INPUT" === target.nodeName && /ptSelectConversation/.test(target.className)) {
var isChecked = target.checked;
scope.$applyAsync(function() {
if (scope.conversations[index].Selected = isChecked, $rootScope.numberElementChecked = countChecked(scope.conversations), shiftKey && previous) {
var from = Math.min(index, previous.index),
to = Math.max(index, previous.index);
conversationsToSelect(previous, from, to), target.checked = previous.conversation.Selected
}
$rootScope.showWelcome = !1, previous = {
index: index,
conversation: scope.conversations[index]
}
})
}
}
var previous = null,
conversationsToSelect = selectConversations(scope),
unsubscribe = $rootScope.$on("dnd", function(e, _ref) {
var type = _ref.type,
data = _ref.data;
"hook.dragstart" === type && (CACHE.number = data.before.number, CACHE.ids = data.before.ids, $rootScope.numberElementChecked = 1, _.each(scope.conversations, function(item) {
item.Selected = !1
}))
}),
onDragEnd = function() {
_rAF(function() {
scope.$applyAsync(function() {
_.each(scope.conversations, function(item) {
CACHE.ids && (item.Selected = -1 !== CACHE.ids.indexOf(item.ID)), 1 !== $rootScope.numberElementChecked || CACHE.number || (item.Selected = !1)
}), $rootScope.numberElementChecked = CACHE.number || countChecked(scope.conversations), delete CACHE.number, delete CACHE.ids
})
})
};
el.on("click", onClick), document.addEventListener("dragend", onDragEnd), scope.$on("$destroy", function() {
el.off("click", onClick), document.removeEventListener("dragend", onDragEnd), unsubscribe(), delete CACHE.number,
delete CACHE.ids
})
}
}
}), angular.module("proton.elements").directive("ptStar", function($rootScope, CONSTANTS, gettextCatalog, tools, actionConversation) {
function isStarred(_ref) {
var _ref$LabelIDs = _ref.LabelIDs,
LabelIDs = void 0 === _ref$LabelIDs ? [] : _ref$LabelIDs,
_ref$Labels = _ref.Labels,
Labels = void 0 === _ref$Labels ? [] : _ref$Labels;
return Labels.length ? _.findWhere(Labels, {
ID: CONSTANTS.MAILBOX_IDENTIFIERS.starred
}) : LabelIDs.some(function(label) {
return label === CONSTANTS.MAILBOX_IDENTIFIERS.starred
})
}
function toggleStar(_ref2) {
var model = _ref2.model,
type = _ref2.type,
action = isStarred(model) ? "unstar" : "star";
"conversation" === type && actionConversation[action]([model.ID]), "message" === type && $rootScope.$emit("messageActions", {
action: action,
data: {
ids: [model.ID]
}
})
}
return $rootScope.$on("elements", function(e, _ref3) {
var type = _ref3.type,
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
"toggleStar" === type && toggleStar(data)
}), {
scope: {
model: "="
},
replace: !0,
templateUrl: "templates/elements/ptStar.tpl.html",
link: function(scope, el, attr) {
function onClick(e) {
"A" === e.target.nodeName && (e.preventDefault(), e.stopPropagation(), toggleStar({
model: scope.model,
type: type
}))
}
var type = attr.ptStarType || tools.getTypeList();
scope.isStarred = function() {
return isStarred(scope.model)
}, el.on("click", onClick), scope.$on("$destroy", function() {
el.off("click", onClick), $(".tooltip").remove()
})
}
}
}), angular.module("proton.elements").directive("searchLimitReached", function(gettextCatalog) {
var message = gettextCatalog.getString("Your search matched too many results. Please limit your search and try again.", null, "Inform the user that he reach the search limit");
return {
replace: !0,
restrict: "E",
template: '<div class="searchLimit-container"></div>',
link: function(scope, element) {
element[0].textContent = message
}
}
}), angular.module("proton.ui").directive("timeElement", function($rootScope, cache, tools) {
function getTime(_ref) {
var ID = _ref.ID,
Time = _ref.Time,
type = tools.getTypeList(),
loc = tools.currentLocation(),
time = "conversation" === type ? cache.getTime(ID, loc) : Time,
m = moment.unix(time),
format = m.isSame(moment(), "day") ? "LT" : "ll";
return m.format(format)
}
return {
restrict: "E",
replace: !0,
template: '<time class="time"></time>',
link: function(scope, element) {
function displayTime() {
element[0].textContent = getTime(scope.conversation)
}
var unsubscribe = $rootScope.$on("elements", function(e, _ref2) {
"refresh.time" === _ref2.type && displayTime()
});
displayTime(), scope.$on("$destroy", function() {
return unsubscribe()
})
}
}
}), angular.module("proton.elements").factory("elementsError", function($rootScope) {
function last() {
return errors.length ? _.last(errors) : {}
}
var errors = [];
return $rootScope.$on("elements", function(event, _ref) {
var type = _ref.type,
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
"error" === type && errors.push(data)
}), $rootScope.$on("$stateChangeSuccess", function() {
errors.length = 0
}), {
init: angular.noop,
last: last
}
}), angular.module("proton.elements").factory("firstLoad", function($rootScope, tools) {
function cleanState(state) {
return tools.filteredState(state)
}
function get() {
return first
}
function set(state) {
first = state
}
var first = !0;
return $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState) {
first = cleanState(fromState.name) !== cleanState(toState.name)
}), {
get: get,
set: set
}
}), angular.module("proton.elements").factory("limitElementsModel", function($rootScope) {
function set(_ref) {
var _ref$Limit = _ref.Limit,
Limit = void 0 === _ref$Limit ? 0 : _ref$Limit,
_ref$Total = _ref.Total,
Total = void 0 === _ref$Total ? 0 : _ref$Total;
CACHE.limit = Limit, CACHE.total = Total
}
var CACHE = {},
isReached = function() {
return CACHE.total !== CACHE.limit
};
return $rootScope.$on("elements", function(event, _ref2) {
var type = _ref2.type,
_ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
"setLimit" === type && set(data)
}), {
init: angular.noop,
isReached: isReached
}
}), angular.module("proton.elements").factory("removeElement", function(gettextCatalog, AppModel, actionConversation, messageActions, confirmModal, $state, $rootScope, notification, tools) {
function redirectUser() {
var route = $state.$current.name.replace(".element", "");
$state.go(route, {
id: ""
})
}
var I18N = {
TITLE: gettextCatalog.getString("Delete", null, "Title"),
MESSAGE: gettextCatalog.getString("Are you sure? This cannot be undone.", null, "Info"),
DRAFT_INFO: gettextCatalog.getString("A draft selected is open in a composer, this action will close the composer and delete the message.", null, "Info"),
TYPES: {
message: function(n) {
return gettextCatalog.getPlural(n, "message", "messages", {}, "Type element")
},
conversation: function(n) {
return gettextCatalog.getPlural(n, "conversation", "conversations", {}, "Type element")
}
},
success: function(total, item) {
return gettextCatalog.getString("{{total}} {{item}} removed", {
total: total,
item: item
}, "Remove element")
}
},
lookForOpenDraft = function() {
var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
getElementsSelected = arguments[1],
mapComposer = (AppModel.get("composerList") || []).reduce(function(acc, item) {
return acc[item.ID] = "ID", acc[item.ConversationID] = "ConversationID", acc
}, {}),
listOpenedDraft = ids.reduce(function(acc, id) {
return mapComposer[id] && acc.push({
id: id,
key: mapComposer[id]
}), acc
}, []);
if ($state.includes("secured.drafts.**") && listOpenedDraft.length) {
var selectedMap = getElementsSelected().reduce(function(acc, msg) {
return acc.ConversationID[msg.ConversationID] = msg, acc.ID[msg.ID] = msg, acc
}, {
ConversationID: {},
ID: {}
});
return {
isDraftOpen: !0,
drafts: listOpenedDraft.map(function(_ref) {
var id = _ref.id,
key = _ref.key;
return selectedMap[key][id]
}),
message: I18N.MESSAGE + " <br><p><i>" + I18N.DRAFT_INFO + "</i></p>"
}
}
return {
message: I18N.MESSAGE
}
},
removeList = function() {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(ids, context, labelID) {
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
if ("conversation" !== context) {
_context.next = 2;
break
}
return _context.abrupt("return", actionConversation.remove(ids, labelID));
case 2:
return _context.abrupt("return", messageActions.destroy(ids));
case 3:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x2, _x3, _x4) {
return _ref2.apply(this, arguments)
}
}();
return function() {
var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
getElementsSelected = _ref3.getElementsSelected,
idsSelected = _ref3.idsSelected,
getTypeSelected = _ref3.getTypeSelected,
ids = idsSelected(),
context = getTypeSelected(),
_lookForOpenDraft = lookForOpenDraft(ids, getElementsSelected),
message = _lookForOpenDraft.message,
isDraftOpen = _lookForOpenDraft.isDraftOpen,
_lookForOpenDraft$dra = _lookForOpenDraft.drafts,
drafts = void 0 === _lookForOpenDraft$dra ? [] : _lookForOpenDraft$dra,
labelID = tools.currentLocation();
confirmModal.activate({
params: {
message: message,
title: I18N.TITLE,
cancel: confirmModal.deactivate,
confirm: function() {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
return confirmModal.deactivate(), _context2.next = 3, removeList(ids, context, labelID);
case 3:
isDraftOpen && drafts.forEach(function(message) {
$rootScope.$emit("composer.update", {
type: "close.message",
data: {
message: message
}
})
}), notification.success(I18N.success(ids.length, I18N.TYPES[context](ids.length))), $rootScope.showWelcome = !1, $rootScope.numberElementChecked = 0, redirectUser();
case 8:
case "end":
return _context2.stop()
}
}, _callee2, void 0)
}));
return function() {
return _ref4.apply(this, arguments)
}
}()
}
})
}
}), angular.module("proton.filter").directive("customFilterList", function($rootScope, authentication, networkActivityTracker, Filter, gettextCatalog, notification, filterModal, confirmModal, eventManager) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/customFilterList.tpl.html",
scope: {},
link: function(scope) {
function changeCustomFilterStatus(filter, status) {
filter.Status = status ? 1 : 0, 0 === filter.Status ? scope.disableCustomFilter(filter) : 1 === filter.Status && scope.enableCustomFilter(filter)
}
var unsubscribe = [];
scope.customFilters = null, networkActivityTracker.track(Filter.query().then(function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) return data.Filters;
throw new Error(data.Error)
})).then(function(result) {
return scope.customFilters = result
}), unsubscribe.push($rootScope.$on("changeCustomFilterStatus", function(event, _ref2) {
var id = _ref2.id,
status = _ref2.status,
filter = _.findWhere(scope.customFilters, {
ID: id
});
filter && changeCustomFilterStatus(filter, status)
})), scope.filterDragControlListeners = {
containment: ".pm_sort",
accept: function(sourceItemHandleScope, destSortableScope) {
return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id
},
dragStart: function() {
scope.itemMoved = !0
},
dragEnd: function() {
scope.itemMoved = !1
},
orderChanged: function() {
var order = [];
_.each(scope.customFilters, function(filter, index) {
order[index] = filter.Priority, filter.Priority = index + 1
}), networkActivityTracker.track(Filter.order({
Order: order
}).then(function(_ref3) {
var _ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Order saved", null, "Info"));
throw new Error(data.Error || gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error"))
}))
}
}, scope.$on("$destroy", function() {
unsubscribe.forEach(function(cb) {
return cb()
}), unsubscribe.length = 0
}), scope.$on("deleteFilter", function(event, filterId) {
if (!scope.itemMoved) {
var index = _.findIndex(scope.customFilters, {
ID: filterId
}); - 1 !== index && scope.customFilters.splice(index, 1)
}
}), scope.$on("createFilter", function(event, filterId, filter) {
if (!scope.itemMoved) {
var index = _.findIndex(scope.customFilters, {
ID: filterId
}); - 1 === index ? scope.customFilters.push(filter) : scope.customFilters[index] = filter
}
}), scope.$on("updateFilter", function(event, filterId, filter) {
if (!scope.itemMoved) {
var index = _.findIndex(scope.customFilters, {
ID: filterId
}); - 1 === index ? scope.customFilters.push(filter) : scope.customFilters[index] = filter
}
}), scope.addCustomFilter = function() {
var activeCustomFilters = _.where(scope.customFilters, {
Status: 1
});
if (!authentication.hasPaidMail() && 1 === activeCustomFilters.length) return notification.info(gettextCatalog.getString('Free ProtonMail accounts are limited to 1 custom filter. Please <a href="/dashboard">upgrade</a> to get unlimited filters.', null, "Info"));
filterModal.activate({
params: {
mode: "simple",
close: function() {
filterModal.deactivate()
}
}
})
}, scope.addSieveFilter = function() {
var activeCustomFilters = _.where(scope.customFilters, {
Status: 1
});
if (!authentication.hasPaidMail() && 1 === activeCustomFilters.length) return notification.info(gettextCatalog.getString('Free ProtonMail accounts are limited to 1 custom filter. Please <a href="/dashboard">upgrade</a> to get unlimited filters.', null, "Info"));
filterModal.activate({
params: {
mode: "complex",
close: function() {
filterModal.deactivate()
}
}
})
}, scope.isSimple = function(filter) {
return filter.Simple && Object.keys(filter.Simple).length
}, scope.editCustomFilter = function(filter) {
var complex = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
filterModal.activate({
params: {
mode: !complex && scope.isSimple(filter) ? "simple" : "complex",
filter: filter,
close: function() {
filterModal.deactivate()
}
}
})
}, scope.deleteCustomFilter = function(filter) {
var title = gettextCatalog.getString("Delete Filter", null, "Title"),
message = gettextCatalog.getString("Are you sure you want to delete this filter?", null, "Info");
confirmModal.activate({
params: {
title: title,
message: message,
confirm: function() {
networkActivityTracker.track(Filter.delete(filter).then(function(_ref4) {
var _ref4$data = _ref4.data,
data = void 0 === _ref4$data ? {} : _ref4$data;
if (1e3 === data.Code) return eventManager.call(), notification.success(gettextCatalog.getString("Custom filter deleted", null, "Info"));
throw new Error(data.Error)
})), confirmModal.deactivate()
},
cancel: function() {
confirmModal.deactivate()
}
}
})
}, scope.enableCustomFilter = function(filter) {
return networkActivityTracker.track(Filter.enable(filter).then(function(_ref5) {
var _ref5$data = _ref5.data,
data = void 0 === _ref5$data ? {} : _ref5$data;
if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Status updated", null, "Info"));
throw filter.Status = 0, new Error(data.Error)
}))
}, scope.disableCustomFilter = function(filter) {
return networkActivityTracker.track(Filter.disable(filter).then(function(_ref6) {
var _ref6$data = _ref6.data,
data = void 0 === _ref6$data ? {} : _ref6$data;
if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Status updated", null, "Info"));
throw filter.Status = 1, new Error(data.Error)
}))
}
}
}
}), angular.module("proton.filter").directive("emailBlockButton", function(filterAddressModal) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/emailBlockButton.tpl.html",
scope: {},
link: function(scope, elem, _ref) {
var targetList = _ref.targetList,
onClick = function() {
filterAddressModal.activate({
params: {
type: targetList,
close: function() {
filterAddressModal.deactivate()
}
}
})
};
elem.on("click", onClick), scope.$on("$destroy", function() {
elem.off("click", onClick)
})
}
}
}), angular.module("proton.filter").directive("emailBlockList", function($rootScope, spamListModel, gettextCatalog) {
var I18N = {
whitelist: gettextCatalog.getString("Whitelist", null, "Info"),
blacklist: gettextCatalog.getString("Blacklist", null, "Info")
},
CLASSNAMES = {
LIST: "emailBlockList-list",
BTN_SWITCH: "emailBlockList-btn-switch",
BTN_DELETE: "emailBlockList-btn-delete"
},
onEvent = function(element, type, callback) {
return element.addEventListener(type, callback),
function() {
return element.removeEventListener(type, callback)
}
};
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/emailBlockList.tpl.html",
scope: {
listType: "@"
},
link: function(scope, elem, _ref) {
var switchTo = _ref.switchTo,
unsubscribe = [],
list = spamListModel.list(spamListModel.getType(scope.listType)),
tbody = elem[0].querySelector("." + CLASSNAMES.LIST);
scope.filterName = I18N[scope.listType], list.get().then(function(list) {
scope.$applyAsync(function() {
return scope.entries = list
})
}), unsubscribe.push($rootScope.$on("filters", function() {
list.get().then(function(list) {
scope.$applyAsync(function() {
scope.entries = _.uniq(list, !1, "ID"), $(".tooltip").hide()
})
})
}));
var onScroll = _.throttle(function() {
if (!list.isLoading() && !list.isEnding()) {
var elementCount = scope.entries.length,
triggerFetch = elementCount - 50;
(tbody.scrollTop + tbody.clientHeight) / tbody.scrollHeight > triggerFetch / elementCount && list.get().then(function(list) {
scope.$applyAsync(function() {
scope.entries = _.uniq(scope.entries.concat(list), !1, "ID")
})
})
}
}, 100),
onClick = function(_ref2) {
var target = _ref2.target;
"BUTTON" === target.nodeName && (target.classList.contains(CLASSNAMES.BTN_SWITCH) && spamListModel.move(target.dataset.entryId, spamListModel.getType(switchTo)), target.classList.contains(CLASSNAMES.BTN_DELETE) && spamListModel.destroy(target.dataset.entryId))
};
unsubscribe.push(onEvent(tbody, "scroll", onScroll)), unsubscribe.push(onEvent(elem[0], "click", onClick)), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0, spamListModel.clear()
})
}
}
}), angular.module("proton.filter").directive("filterView", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/filterView.tpl.html",
scope: {}
}
}), angular.module("proton.filter").directive("sieveLabelInput", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/sieveLabelInput.tpl.html",
scope: {
sieve: "="
},
link: {
pre: function(scope, elem) {
var unsubscribe = [];
scope.codeMirrorOptions = {
lineWrapping: !0,
lineNumbers: !0,
readOnly: !1,
fixedGutter: !1,
lint: {
delay: 800
},
gutters: ["CodeMirror-lint-markers"],
autoRefresh: !0,
mode: "sieve"
};
var editor = null,
unicodeClassification = {
"'": ["‹", "›", "‚", "‘", "‛", "’", "❛", "❜", "❮", "❯"],
'"': ["«", "»", "„", "“", "‟", "”", "❝", "❞", "〝", "〞", "〟", """]
},
regexMap = _.mapObject(unicodeClassification, function(value) {
return new RegExp("[" + value.join("") + "]", "g")
});
scope.codeMirrorLoaded = function(codemirror) {
editor = codemirror, editor.on("change", function() {
var value = editor.getValue();
if (_.values(regexMap).some(function(regex) {
return regex.exec(value)
})) {
var sanitizedValue = _.reduce(_.keys(regexMap), function(interValue, ascii) {
return interValue.replace(regexMap[ascii], ascii)
}, value),
cursor = editor.getCursor();
editor.setValue(sanitizedValue), editor.setCursor(cursor)
}
})
};
var focusCodeMirror = function() {
null !== editor && editor.focus()
},
sieveLabel = elem.find("label");
sieveLabel.on("click.focusSieve", focusCodeMirror), unsubscribe.push(function() {
return sieveLabel.off("click.focusSieve")
}), scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
})
}
}
}
}), angular.module("proton.filter").directive("spamListSearch", function(spamListModel) {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/spamListSearch.tpl.html",
scope: {},
link: function(scope, el) {
var $input = el.find("input"),
onInput = _.debounce(function(_ref) {
var target = _ref.target;
spamListModel.search(target.value.trim())
}, 500);
$input.on("input", onInput), scope.$on("$destroy", function() {
$input.off("input", onInput)
})
}
}
}), angular.module("proton.filter").directive("spamLists", function() {
return {
replace: !0,
restrict: "E",
templateUrl: "templates/filter/spamLists.tpl.html"
}
}), angular.module("proton.filter").factory("filterModal", function($timeout, $rootScope, pmModal, gettextCatalog, Filter, networkActivityTracker, notify, CONSTANTS, eventManager, labelModal, labelsModel, sieveLint) {
var TRANSLATIONS = {
TYPES: [{
label: gettextCatalog.getString("Select", null, "Filter modal type"),
value: "select"
}, {
label: gettextCatalog.getString("the subject", null, "Filter modal type"),
value: "subject"
}, {
label: gettextCatalog.getString("the sender", null, "Filter modal type"),
value: "sender"
}, {
label: gettextCatalog.getString("the recipient", null, "Filter modal type"),
value: "recipient"
}, {
label: gettextCatalog.getString("the attachments", null, "Filter modal type"),
value: "attachments"
}],
COMPARATORS: [{
label: gettextCatalog.getString("contains", null, "Condition for custom filter"),
value: "contains"
}, {
label: gettextCatalog.getString("is exactly", null, "Condition for custom filter"),
value: "is"
}, {
label: gettextCatalog.getString("begins with", null, "Condition for custom filter"),
value: "starts"
}, {
label: gettextCatalog.getString("ends with", null, "Condition for custom filter"),
value: "ends"
}, {
label: gettextCatalog.getString("matches", null, "Condition for custom filter"),
value: "matches"
}, {
label: gettextCatalog.getString("does not contain", null, "Condition for custom filter"),
value: "!contains"
}, {
label: gettextCatalog.getString("is not", null, "Condition for custom filter"),
value: "!is"
}, {
label: gettextCatalog.getString("does not begin with", null, "Condition for custom filter"),
value: "!starts"
}, {
label: gettextCatalog.getString("does not end with", null, "Condition for custom filter"),
value: "!ends"
}, {
label: gettextCatalog.getString("does not match", null, "Condition for custom filter"),
value: "!matches"
}],
OPERATORS: [{
label: gettextCatalog.getString("all", null, "Filter modal operators"),
value: "all"
}, {
label: gettextCatalog.getString("any", null, "Filter modal operators"),
value: "any"
}],
ERROR_PATTERN: gettextCatalog.getString("Text or pattern already included", null, "Error"),
FILTER_UPDATED_SUCCESS: gettextCatalog.getString("Filter updated", null, "Notification"),
FILTER_CREATED_SUCCESS: gettextCatalog.getString("Filter created", null, "Notification")
},
filterNewLabel = function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$create = _ref.create,
create = void 0 === _ref$create ? [] : _ref$create,
type = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : labelsModel.IS_LABEL;
return angular.copy(create).filter(function(_ref2) {
return _ref2.Exclusive === type
})
};
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/filter/modal.tpl.html",
controller: function(params, $scope) {
function openLabelModal() {
var Exclusive = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0;
labelModal.activate({
params: {
label: {
Exclusive: Exclusive
},
close: function() {
labelModal.deactivate()
}
}
})
}
function prepareConditions() {
var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref3$Simple = _ref3.Simple,
Simple = void 0 === _ref3$Simple ? {} : _ref3$Simple,
_Simple$Conditions = Simple.Conditions,
Conditions = void 0 === _Simple$Conditions ? [] : _Simple$Conditions,
conditions = Conditions.map(function(_ref4) {
var _ref4$Type = _ref4.Type,
Type = void 0 === _ref4$Type ? {} : _ref4$Type,
_ref4$Comparator = _ref4.Comparator,
Comparator = void 0 === _ref4$Comparator ? {} : _ref4$Comparator,
_ref4$Values = _ref4.Values;
return {
Values: void 0 === _ref4$Values ? [] : _ref4$Values,
value: "",
Type: _.findWhere(ctrl.types, {
value: Type.value
}),
Comparator: _.findWhere(ctrl.comparators, {
value: Comparator.value
})
}
});
return 0 === conditions.length && conditions.push({
Values: [],
value: "",
Type: ctrl.types[0],
Comparator: ctrl.comparators[0]
}), conditions
}
function prepareActions() {
var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref5$Simple = _ref5.Simple,
Simple = void 0 === _ref5$Simple ? {} : _ref5$Simple,
_ref6 = Simple.Actions || {},
_ref6$FileInto = _ref6.FileInto,
FileInto = void 0 === _ref6$FileInto ? [] : _ref6$FileInto,
_ref6$Mark = _ref6.Mark,
Mark = void 0 === _ref6$Mark ? {
Read: !1,
Starred: !1
} : _ref6$Mark,
move = findCurrentMoveFolder(FileInto);
ctrl.hasMove = !!move, ctrl.hasMark = Mark.Read || Mark.Starred;
var actions = {
Labels: labelsOrdered.map(function(label) {
return label.Selected = -1 !== FileInto.indexOf(label.Name), label
}),
Move: move || "inbox",
Mark: Mark
};
return ctrl.hasLabels = !!_.where(actions.Labels, {
Selected: !0
}).length, actions
}
function prepareOperator() {
var _ref7 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref7$Simple = _ref7.Simple,
Simple = void 0 === _ref7$Simple ? {} : _ref7$Simple,
_ref8 = Simple.Operator || {},
_ref8$value = _ref8.value,
value = void 0 === _ref8$value ? "all" : _ref8$value;
return _.findWhere(ctrl.operators, {
value: value
})
}
function prepareID() {
var _ref9 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref9$ID = _ref9.ID;
return void 0 === _ref9$ID ? "" : _ref9$ID
}
function prepareName() {
var _ref10 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref10$Name = _ref10.Name;
return void 0 === _ref10$Name ? "" : _ref10$Name
}
function prepareStatus() {
var _ref11 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref11$Status = _ref11.Status;
return void 0 === _ref11$Status ? 1 : _ref11$Status
}
var labelsOrdered = labelsModel.get("labels"),
foldersOrdered = labelsModel.get("folders"),
ctrl = this,
model = angular.copy(params.filter);
ctrl.hasLabels = !1, ctrl.hasMove = !1, ctrl.hasMark = !1, ctrl.folders = foldersOrdered, ctrl.types = angular.copy(TRANSLATIONS.TYPES), ctrl.comparators = angular.copy(TRANSLATIONS.COMPARATORS), ctrl.operators = angular.copy(TRANSLATIONS.OPERATORS);
var findCurrentMoveFolder = function() {
var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [],
map = labelsModel.get("folders").reduce(function(acc, label) {
return acc[label.Name] = label, acc
}, {});
return _.find(list, function(key) {
return CONSTANTS.MAILBOX_IDENTIFIERS[key] || map[key]
}) || ""
};
ctrl.addLabel = function() {
return openLabelModal(0)
}, ctrl.addFolder = function() {
return openLabelModal(1)
}, ctrl.initialization = function() {
ctrl.filter = {
ID: prepareID(model),
Name: prepareName(model),
Status: prepareStatus(model),
Version: CONSTANTS.FILTER_VERSION
}, sieveLint.resetLastCheck(), "simple" === params.mode ? (ctrl.mode = "simple", ctrl.filter.Simple = {
Operator: prepareOperator(model),
Conditions: prepareConditions(model),
Actions: prepareActions(model)
}) : "complex" === params.mode && (ctrl.mode = "complex", ctrl.filter.Sieve = model ? model.Sieve : "");
var unsubscribe = [];
angular.isObject(ctrl.filter.Simple) && (unsubscribe.push($rootScope.$on("labelsModel", function(e, _ref12) {
var type = _ref12.type,
data = _ref12.data;
"cache.update" === type && $scope.$applyAsync(function() {
ctrl.filter.Simple.Actions.Labels = ctrl.filter.Simple.Actions.Labels.concat(filterNewLabel(data)), ctrl.folders = ctrl.folders.concat(filterNewLabel(data, labelsModel.IS_FOLDER))
})
})), unsubscribe.push($rootScope.$on("autocompleteEmail", function(e, _ref13) {
var type = _ref13.type,
data = _ref13.data;
"input.blur" === type && "filter-modal-add-condition-input" === data.type && ctrl.addValue(ctrl.filter.Simple.Conditions[Number(data.eventData)])
}))), $scope.$on("$destroy", function() {
_.each(unsubscribe, function(cb) {
return cb()
}), unsubscribe.length = 0
}), $timeout(function() {
angular.element("#filterName").focus()
}, 100, !1)
}, ctrl.onChangeAttachements = function(model, value) {
model.Comparator = _.findWhere(ctrl.comparators, {
value: value
})
}, ctrl.displaySeparator = function() {
if (ctrl.filter.Simple) {
var conditions = ctrl.filter.Simple.Conditions;
return conditions.length > 0 && "select" !== conditions[0].Type.value
}
return !1
}, ctrl.valid = function() {
var pass = !0;
if (pass = ctrl.filter.Name.length > 0, Object.keys(ctrl.filter.Simple || {}).length > 0) {
var attachmentsCondition = 0;
return _.each(ctrl.filter.Simple.Conditions, function(condition) {
pass = pass && "select" !== condition.Type.value, "subject" !== condition.Type.value && "sender" !== condition.Type.value && "recipient" !== condition.Type.value || (pass = pass && condition.Values.length > 0), "attachments" === condition.Type.value && attachmentsCondition++
}), pass = pass && attachmentsCondition <= 1, pass = pass && (ctrl.hasLabels || ctrl.hasMove || ctrl.hasMark), !0 === ctrl.hasLabels && (pass = pass && _.where(ctrl.filter.Simple.Actions.Labels, {
Selected: !0
}).length > 0), !0 === ctrl.hasMark && (pass = pass && (ctrl.filter.Simple.Actions.Mark.Starred || ctrl.filter.Simple.Actions.Mark.Read)), !0 === ctrl.hasMove && (pass = pass && !!ctrl.filter.Simple.Actions.Move), pass
}
return ctrl.filter.Sieve.length > 0 && sieveLint.lastCheckWasValid()
}, ctrl.addCondition = function() {
ctrl.filter.Simple.Conditions.push({
Type: _.first(ctrl.types),
Comparator: _.first(ctrl.comparators),
Values: [],
value: ""
})
}, ctrl.addValue = function(condition) {
-1 === condition.Values.indexOf(condition.value) ? condition.value && (condition.Values.push(condition.value), condition.value = "") : notify({
message: TRANSLATIONS.ERROR_PATTERN,
classes: "notification-danger"
})
}, ctrl.removeCondition = function(condition) {
var index = ctrl.filter.Simple.Conditions.indexOf(condition);
ctrl.filter.Simple.Conditions.splice(index, 1)
};
var bindFileInto = function() {
var _ref14 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref14$FileInto = _ref14.FileInto,
FileInto = void 0 === _ref14$FileInto ? [] : _ref14$FileInto,
_ref14$Move = _ref14.Move,
Move = void 0 === _ref14$Move ? "" : _ref14$Move,
labels = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [];
return _.uniq([Move].filter(Boolean).concat(FileInto, labels))
},
requestUpdate = function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
onSuccess = function() {
var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
return function(result) {
result.data && 1e3 === result.data.Code ? (notify({
message: message,
classes: "notification-success"
}), eventManager.call(), params.close()) : result.data && result.data.Error && (notify({
message: result.data.Error,
classes: "notification-danger"
}), 50016 === result.data.Code && (eventManager.call(), params.close()))
}
};
return data.ID ? Filter.update(data).then(onSuccess(TRANSLATIONS.FILTER_UPDATED_SUCCESS)) : Filter.create(data).then(onSuccess(TRANSLATIONS.FILTER_CREATED_SUCCESS))
};
ctrl.save = function() {
if ("complex" === params.mode) return void $timeout(function() {
var clone = angular.copy(ctrl.filter);
delete clone.Simple, delete clone.Tree, networkActivityTracker.track(requestUpdate(clone))
}, 100, !1);
var clone = angular.copy(ctrl.filter);
if (Object.keys(ctrl.filter.Simple || {}).length > 0) {
if (!1 === ctrl.hasMove && (clone.Simple.Actions.Move = ""), !1 === ctrl.hasMark && (clone.Simple.Actions.Mark = {
Read: !1,
Starred: !1
}), !0 === ctrl.hasLabels) {
var labels = _.filter(clone.Simple.Actions.Labels, function(_ref15) {
return !0 === _ref15.Selected
}).map(function(_ref16) {
return _ref16.Name
}),
fileInto = bindFileInto(clone.Simple.Actions, labels);
clone.Simple.Actions.FileInto = fileInto, delete clone.Simple.Actions.Labels
} else delete clone.Simple.Actions.Labels;
clone.Simple.Actions.FileInto = bindFileInto(clone.Simple.Actions), delete clone.Simple.Actions.Move
}
networkActivityTracker.track(requestUpdate(clone))
}, ctrl.cancel = function() {
params.close()
}, ctrl.initialization()
}
})
}), angular.module("proton.filter").factory("incomingModel", function(notify, gettextCatalog, IncomingDefault, networkActivityTracker) {
var I18N = {
ADD_SUCCESS: gettextCatalog.getString("Spam Filter Added", null, "Filters"),
UPDATE_SUCCESS: gettextCatalog.getString("Spam Filter Updated", null, "Filters"),
DELETE_SUCCESS: gettextCatalog.getString("Spam Filter Deleted", null, "Filters")
},
notifySuccess = function(message) {
return notify({
message: message,
classes: "notification-success"
})
};
return {
get: function(config) {
var promise = IncomingDefault.get(config).then(function(_ref) {
var _ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (data.Error) throw new Error(data.Error);
return data.IncomingDefaults
});
return networkActivityTracker.track(promise), promise
},
update: function(ID, Location) {
var promise = IncomingDefault.update({
ID: ID,
Location: Location
}).then(function(_ref2) {
var _ref2$data = _ref2.data,
data = void 0 === _ref2$data ? {} : _ref2$data;
if (data.Error) {
var error = new Error(data.Error);
throw error.Code = data.Code, error
}
return notifySuccess(I18N.UPDATE_SUCCESS), data.IncomingDefault
});
return networkActivityTracker.track(promise), promise
},
remove: function(ID) {
var promise = IncomingDefault.delete({
IDs: [ID]
}).then(function(_ref3) {
var _ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
if (data.Error) throw new Error(data.Error);
return notifySuccess(I18N.DELETE_SUCCESS), data.IncomingDefault
});
return networkActivityTracker.track(promise), promise
},
create: function(params) {
var promise = IncomingDefault.add(params).then(function(_ref4) {
var _ref4$data = _ref4.data,
data = void 0 === _ref4$data ? {} : _ref4$data;
if (data.Error) throw new Error(data.Error);
return notifySuccess(I18N.ADD_SUCCESS), data.IncomingDefault
});
return networkActivityTracker.track(promise), promise
}
}
}), angular.module("proton.filter").factory("spamListModel", function($q, $rootScope, CONSTANTS, incomingModel) {
function getDefault() {
var _ref;
return _ref = {
MAP: Object.create(null)
}, _defineProperty(_ref, BLACKLIST_TYPE, {
list: [],
page: 0
}), _defineProperty(_ref, WHITELIST_TYPE, {
list: [],
page: 0
}), _ref
}
function updateCache(reset) {
reset && (MAIN_CACHE.MAP = Object.create(null));
var map = MAIN_CACHE[BLACKLIST_TYPE].list.concat(MAIN_CACHE[WHITELIST_TYPE].list).reduce(function(acc, item) {
return acc[item.ID] = item, acc
}, Object.create(null));
_.extend(MAIN_CACHE.MAP, map)
}
function refresh() {
if (MAIN_CACHE.query) return search(MAIN_CACHE.query);
dispatch("change", {
type: "refresh"
})
}
var load = function() {
var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4() {
var config, whitelist, blacklist, params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
noEvent = arguments[1];
return regeneratorRuntime.wrap(function(_context4) {
for (;;) switch (_context4.prev = _context4.next) {
case 0:
return config = {
Page: 0,
PageSize: PAGE_SIZE
}, whitelist = list(WHITELIST_TYPE), blacklist = list(BLACKLIST_TYPE), whitelist.setLoader(!0), blacklist.setLoader(!0), _context4.next = 7, Promise.all([whitelist.loadList(_.extend({}, config, params)), blacklist.loadList(_.extend({}, config, params))]);
case 7:
whitelist.setLoader(!1), blacklist.setLoader(!1), updateCache(), !noEvent && resetIndex(), !noEvent && dispatch("change", {
type: "load"
});
case 12:
case "end":
return _context4.stop()
}
}, _callee4, this)
}));
return function() {
return _ref5.apply(this, arguments)
}
}(),
search = function() {
var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(query) {
return regeneratorRuntime.wrap(function(_context7) {
for (;;) switch (_context7.prev = _context7.next) {
case 0:
return MAIN_CACHE.query = query, resetIndex(), _context7.next = 4, load({
Keyword: query
}, !0);
case 4:
dispatch("search");
case 5:
case "end":
return _context7.stop()
}
}, _callee7, this)
}));
return function(_x8) {
return _ref8.apply(this, arguments)
}
}(),
MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS,
BLACKLIST_TYPE = +MAILBOX_IDENTIFIERS.spam,
WHITELIST_TYPE = +MAILBOX_IDENTIFIERS.inbox,
PAGE_SIZE = 100,
MAIN_CACHE = getDefault(),
dispatch = function(type) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
return $rootScope.$emit("filters", {
type: type,
data: data
})
},
getType = function(type) {
return "whitelist" === type ? WHITELIST_TYPE : BLACKLIST_TYPE
},
resetIndex = function(type) {
if (type) return MAIN_CACHE[WHITELIST_TYPE].ending && (MAIN_CACHE[WHITELIST_TYPE].page = 0, MAIN_CACHE[WHITELIST_TYPE].ending = !1), MAIN_CACHE[BLACKLIST_TYPE].ending && (MAIN_CACHE[BLACKLIST_TYPE].page = 0,
MAIN_CACHE[BLACKLIST_TYPE].ending = !1), MAIN_CACHE[type].page = 0;
MAIN_CACHE[WHITELIST_TYPE].page = 0, MAIN_CACHE[BLACKLIST_TYPE].page = 0, MAIN_CACHE[WHITELIST_TYPE].ending = !1, MAIN_CACHE[BLACKLIST_TYPE].ending = !1
},
list = function(type) {
var CACHE = MAIN_CACHE[type],
extendPage = function(value) {
return CACHE.page += value
},
setLoader = function(value) {
return CACHE.loading = value
},
loadList = function() {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(params) {
var list;
return regeneratorRuntime.wrap(function(_context) {
for (;;) switch (_context.prev = _context.next) {
case 0:
return _context.next = 2, incomingModel.get(_.extend({
Location: type
}, params));
case 2:
return list = _context.sent, !CACHE.ending && (CACHE.list = list), _context.abrupt("return", list);
case 5:
case "end":
return _context.stop()
}
}, _callee, void 0)
}));
return function(_x2) {
return _ref2.apply(this, arguments)
}
}(),
get = function() {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
var pageFrom, list;
return regeneratorRuntime.wrap(function(_context2) {
for (;;) switch (_context2.prev = _context2.next) {
case 0:
if (pageFrom = CACHE.page, !(CACHE.list.length && CACHE.list.length >= (pageFrom + 2) * PAGE_SIZE)) {
_context2.next = 5;
break
}
return CACHE.ending = CACHE.list.length < PAGE_SIZE && !CACHE.invalidate, delete CACHE.invalidate, _context2.abrupt("return", angular.copy(CACHE.list));
case 5:
return extendPage(1), setLoader(!0), _context2.next = 9, loadList({
Location: type,
Page: pageFrom,
Keyword: MAIN_CACHE.query,
PageSize: PAGE_SIZE
});
case 9:
return list = _context2.sent, updateCache(), setLoader(!1), CACHE.ending = list.length < PAGE_SIZE && !CACHE.invalidate, delete CACHE.invalidate, _context2.abrupt("return", list);
case 15:
case "end":
return _context2.stop()
}
}, _callee2, void 0)
}));
return function() {
return _ref3.apply(this, arguments)
}
}(),
add = function() {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(Email) {
var item;
return regeneratorRuntime.wrap(function(_context3) {
for (;;) switch (_context3.prev = _context3.next) {
case 0:
return _context3.next = 2, incomingModel.create({
Email: Email,
Location: type
});
case 2:
item = _context3.sent, CACHE.list.unshift(item), MAIN_CACHE.MAP[item.ID] = item, resetIndex(item.Location), refresh();
case 7:
case "end":
return _context3.stop()
}
}, _callee3, void 0)
}));
return function(_x3) {
return _ref4.apply(this, arguments)
}
}();
return {
extendPage: extendPage,
setLoader: setLoader,
loadList: loadList,
get: get,
add: add,
isLoading: function() {
return !!CACHE.loading
},
isEnding: function() {
return !!CACHE.ending
}
}
},
move = function() {
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(id, location) {
var data, item, index;
return regeneratorRuntime.wrap(function(_context5) {
for (;;) switch (_context5.prev = _context5.next) {
case 0:
return _context5.prev = 0, _context5.next = 3, incomingModel.update(id, location);
case 3:
data = _context5.sent, item = MAIN_CACHE.MAP[id], index = _.findIndex(MAIN_CACHE[item.Location].list, function(o) {
return o.ID === item.ID
}), MAIN_CACHE[item.Location].list.splice(index, 1), MAIN_CACHE[location].list.unshift(data), MAIN_CACHE.MAP[item.ID] = data, MAIN_CACHE[item.Location].invalidate = !MAIN_CACHE[item.Location].ending, resetIndex(), refresh(), _context5.next = 17;
break;
case 14:
_context5.prev = 14, _context5.t0 = _context5.catch(0), 35023 === _context5.t0.Code && (delete MAIN_CACHE.MAP[id], load({
Search: MAIN_CACHE.query
}));
case 17:
case "end":
return _context5.stop()
}
}, _callee5, void 0, [
[0, 14]
])
}));
return function(_x5, _x6) {
return _ref6.apply(this, arguments)
}
}(),
destroy = function() {
var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(id) {
var item, index;
return regeneratorRuntime.wrap(function(_context6) {
for (;;) switch (_context6.prev = _context6.next) {
case 0:
return _context6.next = 2, incomingModel.remove(id);
case 2:
item = MAIN_CACHE.MAP[id], index = _.findIndex(MAIN_CACHE[item.Location].list, function(o) {
return o.ID === item.ID
}), MAIN_CACHE[item.Location].list.splice(index, 1), MAIN_CACHE[item.Location].invalidate = !MAIN_CACHE[item.Location].ending, delete MAIN_CACHE.MAP[id], resetIndex(item.Location), refresh();
case 9:
case "end":
return _context6.stop()
}
}, _callee6, void 0)
}));
return function(_x7) {
return _ref7.apply(this, arguments)
}
}();
return {
list: list,
load: load,
move: move,
destroy: destroy,
search: search,
refresh: refresh,
clear: function() {
return MAIN_CACHE = getDefault()
},
getType: getType
}
}), angular.module("proton.filter").factory("filterAddressModal", function(pmModal, spamListModel) {
return pmModal({
controllerAs: "ctrl",
templateUrl: "templates/filter/filterAddressModal.tpl.html",
controller: function(params) {
var _this = this;
this.filter = {
Email: ""
}, this.cancel = params.close, this.type = params.type, this.create = function() {
spamListModel.list(spamListModel.getType(params.type)).add(_this.filter.Email), params.close()
}, setTimeout(function() {
angular.element("#emailAddress").focus()
}, 100)
}
})
}), angular.module("proton.filter").factory("sieveLint", function(Filter, CONSTANTS) {
function register() {
window.CodeMirror.registerHelper("lint", "sieve", function(text) {
if ("" === text.trim()) {
var line = text.split("\n")[0];
return [{
message: "A sieve script cannot be empty",
severity: "error",
from: window.CodeMirror.Pos(0, 0),
to: window.CodeMirror.Pos(0, line.length)
}]
}
return Filter.check({
Version: CONSTANTS.FILTER_VERSION,
Sieve: text
}).then(function(response) {
return 200 !== response.status ? [] : (wasValid = 0 === response.data.Issues.length, response.data.Issues)
})
})
}
function lastCheckWasValid() {
return wasValid
}
function resetLastCheck() {
wasValid = !0
}
var wasValid = !0;
return {
init: register,
lastCheckWasValid: lastCheckWasValid,
resetLastCheck: resetLastCheck
}
}), angular.module("proton.formUtils").directive("captcha", function($rootScope, CONSTANTS, url, $httpParamSerializer) {
var IFRAME_SECURE_ORIGIN = CONSTANTS.IFRAME_SECURE_ORIGIN,
APP_HOST = url.host(),
captchaMessage = {
type: "pm_captcha",
language: "en",
key: "6LcWsBUTAAAAAOkRfBk-EXkGzOfcSz3CzvYbxfTn"
},
captchaReceiveMessage = function($iframe) {
return function(event) {
if (void 0 !== event.origin || void 0 !== event.originalEvent.origin) {
if ((event.origin || event.originalEvent.origin) === IFRAME_SECURE_ORIGIN) {
var data = event.data;
"pm_captcha" === data.type && $rootScope.$emit("humanVerification", {
type: "captcha",
data: data
}), "pm_height" === data.type && $iframe.height(event.data.height + 40)
}
}
}
};
return {
replace: !0,
templateUrl: "templates/formUtils/captcha.tpl.html",
link: function(scope, el, _ref) {
var _ref$token = _ref.token,
token = void 0 === _ref$token ? "signup" : _ref$token,
iframe = el.find("iframe"),
listener = captchaReceiveMessage(iframe),
parameters = $httpParamSerializer({
token: token,
client: "web",
host: APP_HOST
});
window.captchaSendMessage = function() {
iframe[0].contentWindow.postMessage(captchaMessage, IFRAME_SECURE_ORIGIN)
}, iframe[0].onload = window.captchaSendMessage, iframe[0].src = "https://secure.protonmail.com/captcha/captcha.html?" + parameters, window.addEventListener("message", listener, !1), scope.$on("$destroy", function() {
window.removeEventListener("message", listener, !1)
})
}
}
}), angular.module("proton.formUtils").directive("captchaView", function($httpParamSerializer, $rootScope, url) {
return {
restrict: "E",
templateUrl: "templates/formUtils/captchaView.tpl.html",
link: function(scope, element, _ref) {
function receiveMessage(event) {
var origin = event.origin,
originalEvent = event.originalEvent,
data = event.data;
if (void 0 !== origin || void 0 !== originalEvent.origin) {
if ("https://secure.protonmail.com" === (origin || originalEvent.origin) && ("pm_captcha" === data.type && $rootScope.$emit("captcha.token", data.token), "pm_height" === data.type)) {
var height = event.data.height + 40;
iframe.style.height = height + "px"
}
}
}
var token = _ref.token,
iframe = element[0].querySelector("iframe"),
host = url.host(),
parameters = $httpParamSerializer({
token: token,
client: "web",
host: host
});
window.addEventListener("message", receiveMessage, !1), iframe.src = "https://secure.protonmail.com/captcha/captcha.html?" + parameters, scope.$on("$destroy", function() {
window.removeEventListener("message", receiveMessage, !1)
})
}
}
}), angular.module("proton.formUtils").directive("cardCvc", function() {
return {
require: "ngModel",
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.cardCvc = function(modelValue) {
return $.payment.validateCardCVC(modelValue)
}
}
}
}), angular.module("proton.formUtils").directive("cardNumber", function() {
return {
require: "ngModel",
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.cardNumber = function(modelValue) {
return $.payment.validateCardNumber(modelValue)
}
}
}
}), angular.module("proton.formUtils").directive("cardView", function(countriesListModel) {
var countries = countriesListModel(),
currentYear = (new Date).getFullYear(),
months = _.range(1, 13).map(function(i) {
return ("0" + i).slice(-2)
}),
years = _.range(currentYear, currentYear + 12);
return {
replace: !0,
templateUrl: "templates/formUtils/cardView.tpl.html",
scope: {
card: "=",
form: "="
},
link: function(scope) {
var country = scope.card.country ? _.findWhere(countries, {
value: scope.card.country.value
}) : countries[0];
scope.months = months, scope.years = years, scope.countries = countries, scope.card.country = country, scope.card.month = scope.months[0], scope.card.year = scope.years[0]
}
}
}), angular.module("proton.formUtils").directive("compareTo", function() {
return {
require: "ngModel",
scope: {
otherModelValue: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
return !scope.otherModelValue || modelValue === scope.otherModelValue
}, scope.$watch("otherModelValue", function() {
ngModel.$validate()
})
}
}
}), angular.module("proton.formUtils").directive("cvcTooltip", function(gettextCatalog) {
var line1 = gettextCatalog.getString("For Visa, MasterCard and Discover, the 3 digits on the back of your card.", null, "Info"),
line2 = gettextCatalog.getString("For American Express, the 4 digits on the front of your card.", null, "Info"),
title = gettextCatalog.getString("Security Code", null, "Credit card CVC");
return {
restrict: "A",
link: function(scope, element) {
element[0].setAttribute("tabindex", 0), element[0].setAttribute("role", "button");
var options = {
placement: "top",
container: "body",
html: !0,
title: title,
trigger: "focus",
content: "\n <p>" + line1 + "</p>\n <p>" + line2 + "</p>\n ",
template: '\n <div class="popover" role="tooltip">\n <div class="arrow"></div>\n <div class="popover-title bold"></div>\n <div class="popover-content"></div>\n </div>\n '
};
element.popover(options), scope.$on("$destroy", function() {
element.popover("destroy")
})
}
}
}), angular.module("proton.formUtils").directive("danger", function(gettextCatalog) {
function isDanger(value) {
return value === dangerWord
}
var dangerWord = gettextCatalog.getString("DANGER"),
placeholder = gettextCatalog.getString("Enter the word 'DANGER' here.");
return {
require: "ngModel",
restrict: "A",
scope: {
dangerWord: "="
},
link: function(scope, element, attributes, ngModel) {
scope.dangerWord = dangerWord, element.attr("placeholder", placeholder), ngModel.$validators.danger = isDanger
}
}
}), angular.module("proton.formUtils").directive("formIsInvalid", function() {
var getClassName = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "") + "-is-invalid"
};
return {
link: function(scope, el, _ref) {
var name = _ref.name;
if (!name) throw new Error("A form must contains a name attribute");
var onSubmit = function() {
if (scope[name].$invalid) return el[0].classList.add(getClassName(name));
el[0].classList.remove(getClassName(name))
};
el.on("submit", onSubmit), scope.$on("$destroy", function() {
el.off("submit", onSubmit)
})
}
}
}), angular.module("proton.formUtils").directive("password", function() {
return {
restrict: "E",
replace: !0,
templateUrl: "templates/formUtils/password.tpl.html",
scope: {
value: "=",
form: "=",
compare: "="
},
compile: function(element, _ref) {
var autofocus = _ref.autofocus,
compare = _ref.compare,
_ref$id = _ref.id,
id = void 0 === _ref$id ? "" : _ref$id,
_ref$name = _ref.name,
name = void 0 === _ref$name ? "" : _ref$name,
_ref$placeholder = _ref.placeholder,
placeholder = void 0 === _ref$placeholder ? "" : _ref$placeholder,
_ref$tabindex = _ref.tabindex,
tabindex = void 0 === _ref$tabindex ? 0 : _ref$tabindex,
input = element[0].querySelector("input");
return input.setAttribute("id", id), input.setAttribute("name", name), input.setAttribute("placeholder", placeholder), input.setAttribute("tabindex", tabindex), compare && input.setAttribute("data-compare-to", "compare"), autofocus && input.setAttribute("autofocus", !0),
function(scope, el, _ref2) {
var autofocus = _ref2.autofocus,
$input = el[0].querySelector(".password-input");
scope.message = scope.form[name].$error, autofocus && document.activeElement !== $input && _rAF(function() {
return $input.focus()
})
}
}
}
});
var _templateObject = _taggedTemplateLiteral(['<button type="button" class="togglePassword-btn-toggle">\n <i class="togglePassword-icon-toText fa fa-eye" pt-tooltip="', '"></i>\n <i class="togglePassword-icon-toPassword fa fa-eye-slash" pt-tooltip="', '"></i>\n </button>'], ['<button type="button" class="togglePassword-btn-toggle">\n <i class="togglePassword-icon-toText fa fa-eye" pt-tooltip="', '"></i>\n <i class="togglePassword-icon-toPassword fa fa-eye-slash" pt-tooltip="', '"></i>\n </button>']);
angular.module("proton.formUtils").directive("togglePassword", function(gettextCatalog, dedentTpl) {
var hasNativeButton = "IE" === $.ua.browser.name || "Edge" === $.ua.browser.name,
TOOLTIPS = {
SHOW: gettextCatalog.getString("Show password", null, "toggle password"),
HIDE: gettextCatalog.getString("Hide password", null, "toggle password")
},
template = dedentTpl(_templateObject, TOOLTIPS.SHOW, TOOLTIPS.HIDE);
return {
restrict: "A",
compile: function(el) {
if (!hasNativeButton) {
var container = el[0].parentElement;
return container.insertAdjacentHTML("beforeEnd", template), container.classList.add("customPasswordToggler"),
function(scope, el) {
var btn = el[0].parentElement.querySelector(".togglePassword-btn-toggle"),
onClick = function() {
var type = "text" === el[0].type ? "password" : "text";
el[0].setAttribute("type", type), btn.classList.toggle("togglePassword-btn-display")
};
btn.addEventListener("click", onClick), scope.$on("$destroy", function() {
btn.removeEventListener("click", onClick)
})
}
}
}
}
}), angular.module("proton.formUtils").directive("uniqueUsername", function($stateParams, gettextCatalog, User) {
var clean = function() {
return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").toLowerCase().replace(/\.|-|_/, "")
},
validator = function(ngModel) {
return function(username) {
var usernameCleaned = clean(username);
return delete ngModel.$error.alreadyTaken, delete ngModel.$error.tooMuch, delete ngModel.$error.uniqueError, usernameCleaned === $stateParams.inviteSelector ? Promise.resolve() : User.available(username).then(function() {
var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref$data = _ref.data,
data = void 0 === _ref$data ? {} : _ref$data;
if (1e3 === data.Code) {
if (data.Available) return Promise.resolve();
ngModel.$error.alreadyTaken = !0
}
return 429 === data.Error && (ngModel.$error.tooMuch = !0), ngModel.$error.uniqueError = !0, Promise.reject(!1)
})
}
};
return {
require: "ngModel",
restrict: "A",
link: function(scope, el, attr, ngModel) {
ngModel.$asyncValidators.unique = validator(ngModel)
}
}
}), angular.module("proton.formUtils").directive("validRecovery", function() {
var validator = function(scope) {
return function(email) {
var _scope$username = scope.username,
username = void 0 === _scope$username ? "" : _scope$username,
_scope$domain = scope.domain;
return email !== username + "@" + (void 0 === _scope$domain ? "" : _scope$domain)
}
};
return {
require: "ngModel",
restrict: "A",
scope: {
domain: "=validRecoveryDomain",
username: "=validRecoveryUsername"
},
link: function(scope, el, attr, ngModel) {
ngModel.$validators.validUsername = validator(scope)
}
}
}), angular.module("proton.formUtils").directive("validUsername", function() {
var IS_VALID = new RegExp(/^[A-Za-z0-9]+(?:[_.-][A-Za-z0-9]+)*$/);
return {
require: "ngModel",
restrict: "A",
link: function(scope, el, attr, ngModel) {
ngModel.$validators.valid = function(input) {
return IS_VALID.test(input)
}
}
}
}), angular.module("proton.formUtils").directive("validatorTypoEmail", function(checkTypoEmails) {
return {
link: function(scope, el) {
var ngMessages = el[0].nextElementSibling,
warningMessage = ngMessages.querySelector('[ng-message-warning="typo-email"]'),
toggleWarning = function(valid) {
var method = valid ? "add" : "remove";
el[0].classList[method]("ng-warning-typo-email"), warningMessage.style.display = valid ? "initial" : "none"
},
onBlur = function(_ref) {
var target = _ref.target;
toggleWarning(checkTypoEmails(target.value))
};
el[0].addEventListener("blur", onBlur), scope.$on("$destroy", function() {
el[0].removeEventListener("blur", onBlur)
})
}
}
}), angular.module("proton.formUtils").factory("cardModel", function() {
var clean = function(value) {
return String(value).replace(/\s+/g, "")
},
formatYear = function(year) {
return (2 === String(year).length ? "20" : "") + year
};
return function() {
var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
card = angular.copy(data),
number = function() {
return clean(card.number)
},
month = function() {
return card.month
},
year = function() {
return formatYear(card.year)
},
cvc = function() {
return clean(card.cvc)
},
fullname = function() {
return card.fullname
},
zip = function() {
return card.zip
},
country = function() {
return card.country.value
};
return {
number: number,
month: month,
year: year,
cvc: cvc,
fullname: fullname,
zip: zip,
country: country,
details: function() {
return {
Number: number(),
ExpMonth: month(),
ExpYear: year(),
CVC: cvc(),
Name: fullname(),
Country: country(),
ZIP: zip()
}
}
}
}
}), angular.module("proton.commons").factory("countriesListModel", function() {
var DEFAULT_SEPARATOR = {
label: "------------------",
value: "",
disabled: !0
},
list = [{
value: "AF",
label: "Afghanistan"
}, {
value: "AL",
label: "Albania"
}, {
value: "DZ",
label: "Algeria"
}, {
value: "AD",
label: "Andorra"
}, {
value: "AO",
label: "Angola"
}, {
value: "AI",
label: "Anguilla"
}, {
value: "AG",
label: "Antigua and Barbuda"
}, {
value: "AR",
label: "Argentina"
}, {
value: "AM",
label: "Armenia"
}, {
value: "AW",
label: "Aruba"
}, {
value: "AU",
label: "Australia"
}, {
value: "AT",
label: "Austria"
}, {
value: "AZ",
label: "Azerbaijan"
}, {
value: "BS",
label: "Bahamas"
}, {
value: "BH",
label: "Bahrain"
}, {
value: "BD",
label: "Bangladesh"
}, {
value: "BB",
label: "Barbados"
}, {
value: "BY",
label: "Belarus"
}, {
value: "BE",
label: "Belgium"
}, {
value: "BZ",
label: "Belize"
}, {
value: "BJ",
label: "Benin"
}, {
value: "BM",
label: "Bermuda"
}, {
value: "BT",
label: "Bhutan"
}, {
value: "BO",
label: "Bolivia"
}, {
value: "BA",
label: "Bosnia Herzegovina"
}, {
value: "BW",
label: "Botswana"
}, {
value: "BV",
label: "Bouvet Island"
}, {
value: "BR",
label: "Brazil"
}, {
value: "IO",
label: "British Indian Ocean Territory"
}, {
value: "VG",
label: "British Virgin Islands"
}, {
value: "BN",
label: "Brunei Darussalam"
}, {
value: "BG",
label: "Bulgaria"
}, {
value: "BF",
label: "Burkina Faso"
}, {
value: "BI",
label: "Burundi"
}, {
value: "KH",
label: "Cambodia"
}, {
value: "CM",
label: "Cameroon"
}, {
value: "CA",
label: "Canada"
}, {
value: "CV",
label: "Cape Verde"
}, {
value: "KY",
label: "Cayman Islands"
}, {
value: "CF",
label: "Central African Republic"
}, {
value: "TD",
label: "Chad"
}, {
value: "CL",
label: "Chile"
}, {
value: "CN",
label: "China"
}, {
value: "CX",
label: "Christmas Island"
}, {
value: "CC",
label: "Cocos (Keeling) Islands"
}, {
value: "CO",
label: "Colombia"
}, {
value: "KM",
label: "Comoros"
}, {
value: "CG",
label: "Congo"
}, {
value: "CD",
label: "Congo (The Democratic Republic of the)"
}, {
value: "CK",
label: "Cook Islands"
}, {
value: "CR",
label: "Costa Rica"
}, {
value: "CI",
label: "Cote d Ivoire (Ivory Coast)"
}, {
value: "HR",
label: "Croatia"
}, {
value: "CU",
label: "Cuba"
}, {
value: "CY",
label: "Cyprus"
}, {
value: "CZ",
label: "Czech Republic"
}, {
value: "DK",
label: "Denmark"
}, {
value: "DJ",
label: "Djibouti"
}, {
value: "DM",
label: "Dominica"
}, {
value: "DO",
label: "Dominican Republic"
}, {
value: "TL",
label: "East Timor"
}, {
value: "EC",
label: "Ecuador"
}, {
value: "EG",
label: "Egypt"
}, {
value: "SV",
label: "El Salvador"
}, {
value: "GQ",
label: "Equatorial Guinea"
}, {
value: "ER",
label: "Eritrea"
}, {
value: "EE",
label: "Estonia"
}, {
value: "ET",
label: "Ethiopia"
}, {
value: "FK",
label: "Falkland Islands (Malvinas)"
}, {
value: "FO",
label: "Faroe Islands"
}, {
value: "FJ",
label: "Fiji"
}, {
value: "FI",
label: "Finland"
}, {
value: "FR",
label: "France"
}, {
value: "GF",
label: "French Guiana"
}, {
value: "PF",
label: "French Polynesia"
}, {
value: "TF",
label: "French Southern Territories"
}, {
value: "GA",
label: "Gabon"
}, {
value: "GM",
label: "Gambia"
}, {
value: "GE",
label: "Georgia"
}, {
value: "DE",
label: "Germany"
}, {
value: "GH",
label: "Ghana"
}, {
value: "GI",
label: "Gibraltar"
}, {
value: "GR",
label: "Greece"
}, {
value: "GL",
label: "Greenland"
}, {
value: "GD",
label: "Grenada"
}, {
value: "GP",
label: "Guadeloupe"
}, {
value: "GT",
label: "Guatemala"
}, {
value: "GN",
label: "Guinea"
}, {
value: "GW",
label: "Guinea-Bissau"
}, {
value: "GY",
label: "Guyana"
}, {
value: "HT",
label: "Haiti"
}, {
value: "HM",
label: "Heard Island and McDonald Islands"
}, {
value: "VA",
label: "Holy See (Vatican City State)"
}, {
value: "HN",
label: "Honduras"
}, {
value: "HK",
label: "Hong Kong"
}, {
value: "HU",
label: "Hungary"
}, {
value: "IS",
label: "Iceland"
}, {
value: "IN",
label: "India"
}, {
value: "ID",
label: "Indonesia"
}, {
value: "IQ",
label: "Iraq"
}, {
value: "IE",
label: "Ireland"
}, {
value: "IR",
label: "Islamic Republic of Iran"
}, {
value: "IL",
label: "Israel"
}, {
value: "IT",
label: "Italy"
}, {
value: "JM",
label: "Jamaica"
}, {
value: "JP",
label: "Japan"
}, {
value: "JO",
label: "Jordan"
}, {
value: "KZ",
label: "Kazakhstan"
}, {
value: "KE",
label: "Kenya"
}, {
value: "KI",
label: "Kiribati"
}, {
value: "KP",
label: "Korea (Democratic People s Republic of)"
}, {
value: "KR",
label: "Korea (Republic of)"
}, {
value: "KW",
label: "Kuwait"
}, {
value: "KG",
label: "Kyrgzstan"
}, {
value: "LA",
label: "Lao People s Democratic Republic"
}, {
value: "LV",
label: "Latvia"
}, {
value: "LB",
label: "Lebanon"
}, {
value: "LS",
label: "Lesotho"
}, {
value: "LR",
label: "Liberia"
}, {
value: "LY",
label: "Libyan Arab Jamahiriya"
}, {
value: "LI",
label: "Liechtenstein"
}, {
value: "LT",
label: "Lithuania"
}, {
value: "LU",
label: "Luxembourg"
}, {
value: "MO",
label: "Macao"
}, {
value: "MK",
label: "Macedonia"
}, {
value: "MG",
label: "Madagascar"
}, {
value: "MW",
label: "Malawi"
}, {
value: "MY",
label: "Malaysia"
}, {
value: "MV",
label: "Maldives"
}, {
value: "ML",
label: "Mali"
}, {
value: "MT",
label: "Malta"
}, {
value: "MH",
label: "Marshall Islands"
}, {
value: "MQ",
label: "Martinique"
}, {
value: "MR",
label: "Mauritania"
}, {
value: "MU",
label: "Mauritius"
}, {
value: "YT",
label: "Mayotte"
}, {
value: "MX",
label: "Mexico"
}, {
value: "MD",
label: "Moldova"
}, {
value: "MC",
label: "Monaco"
}, {
value: "MN",
label: "Mongolia"
}, {
value: "MS",
label: "Montserrat"
}, {
value: "MA",
label: "Morocco"
}, {
value: "MZ",
label: "Mozambique"
}, {
value: "MM",
label: "Myanmar"
}, {
value: "NA",
label: "Namibia"
}, {
value: "NR",
label: "Nauru"
}, {
value: "NP",
label: "Nepal"
}, {
value: "NL",
label: "Netherlands"
}, {
value: "AN",
label: "Netherlands Antilles"
}, {
value: "NC",
label: "New Caledonia"
}, {
value: "NZ",
label: "New Zealand"
}, {
value: "NI",
label: "Nicaragua"
}, {
value: "NE",
label: "Niger"
}, {
value: "NG",
label: "Nigeria"
}, {
value: "NU",
label: "Niue"
}, {
value: "NF",
label: "Norfolk Island"
}, {
value: "NO",
label: "Norway"
}, {
value: "OM",
label: "Oman"
}, {
value: "PK",
label: "Pakistan"
}, {
value: "PW",
label: "Palau"
}, {
value: "PA",
label: "Panama"
}, {
value: "PG",
label: "Papua New Guinea"
}, {
value: "PY",
label: "Paraguay"
}, {
value: "PE",
label: "Peru"
}, {
value: "PH",
label: "Philippines"
}, {
value: "PN",
label: "Pitcairn"
}, {
value: "PL",
label: "Poland"
}, {
value: "PT",
label: "Portugal"
}, {
value: "QA",
label: "Qatar"
}, {
value: "RE",
label: "Reunion"
}, {
value: "RO",
label: "Romania"
}, {
value: "RU",
label: "Russian Federation"
}, {
value: "RW",
label: "Rwanda"
}, {
value: "SH",
label: "Saint Helena"
}, {
value: "KN",
label: "Saint Kitts and Nevis"
}, {
value: "LC",
label: "Saint Lucia"
}, {
value: "PM",
label: "Saint Pierre and Miquelon"
}, {
value: "VC",
label: "Saint Vincent and the Grenadines"
}, {
value: "WS",
label: "Samoa"
}, {
value: "SM",
label: "San Marino"
}, {
value: "ST",
label: "Sao Tome and Principe"
}, {
value: "SA",
label: "Saudi Arabia"
}, {
value: "SN",
label: "Senegal"
}, {
value: "RS",
label: "Serbia"
}, {
value: "SC",
label: "Seychelles"
}, {
value: "SL",
label: "Sierra Leone"
}, {
value: "SG",
label: "Singapore"
}, {
value: "SK",
label: "Slovakia"
}, {
value: "SI",
label: "Slovenia"
}, {
value: "SB",
label: "Solomon Islands"
}, {
value: "SO",
label: "Somalia"
}, {
value: "ZA",
label: "South Africa"
}, {
value: "GS",
label: "South Georgia and the South Sandwich Islands"
}, {
value: "ES",
label: "Spain"
}, {
value: "LK",
label: "Sri Lanka"
}, {
value: "SD",
label: "Sudan"
}, {
value: "SR",
label: "Suriname"
}, {
value: "SJ",
label: "Svalbard and Jan Mayen"
}, {
value: "SZ",
label: "Swaziland"
}, {
value: "SE",
label: "Sweden"
}, {
value: "CH",
label: "Switzerland"
}, {
value: "SY",
label: "Syrian Arab Republic"
}, {
value: "TW",
label: "Taiwan"
}, {
value: "TJ",
label: "Tajikstan"
}, {
value: "TZ",
label: "Tanzania United Republic"
}, {
value: "TH",
label: "Thailand"
}, {
value: "TG",
label: "Togo"
}, {
value: "TK",
label: "Tokelau"
}, {
value: "TO",
label: "Tonga"
}, {
value: "TT",
label: "Trinidad and Tobago"
}, {
value: "TN",
label: "Tunisia"
}, {
value: "TR",
label: "Turkey"
}, {
value: "TM",
label: "Turkmenistan"
}, {
value: "TC",
label: "Turks and Caicos Islands"
}, {
value: "TV",
label: "Tuvalu"
}, {
value: "UG",
label: "Uganda"
}, {
value: "UA",
label: "Ukraine"
}, {
value: "AE",
label: "United Arab Emirates"
}, {
value: "GB",
label: "United Kingdom"
}, {
value: "US",
label: "United States"
}, {
value: "UY",
label: "Uruguay"
}, {
value: "UZ",
label: "Uzbekistan"
}, {
value: "VU",
label: "Vanuatu"
}, {
value: "VE",
label: "Venezuela"
}, {
value: "VN",
label: "Vietnam"
}, {
value: "WF",
label: "Wallis and Futuna"
}, {
value: "EH",
label: "Western Sahara"
}, {
value: "YE",
label: "Yemen"
}, {
value: "ZM",
label: "Zambia"
}, {
value: "ZW",
label: "Zimbabwe"
}],
topList = [{
label: "United States",
value: "US"
}, {
label: "United Kingdom",
value: "GB"
}, {
label: "Switzerland",
value: "CH"
}, {
label: "France",
value: "FR"
}, {
label: "Germany",
value: "DE"
}, {
label: "Canada",
value: "CA"
}];
return function() {
var separator = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : DEFAULT_SEPARATOR;
return topList.concat([separator], list)
}
});
var _slicedToArray = function() {
function sliceIterator(arr, i) {
var _arr = [],
_n = !0,
_d = !1,
_e = void 0;
try {
for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0);
} catch (err) {
_d = !0, _e = err
} finally {
try {
!_n && _i.return && _i.return()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) return arr;
if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i);
throw new TypeError("Invalid attempt to destructure non-iterable instance")
}
}();
angular.module("proton.keys").factory("changeMailboxPassword", function($log, authentication, CONSTANTS, gettextCatalog, Key, networkActivityTracker, organizationApi, passwords, pmcw, User) {
function getUser() {
var newMailPwd = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
keySalt = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return Promise.all([passwords.computeKeyPassword(newMailPwd, keySalt), User.get()]).then(function(_ref) {
var _ref2 = _slicedToArray(_ref, 2),
password = _ref2[0],
_ref2$ = _ref2[1];
_ref2$ = void 0 === _ref2$ ? {} : _ref2$;
var _ref2$$data = _ref2$.data,
data = void 0 === _ref2$$data ? {} : _ref2$$data;
if (1e3 === data.Code) return Promise.resolve({
password: password,
user: data.User
});
throw new Error(data.Error || gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error"))
})
}
function manageOrganizationKeys() {
var password = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
oldMailPwd = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
return (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}).Role === CONSTANTS.PAID_ADMIN_ROLE ? organizationApi.getKeys().then(function() {
var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
_ref3$data = _ref3.data,
data = void 0 === _ref3$data ? {} : _ref3$data;
if (1e3 === data.Code) {
var encryptPrivateKey = data.PrivateKey;
return pmcw.decryptPrivateKey(encryptPrivateKey, oldMailPwd).then(function(pkg) {
return Promise.resolve(pmcw.encryptPrivateKey(pkg, password))
}, function() {
return Promise.resolve(0)
})
}
throw new Error(data.Error || gettextCatalog.getString("Unable to get organization keys", null, "Error"))
}) : Promise.resolve(0)
}
function manageUserKeys() {
var password = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
oldMailPwd = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "",
user = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
inputKeys = [];
user.Keys.forEach(function(key) {
return inputKeys.push(key)
}), user.Addresses.forEach(function(address) {
address.Keys.forEach(function(key) {
return inputKeys.push(key)
})
});
var promises = [];
if (user.OrganizationPrivateKey) {
var organizationKey = pmcw.decryptPrivateKey(user.OrganizationPrivateKey, oldMailPwd);
promises = inputKeys.map(function(_ref4) {
var PrivateKey = _ref4.PrivateKey,
ID = _ref4.ID,
Token = _ref4.Token;
return organizationKey.then(function(key) {
return pmcw.decryptMessage({
message: pmcw.getMessage(Token),
privateKey: key
})
}).then(function(_ref5) {
var data = _ref5.data;
return pmcw.decryptPrivateKey(PrivateKey, data)
}).then(function(pkg) {
return {
ID: ID,
pkg: pkg
}
})
})
} else promises = inputKeys.map(function(_ref6) {
var PrivateKey = _ref6.PrivateKey,
ID = _ref6.ID;
return pmcw.decryptPrivateKey(PrivateKey, oldMailPwd).then(function(pkg) {
return {
ID: ID,
pkg: pkg
}
})
});
return promises.map(function(promise) {
return promise.then(function(_ref7) {
var ID = _ref7.ID,
pkg = _ref7.pkg;
return pmcw.encryptPrivateKey(pkg, password).then(function(PrivateKey) {
return {
ID: ID,
PrivateKey: PrivateKey
}
})
}, function(error) {
return $log.error(error), 0
})
})
}
function sendNewKeys(_ref8) {
var _ref8$keys = _ref8.keys,
keys = void 0 === _ref8$keys ? [] : _ref8$keys,
_ref8$keySalt = _ref8.keySalt,
keySalt = void 0 === _ref8$keySalt ? "" : _ref8$keySalt,
_ref8$organizationKey = _ref8.organizationKey,
organizationKey = void 0 === _ref8$organizationKey ? 0 : _ref8$organizationKey,
_ref8$newLoginPasswor = _ref8.newLoginPassword,
newLoginPassword = void 0 === _ref8$newLoginPasswor ? "" : _ref8$newLoginPasswor,
keysFiltered = keys.filter(function(key) {
return 0 !== key
}),
payload = {
KeySalt: keySalt,
Keys: keysFiltered
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment