fix: typescript errors

This commit is contained in:
Baptiste Grob
2020-08-12 14:43:56 +02:00
parent 0c1f3d43d1
commit 2fb6adb6ea
31 changed files with 233 additions and 1463 deletions

View File

@@ -1,622 +0,0 @@
import { isDesktopApplication, isNullOrUndefined } from '@/utils';
import { PrivilegesManager } from '@/services/privilegesManager';
import template from '%/directives/account-menu.pug';
import { protocolManager } from 'snjs';
import { PureCtrl } from '@Controllers';
import {
STRING_ACCOUNT_MENU_UNCHECK_MERGE,
STRING_SIGN_OUT_CONFIRMATION,
STRING_ERROR_DECRYPTING_IMPORT,
STRING_E2E_ENABLED,
STRING_LOCAL_ENC_ENABLED,
STRING_ENC_NOT_ENABLED,
STRING_IMPORT_SUCCESS,
STRING_REMOVE_PASSCODE_CONFIRMATION,
STRING_REMOVE_PASSCODE_OFFLINE_ADDENDUM,
STRING_NON_MATCHING_PASSCODES,
STRING_NON_MATCHING_PASSWORDS,
STRING_INVALID_IMPORT_FILE,
STRING_GENERATING_LOGIN_KEYS,
STRING_GENERATING_REGISTER_KEYS,
StringImportError
} from '@/strings';
const ELEMENT_ID_IMPORT_PASSWORD_INPUT = 'import-password-request';
const ELEMENT_NAME_AUTH_EMAIL = 'email';
const ELEMENT_NAME_AUTH_PASSWORD = 'password';
const ELEMENT_NAME_AUTH_PASSWORD_CONF = 'password_conf';
class AccountMenuCtrl extends PureCtrl {
/* @ngInject */
constructor(
$scope,
$rootScope,
$timeout,
alertManager,
archiveManager,
appVersion,
authManager,
modelManager,
passcodeManager,
privilegesManager,
storageManager,
syncManager,
) {
super($timeout);
this.$scope = $scope;
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.alertManager = alertManager;
this.archiveManager = archiveManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.passcodeManager = passcodeManager;
this.privilegesManager = privilegesManager;
this.storageManager = storageManager;
this.syncManager = syncManager;
this.state = {
appVersion: 'v' + (window.electronAppVersion || appVersion),
user: this.authManager.user,
canAddPasscode: !this.authManager.isEphemeralSession(),
passcodeAutoLockOptions: this.passcodeManager.getAutoLockIntervalOptions(),
formData: {
mergeLocal: true,
ephemeral: false
},
mutable: {
backupEncrypted: this.encryptedBackupsAvailable()
}
};
this.syncStatus = this.syncManager.syncStatus;
this.syncManager.getServerURL().then((url) => {
this.setState({
server: url,
formData: { ...this.state.formData, url: url }
});
});
this.authManager.checkForSecurityUpdate().then((available) => {
this.setState({
securityUpdateAvailable: available
});
});
this.reloadAutoLockInterval();
}
$onInit() {
this.initProps({
closeFunction: this.closeFunction
});
}
close() {
this.$timeout(() => {
this.props.closeFunction()();
});
}
encryptedBackupsAvailable() {
return !isNullOrUndefined(this.authManager.user) || this.passcodeManager.hasPasscode();
}
submitMfaForm() {
const params = {
[this.state.formData.mfa.payload.mfa_key]: this.state.formData.userMfaCode
};
this.login(params);
}
blurAuthFields() {
const names = [
ELEMENT_NAME_AUTH_EMAIL,
ELEMENT_NAME_AUTH_PASSWORD,
ELEMENT_NAME_AUTH_PASSWORD_CONF
];
for(const name of names) {
const element = document.getElementsByName(name)[0];
if(element) {
element.blur();
}
}
}
submitAuthForm() {
if (!this.state.formData.email || !this.state.formData.user_password) {
return;
}
this.blurAuthFields();
if (this.state.formData.showLogin) {
this.login();
} else {
this.register();
}
}
async setFormDataState(formData) {
return this.setState({
formData: {
...this.state.formData,
...formData
}
});
}
async login(extraParams) {
/** Prevent a timed sync from occuring while signing in. */
this.syncManager.lockSyncing();
await this.setFormDataState({
status: STRING_GENERATING_LOGIN_KEYS,
authenticating: true
});
const response = await this.authManager.login(
this.state.formData.url,
this.state.formData.email,
this.state.formData.user_password,
this.state.formData.ephemeral,
this.state.formData.strictSignin,
extraParams
);
const hasError = !response || response.error;
if (!hasError) {
this.setFormDataState({
user_password: null
});
await this.onAuthSuccess();
this.syncManager.unlockSyncing();
this.syncManager.sync({ performIntegrityCheck: true });
return;
}
this.syncManager.unlockSyncing();
await this.setFormDataState({
status: null
});
const error = response
? response.error
: { message: "An unknown error occured." };
if (error.tag === 'mfa-required' || error.tag === 'mfa-invalid') {
await this.setFormDataState({
showLogin: false,
mfa: error
});
} else {
await this.setFormDataState({
showLogin: true,
mfa: null
});
if (error.message) {
this.alertManager.alert({
text: error.message
});
}
}
await this.setFormDataState({
authenticating: false,
});
}
async register() {
const confirmation = this.state.formData.password_conf;
if (confirmation !== this.state.formData.user_password) {
this.alertManager.alert({
text: STRING_NON_MATCHING_PASSWORDS
});
return;
}
await this.setFormDataState({
confirmPassword: false,
status: STRING_GENERATING_REGISTER_KEYS,
authenticating: true
});
const response = await this.authManager.register(
this.state.formData.url,
this.state.formData.email,
this.state.formData.user_password,
this.state.formData.ephemeral
);
if (!response || response.error) {
await this.setFormDataState({
status: null
});
const error = response
? response.error
: { message: "An unknown error occured." };
await this.setFormDataState({
authenticating: false
});
this.alertManager.alert({
text: error.message
});
} else {
await this.onAuthSuccess();
this.syncManager.sync();
}
}
mergeLocalChanged() {
if (!this.state.formData.mergeLocal) {
this.alertManager.confirm({
text: STRING_ACCOUNT_MENU_UNCHECK_MERGE,
destructive: true,
onCancel: () => {
this.setFormDataState({
mergeLocal: true
});
}
});
}
}
async onAuthSuccess() {
if (this.state.formData.mergeLocal) {
this.$rootScope.$broadcast('major-data-change');
await this.clearDatabaseAndRewriteAllItems({ alternateUuids: true });
} else {
this.modelManager.removeAllItemsFromMemory();
await this.storageManager.clearAllModels();
}
await this.setFormDataState({
authenticating: false
});
this.syncManager.refreshErroredItems();
this.close();
}
openPasswordWizard(type) {
this.close();
this.authManager.presentPasswordWizard(type);
}
async openPrivilegesModal() {
this.close();
const run = () => {
this.privilegesManager.presentPrivilegesManagementModal();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePrivileges
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePrivileges,
() => {
run();
}
);
} else {
run();
}
}
/**
* Allows IndexedDB unencrypted logs to be deleted
* `clearAllModels` will remove data from backing store,
* but not from working memory See:
* https://github.com/standardnotes/desktop/issues/131
*/
async clearDatabaseAndRewriteAllItems({ alternateUuids } = {}) {
await this.storageManager.clearAllModels();
await this.syncManager.markAllItemsDirtyAndSaveOffline(alternateUuids);
}
destroyLocalData() {
this.alertManager.confirm({
text: STRING_SIGN_OUT_CONFIRMATION,
destructive: true,
onConfirm: async () => {
await this.authManager.signout(true);
window.location.reload();
}
});
}
async submitImportPassword() {
await this.performImport(
this.state.importData.data,
this.state.importData.password
);
}
async readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (e) {
try {
const data = JSON.parse(e.target.result);
resolve(data);
} catch (e) {
this.alertManager.alert({
text: STRING_INVALID_IMPORT_FILE
});
}
};
reader.readAsText(file);
});
}
/**
* @template
*/
async importFileSelected(files) {
const run = async () => {
const file = files[0];
const data = await this.readFile(file);
if (!data) {
return;
}
if (data.auth_params) {
await this.setState({
importData: {
...this.state.importData,
requestPassword: true,
data: data
}
});
const element = document.getElementById(
ELEMENT_ID_IMPORT_PASSWORD_INPUT
);
if (element) {
element.scrollIntoView(false);
}
} else {
await this.performImport(data, null);
}
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManageBackups
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManageBackups,
run
);
} else {
run();
}
}
async performImport(data, password) {
await this.setState({
importData: {
...this.state.importData,
loading: true
}
});
const errorCount = await this.importJSONData(data, password);
this.setState({
importData: null
});
if (errorCount > 0) {
const message = StringImportError({ errorCount: errorCount });
this.alertManager.alert({
text: message
});
} else {
this.alertManager.alert({
text: STRING_IMPORT_SUCCESS
});
}
}
async importJSONData(data, password) {
let errorCount = 0;
if (data.auth_params) {
const keys = await protocolManager.computeEncryptionKeysForUser(
password,
data.auth_params
);
try {
const throws = false;
await protocolManager.decryptMultipleItems(data.items, keys, throws);
const items = [];
for (const item of data.items) {
item.enc_item_key = null;
item.auth_hash = null;
if (item.errorDecrypting) {
errorCount++;
} else {
items.push(item);
}
}
data.items = items;
} catch (e) {
this.alertManager.alert({
text: STRING_ERROR_DECRYPTING_IMPORT
});
return;
}
}
const items = await this.modelManager.importItems(data.items);
for (const item of items) {
/**
* Don't want to activate any components during import process in
* case of exceptions breaking up the import proccess
*/
if (item.content_type === 'SN|Component') {
item.active = false;
}
}
this.syncManager.sync();
return errorCount;
}
async downloadDataArchive() {
this.archiveManager.downloadBackup(this.state.mutable.backupEncrypted);
this.close();
}
notesAndTagsCount() {
return this.modelManager.allItemsMatchingTypes([
'Note',
'Tag'
]).length;
}
encryptionStatusForNotes() {
const length = this.notesAndTagsCount();
return length + "/" + length + " notes and tags encrypted";
}
encryptionEnabled() {
return this.passcodeManager.hasPasscode() || !this.authManager.offline();
}
encryptionSource() {
if (!this.authManager.offline()) {
return "Account keys";
} else if (this.passcodeManager.hasPasscode()) {
return "Local Passcode";
} else {
return null;
}
}
encryptionStatusString() {
if (!this.authManager.offline()) {
return STRING_E2E_ENABLED;
} else if (this.passcodeManager.hasPasscode()) {
return STRING_LOCAL_ENC_ENABLED;
} else {
return STRING_ENC_NOT_ENABLED;
}
}
async reloadAutoLockInterval() {
const interval = await this.passcodeManager.getAutoLockInterval();
this.setState({
selectedAutoLockInterval: interval
});
}
async selectAutoLockInterval(interval) {
const run = async () => {
await this.passcodeManager.setAutoLockInterval(interval);
this.reloadAutoLockInterval();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
() => {
run();
}
);
} else {
run();
}
}
hidePasswordForm() {
this.setFormDataState({
showLogin: false,
showRegister: false,
user_password: null,
password_conf: null
});
}
hasPasscode() {
return this.passcodeManager.hasPasscode();
}
addPasscodeClicked() {
this.setFormDataState({
showPasscodeForm: true
});
}
submitPasscodeForm() {
const passcode = this.state.formData.passcode;
if (passcode !== this.state.formData.confirmPasscode) {
this.alertManager.alert({
text: STRING_NON_MATCHING_PASSCODES
});
return;
}
const func = this.state.formData.changingPasscode
? this.passcodeManager.changePasscode.bind(this.passcodeManager)
: this.passcodeManager.setPasscode.bind(this.passcodeManager);
func(passcode, async () => {
await this.setFormDataState({
passcode: null,
confirmPasscode: null,
showPasscodeForm: false
});
if (await this.authManager.offline()) {
this.$rootScope.$broadcast('major-data-change');
this.clearDatabaseAndRewriteAllItems();
}
});
}
async changePasscodePressed() {
const run = () => {
this.state.formData.changingPasscode = true;
this.addPasscodeClicked();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
run
);
} else {
run();
}
}
async removePasscodePressed() {
const run = () => {
const signedIn = !this.authManager.offline();
let message = STRING_REMOVE_PASSCODE_CONFIRMATION;
if (!signedIn) {
message += STRING_REMOVE_PASSCODE_OFFLINE_ADDENDUM;
}
this.alertManager.confirm({
text: message,
destructive: true,
onConfirm: () => {
this.passcodeManager.clearPasscode();
if (this.authManager.offline()) {
this.syncManager.markAllItemsDirtyAndSaveOffline();
}
}
});
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
run
);
} else {
run();
}
}
isDesktopApplication() {
return isDesktopApplication();
}
}
export class AccountMenu {
constructor() {
this.restrict = 'E';
this.template = template;
this.controller = AccountMenuCtrl;
this.controllerAs = 'self';
this.bindToController = true;
this.scope = {
closeFunction: '&'
};
}
}

