import require password

This commit is contained in:
Mo Bitar
2017-01-08 14:15:33 -06:00
parent 93e3a72d30
commit ca3eff7f15
8 changed files with 166 additions and 43 deletions

View File

@@ -193,19 +193,39 @@ angular.module('app.frontend')
link.click(); link.click();
} }
this.performImport = function(data, password) {
apiController.importJSONData(data, password, function(success, response){
console.log("import response", success, response);
if(success) {
this.importData = null;
} else {
alert("There was an error importing your data. Please try again.");
}
}.bind(this))
}
this.submitImportPassword = function() {
this.performImport(this.importData.data, this.importData.password);
}
this.importFileSelected = function(files) { this.importFileSelected = function(files) {
this.importData = {};
var file = files[0]; var file = files[0];
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function(e) { reader.onload = function(e) {
apiController.importJSONData(e.target.result, function(success, response){ var data = JSON.parse(e.target.result);
console.log("import response", success, response); $timeout(function(){
if(success) { if(data.auth_params) {
// window.location.reload(); // request password
this.importData.requestPassword = true;
this.importData.data = data;
} else { } else {
alert("There was an error importing your data. Please try again."); this.performImport(data, null);
} }
}) }.bind(this))
} }.bind(this)
reader.readAsText(file); reader.readAsText(file);
} }

View File

