encryption updates

This commit is contained in:
Mo Bitar
2016-12-12 20:00:21 -06:00
parent 8ad3776819
commit d200df0b85
12 changed files with 136 additions and 144 deletions

View File

@@ -235,11 +235,13 @@ angular.module('app.frontend')
this.saveUrl = function($event) { this.saveUrl = function($event) {
$event.target.blur(); $event.target.blur();
var original = this.note.presentation.root_path;
this.note.presentation.root_path = this.url.token; var original = this.note.presentation.relative_path;
apiController.saveNote(this.user, this.note, function(note){ this.note.presentation.relative_path = this.url.token;
if(!note) {
this.note.token = original; apiController.updatePresentation(this.note, this.note.presentation, function(response){
if(!response) {
this.note.presentation.relative_path = original;
this.url.token = original; this.url.token = original;
alert("This URL is not available."); alert("This URL is not available.");
} else { } else {

View File

@@ -53,7 +53,7 @@ angular.module('app.frontend')
return; return;
} }
this.newGroup = {notes : []}; this.newGroup = new Group({notes : []});
if(!this.user.id) { if(!this.user.id) {
this.newGroup.id = Neeto.crypto.generateRandomKey() this.newGroup.id = Neeto.crypto.generateRandomKey()
} }
@@ -92,7 +92,7 @@ angular.module('app.frontend')
} }
this.noteCount = function(group) { this.noteCount = function(group) {
var validNotes = apiController.filterDummyNotes(group.notes); var validNotes = Note.filterDummyNotes(group.notes);
return validNotes.length; return validNotes.length;
} }

View File

@@ -13,17 +13,7 @@ angular.module('app.frontend')
bindToController: true, bindToController: true,
link:function(scope, elem, attrs, ctrl) { link:function(scope, elem, attrs, ctrl) {
// scope.$on('auth:login-success', function(event, user) {
// ctrl.onAuthSuccess(user);
// });
scope.$on('auth:validation-success', function(ev) {
// TODO
setTimeout(function(){
ctrl.onValidationSuccess();
})
});
} }
} }
}) })
@@ -118,17 +108,11 @@ angular.module('app.frontend')
}.bind(this)); }.bind(this));
} }
this.onValidationSuccess = function() {
apiController.verifyEncryptionStatusOfAllNotes(this.user, function(success){
});
}
this.encryptionStatusForNotes = function() { this.encryptionStatusForNotes = function() {
var allNotes = this.user.filteredNotes(); var allNotes = this.user.filteredNotes();
var countEncrypted = 0; var countEncrypted = 0;
allNotes.forEach(function(note){ allNotes.forEach(function(note){
if(note.isEncrypted()) { if(note.encryptionEnabled()) {
countEncrypted++; countEncrypted++;
} }
}.bind(this)) }.bind(this))

View File

@@ -6,21 +6,12 @@ angular.module('app.frontend')
var onUserSet = function() { var onUserSet = function() {
$scope.defaultUser.notes = _.map($scope.defaultUser.notes, function(json_obj) { $scope.allGroup = new Group({name: "All", all: true});
return new Note(json_obj); $scope.groups = $scope.defaultUser.groups;
});
$scope.defaultUser.filteredNotes = function() { apiController.verifyEncryptionStatusOfAllNotes($scope.defaultUser, function(success){
return apiController.filterDummyNotes($scope.defaultUser.notes);
} });
var groups = $scope.defaultUser.groups;
var allNotes = $scope.defaultUser.notes;
groups.forEach(function(group){
var notes = allNotes.filter(function(note){return note.group_id && note.group_id == group.id});
group.notes = notes;
})
$scope.allGroup = {name: "All", all: true};
$scope.groups = groups;
} }
apiController.getCurrentUser(function(response){ apiController.getCurrentUser(function(response){
@@ -39,7 +30,7 @@ angular.module('app.frontend')
*/ */
$scope.updateAllGroup = function() { $scope.updateAllGroup = function() {
var allNotes = apiController.filterDummyNotes($scope.defaultUser.notes); var allNotes = Note.filterDummyNotes($scope.defaultUser.notes);
$scope.defaultUser.notes = allNotes; $scope.defaultUser.notes = allNotes;
$scope.allGroup.notes = allNotes; $scope.allGroup.notes = allNotes;
} }
@@ -78,6 +69,8 @@ angular.module('app.frontend')
originalNote.group_id = null; originalNote.group_id = null;
} else { } else {
originalNote.group_id = newGroup.id originalNote.group_id = newGroup.id
originalNote.group = newGroup;
newGroup.notes.unshift(originalNote); newGroup.notes.unshift(originalNote);
newGroup.notes.sort(function(a,b){ newGroup.notes.sort(function(a,b){
//subtract to get a value that is either negative, positive, or zero. //subtract to get a value that is either negative, positive, or zero.
@@ -85,8 +78,6 @@ angular.module('app.frontend')
}); });
} }
originalNote.shared_via_group = newGroup.presentation && newGroup.presentation.enabled;
apiController.saveNote($scope.defaultUser, originalNote, function(note){ apiController.saveNote($scope.defaultUser, originalNote, function(note){
_.merge(originalNote, note); _.merge(originalNote, note);
}); });
@@ -97,7 +88,7 @@ angular.module('app.frontend')
*/ */
$scope.notesRemoveGroup = function(group) { $scope.notesRemoveGroup = function(group) {
var validNotes = apiController.filterDummyNotes(group.notes); var validNotes = Note.filterDummyNotes(group.notes);
if(validNotes == 0) { if(validNotes == 0) {
// if no more notes, delete group // if no more notes, delete group
apiController.deleteGroup($scope.defaultUser, group, function(){ apiController.deleteGroup($scope.defaultUser, group, function(){

View File

@@ -138,7 +138,7 @@ angular.module('app.frontend')
var title = "New Note" + (this.notes ? (" " + (this.notes.length + 1)) : ""); var title = "New Note" + (this.notes ? (" " + (this.notes.length + 1)) : "");
this.newNote = new Note({dummy: true}); this.newNote = new Note({dummy: true});
this.newNote.content.title = title; this.newNote.content.title = title;
this.newNote.shared_via_group = this.group.presentation && this.group.presentation.enabled; this.newNote.group = this.group;
this.selectNote(this.newNote); this.selectNote(this.newNote);
this.addNew()(this.newNote); this.addNew()(this.newNote);
} }

View File

@@ -0,0 +1,3 @@
var Group = function (json_obj) {
_.merge(this, json_obj);
};

View File

@@ -23,6 +23,10 @@ var Note = function (json_obj) {
enumerable: true, enumerable: true,
}); });
this.setContentRaw = function(rawContent) {
content = rawContent;
}
_.merge(this, json_obj); _.merge(this, json_obj);
if(!this.content) { if(!this.content) {
@@ -30,17 +34,22 @@ var Note = function (json_obj) {
} }
}; };
Note.filterDummyNotes = function(notes) {
var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});
return filtered;
}
/* Returns true if note is shared individually or via group */ /* Returns true if note is shared individually or via group */
Note.prototype.isPublic = function() { Note.prototype.isPublic = function() {
return this.hasEnabledPresentation() || this.shared_via_group; return this.presentation || (this.group && this.group.presentation);
}; };
Note.prototype.isEncrypted = function() { Note.prototype.isEncrypted = function() {
return (this.loc_eek || this.local_eek) && typeof this.content === 'string' ? true : false; return this.encryptionEnabled() && typeof this.content === 'string' ? true : false;
} }
Note.prototype.hasEnabledPresentation = function() { Note.prototype.encryptionEnabled = function() {
return this.presentation && this.presentation.enabled; return this.loc_eek;
} }
Note.prototype.presentationURL = function() { Note.prototype.presentationURL = function() {

View File

@@ -1,3 +1,23 @@
var User = function (json_obj) { var User = function (json_obj) {
_.merge(this, json_obj); _.merge(this, json_obj);
this.notes = _.map(this.notes, function(json_obj) {
return new Note(json_obj);
});
this.groups = _.map(this.groups, function(json_obj) {
return new Group(json_obj);
});
this.groups.forEach(function(group){
var notes = this.notes.filter(function(note){return note.group_id && note.group_id == group.id});
notes.forEach(function(note){
note.group = group;
})
group.notes = notes;
}.bind(this))
}; };
User.prototype.filteredNotes = function() {
return Note.filterDummyNotes(this.notes);
}

View File

@@ -147,25 +147,21 @@ angular.module('app.services')
this.verifyEncryptionStatusOfAllNotes = function(user, callback) { this.verifyEncryptionStatusOfAllNotes = function(user, callback) {
var allNotes = user.filteredNotes(); var allNotes = user.filteredNotes();
var notesNeedingUpdate = []; var notesNeedingUpdate = [];
var key = this.retrieveGk();
allNotes.forEach(function(note){ allNotes.forEach(function(note){
if(!note.isPublic()) { if(!note.isPublic()) {
if(!note.isEncrypted()) { if(note.encryptionEnabled() && !note.isEncrypted()) {
// needs encryption
this.encryptSingleNote(note, key);
notesNeedingUpdate.push(note); notesNeedingUpdate.push(note);
} }
} else { } else {
if(note.isEncrypted()) { if(note.isEncrypted()) {
// needs decrypting
this.decryptSingleNote(note, key);
notesNeedingUpdate.push(note); notesNeedingUpdate.push(note);
} }
} }
}.bind(this)) }.bind(this))
if(notesNeedingUpdate.length > 0) { if(notesNeedingUpdate.length > 0) {
this.saveBatchNotes(user, notesNeedingUpdate, true, callback) console.log("verifying encryption, notes need updating", notesNeedingUpdate);
this.saveBatchNotes(user, notesNeedingUpdate, callback)
} }
} }
@@ -210,41 +206,31 @@ angular.module('app.services')
} }
this.shareGroup = function(user, group, callback) { this.shareGroup = function(user, group, callback) {
var shareFn = function() {
Restangular.one("users", user.id).one("groups", group.id).one("presentations").post() Restangular.one("users", user.id).one("groups", group.id).one("presentations").post()
.then(function(response){ .then(function(response){
var presentation = response.plain(); var presentation = response.plain();
group.notes.forEach(function(note){
note.shared_via_group = true;
});
_.merge(group, {presentation: presentation}); _.merge(group, {presentation: presentation});
callback(presentation); callback(presentation);
})
}
if(group.notes.length > 0) { if(group.notes.length > 0) {
// decrypt group notes first // decrypt notes
var notes = group.notes; this.saveBatchNotes(user, group.notes, function(success){})
notes.forEach(function(note){ }
note.shared_via_group = true; }.bind(this))
})
this.decryptNotesWithLocalKey(notes);
this.saveBatchNotes(user, notes, false, function(success){
shareFn();
})
} else {
shareFn();
}
} }
this.unshareGroup = function(user, group, callback) { this.unshareGroup = function(user, group, callback) {
var request = Restangular.one("users", user.id).one("groups", group.id).one("presentations", group.presentation.id); var request = Restangular.one("users", user.id).one("groups", group.id).one("presentations", group.presentation.id);
request.enabled = false; request.remove().then(function(response){
request.patch().then(function(response){ group.presentation = null;
var presentation = response.plain(); callback(null);
_.merge(group, {presentation: presentation});
callback(presentation); if(group.notes.length > 0) {
}) // encrypt notes
var notes = group.notes;
this.saveBatchNotes(user, notes, function(success){})
}
}.bind(this))
} }
@@ -255,7 +241,7 @@ angular.module('app.services')
Notes Notes
*/ */
this.saveBatchNotes = function(user, notes, encryptionEnabled, callback) { this.saveBatchNotes = function(user, notes, callback) {
var request = Restangular.one("users", user.id).one("notes/batch_update"); var request = Restangular.one("users", user.id).one("notes/batch_update");
request.notes = _.map(notes, function(note){ request.notes = _.map(notes, function(note){
return this.createRequestParamsFromNote(note, user); return this.createRequestParamsFromNote(note, user);
@@ -302,6 +288,7 @@ angular.module('app.services')
else { else {
// decrypted // decrypted
params.content = JSON.stringify(note.content); params.content = JSON.stringify(note.content);
params.loc_eek = null;
} }
return params; return params;
} }
@@ -351,15 +338,29 @@ angular.module('app.services')
this.unshareNote = function(user, note, callback) { this.unshareNote = function(user, note, callback) {
var request = Restangular.one("users", user.id).one("notes", note.id).one("presentations", note.presentation.id); var request = Restangular.one("users", user.id).one("notes", note.id).one("presentations", note.presentation.id);
request.enabled = false; request.remove().then(function(response){
request.patch().then(function(response){ note.presentation = null;
var presentation = response.plain(); callback(null);
_.merge(note, {presentation: presentation});
callback(note);
}) })
} }
/*
Presentations
*/
this.updatePresentation = function(resource, presentation, callback) {
var request = Restangular.one("users", user.id)
.one(resource.constructor.name.toLowerCase() + "s", resource.id)
.one("presentations", resource.presentation.id);
_.merge(request, presentation);
request.patch().then(function(response){
callback(response.plain());
})
.catch(function(error){
callback(nil);
})
}
/* /*
@@ -368,32 +369,26 @@ angular.module('app.services')
this.importJSONData = function(jsonString, callback) { this.importJSONData = function(jsonString, callback) {
var data = JSON.parse(jsonString); var data = JSON.parse(jsonString);
var user = new User(data);
console.log("importing data", JSON.parse(jsonString)); console.log("importing data", JSON.parse(jsonString));
// data.notes = _.map(data.notes, function(json_obj) { user.notes.forEach(function(note) {
// return new Note(json_obj); if(note.isPublic()) {
// }); note.setContentRaw(JSON.stringify(note.content));
console.log("objectifying data", this.staticifyObject(data));
data.notes.forEach(function(note){
var presentation = data.presentations.find(function(presentation){
return presentation.presentable_type == "Note" && presentation.presentable_id == note.id;
})
if(presentation) {
// public
// console.log("public note", note);
note.content = JSON.stringify(note.content);
// console.log("after json", note);
} else { } else {
// private
this.encryptSingleNoteWithLocalKey(note); this.encryptSingleNoteWithLocalKey(note);
} }
// prevent circular links
note.group = null;
}.bind(this)) }.bind(this))
user.groups.forEach(function(group){
// prevent circular links
group.notes = null;
})
var request = Restangular.one("import"); var request = Restangular.one("import");
request.data = data; request.data = {notes: user.notes, groups: user.groups};
console.log("posting import request", request);
request.post().then(function(response){ request.post().then(function(response){
callback(true, response); callback(true, response);
}) })
@@ -423,9 +418,24 @@ angular.module('app.services')
return textFile; return textFile;
}.bind(this); }.bind(this);
var presentationParams = function(presentation) {
if(!presentation) {
return null;
}
return {
id: presentation.id,
uuid: presentation.uuid,
root_path: presentation.root_path,
relative_path: presentation.relative_path,
presentable_type: presentation.presentable_type,
presentable_id: presentation.presentable_id,
created_at: presentation.created_at,
modified_at: presentation.modified_at,
}
}
var notes = _.map(user.filteredNotes(), function(note){ var notes = _.map(user.filteredNotes(), function(note){
console.log("mapping note", note);
return { return {
id: note.id, id: note.id,
uuid: note.uuid, uuid: note.uuid,
@@ -433,6 +443,7 @@ angular.module('app.services')
group_id: note.group_id, group_id: note.group_id,
created_at: note.created_at, created_at: note.created_at,
modified_at: note.modified_at, modified_at: note.modified_at,
presentation: presentationParams(note.presentation)
} }
}); });
@@ -443,36 +454,13 @@ angular.module('app.services')
name: group.name, name: group.name,
created_at: group.created_at, created_at: group.created_at,
modified_at: group.modified_at, modified_at: group.modified_at,
} presentation: presentationParams(group.presentation)
});
var modelsWithPresentations = user.groups.concat(user.notes).filter(function(model){
return model.presentation != null;
})
var presentations = _.map(modelsWithPresentations, function(model){
return model.presentation;
})
presentations = _.map(presentations, function(presentation){
return {
id: presentation.id,
uuid: presentation.uuid,
host: presentation.host,
root_path: presentation.root_path,
relative_path: presentation.relative_path,
presentable_type: presentation.presentable_type,
presentable_id: presentation.presentable_id,
enabled: presentation.enabled,
created_at: presentation.created_at,
modified_at: presentation.modified_at,
} }
}); });
var data = { var data = {
notes: notes, notes: notes,
groups: groups, groups: groups
presentations: presentations
} }
return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */)); return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));
@@ -505,18 +493,13 @@ angular.module('app.services')
this.filterDummyNotes = function(notes) {
var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});
return filtered;
}
this.staticifyObject = function(object) { this.staticifyObject = function(object) {
return JSON.parse(JSON.stringify(object)); return JSON.parse(JSON.stringify(object));
} }
this.writeUserToLocalStorage = function(user) { this.writeUserToLocalStorage = function(user) {
var saveUser = _.cloneDeep(user); var saveUser = _.cloneDeep(user);
saveUser.notes = this.filterDummyNotes(saveUser.notes); saveUser.notes = Note.filterDummyNotes(saveUser.notes);
saveUser.groups.forEach(function(group){ saveUser.groups.forEach(function(group){
group.notes = null; group.notes = null;
}.bind(this)) }.bind(this))
@@ -645,7 +628,7 @@ angular.module('app.services')
} }
}); });
this.saveBatchNotes(user, notes, true, function(success) { this.saveBatchNotes(user, notes, function(success) {
callback(success); callback(success);
}.bind(this)); }.bind(this));
} }

