This commit is contained in:
Mo Bitar
2020-02-11 11:17:03 -06:00
parent 1497048c72
commit d91d141417
12 changed files with 253 additions and 349 deletions

View File

@@ -112,17 +112,13 @@ class EditorCtrl extends PureCtrl {
return;
}
if (eventName === ApplicationEvents.HighLatencySync) {
this.setState({
syncTakingTooLong: true
});
this.setState({ syncTakingTooLong: true });
} else if (eventName === ApplicationEvents.CompletedSync) {
this.setState({
syncTakingTooLong: false
});
this.setState({ syncTakingTooLong: false });
if (this.state.note.dirty) {
/** if we're still dirty, don't change status, a sync is likely upcoming. */
} else {
const saved = this.state.note.updated_at > this.state.note.lastSyncBegan;
const saved = this.state.note.lastSyncEnd > this.state.note.lastSyncBegan;
const isInErrorState = this.state.saveError;
if (isInErrorState || saved) {
this.showAllChangesSavedStatus();
@@ -792,8 +788,8 @@ class EditorCtrl extends PureCtrl {
this.reloadFont();
if (
this.state.marginResizersEnabled &&
this.leftPanelPuppet.ready &&
this.state.marginResizersEnabled &&
this.leftPanelPuppet.ready &&
this.rightPanelPuppet.ready
) {
const width = this.preferencesManager.getValue(

View File

@@ -59,7 +59,6 @@ class FooterCtrl extends PureCtrl {
});
this.user = this.application.getUser();
this.updateOfflineStatus();
this.addAppEventObserver();
this.findErrors();
this.streamItems();
this.registerComponentHandler();
@@ -111,15 +110,14 @@ class FooterCtrl extends PureCtrl {
/** @override */
onApplicationEvent(eventName) {
if (eventName === ApplicationEvents.LoadedLocalData) {
if (this.offline && this.application.getNoteCount() === 0) {
this.showAccountMenu = true;
}
} else if (eventName === ApplicationEvents.EnteredOutOfSync) {
if (eventName === ApplicationEvents.EnteredOutOfSync) {
this.outOfSync = true;
} else if (eventName === ApplicationEvents.ExitedOutOfSync) {
this.outOfSync = false;
} else if (eventName === ApplicationEvents.CompletedSync) {
if (this.offline && this.application.getNoteCount() === 0) {
this.showAccountMenu = true;
}
this.syncUpdated();
this.findErrors();
this.updateOfflineStatus();

View File

@@ -113,6 +113,9 @@ class NotesCtrl extends PureCtrl {
this.createDummyOnSynCompletionIfNoNotes = true;
}
} else if (eventName === ApplicationEvents.CompletedSync) {
if (this.state.notes.length === 0) {
this.createNewNote();
}
if (this.createDummyOnSynCompletionIfNoNotes && this.state.notes.length === 0) {
this.createDummyOnSynCompletionIfNoNotes = false;
this.createNewNote();

View File

@@ -37,7 +37,7 @@ class RootCtrl extends PureCtrl {
this.themeManager = themeManager;
this.platformString = getPlatformString();
this.state = {
needsUnlock: true,
ready: false,
appClass: ''
};
this.loadApplication();
@@ -86,17 +86,18 @@ class RootCtrl extends PureCtrl {
}
});
await this.application.launch();
this.setState({ ready: true });
// this.addSyncStatusObserver();
// this.addSyncEventHandler();
}
onUpdateAvailable() {
this.$rootScope.$broadcast('new-update-available');
};
/** @override */
async onApplicationEvent(eventName) {
if (eventName === ApplicationEvents.ApplicationUnlocked) {
if (eventName === ApplicationEvents.ApplicationUnlocked) {
this.setState({ needsUnlock: false });
this.application.componentManager.setDesktopManager(this.desktopManager);
this.application.registerService(this.themeManager);

View File

@@ -53,7 +53,9 @@ class AccountMenuCtrl extends PureCtrl {
passcodeAutoLockOptions: this.lockManager.getAutoLockIntervalOptions(),
formData: {
mergeLocal: true,
ephemeral: false
ephemeral: false,
email: "b@bitar.io",
user_password: "password"
},
mutable: {}
};
@@ -182,7 +184,7 @@ class AccountMenuCtrl extends PureCtrl {
password: this.state.formData.user_password,
strict: this.state.formData.strictSignin,
ephemeral: this.state.formData.ephemeral,
mfaKeyPath: this.state.formData.mfa.payload.mfa_key,
mfaKeyPath: this.state.formData.mfa && this.state.formData.mfa.payload.mfa_key,
mfaCode: this.state.formData.userMfaCode,
mergeLocal: this.state.formData.mergeLocal
});
@@ -314,7 +316,7 @@ class AccountMenuCtrl extends PureCtrl {
* https://github.com/standardnotes/desktop/issues/131
*/
async rewriteDatabase({ alternateUuids } = {}) {
await this.application.destroyDatabase();
await this.application.clearDatabase();
await this.application.markAllItemsAsNeedingSync({ alternateUuids });
}
@@ -324,7 +326,6 @@ class AccountMenuCtrl extends PureCtrl {
destructive: true,
onConfirm: async () => {
await this.application.signOut();
window.location.reload();
}
});
}

View File

@@ -4,31 +4,24 @@ import { isNullOrUndefined } from '../../utils';
const DEFAULT_CONTINUE_TITLE = "Continue";
const Steps = {
IntroStep: 0,
BackupStep: 1,
SignoutStep: 2,
PasswordStep: 3,
SyncStep: 4,
FinishStep: 5
FinishStep: 5
};
class PasswordWizardCtrl {
class PasswordWizardCtrl {
/* @ngInject */
constructor(
$element,
$scope,
$timeout,
archiveManager
$timeout
) {
this.$element = $element;
this.$timeout = $timeout;
this.$scope = $scope;
this.archiveManager = archiveManager;
this.registerWindowUnloadStopper();
}
$onInit() {
this.syncStatus = this.application.getSyncStatus();
this.formData = {};
this.configureDefaults();
}
@@ -44,7 +37,7 @@ class PasswordWizardCtrl {
this.continueTitle = DEFAULT_CONTINUE_TITLE;
this.step = Steps.IntroStep;
}
/** Confirms with user before closing tab */
registerWindowUnloadStopper() {
window.onbeforeunload = (e) => {
@@ -57,18 +50,12 @@ class PasswordWizardCtrl {
titleForStep(step) {
switch (step) {
case Steps.BackupStep:
return "Download a backup of your data";
case Steps.SignoutStep:
return "Sign out of all your devices";
case Steps.PasswordStep:
return this.changePassword
? "Password information"
return this.changePassword
? "Password information"
: "Enter your current password";
case Steps.SyncStep:
return "Encrypt and sync data with new keys";
case Steps.FinishStep:
return "Sign back in to your devices";
return "Success";
default:
return null;
}
@@ -112,9 +99,7 @@ class PasswordWizardCtrl {
}
async initializeStep(step) {
if (step === Steps.SyncStep) {
await this.initializeSyncingStep();
} else if (step === Steps.FinishStep) {
if (step === Steps.FinishStep) {
this.continueTitle = "Finish";
}
}
@@ -123,11 +108,10 @@ class PasswordWizardCtrl {
this.lockContinue = true;
this.formData.status = "Processing encryption keys...";
this.formData.processing = true;
const passwordSuccess = await this.processPasswordChange();
this.formData.statusError = !passwordSuccess;
this.formData.processing = passwordSuccess;
if(!passwordSuccess) {
if (!passwordSuccess) {
this.formData.status = "Unable to process your password. Please try again.";
return;
}
@@ -143,74 +127,70 @@ class PasswordWizardCtrl {
const currentPassword = this.formData.currentPassword;
const newPass = this.securityUpdate ? currentPassword : this.formData.newPassword;
if (!currentPassword || currentPassword.length === 0) {
this.application.alertManager.alert({
text: "Please enter your current password."
this.application.alertManager.alert({
text: "Please enter your current password."
});
return false;
}
if (this.changePassword) {
if (!newPass || newPass.length === 0) {
this.application.alertManager.alert({
text: "Please enter a new password."
this.application.alertManager.alert({
text: "Please enter a new password."
});
return false;
}
if (newPass !== this.formData.newPasswordConfirmation) {
this.application.alertManager.alert({
text: "Your new password does not match its confirmation."
this.application.alertManager.alert({
text: "Your new password does not match its confirmation."
});
this.formData.status = null;
return false;
}
}
if (!this.application.getUser().email) {
this.application.alertManager.alert({
text: "We don't have your email stored. Please log out then log back in to fix this issue."
this.application.alertManager.alert({
text: "We don't have your email stored. Please log out then log back in to fix this issue."
});
this.formData.status = null;
return false;
}
/** Validate current password */
const key = await this.application.validateAccountPassword({
const key = await this.application.validateAccountPassword({
password: this.formData.currentPassword
});
if (key) {
this.currentServerPassword = key.serverPassword;
} else {
this.application.alertManager.alert({
text: "The current password you entered is not correct. Please try again."
this.application.alertManager.alert({
text: "The current password you entered is not correct. Please try again."
});
}
return !isNullOrUndefined(key);
}
async processPasswordChange() {
const newPassword = this.securityUpdate
? this.formData.currentPassword
const newPassword = this.securityUpdate
? this.formData.currentPassword
: this.formData.newPassword;
const response = await this.application.changePassword({
email: this.application.getUser().email,
currentPassword: this.formData.currentPassword,
email: this.application.getUser().email,
currentPassword: this.formData.currentPassword,
newPassword: newPassword
});
if (response.error) {
this.application.alertManager.alert({
text: response.error.message
? response.error.message
: "There was an error changing your password. Please try again."
});
return false;
this.application.alertManager.alert({
text: response.error.message
? response.error.message
: "There was an error changing your password. Please try again."
});
return false;
} else {
return true;
}
}
downloadBackup(encrypted) {
this.archiveManager.downloadBackup(encrypted);
}
dismiss() {
if (this.lockContinue) {
this.application.alertManager.alert({

View File

@@ -1,6 +1,5 @@
import { isDesktopApplication, dictToArray } from '@/utils';
import { SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs';
import { AppStateEvents } from '@/state';
const STREAM_ITEMS_PERMISSION = 'stream-items';
@@ -11,18 +10,29 @@ export class NativeExtManager {
this.application = application;
this.extManagerId = 'org.standardnotes.extensions-manager';
this.batchManagerId = 'org.standardnotes.batch-manager';
this.systemExtensions = [];
this.resolveExtensionsManager();
this.resolveBatchManager();
application.onUnlock(() => {
this.resolveExtensionsManager();
this.resolveBatchManager();
this.reload();
this.streamChanges();
});
}
isSystemExtension(extension) {
return this.systemExtensions.includes(extension.uuid);
return this.nativeExtIds.includes(extension.uuid);
}
streamChanges() {
this.application.streamItems({
contentType: ContentTypes.Component,
stream: () => {
this.reload();
}
});
}
reload() {
this.nativeExtIds = [];
// this.resolveExtensionsManager();
// this.resolveBatchManager();
}
extensionsManagerTemplatePayload() {
@@ -76,7 +86,7 @@ export class NativeExtManager {
predicate: predicate,
createPayload: this.extensionsManagerTemplatePayload()
});
this.systemExtensions.push(extensionsManager.uuid);
this.nativeExtIds.push(extensionsManager.uuid);
let needsSync = false;
if (isDesktopApplication()) {
if (!extensionsManager.local_url) {
@@ -144,7 +154,7 @@ export class NativeExtManager {
predicate: predicate,
createPayload: this.batchManagerTemplatePayload()
});
this.systemExtensions.push(batchManager.uuid);
this.nativeExtIds.push(batchManager.uuid);
let needsSync = false;
if (isDesktopApplication()) {
if (!batchManager.local_url) {

View File

@@ -1,4 +1,4 @@
import { SFPredicate, CreateMaxPayloadFromAnyObject } from 'snjs';
import { SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs';
export const PrefKeys = {
TagsPanelWidth: 'tagsPanelWidth',
@@ -33,24 +33,26 @@ export class PreferencesManager {
streamPreferences() {
this.application.streamItems({
contentType: 'SN|UserPreferences',
contentType: ContentTypes.UserPrefs,
stream: () => {
this.preferencesDidChange();
this.loadSingleton();
}
});
}
async loadSingleton() {
const contentType = 'SN|UserPreferences';
const contentType = ContentTypes.UserPrefs;
const predicate = new SFPredicate('content_type', '=', contentType);
this.userPreferences = await this.application.singletonManager.findOrCreateSingleton({
predicate: predicate,
createPayload: CreateMaxPayloadFromAnyObject({
object: {
content_type: contentType
content_type: contentType,
content: {}
}
})
});
this.preferencesDidChange();
}
preferencesDidChange() {

View File

@@ -8,125 +8,38 @@
.sk-panel-header-title {{ctrl.title}}
a.sk-a.info.close-button(ng-click='ctrl.dismiss()') Close
.sk-panel-content
div(ng-if='ctrl.step == 0')
div(ng-if='ctrl.changePassword')
p.sk-p.sk-panel-row
| Changing your password involves changing your encryption key,
| which requires your data to be re-encrypted and synced.
| If you have many items, syncing your data can take several minutes.
p.sk-p.sk-panel-row
| You must keep the application window open during this process.
div(ng-if='ctrl.securityUpdate')
p.sk-p.sk-panel-row
| A new update is available for your account. Updates address
| improvements and enhancements to our security specification.
| This process will guide you through the update, and perform the
| steps necessary with your supervision.
.sk-panel-row
.sk-panel-column
p.sk-p For more information about account updates, please visit
a.sk-a.info(
href='https://standardnotes.org/help/security',
rel='noopener',
target='_blank'
) standardnotes.org/help/security.
p.sk-panel-row.sk-p
.info Press Continue to proceed.
p
.sk-panel-section(ng-if='ctrl.step > 0')
.sk-panel-section-title Step {{ctrl.step}} — {{ctrl.titleForStep(ctrl.step)}}
div(ng-if='ctrl.step == 1')
p.sk-panel-row.sk-p
| As a result of this process, the entirety of your data will be
| re-encrypted and synced to your account. This is a generally safe
| process, but unforeseen factors like poor network connectivity or a
| sudden shutdown of your computer may cause this process to fail. It's
| best to be on the safe side before large operations such as this one.
.sk-panel-row
.sk-panel-row
.sk-button-group
.sk-button.info(ng-click='ctrl.downloadBackup(true)')
.sk-label Download Encrypted Backup
.sk-button.info(ng-click='ctrl.downloadBackup(false)')
.sk-label Download Decrypted Backup
div(ng-if='ctrl.step == 2')
p.sk-p.sk-panel-row
| As a result of this process, your encryption keys will change. Any
| device on which you use Standard Notes will need to end its session.
| After this process completes, you will be asked to sign back in.
p.sk-p.bold.sk-panel-row.info-i
| Please sign out of all applications (excluding this one), including:
ul
li.sk-p Desktop
li.sk-p Web (Chrome, Firefox, Safari)
li.sk-p Mobile (iOS and Android)
p.sk-p.sk-panel-row
| If you do not currently have access to a device you're signed in on,
| you may proceed, but must make signing out and back in the first step
| upon gaining access to that device.
p.sk-p.sk-panel-row
| Press Continue only when you have
| completed signing out of all your devices.
div(ng-if='ctrl.step == 3')
div(ng-if='ctrl.changePassword')
div(ng-if='ctrl.securityUpdate')
p.sk-panel-row
| Enter your current password. We'll run this through our encryption
| scheme to generate strong new encryption keys.
.sk-panel-row
.sk-panel-row
.sk-panel-column.stretch
form.sk-panel-form
input.sk-input.contrast(
ng-model='ctrl.formData.currentPassword',
placeholder='Current Password',
should-focus='true',
sn-autofocus='true',
type='password'
)
input.sk-input.contrast(
ng-if='ctrl.changePassword',
ng-model='ctrl.formData.newPassword',
placeholder='New Password',
type='password'
)
input.sk-input.contrast(
ng-if='ctrl.changePassword',
ng-model='ctrl.formData.newPasswordConfirmation',
placeholder='Confirm New Password',
type='password'
)
div(ng-if='ctrl.step == 4')
p.sk-panel-row
| Your data is being re-encrypted with your new
| keys and synced to your account.
p.sk-panel-row.danger(ng-if='ctrl.lockContinue')
| Do not close this window until this process completes.
.sk-panel-row
.sk-panel-column
.sk-spinner.small.inline.info.mr-5(ng-if='ctrl.formData.processing')
.inline.bold(
ng-class="{'info' : !ctrl.formData.statusError, 'error' : ctrl.formData.statusError}"
div(ng-if='ctrl.step == 3')
.sk-panel-row
.sk-panel-column.stretch
form.sk-panel-form
input.sk-input.contrast(
ng-model='ctrl.formData.currentPassword',
placeholder='Current Password',
should-focus='true',
sn-autofocus='true',
type='password'
)
| {{ctrl.formData.status}}
.sk-panel-column(
delay='1000',
delay-hide='true',
show='ctrl.syncStatus.syncOpInProgress || ctrl.syncStatus.needsMoreSync'
)
p.info
| Syncing {{ctrl.syncStatus.current}}/{{ctrl.syncStatus.total}}
div(ng-if='ctrl.step == 5')
div(ng-if='ctrl.changePassword')
p.sk-p.sk-panel-row.info-i Your password has been successfully changed.
div(ng-if='ctrl.securityUpdate')
p.sk-p.sk-panel-row.info-i
| The account update has been successfully applied to your account.
p.sk-p.sk-panel-row
| Please ensure you are running the latest version of Standard Notes
| on all platforms to ensure maximum compatibility.
p.sk-p.sk-panel-row
| You may now sign back in on all your devices and close this window.
input.sk-input.contrast(
ng-if='ctrl.changePassword',
ng-model='ctrl.formData.newPassword',
placeholder='New Password',
type='password'
)
input.sk-input.contrast(
ng-if='ctrl.changePassword',
ng-model='ctrl.formData.newPasswordConfirmation',
placeholder='Confirm New Password',
type='password'
)
div(ng-if='ctrl.step == 5')
div(ng-if='ctrl.changePassword')
p.sk-p.sk-panel-row.info-i Your password has been successfully changed.
div(ng-if='ctrl.securityUpdate')
p.sk-p.sk-panel-row.info-i
| The account update has been successfully applied to your account.
p.sk-p.sk-panel-row
| Please ensure you are running the latest version of Standard Notes
| on all platforms to ensure maximum compatibility.
.sk-panel-footer
.empty
a.sk-a.info.right(

View File

@@ -1,5 +1,6 @@
.main-ui-view(
ng-class='self.platformString'
ng-if='self.state.ready'
)
lock-screen(
ng-if='self.state.needsUnlock'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long