account menu complete

This commit is contained in:
Mo Bitar
2017-01-28 00:09:44 -06:00
parent f296b0e49e
commit 2b0aa2d4ca
6 changed files with 110 additions and 53 deletions

View File

@@ -32,11 +32,10 @@ angular.module('app.frontend')
this.updateOfflineStatus();
this.findErrors = function() {
this.error = syncManager.error;
this.error = syncManager.syncStatus.error;
}
this.findErrors();
this.accountMenuPressed = function() {
this.serverData = {};
this.showAccountMenu = !this.showAccountMenu;

View File

@@ -92,7 +92,7 @@ angular.module('app.frontend')
this.handleAuthResponse = function(response, email, url, authParams, mk) {
localStorage.setItem("server", url);
localStorage.setItem("user", JSON.stringify(response.plain()));
localStorage.setItem("user", JSON.stringify(response.plain().user));
localStorage.setItem("auth_params", JSON.stringify(_.omit(authParams, ["pw_nonce"])));
localStorage.setItem("mk", mk);
localStorage.setItem("jwt", response.token);
@@ -243,10 +243,8 @@ angular.module('app.frontend')
items: items
}
if(ek.name == SNKeyName) {
// auth params are only needed when encrypted with a standard file key
data["auth_params"] = this.getAuthParams();
}
// auth params are only needed when encrypted with a standard file key
data["auth_params"] = this.getAuthParams();
return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));
}

View File