View File

@@ -26,11 +26,11 @@
%li %li
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleMarkdown()"} Toggle Markdown Preview %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleMarkdown()"} Toggle Markdown Preview
.shortcut Cmd + M .shortcut Cmd + M
%li{"ng-if" => "!ctrl.note.hasEnabledPresentation()"} %li{"ng-if" => "!ctrl.note.presentation"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.shareNote()"} Share %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.shareNote()"} Share
%li{"ng-if" => "ctrl.note.hasEnabledPresentation()"} %li{"ng-if" => "ctrl.note.presentation"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.editUrlPressed()"} Edit URL %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.editUrlPressed()"} Edit URL
%li{"ng-if" => "ctrl.note.hasEnabledPresentation()"} %li{"ng-if" => "ctrl.note.presentation"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.unshareNote()"} Unshare %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.unshareNote()"} Unshare
%li %li
%a.text{"ng-click" => "ctrl.deleteNote()"} Delete %a.text{"ng-click" => "ctrl.deleteNote()"} Delete
@@ -40,7 +40,7 @@
.panel-body{"style" => "text-align: center; color: black;"} .panel-body{"style" => "text-align: center; color: black;"}
This editor is Markdown enabled. This editor is Markdown enabled.
.menu-right-container .menu-right-container
.public-link{"ng-if" => "ctrl.note.hasEnabledPresentation()"} .public-link{"ng-if" => "ctrl.note.presentation"}
%a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForNote(ctrl.note)}}", "target" => "_blank"} %a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForNote(ctrl.note)}}", "target" => "_blank"}
%span.icon-rss.icon %span.icon-rss.icon
{{ctrl.publicUrlForNote(note)}} {{ctrl.publicUrlForNote(note)}}