View File

@@ -137,8 +137,8 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope {
...action,
running: params?.running,
error: params?.error,
subrows: params?.subrows || act?.subrows,
};
subrows: params?.subrows || act?.subrows,
} as Action;
}
return act;
});
@@ -147,12 +147,12 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope {
}
private async updateExtension(
extension: SNActionsExtension,
extension: SNActionsExtension,
params?: UpdateExtensionParams
) {
const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => {
const extensionMutator = mutator as ActionsExtensionMutator;
extensionMutator.hidden = params && params.hidden;
extensionMutator.hidden = Boolean(params?.hidden);
}) as SNActionsExtension;
const extensions = this.state.extensions.map((ext: SNActionsExtension) => {
if (extension.uuid === ext.uuid) {

View File

@@ -1,280 +0,0 @@
import template from '%/directives/component-view.pug';
import { isDesktopApplication } from '../../utils';
/**
* The maximum amount of time we'll wait for a component
* to load before displaying error
*/
const MAX_LOAD_THRESHOLD = 4000;
const VISIBILITY_CHANGE_LISTENER_KEY = 'visibilitychange';
class ComponentViewCtrl {
/* @ngInject */
constructor(
$scope,
$rootScope,
$timeout,
componentManager,
desktopManager,
themeManager
) {
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.themeManager = themeManager;
this.desktopManager = desktopManager;
this.componentManager = componentManager;
this.componentValid = true;
this.destroyed = false;
$scope.$watch('ctrl.component', (component, prevComponent) => {
this.componentValueDidSet(component, prevComponent);
});
$scope.$on('ext-reload-complete', () => {
this.reloadStatus(false);
});
$scope.$on('$destroy', () => {
this.destroyed = true;
this.destroy();
});
}
$onInit() {
this.registerComponentHandlers();
this.registerPackageUpdateObserver();
};
registerPackageUpdateObserver() {
this.updateObserver = this.desktopManager
.registerUpdateObserver((component) => {
if(component === this.component && component.active) {
this.reloadComponent();
}
});
}
registerComponentHandlers() {
this.themeHandlerIdentifier = 'component-view-' + Math.random();
this.componentManager.registerHandler({
identifier: this.themeHandlerIdentifier,
areas: ['themes'],
activationHandler: (component) => {
this.reloadThemeStatus();
}
});
this.identifier = 'component-view-' + Math.random();
this.componentManager.registerHandler({
identifier: this.identifier,
areas: [this.component.area],
activationHandler: (component) => {
if(component !== this.component) {
return;
}
this.$timeout(() => {
this.handleActivation();
});
},
actionHandler: (component, action, data) => {
if(action === 'set-size') {
this.componentManager.handleSetSizeEvent(component, data);
}
}
});
}
onVisibilityChange() {
if(document.visibilityState === 'hidden') {
return;
}
if(this.issueLoading) {
this.reloadComponent();
}
}
async reloadComponent() {
this.componentValid = false;
await this.componentManager.reloadComponent(this.component);
if (this.destroyed) return;
this.reloadStatus();
}
reloadStatus(doManualReload = true) {
this.reloading = true;
const component = this.component;
const previouslyValid = this.componentValid;
const offlineRestricted = component.offlineOnly && !isDesktopApplication();
const hasUrlError = function(){
if(isDesktopApplication()) {
return !component.local_url && !component.hasValidHostedUrl();
} else {
return !component.hasValidHostedUrl();
}
}();
this.expired = component.valid_until && component.valid_until <= new Date();
if(!component.lockReadonly) {
component.readonly = this.expired;
}
this.componentValid = !offlineRestricted && !hasUrlError;
if(!this.componentValid) {
this.loading = false;
}
if(offlineRestricted) {
this.error = 'offline-restricted';
} else if(hasUrlError) {
this.error = 'url-missing';
} else {
this.error = null;
}
if(this.componentValid !== previouslyValid) {
if(this.componentValid) {
this.componentManager.reloadComponent(component, true);
}
}
if(this.expired && doManualReload) {
this.$rootScope.$broadcast('reload-ext-dat');
}
this.reloadThemeStatus();
this.$timeout(() => {
this.reloading = false;
}, 500);
}
handleActivation() {
if(!this.component.active) {
return;
}
const iframe = this.componentManager.iframeForComponent(
this.component
);
if(!iframe) {
return;
}
this.loading = true;
if(this.loadTimeout) {
this.$timeout.cancel(this.loadTimeout);
}
this.loadTimeout = this.$timeout(() => {
this.handleIframeLoadTimeout();
}, MAX_LOAD_THRESHOLD);
iframe.onload = (event) => {
this.handleIframeLoad(iframe);
};
}
async handleIframeLoadTimeout() {
if(this.loading) {
this.loading = false;
this.issueLoading = true;
if(!this.didAttemptReload) {
this.didAttemptReload = true;
this.reloadComponent();
} else {
document.addEventListener(
VISIBILITY_CHANGE_LISTENER_KEY,
this.onVisibilityChange.bind(this)
);
}
}
}
async handleIframeLoad(iframe) {
let desktopError = false;
if(isDesktopApplication()) {
try {
/** Accessing iframe.contentWindow.origin only allowed in desktop app. */
if(!iframe.contentWindow.origin || iframe.contentWindow.origin === 'null') {
desktopError = true;
}
} catch (e) {}
}
this.$timeout.cancel(this.loadTimeout);
await this.componentManager.registerComponentWindow(
this.component,
iframe.contentWindow
);
const avoidFlickerTimeout = 7;
this.$timeout(() => {
this.loading = false;
// eslint-disable-next-line no-unneeded-ternary
this.issueLoading = desktopError ? true : false;
this.onLoad && this.onLoad(this.component);
}, avoidFlickerTimeout);
}
componentValueDidSet(component, prevComponent) {
const dontSync = true;
if(prevComponent && component !== prevComponent) {
this.componentManager.deactivateComponent(
prevComponent,
dontSync
);
}
if(component) {
this.componentManager.activateComponent(
component,
dontSync
);
this.reloadStatus();
}
}
reloadThemeStatus() {
if(this.component.acceptsThemes()) {
return;
}
if(this.themeManager.hasActiveTheme()) {
if(!this.dismissedNoThemesMessage) {
this.showNoThemesMessage = true;
}
} else {
this.showNoThemesMessage = false;
}
}
dismissNoThemesMessage() {
this.showNoThemesMessage = false;
this.dismissedNoThemesMessage = true;
}
disableActiveTheme() {
this.themeManager.deactivateAllThemes();
this.dismissNoThemesMessage();
}
getUrl() {
const url = this.componentManager.urlForComponent(this.component);
this.component.runningLocally = (url === this.component.local_url);
return url;
}
destroy() {
this.componentManager.deregisterHandler(this.themeHandlerIdentifier);
this.componentManager.deregisterHandler(this.identifier);
if(this.component && !this.manualDealloc) {
const dontSync = true;
this.componentManager.deactivateComponent(this.component, dontSync);
}
this.desktopManager.deregisterUpdateObserver(this.updateObserver);
document.removeEventListener(
VISIBILITY_CHANGE_LISTENER_KEY,
this.onVisibilityChange.bind(this)
);
}
}
export class ComponentView {
constructor() {
this.restrict = 'E';
this.template = template;
this.scope = {
component: '=',
onLoad: '=?',
manualDealloc: '=?'
};
this.controller = ComponentViewCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
}
}

View File

@@ -1,302 +0,0 @@
import { protocolManager } from 'snjs';
import template from '%/directives/password-wizard.pug';
import { STRING_FAILED_PASSWORD_CHANGE } from '@/strings';
const DEFAULT_CONTINUE_TITLE = "Continue";
const Steps = {
IntroStep: 0,
BackupStep: 1,
SignoutStep: 2,
PasswordStep: 3,
SyncStep: 4,
FinishStep: 5
};
class PasswordWizardCtrl {
/* @ngInject */
constructor(
$element,
$scope,
$timeout,
alertManager,
archiveManager,
authManager,
modelManager,
syncManager,
) {
this.$element = $element;
this.$timeout = $timeout;
this.$scope = $scope;
this.alertManager = alertManager;
this.archiveManager = archiveManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.syncManager = syncManager;
this.registerWindowUnloadStopper();
}
$onInit() {
this.syncStatus = this.syncManager.syncStatus;
this.formData = {};
this.configureDefaults();
}
configureDefaults() {
if (this.type === 'change-pw') {
this.title = "Change Password";
this.changePassword = true;
} else if (this.type === 'upgrade-security') {
this.title = "Security Update";
this.securityUpdate = true;
}
this.continueTitle = DEFAULT_CONTINUE_TITLE;
this.step = Steps.IntroStep;
}
/** Confirms with user before closing tab */
registerWindowUnloadStopper() {
window.onbeforeunload = (e) => {
return true;
};
this.$scope.$on("$destroy", () => {
window.onbeforeunload = null;
});
}
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"
: "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";
default:
return null;
}
}
async nextStep() {
if (this.lockContinue || this.isContinuing) {
return;
}
this.isContinuing = true;
if (this.step === Steps.FinishStep) {
this.dismiss();
return;
}
const next = () => {
this.step++;
this.initializeStep(this.step);
this.isContinuing = false;
};
const preprocessor = this.preprocessorForStep(this.step);
if (preprocessor) {
await preprocessor().then((success) => {
if(success) {
next();
} else {
this.$timeout(() => {
this.isContinuing = false;
});
}
}).catch(() => {
this.isContinuing = false;
});
} else {
next();
}
}
preprocessorForStep(step) {
if (step === Steps.PasswordStep) {
return async () => {
this.showSpinner = true;
this.continueTitle = "Generating Keys...";
const success = await this.validateCurrentPassword();
this.showSpinner = false;
this.continueTitle = DEFAULT_CONTINUE_TITLE;
return success;
};
}
}
async initializeStep(step) {
if (step === Steps.SyncStep) {
await this.initializeSyncingStep();
} else if (step === Steps.FinishStep) {
this.continueTitle = "Finish";
}
}
async initializeSyncingStep() {
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) {
this.formData.status = "Unable to process your password. Please try again.";
return;
}
this.formData.status = "Encrypting and syncing data with new keys...";
const syncSuccess = await this.resyncData();
this.formData.statusError = !syncSuccess;
this.formData.processing = !syncSuccess;
if (syncSuccess) {
this.lockContinue = false;
if (this.changePassword) {
this.formData.status = "Successfully changed password and synced all items.";
} else if (this.securityUpdate) {
this.formData.status = "Successfully performed security update and synced all items.";
}
} else {
this.formData.status = STRING_FAILED_PASSWORD_CHANGE;
}
}
async validateCurrentPassword() {
const currentPassword = this.formData.currentPassword;
const newPass = this.securityUpdate ? currentPassword : this.formData.newPassword;
if (!currentPassword || currentPassword.length === 0) {
this.alertManager.alert({
text: "Please enter your current password."
});
return false;
}
if (this.changePassword) {
if (!newPass || newPass.length === 0) {
this.alertManager.alert({
text: "Please enter a new password."
});
return false;
}
if (newPass !== this.formData.newPasswordConfirmation) {
this.alertManager.alert({
text: "Your new password does not match its confirmation."
});
this.formData.status = null;
return false;
}
}
if (!this.authManager.user.email) {
this.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;
}
const minLength = this.authManager.getMinPasswordLength();
if (!this.securityUpdate && newPass.length < minLength) {
const message = `Your password must be at least ${minLength} characters in length. For your security, please choose a longer password or, ideally, a passphrase, and try again.`;
this.alertManager.alert({
text: message
});
return false;
}
/** Validate current password */
const authParams = await this.authManager.getAuthParams();
const password = this.formData.currentPassword;
const keys = await protocolManager.computeEncryptionKeysForUser(
password,
authParams
);
const success = keys.mk === (await this.authManager.keys()).mk;
if (success) {
this.currentServerPw = keys.pw;
} else {
this.alertManager.alert({
text: "The current password you entered is not correct. Please try again."
});
}
return success;
}
async resyncData() {
await this.modelManager.setAllItemsDirty();
const response = await this.syncManager.sync();
if (!response || response.error) {
this.alertManager.alert({
text: STRING_FAILED_PASSWORD_CHANGE
});
return false;
} else {
return true;
}
}
async processPasswordChange() {
const newUserPassword = this.securityUpdate
? this.formData.currentPassword
: this.formData.newPassword;
const currentServerPw = this.currentServerPw;
const results = await protocolManager.generateInitialKeysAndAuthParamsForUser(
this.authManager.user.email,
newUserPassword
);
const newKeys = results.keys;
const newAuthParams = results.authParams;
/**
* Perform a sync beforehand to pull in any last minutes changes before we change
* the encryption key (and thus cant decrypt new changes).
*/
await this.syncManager.sync();
const response = await this.authManager.changePassword(
await this.syncManager.getServerURL(),
this.authManager.user.email,
currentServerPw,
newKeys,
newAuthParams
);
if (response.error) {
this.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.alertManager.alert({
text: "Cannot close window until pending tasks are complete."
});
} else {
this.$element.remove();
this.$scope.$destroy();
}
}
}
export class PasswordWizard {
constructor() {
this.restrict = 'E';
this.template = template;
this.controller = PasswordWizardCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
type: '='
};
}
}