@@ -56,6 +56,10 @@ angular.module('app.frontend')
Auth Auth
*/ */
this.getAuthParams = function() {
return JSON.parse(localStorage.getItem("auth_params"));
}
this.isUserSignedIn = function() { this.isUserSignedIn = function() {
return localStorage.getItem("jwt"); return localStorage.getItem("jwt");
} }
@@ -97,7 +101,7 @@ angular.module('app.frontend')
callback(null); callback(null);
return; return;
} }
Neeto.crypto.computeEncryptionKeysForUser(_.merge({email: email, password: password}, authParams), function(keys){ Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, authParams), function(keys){
this.setMk(keys.mk); this.setMk(keys.mk);
var request = Restangular.one("auth/sign_in"); var request = Restangular.one("auth/sign_in");
var params = {password: keys.pw, email: email}; var params = {password: keys.pw, email: email};
@@ -105,6 +109,7 @@ angular.module('app.frontend')
request.post().then(function(response){ request.post().then(function(response){
localStorage.setItem("jwt", response.token); localStorage.setItem("jwt", response.token);
localStorage.setItem("uuid", response.uuid); localStorage.setItem("uuid", response.uuid);
localStorage.setItem("auth_params", JSON.stringify(authParams));
callback(response); callback(response);
}) })
.catch(function(response){ .catch(function(response){
@@ -124,6 +129,7 @@ angular.module('app.frontend')
request.post().then(function(response){ request.post().then(function(response){
localStorage.setItem("jwt", response.token); localStorage.setItem("jwt", response.token);
localStorage.setItem("uuid", response.uuid); localStorage.setItem("uuid", response.uuid);
localStorage.setItem("auth_params", JSON.stringify(authParams));
callback(response); callback(response);
}) })
.catch(function(response){ .catch(function(response){
@@ -352,15 +358,34 @@ angular.module('app.frontend')
Import Import
*/ */
this.importJSONData = function(jsonString, callback) { this.importJSONData = function(data, password, callback) {
var data = JSON.parse(jsonString); console.log("Importing data", data);
console.log("importing data", data);
this.decryptItems(data.items); var onDataReady = function() {
modelManager.mapResponseItemsToLocalModels(data.items); modelManager.mapResponseItemsToLocalModels(data.items);
modelManager.allItems.forEach(function(item){ modelManager.allItems.forEach(function(item){
item.setDirty(true); item.setDirty(true);
}) })
this.syncWithOptions(callback, {additionalFields: ["created_at", "updated_at"]}); this.syncWithOptions(callback, {additionalFields: ["created_at", "updated_at"]});
}.bind(this)
if(data.auth_params) {
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, data.auth_params), function(keys){
var mk = keys.mk;
try {
this.decryptItemsWithKey(data.items, mk);
onDataReady();
}
catch (e) {
console.log("Error decrypting", e);
alert("There was an error decrypting your items. Make sure the password you entered is correct and try again.");
callback(false, null);
return;
}
}.bind(this));
} else {
onDataReady();
}
} }
/* /*
@@ -392,6 +417,10 @@ angular.module('app.frontend')
items: items items: items
} }
if(encrypted) {
data["auth_params"] = this.getAuthParams();
}
return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */)); return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));
} }
@@ -530,6 +559,10 @@ angular.module('app.frontend')
this.decryptItems = function(items) { this.decryptItems = function(items) {
var masterKey = this.retrieveMk(); var masterKey = this.retrieveMk();
this.decryptItemsWithKey(items, masterKey);
}
this.decryptItemsWithKey = function(items, key) {
for (var item of items) { for (var item of items) {
if(item.deleted == true) { if(item.deleted == true) {
continue; continue;
@@ -538,7 +571,7 @@ angular.module('app.frontend')
if(isString) { if(isString) {
if(item.content.substring(0, 3) == "001" && item.enc_item_key) { if(item.content.substring(0, 3) == "001" && item.enc_item_key) {
// is encrypted // is encrypted
this.decryptSingleItem(item, masterKey); this.decryptSingleItem(item, key);
} else { } else {
// is base64 encoded // is base64 encoded
item.content = Neeto.crypto.base64Decode(item.content.substring(3, item.content.length)) item.content = Neeto.crypto.base64Decode(item.content.substring(3, item.content.length))

View File

@@ -255,6 +255,9 @@ class ExtensionManager {
performPost(action, extension, params, callback) { performPost(action, extension, params, callback) {
var request = this.Restangular.oneUrl(action.url, action.url); var request = this.Restangular.oneUrl(action.url, action.url);
if(this.extensionUsesEncryptedData(extension)) {
request.auth_params = this.apiController.getAuthParams();
}
_.merge(request, params); _.merge(request, params);
request.post().then(function(response){ request.post().then(function(response){

View File

@@ -80,7 +80,7 @@ class SNCrypto {
return CryptoJS.HmacSHA256(messageData, keyData).toString(); return CryptoJS.HmacSHA256(messageData, keyData).toString();
} }
computeEncryptionKeysForUser({email, password, pw_salt, pw_func, pw_alg, pw_cost, pw_key_size} = {}, callback) { computeEncryptionKeysForUser({password, pw_salt, pw_func, pw_alg, pw_cost, pw_key_size} = {}, callback) {
this.generateSymmetricKeyPair({password: password, pw_salt: pw_salt, this.generateSymmetricKeyPair({password: password, pw_salt: pw_salt,
pw_func: pw_func, pw_alg: pw_alg, pw_cost: pw_cost, pw_key_size: pw_key_size}, function(keys){ pw_func: pw_func, pw_alg: pw_alg, pw_cost: pw_cost, pw_key_size: pw_key_size}, function(keys){
var pw = keys[0]; var pw = keys[0];
@@ -99,7 +99,7 @@ class SNCrypto {
var pw = keys[0]; var pw = keys[0];
var mk = keys[1]; var mk = keys[1];
callback(_.merge({pw: pw, mk: mk, pw_nonce: pw_nonce}, defaults)); callback({pw: pw, mk: mk, pw_nonce: pw_nonce}, defaults);
}); });
} }
} }

View File

@@ -129,7 +129,7 @@
margin-bottom: 8px; margin-bottom: 8px;
a { a {
font-size: 12px; font-size: 12px;
color: #00228f; color: $blue-color;
font-weight: bold; font-weight: bold;
} }
} }
@@ -152,7 +152,7 @@
margin-bottom: 34px; margin-bottom: 34px;
a { a {
color: #00228f; color: $blue-color;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
} }
@@ -186,6 +186,15 @@
} }
} }
.import-password {
margin-top: 14px;
> .field {
display: block;
margin: 5px 0px;
}
}
.encryption-confirmation { .encryption-confirmation {
position: relative; position: relative;
.buttons { .buttons {

View File

@@ -90,6 +90,10 @@
%a.disabled %a.disabled
%span %span
Import Data from Archive Import Data from Archive
.import-password{"ng-if" => "ctrl.importData.requestPassword"}
Enter the account password associated with the import file.
%input.field{"type" => "text", "ng-model" => "ctrl.importData.password"}
%button{"ng-click" => "ctrl.submitImportPassword()"} Decrypt & Import
.item .item
%a{"ng-click" => "ctrl.toggleExtensions()"} Extensions %a{"ng-click" => "ctrl.toggleExtensions()"} Extensions

View File

@@ -118,7 +118,6 @@ var SNCrypto = function () {
key: 'computeEncryptionKeysForUser', key: 'computeEncryptionKeysForUser',
value: function computeEncryptionKeysForUser() { value: function computeEncryptionKeysForUser() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
email = _ref.email,
password = _ref.password, password = _ref.password,
pw_salt = _ref.pw_salt, pw_salt = _ref.pw_salt,
pw_func = _ref.pw_func, pw_func = _ref.pw_func,
@@ -157,7 +156,7 @@ var SNCrypto = function () {
var pw = keys[0]; var pw = keys[0];
var mk = keys[1]; var mk = keys[1];
callback(_.merge({ pw: pw, mk: mk, pw_nonce: pw_nonce }, defaults)); callback({ pw: pw, mk: mk, pw_nonce: pw_nonce }, defaults);
}); });
} }
}]); }]);
@@ -903,19 +902,39 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
link.click(); link.click();
}; };
this.performImport = function (data, password) {
apiController.importJSONData(data, password, function (success, response) {
console.log("import response", success, response);
if (success) {
this.importData = null;
} else {
alert("There was an error importing your data. Please try again.");
}
}.bind(this));
};
this.submitImportPassword = function () {
this.performImport(this.importData.data, this.importData.password);
};
this.importFileSelected = function (files) { this.importFileSelected = function (files) {
this.importData = {};
var file = files[0]; var file = files[0];
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function (e) { reader.onload = function (e) {
apiController.importJSONData(e.target.result, function (success, response) { var data = JSON.parse(e.target.result);
console.log("import response", success, response); $timeout(function () {
if (success) { if (data.auth_params) {
// window.location.reload(); // request password
this.importData.requestPassword = true;
this.importData.data = data;
} else { } else {
alert("There was an error importing your data. Please try again."); this.performImport(data, null);
} }
}); }.bind(this));
}; }.bind(this);
reader.readAsText(file); reader.readAsText(file);
}; };
@@ -1926,6 +1945,10 @@ var Tag = function (_Item3) {
Auth Auth
*/ */
this.getAuthParams = function () {
return JSON.parse(localStorage.getItem("auth_params"));
};
this.isUserSignedIn = function () { this.isUserSignedIn = function () {
return localStorage.getItem("jwt"); return localStorage.getItem("jwt");
}; };
@@ -1965,7 +1988,7 @@ var Tag = function (_Item3) {
callback(null); callback(null);
return; return;
} }
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ email: email, password: password }, authParams), function (keys) { Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: password }, authParams), function (keys) {
this.setMk(keys.mk); this.setMk(keys.mk);
var request = Restangular.one("auth/sign_in"); var request = Restangular.one("auth/sign_in");
var params = { password: keys.pw, email: email }; var params = { password: keys.pw, email: email };
@@ -1973,6 +1996,7 @@ var Tag = function (_Item3) {
request.post().then(function (response) { request.post().then(function (response) {
localStorage.setItem("jwt", response.token); localStorage.setItem("jwt", response.token);
localStorage.setItem("uuid", response.uuid); localStorage.setItem("uuid", response.uuid);
localStorage.setItem("auth_params", JSON.stringify(authParams));
callback(response); callback(response);
}).catch(function (response) { }).catch(function (response) {
callback(response.data); callback(response.data);
@@ -1991,6 +2015,7 @@ var Tag = function (_Item3) {
request.post().then(function (response) { request.post().then(function (response) {
localStorage.setItem("jwt", response.token); localStorage.setItem("jwt", response.token);
localStorage.setItem("uuid", response.uuid); localStorage.setItem("uuid", response.uuid);
localStorage.setItem("auth_params", JSON.stringify(authParams));
callback(response); callback(response);
}).catch(function (response) { }).catch(function (response) {
callback(response.data); callback(response.data);
@@ -2216,15 +2241,33 @@ var Tag = function (_Item3) {
Import Import
*/ */
this.importJSONData = function (jsonString, callback) { this.importJSONData = function (data, password, callback) {
var data = JSON.parse(jsonString); console.log("Importing data", data);
console.log("importing data", data);
this.decryptItems(data.items); var onDataReady = function () {
modelManager.mapResponseItemsToLocalModels(data.items); modelManager.mapResponseItemsToLocalModels(data.items);
modelManager.allItems.forEach(function (item) { modelManager.allItems.forEach(function (item) {
item.setDirty(true); item.setDirty(true);
}); });
this.syncWithOptions(callback, { additionalFields: ["created_at", "updated_at"] }); this.syncWithOptions(callback, { additionalFields: ["created_at", "updated_at"] });
}.bind(this);
if (data.auth_params) {
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: password }, data.auth_params), function (keys) {
var mk = keys.mk;
try {
this.decryptItemsWithKey(data.items, mk);
onDataReady();
} catch (e) {
console.log("Error decrypting", e);
alert("There was an error decrypting your items. Make sure the password you entered is correct and try again.");
callback(false, null);
return;
}
}.bind(this));
} else {
onDataReady();
}
}; };
/* /*
@@ -2256,6 +2299,10 @@ var Tag = function (_Item3) {
items: items items: items
}; };
if (encrypted) {
data["auth_params"] = this.getAuthParams();
}
return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */)); return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));
}; };
@@ -2389,6 +2436,10 @@ var Tag = function (_Item3) {
this.decryptItems = function (items) { this.decryptItems = function (items) {
var masterKey = this.retrieveMk(); var masterKey = this.retrieveMk();
this.decryptItemsWithKey(items, masterKey);
};
this.decryptItemsWithKey = function (items, key) {
var _iteratorNormalCompletion4 = true; var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false; var _didIteratorError4 = false;
var _iteratorError4 = undefined; var _iteratorError4 = undefined;
@@ -2404,7 +2455,7 @@ var Tag = function (_Item3) {
if (isString) { if (isString) {
if (item.content.substring(0, 3) == "001" && item.enc_item_key) { if (item.content.substring(0, 3) == "001" && item.enc_item_key) {
// is encrypted // is encrypted
this.decryptSingleItem(item, masterKey); this.decryptSingleItem(item, key);
} else { } else {
// is base64 encoded // is base64 encoded
item.content = Neeto.crypto.base64Decode(item.content.substring(3, item.content.length)); item.content = Neeto.crypto.base64Decode(item.content.substring(3, item.content.length));
@@ -3218,6 +3269,9 @@ var ExtensionManager = function () {
key: 'performPost', key: 'performPost',
value: function performPost(action, extension, params, callback) { value: function performPost(action, extension, params, callback) {
var request = this.Restangular.oneUrl(action.url, action.url); var request = this.Restangular.oneUrl(action.url, action.url);
if (this.extensionUsesEncryptedData(extension)) {
request.auth_params = this.apiController.getAuthParams();
}
_.merge(request, params); _.merge(request, params);
request.post().then(function (response) { request.post().then(function (response) {

File diff suppressed because one or more lines are too long