encryption updates
This commit is contained in:
@@ -235,11 +235,13 @@ angular.module('app.frontend')
|
||||
|
||||
this.saveUrl = function($event) {
|
||||
$event.target.blur();
|
||||
var original = this.note.presentation.root_path;
|
||||
this.note.presentation.root_path = this.url.token;
|
||||
apiController.saveNote(this.user, this.note, function(note){
|
||||
if(!note) {
|
||||
this.note.token = original;
|
||||
|
||||
var original = this.note.presentation.relative_path;
|
||||
this.note.presentation.relative_path = this.url.token;
|
||||
|
||||
apiController.updatePresentation(this.note, this.note.presentation, function(response){
|
||||
if(!response) {
|
||||
this.note.presentation.relative_path = original;
|
||||
this.url.token = original;
|
||||
alert("This URL is not available.");
|
||||
} else {
|
||||
|
||||
@@ -53,7 +53,7 @@ angular.module('app.frontend')
|
||||
return;
|
||||
}
|
||||
|
||||
this.newGroup = {notes : []};
|
||||
this.newGroup = new Group({notes : []});
|
||||
if(!this.user.id) {
|
||||
this.newGroup.id = Neeto.crypto.generateRandomKey()
|
||||
}
|
||||
@@ -92,7 +92,7 @@ angular.module('app.frontend')
|
||||
}
|
||||
|
||||
this.noteCount = function(group) {
|
||||
var validNotes = apiController.filterDummyNotes(group.notes);
|
||||
var validNotes = Note.filterDummyNotes(group.notes);
|
||||
return validNotes.length;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,7 @@ angular.module('app.frontend')
|
||||
bindToController: true,
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
this.onValidationSuccess = function() {
|
||||
apiController.verifyEncryptionStatusOfAllNotes(this.user, function(success){
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
this.encryptionStatusForNotes = function() {
|
||||
var allNotes = this.user.filteredNotes();
|
||||
var countEncrypted = 0;
|
||||
allNotes.forEach(function(note){
|
||||
if(note.isEncrypted()) {
|
||||
if(note.encryptionEnabled()) {
|
||||
countEncrypted++;
|
||||
}
|
||||
}.bind(this))
|
||||
|
||||
@@ -6,21 +6,12 @@ angular.module('app.frontend')
|
||||
|
||||
var onUserSet = function() {
|
||||
|
||||
$scope.defaultUser.notes = _.map($scope.defaultUser.notes, function(json_obj) {
|
||||
return new Note(json_obj);
|
||||
});
|
||||
$scope.allGroup = new Group({name: "All", all: true});
|
||||
$scope.groups = $scope.defaultUser.groups;
|
||||
|
||||
$scope.defaultUser.filteredNotes = function() {
|
||||
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.verifyEncryptionStatusOfAllNotes($scope.defaultUser, function(success){
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
apiController.getCurrentUser(function(response){
|
||||
@@ -39,7 +30,7 @@ angular.module('app.frontend')
|
||||
*/
|
||||
|
||||
$scope.updateAllGroup = function() {
|
||||
var allNotes = apiController.filterDummyNotes($scope.defaultUser.notes);
|
||||
var allNotes = Note.filterDummyNotes($scope.defaultUser.notes);
|
||||
$scope.defaultUser.notes = allNotes;
|
||||
$scope.allGroup.notes = allNotes;
|
||||
}
|
||||
@@ -78,6 +69,8 @@ angular.module('app.frontend')
|
||||
originalNote.group_id = null;
|
||||
} else {
|
||||
originalNote.group_id = newGroup.id
|
||||
originalNote.group = newGroup;
|
||||
|
||||
newGroup.notes.unshift(originalNote);
|
||||
newGroup.notes.sort(function(a,b){
|
||||
//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){
|
||||
_.merge(originalNote, note);
|
||||
});
|
||||
@@ -97,7 +88,7 @@ angular.module('app.frontend')
|
||||
*/
|
||||
|
||||
$scope.notesRemoveGroup = function(group) {
|
||||
var validNotes = apiController.filterDummyNotes(group.notes);
|
||||
var validNotes = Note.filterDummyNotes(group.notes);
|
||||
if(validNotes == 0) {
|
||||
// if no more notes, delete group
|
||||
apiController.deleteGroup($scope.defaultUser, group, function(){
|
||||
|
||||
@@ -138,7 +138,7 @@ angular.module('app.frontend')
|
||||
var title = "New Note" + (this.notes ? (" " + (this.notes.length + 1)) : "");
|
||||
this.newNote = new Note({dummy: true});
|
||||
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.addNew()(this.newNote);
|
||||
}
|
||||
|
||||
3
app/assets/javascripts/app/frontend/models/group.js
Normal file
3
app/assets/javascripts/app/frontend/models/group.js
Normal file
@@ -0,0 +1,3 @@
|
||||
var Group = function (json_obj) {
|
||||
_.merge(this, json_obj);
|
||||
};
|
||||
@@ -23,6 +23,10 @@ var Note = function (json_obj) {
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
this.setContentRaw = function(rawContent) {
|
||||
content = rawContent;
|
||||
}
|
||||
|
||||
_.merge(this, json_obj);
|
||||
|
||||
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 */
|
||||
Note.prototype.isPublic = function() {
|
||||
return this.hasEnabledPresentation() || this.shared_via_group;
|
||||
return this.presentation || (this.group && this.group.presentation);
|
||||
};
|
||||
|
||||
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() {
|
||||
return this.presentation && this.presentation.enabled;
|
||||
Note.prototype.encryptionEnabled = function() {
|
||||
return this.loc_eek;
|
||||
}
|
||||
|
||||
Note.prototype.presentationURL = function() {
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
var User = function (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);
|
||||
}
|
||||
|
||||
@@ -147,25 +147,21 @@ angular.module('app.services')
|
||||
this.verifyEncryptionStatusOfAllNotes = function(user, callback) {
|
||||
var allNotes = user.filteredNotes();
|
||||
var notesNeedingUpdate = [];
|
||||
var key = this.retrieveGk();
|
||||
allNotes.forEach(function(note){
|
||||
if(!note.isPublic()) {
|
||||
if(!note.isEncrypted()) {
|
||||
// needs encryption
|
||||
this.encryptSingleNote(note, key);
|
||||
if(note.encryptionEnabled() && !note.isEncrypted()) {
|
||||
notesNeedingUpdate.push(note);
|
||||
}
|
||||
} else {
|
||||
if(note.isEncrypted()) {
|
||||
// needs decrypting
|
||||
this.decryptSingleNote(note, key);
|
||||
notesNeedingUpdate.push(note);
|
||||
}
|
||||
}
|
||||
}.bind(this))
|
||||
|
||||
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) {
|
||||
var shareFn = function() {
|
||||
Restangular.one("users", user.id).one("groups", group.id).one("presentations").post()
|
||||
.then(function(response){
|
||||
var presentation = response.plain();
|
||||
group.notes.forEach(function(note){
|
||||
note.shared_via_group = true;
|
||||
});
|
||||
_.merge(group, {presentation: presentation});
|
||||
callback(presentation);
|
||||
})
|
||||
}
|
||||
|
||||
if(group.notes.length > 0) {
|
||||
// decrypt group notes first
|
||||
var notes = group.notes;
|
||||
notes.forEach(function(note){
|
||||
note.shared_via_group = true;
|
||||
})
|
||||
this.decryptNotesWithLocalKey(notes);
|
||||
this.saveBatchNotes(user, notes, false, function(success){
|
||||
shareFn();
|
||||
})
|
||||
} else {
|
||||
shareFn();
|
||||
}
|
||||
if(group.notes.length > 0) {
|
||||
// decrypt notes
|
||||
this.saveBatchNotes(user, group.notes, function(success){})
|
||||
}
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
this.unshareGroup = function(user, group, callback) {
|
||||
var request = Restangular.one("users", user.id).one("groups", group.id).one("presentations", group.presentation.id);
|
||||
request.enabled = false;
|
||||
request.patch().then(function(response){
|
||||
var presentation = response.plain();
|
||||
_.merge(group, {presentation: presentation});
|
||||
callback(presentation);
|
||||
})
|
||||
request.remove().then(function(response){
|
||||
group.presentation = null;
|
||||
callback(null);
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
this.saveBatchNotes = function(user, notes, encryptionEnabled, callback) {
|
||||
this.saveBatchNotes = function(user, notes, callback) {
|
||||
var request = Restangular.one("users", user.id).one("notes/batch_update");
|
||||
request.notes = _.map(notes, function(note){
|
||||
return this.createRequestParamsFromNote(note, user);
|
||||
@@ -302,6 +288,7 @@ angular.module('app.services')
|
||||
else {
|
||||
// decrypted
|
||||
params.content = JSON.stringify(note.content);
|
||||
params.loc_eek = null;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
@@ -351,15 +338,29 @@ angular.module('app.services')
|
||||
|
||||
this.unshareNote = function(user, note, callback) {
|
||||
var request = Restangular.one("users", user.id).one("notes", note.id).one("presentations", note.presentation.id);
|
||||
request.enabled = false;
|
||||
request.patch().then(function(response){
|
||||
var presentation = response.plain();
|
||||
_.merge(note, {presentation: presentation});
|
||||
callback(note);
|
||||
request.remove().then(function(response){
|
||||
note.presentation = null;
|
||||
callback(null);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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) {
|
||||
var data = JSON.parse(jsonString);
|
||||
var user = new User(data);
|
||||
console.log("importing data", JSON.parse(jsonString));
|
||||
// data.notes = _.map(data.notes, function(json_obj) {
|
||||
// return new Note(json_obj);
|
||||
// });
|
||||
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);
|
||||
user.notes.forEach(function(note) {
|
||||
if(note.isPublic()) {
|
||||
note.setContentRaw(JSON.stringify(note.content));
|
||||
} else {
|
||||
// private
|
||||
this.encryptSingleNoteWithLocalKey(note);
|
||||
}
|
||||
|
||||
// prevent circular links
|
||||
note.group = null;
|
||||
}.bind(this))
|
||||
|
||||
user.groups.forEach(function(group){
|
||||
// prevent circular links
|
||||
group.notes = null;
|
||||
})
|
||||
|
||||
var request = Restangular.one("import");
|
||||
request.data = data;
|
||||
console.log("posting import request", request);
|
||||
request.data = {notes: user.notes, groups: user.groups};
|
||||
request.post().then(function(response){
|
||||
callback(true, response);
|
||||
})
|
||||
@@ -423,9 +418,24 @@ angular.module('app.services')
|
||||
return textFile;
|
||||
}.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){
|
||||
console.log("mapping note", note);
|
||||
return {
|
||||
id: note.id,
|
||||
uuid: note.uuid,
|
||||
@@ -433,6 +443,7 @@ angular.module('app.services')
|
||||
group_id: note.group_id,
|
||||
created_at: note.created_at,
|
||||
modified_at: note.modified_at,
|
||||
presentation: presentationParams(note.presentation)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -443,36 +454,13 @@ angular.module('app.services')
|
||||
name: group.name,
|
||||
created_at: group.created_at,
|
||||
modified_at: group.modified_at,
|
||||
}
|
||||
});
|
||||
|
||||
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,
|
||||
presentation: presentationParams(group.presentation)
|
||||
}
|
||||
});
|
||||
|
||||
var data = {
|
||||
notes: notes,
|
||||
groups: groups,
|
||||
presentations: presentations
|
||||
groups: groups
|
||||
}
|
||||
|
||||
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) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
|
||||
this.writeUserToLocalStorage = function(user) {
|
||||
var saveUser = _.cloneDeep(user);
|
||||
saveUser.notes = this.filterDummyNotes(saveUser.notes);
|
||||
saveUser.notes = Note.filterDummyNotes(saveUser.notes);
|
||||
saveUser.groups.forEach(function(group){
|
||||
group.notes = null;
|
||||
}.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);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
%li
|
||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleMarkdown()"} Toggle Markdown Preview
|
||||
.shortcut Cmd + M
|
||||
%li{"ng-if" => "!ctrl.note.hasEnabledPresentation()"}
|
||||
%li{"ng-if" => "!ctrl.note.presentation"}
|
||||
%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
|
||||
%li{"ng-if" => "ctrl.note.hasEnabledPresentation()"}
|
||||
%li{"ng-if" => "ctrl.note.presentation"}
|
||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.unshareNote()"} Unshare
|
||||
%li
|
||||
%a.text{"ng-click" => "ctrl.deleteNote()"} Delete
|
||||
@@ -40,7 +40,7 @@
|
||||
.panel-body{"style" => "text-align: center; color: black;"}
|
||||
This editor is Markdown enabled.
|
||||
.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"}
|
||||
%span.icon-rss.icon
|
||||
{{ctrl.publicUrlForNote(note)}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
.count {{ctrl.noteCount(ctrl.allGroup)}}
|
||||
.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"}
|
||||
.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",
|
||||
"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)"}
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
%span.caret
|
||||
%span.sr-only
|
||||
%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
|
||||
%li{"ng-if" => "ctrl.group.presentation.enabled"}
|
||||
%li{"ng-if" => "ctrl.group.presentation"}
|
||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupUnshare()"} Unshare Group
|
||||
%li{"ng-if" => "!ctrl.group.all"}
|
||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupDelete()"} Delete Group
|
||||
.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"}
|
||||
%span.icon-rss.icon
|
||||
{{ctrl.publicUrlForGroup()}}
|
||||
|
||||
Reference in New Issue
Block a user