View File

@@ -167,8 +167,8 @@ class PasswordWizardCtrl extends PureViewCtrl implements PasswordWizardScope {
});
if (!success) {
this.application.alertService!.alert(
response!.error.message
? response!.error.message
response?.error?.message
? response.error.message
: "There was an error changing your password. Please try again."
);
this.setFormDataState({

View File

@@ -9,6 +9,7 @@ import {
} from 'snjs';
import template from '%/directives/revision-preview-modal.pug';
import { PayloadContent } from '@node_modules/snjs/dist/@types/protocol/payloads/generator';
import { confirmDialog } from '@/services/alertService';
interface RevisionPreviewScope {
uuid: string
@@ -88,7 +89,7 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
}
}
restore(asCopy: boolean) {
async restore(asCopy: boolean) {
const run = async () => {
if (asCopy) {
const contentCopy = Object.assign({}, this.content);
@@ -109,15 +110,12 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
};
if (!asCopy) {
this.application.alertService!.confirm(
"Are you sure you want to replace the current note's contents with what you see in this preview?",
undefined,
undefined,
undefined,
run,
undefined,
true,
);
if (await confirmDialog({
text: "Are you sure you want to replace the current note's contents with what you see in this preview?",
confirmButtonStyle: 'danger',
})) {
run();
}
} else {
run();
}

View File

@@ -2,6 +2,7 @@ import { WebDirective } from './../../types';
import { WebApplication } from '@/ui_models/application';
import template from '%/directives/session-history-menu.pug';
import { SNItem, ItemHistoryEntry, ItemHistory } from '@node_modules/snjs/dist/@types';
import { confirmDialog } from '@/services/alertService';
interface SessionHistoryScope {
application: WebApplication
@@ -57,43 +58,33 @@ class SessionHistoryMenuCtrl implements SessionHistoryScope {
}
}
clearItemHistory() {
this.application.alertService!.confirm(
"Are you sure you want to delete the local session history for this note?",
undefined,
undefined,
undefined,
() => {
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadHistory();
});
async clearItemHistory() {
if (await confirmDialog({
text: "Are you sure you want to delete the local session history for this note?",
confirmButtonStyle: 'danger',
})) {
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadHistory();
});
},
undefined,
true,
);
});
}
}
clearAllHistory() {
this.application.alertService!.confirm(
"Are you sure you want to delete the local session history for all notes?",
undefined,
undefined,
undefined,
() => {
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadHistory();
});
if (confirmDialog({
text: "Are you sure you want to delete the local session history for all notes?",
confirmButtonStyle: 'danger'
})) {
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadHistory();
});
},
undefined,
true,
);
});
}
}
toggleDiskSaving() {
async toggleDiskSaving() {
const run = () => {
this.application.historyManager!.toggleDiskSaving().then(() => {
this.$timeout(() => {
@@ -102,17 +93,14 @@ class SessionHistoryMenuCtrl implements SessionHistoryScope {
});
};
if (!this.application.historyManager!.isDiskEnabled()) {
this.application.alertService!.confirm(
`Are you sure you want to save history to disk? This will decrease general
performance, especially as you type. You are advised to disable this feature
if you experience any lagging.`,
undefined,
undefined,
undefined,
run,
undefined,
true,
);
if (await confirmDialog({
text: `Are you sure you want to save history to disk? This will decrease general
performance, especially as you type. You are advised to disable this feature
if you experience any lagging.`,
confirmButtonStyle: 'danger',
})) {
run();
}
} else {
run();
}

View File

@@ -1,163 +0,0 @@
import { PrivilegesManager } from '@/services/privilegesManager';
export class ArchiveManager {
/* @ngInject */
constructor(passcodeManager, authManager, modelManager, privilegesManager) {
this.passcodeManager = passcodeManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.privilegesManager = privilegesManager;
}
/*
Public
*/
async downloadBackup(encrypted) {
return this.downloadBackupOfItems(this.modelManager.allItems, encrypted);
}
async downloadBackupOfItems(items, encrypted) {
const run = async () => {
// download in Standard Notes format
let keys, authParams;
if(encrypted) {
if(this.authManager.offline() && this.passcodeManager.hasPasscode()) {
keys = this.passcodeManager.keys();
authParams = this.passcodeManager.passcodeAuthParams();
} else {
keys = await this.authManager.keys();
authParams = await this.authManager.getAuthParams();
}
const data = await this.__itemsData(items, keys, authParams);
this.__downloadData(data,
`Standard Notes Encrypted Backup and Import File - ${this.__formattedDate()}.txt`);
} else {
this.__downloadZippedItems(items);
}
};
if(await this.privilegesManager.actionRequiresPrivilege(PrivilegesManager.ActionManageBackups)) {
this.privilegesManager.presentPrivilegesModal(PrivilegesManager.ActionManageBackups, () => {
run();
});
} else {
run();
}
}
/*
Private
*/
__formattedDate() {
var string = `${new Date()}`;
// Match up to the first parenthesis, i.e do not include '(Central Standard Time)'
var matches = string.match(/^(.*?) \(/);
if(matches.length >= 2) {
return matches[1];
}
return string;
}
async __itemsData(items, keys, authParams) {
const data = await this.modelManager.getJSONDataForItems(items, keys, authParams);
const blobData = new Blob([data], {type: 'text/json'});
return blobData;
}
__loadZip(callback) {
if(window.zip) {
callback();
return;
}
var scriptTag = document.createElement('script');
scriptTag.src = "/assets/zip/zip.js";
scriptTag.async = false;
var headTag = document.getElementsByTagName('head')[0];
headTag.appendChild(scriptTag);
scriptTag.onload = function() {
zip.workerScriptsPath = "assets/zip/";
callback();
};
}
__downloadZippedItems(items) {
this.__loadZip(() => {
zip.createWriter(new zip.BlobWriter("application/zip"), async (zipWriter) => {
var index = 0;
const data = await this.modelManager.getJSONDataForItems(items);
await new Promise((resolve) => {
const blob = new Blob([data], {type: 'text/plain'});
zipWriter.add(
'Standard Notes Backup and Import File.txt',
new zip.BlobReader(blob),
resolve
);
});
const nextFile = () => {
var item = items[index];
var name, contents;
if(item.content_type === "Note") {
name = item.content.title;
contents = item.content.text;
} else {
name = item.content_type;
contents = JSON.stringify(item.content, null, 2);
}
if(!name) {
name = "";
}
const blob = new Blob([contents], {type: 'text/plain'});
let filePrefix = name.replace(/\//g, "").replace(/\\+/g, "");
const fileSuffix = `-${item.uuid.split("-")[0]}.txt`;
// Standard max filename length is 255. Slice the note name down to allow filenameEnd
filePrefix = filePrefix.slice(0, (255 - fileSuffix.length));
const fileName = `Items/${item.content_type}/${filePrefix}${fileSuffix}`;
zipWriter.add(fileName, new zip.BlobReader(blob), () => {
index++;
if(index < items.length) {
nextFile();
} else {
zipWriter.close((blob) => {
this.__downloadData(blob, `Standard Notes Backup - ${this.__formattedDate()}.zip`);
zipWriter = null;
});
}
});
};
nextFile();
}, onerror);
});
}
__hrefForData(data) {
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (this.textFile !== null) {
window.URL.revokeObjectURL(this.textFile);
}
this.textFile = window.URL.createObjectURL(data);
// returns a URL you can use as a href
return this.textFile;
}
__downloadData(data, fileName) {
var link = document.createElement('a');
link.setAttribute('download', fileName);
link.href = this.__hrefForData(data);
document.body.appendChild(link);
link.click();
link.remove();
}
}