@@ -11,6 +11,9 @@ class AccountMenu {
$scope.formData = {url: syncManager.serverURL};
$scope.user = authManager.user;
$scope.server = syncManager.serverURL;
$scope.syncStatus = syncManager.syncStatus;
$scope.changePasswordPressed = function() {
$scope.showNewPasswordForm = !$scope.showNewPasswordForm;
@@ -37,14 +40,14 @@ class AccountMenu {
console.log("logging in with url", $scope.formData.url);
$timeout(function(){
authManager.login($scope.formData.url, $scope.formData.email, $scope.formData.user_password, function(response){
$scope.formData.status = null;
if(!response || response.error) {
$scope.formData.status = null;
var error = response ? response.error : {message: "An unknown error occured."}
if(!response || (response && !response.didDisplayAlert)) {
alert(error.message);
}
} else {
window.location.reload();
$scope.onAuthSuccess();
}
});
})
@@ -55,17 +58,23 @@ class AccountMenu {
$timeout(function(){
authManager.register($scope.formData.url, $scope.formData.email, $scope.formData.user_password, function(response){
$scope.formData.status = null;
if(!response || response.error) {
$scope.formData.status = null;
var error = response ? response.error : {message: "An unknown error occured."}
alert(error.message);
} else {
window.location.reload();
$scope.onAuthSuccess();
}
});
})
}
$scope.onAuthSuccess = function() {
syncManager.markAllItemsDirtyAndSaveOffline(function(){
window.location.reload();
})
}
$scope.destroyLocalData = function() {
if(!confirm("Are you sure you want to end your session? This will delete all local items and extensions.")) {
return;
@@ -79,24 +88,16 @@ class AccountMenu {
/* Import/Export */
$scope.archiveFormData = {encryption_type: $scope.user ? 'mk' : 'ek'};
$scope.archiveFormData = {encrypted: $scope.user ? true : false};
$scope.user = authManager.user;
$scope.downloadDataArchive = function() {
if($scope.archiveFormData.encryption_type == 'ek') {
if(!$scope.archiveFormData.ek) {
alert("You must set an encryption key to export the data encrypted.")
return;
}
}
var link = document.createElement('a');
link.setAttribute('download', 'notes.json');
var ek = $scope.archiveFormData.encryption_type == 'ek' ? $scope.archiveFormData.ek : null;
var encrypted = $scope.archiveFormData.encryption_type != 'none';
var ek = $scope.archiveFormData.encrypted ? syncManager.masterKey : null;
link.href = authManager.itemsDataFile(encrypted, ek);
link.href = authManager.itemsDataFile(ek);
link.click();
}

View File

@@ -13,6 +13,10 @@ class SyncManager {
return localStorage.getItem("server") || "http://localhost:3000";
}
get masterKey() {
return localStorage.getItem("mk");
}
writeItemsToLocalStorage(items, offlineOnly, callback) {
var params = items.map(function(item) {
var itemParams = new ItemParams(item, null);
@@ -49,13 +53,21 @@ class SyncManager {
}
}
markAllItemsDirtyAndSaveOffline(callback) {
var items = this.modelManager.allItems;
for(var item of items) {
item.setDirty(true);
}
this.writeItemsToLocalStorage(items, false, callback);
}
get syncURL() {
return this.serverURL + "/items/sync";
}
sync(callback, options = {}) {
if(this.syncOpInProgress) {
if(this.syncStatus.syncOpInProgress) {
this.repeatOnCompletion = true;
console.log("Sync op in progress; returning.");
return;
@@ -74,7 +86,7 @@ class SyncManager {
var isContinuationSync = this.needsMoreSync;
this.repeatOnCompletion = false;
this.syncOpInProgress = true;
this.syncStatus.syncOpInProgress = true;
let submitLimit = 100;
var subItems = allDirtyItems.slice(0, submitLimit);
@@ -103,7 +115,7 @@ class SyncManager {
request.post().then(function(response) {
this.modelManager.clearDirtyItems(subItems);
this.error = null;
this.syncStatus.error = null;
this.syncToken = response.sync_token;
this.cursorToken = response.cursor_token;
@@ -119,7 +131,7 @@ class SyncManager {
this.writeItemsToLocalStorage(saved, false, null);
this.writeItemsToLocalStorage(retrieved, false, null);
this.syncOpInProgress = false;
this.syncStatus.syncOpInProgress = false;
this.syncStatus.current += subItems.length;
if(this.cursorToken || this.repeatOnCompletion || this.needsMoreSync) {
@@ -135,8 +147,8 @@ class SyncManager {
console.log("Sync error: ", response);
var error = response.data ? response.data.error : {message: "Could not connect to server."};
this.syncOpInProgress = false;
this.error = error;
this.syncStatus.syncOpInProgress = false;
this.syncStatus.error = error;
this.writeItemsToLocalStorage(allDirtyItems, false, null);
this.$rootScope.$broadcast("sync:error", error);

View File

@@ -18,6 +18,10 @@
margin-top: 15px !important;
}
.mt-25 {
margin-top: 25px !important;
}
.mb-10 {
margin-bottom: 10px !important;
}
@@ -54,22 +58,54 @@
display: block;
}
.medium-v-space {
height: 12px;
display: block;
}
.large-v-space {
height: 24px;
display: block;
}
.medium-padding {
padding: 10px !important;
}
.large-padding {
padding: 15px !important;
padding: 22px !important;
}
.red {
color: red !important;
}
.blue {
color: $blue-color;
}
.bold {
font-weight: bold !important;
}
.normal {
font-weight: normal !important;
}
.inline {
display: inline-block;
}
.fake-link {
font-weight: bold;
cursor: pointer;
color: $blue-color;
&:hover {
text-decoration: underline;
}
}
.footer-bar {
position: relative;
width: 100%;
@@ -114,6 +150,11 @@
display: block;
}
h2 {
margin-bottom: 0px;
margin-top: 0px;
}
h3 {
font-size: 14px !important;
margin-top: 4px !important;
@@ -122,6 +163,7 @@
h4 {
margin-bottom: 0px !important;
font-size: 13px !important;
}
section {

View File

@@ -1,7 +1,5 @@
.panel.panel-default.panel-right.account-data-menu
.panel-body
-# If not user
.panel-body.large-padding
%div{"ng-if" => "!user"}
%p Enter your <a href="https://standardnotes.org" target="_blank">Standard File</a> account information. You can also register for free using the default server address.
.small-v-space
@@ -26,31 +24,38 @@
%p{"style" => "font-size: 13px; text-align: center;"}
Because notes are locally encrypted using a secret key derived from your password, there's no way to decrypt these notes if you forget your password.
For this reason, Standard Notes cannot offer a password reset option. You <strong>must</strong> make sure to store or remember your password.
-# End if not user
-# If user
%div{"ng-if" => "user"}
%label Local Encryption
%h2 {{user.email}}
%p {{server}}
%p.bold.mt-10.blue{"delay-hide" => "true", "show" => "syncStatus.syncOpInProgress", "delay" => "1000"} Syncing: {{syncStatus.current}}/{{syncStatus.total}}
%p.bold.mt-10.red.block{"ng-if" => "syncStatus.error"} Error syncing: {{syncStatus.error.message}}
.medium-v-space
%h4 Local Encryption
%p Notes are encrypted locally before being sent to the server. Neither the server owner nor an intrusive entity can decrypt your locally encrypted notes.
%label Status:
{{encryptionStatusForNotes()}}
-# End if user
%div.mt-5
%label Status:
{{encryptionStatusForNotes()}}
.mt-5{"ng-if" => "user"}
%label{"ng-if" => "user"}
%input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "true", "ng-change" => "archiveFormData.encrypted = true"}
Encrypted
%label
%input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "false", "ng-change" => "archiveFormData.encrypted = false"}
Decrypted
%a{"ng-click" => "downloadDataArchive()"} Download Data Archive
.mt-25{"ng-if" => "!importData.loading"}
%h4 Data Archives
.mt-5{"ng-if" => "user"}
%label.normal.inline{"ng-if" => "user"}
%input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "true", "ng-change" => "archiveFormData.encrypted = true"}
Encrypted
%label.normal.inline
%input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "false", "ng-change" => "archiveFormData.encrypted = false"}
Decrypted
%a.block{"ng-click" => "downloadDataArchive()"} Download Data Archive
%label.block.mt-5
%input{"type" => "file", "style" => "display: none;", "file-change" => "->", "handler" => "ctrl.importFileSelected(files)"}
.fake-link Import Data from Archive
%div{"ng-if" => "!importData.loading"}
%label#import-archive
%input{"type" => "file", "style" => "display: none;", "file-change" => "->", "handler" => "importFileSelected(files)"}
%a.disabled
%span
Import Data from Archive
%div{"ng-if" => "importData.requestPassword"}
Enter the account password associated with the import file.
%input{"type" => "text", "ng-model" => "importData.password"}
@@ -58,4 +63,4 @@
.spinner{"ng-if" => "importData.loading"}
%a{"ng-click" => "destroyLocalData()"} Destroy all local data
%a.block.mt-25.red{"ng-click" => "destroyLocalData()"} Destroy all local data