View File

@@ -9,7 +9,7 @@
.count {{ctrl.noteCount(ctrl.allGroup)}} .count {{ctrl.noteCount(ctrl.allGroup)}}
.group{"ng-repeat" => "group in ctrl.groups", "ng-click" => "ctrl.selectGroup(group)", "ng-class" => "{'selected' : ctrl.selectedGroup == group}", .group{"ng-repeat" => "group in ctrl.groups", "ng-click" => "ctrl.selectGroup(group)", "ng-class" => "{'selected' : ctrl.selectedGroup == group}",
"droppable" => true, "drop" => "ctrl.handleDrop", "group" => "group"} "droppable" => true, "drop" => "ctrl.handleDrop", "group" => "group"}
.icon.icon-rss{"ng-if" => "group.presentation.enabled"} .icon.icon-rss{"ng-if" => "group.presentation"}
%input.title{"ng-disabled" => "group != ctrl.selectedGroup", "ng-model" => "group.name", %input.title{"ng-disabled" => "group != ctrl.selectedGroup", "ng-model" => "group.name",
"ng-keyup" => "$event.keyCode == 13 && ctrl.saveGroup($event, group)", "mb-autofocus" => "true", "should-focus" => "ctrl.newGroup", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveGroup($event, group)", "mb-autofocus" => "true", "should-focus" => "ctrl.newGroup",
"ng-change" => "ctrl.groupTitleDidChange(group)", "ng-focus" => "ctrl.onGroupTitleFocus(group)"} "ng-change" => "ctrl.groupTitleDidChange(group)", "ng-focus" => "ctrl.onGroupTitleFocus(group)"}

View File

@@ -14,14 +14,14 @@
%span.caret %span.caret
%span.sr-only %span.sr-only
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"} %ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
%li{"ng-if" => "!ctrl.group.presentation.enabled"} %li{"ng-if" => "!ctrl.group.presentation"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupShare($event)"} Share Group %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupShare($event)"} Share Group
%li{"ng-if" => "ctrl.group.presentation.enabled"} %li{"ng-if" => "ctrl.group.presentation"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupUnshare()"} Unshare Group %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupUnshare()"} Unshare Group
%li{"ng-if" => "!ctrl.group.all"} %li{"ng-if" => "!ctrl.group.all"}
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupDelete()"} Delete Group %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupDelete()"} Delete Group
.menu-right-container .menu-right-container
.public-link{"ng-if" => "ctrl.group.presentation.enabled"} .public-link{"ng-if" => "ctrl.group.presentation"}
%a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForGroup(ctrl.group)}}", "target" => "_blank"} %a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForGroup(ctrl.group)}}", "target" => "_blank"}
%span.icon-rss.icon %span.icon-rss.icon
{{ctrl.publicUrlForGroup()}} {{ctrl.publicUrlForGroup()}}