feat: clear protection session

This commit is contained in:
Baptiste Grob
2021-02-15 15:36:36 +01:00
parent 42282d1bde
commit badff1568d
5 changed files with 187 additions and 109 deletions

View File

@@ -1,5 +1,5 @@
import { WebDirective } from './../../types'; import { WebDirective } from './../../types';
import { isDesktopApplication, preventRefreshing } from '@/utils'; import { isDesktopApplication, isSameDay, preventRefreshing } from '@/utils';
import template from '%/directives/account-menu.pug'; import template from '%/directives/account-menu.pug';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { import {
@@ -18,17 +18,22 @@ import {
STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE, STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE,
STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL, STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL,
STRING_UNSUPPORTED_BACKUP_FILE_VERSION, STRING_UNSUPPORTED_BACKUP_FILE_VERSION,
Strings Strings,
} from '@/strings'; } from '@/strings';
import { PasswordWizardType } from '@/types'; import { PasswordWizardType } from '@/types';
import { BackupFile, ContentType, Platform } from '@standardnotes/snjs'; import {
ApplicationEvent,
BackupFile,
ContentType,
Platform,
} from '@standardnotes/snjs';
import { confirmDialog, alertDialog } from '@/services/alertService'; import { confirmDialog, alertDialog } from '@/services/alertService';
import { autorun, IReactionDisposer } from 'mobx'; import { autorun, IReactionDisposer } from 'mobx';
import { storage, StorageKey } from '@/services/localStorage'; import { storage, StorageKey } from '@/services/localStorage';
import { import {
disableErrorReporting, disableErrorReporting,
enableErrorReporting, enableErrorReporting,
errorReportingId errorReportingId,
} from '@/services/errorReporting'; } from '@/services/errorReporting';
const ELEMENT_NAME_AUTH_EMAIL = 'email'; const ELEMENT_NAME_AUTH_EMAIL = 'email';
@@ -52,7 +57,7 @@ type FormData = {
passcode: string; passcode: string;
confirmPasscode: string; confirmPasscode: string;
changingPasscode: boolean; changingPasscode: boolean;
} };
type AccountMenuState = { type AccountMenuState = {
formData: Partial<FormData>; formData: Partial<FormData>;
@@ -72,21 +77,19 @@ type AccountMenuState = {
showSessions: boolean; showSessions: boolean;
errorReportingId: string | null; errorReportingId: string | null;
keyStorageInfo: string | null; keyStorageInfo: string | null;
} protectionsDisabledUntil: string | null;
};
class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> { class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
public appVersion: string;
public appVersion: string
/** @template */ /** @template */
private closeFunction?: () => void private closeFunction?: () => void;
private removeBetaWarningListener?: IReactionDisposer private removeBetaWarningListener?: IReactionDisposer;
private removeSyncObserver?: IReactionDisposer private removeSyncObserver?: IReactionDisposer;
private removeProtectionLengthObserver?: () => void;
/* @ngInject */ /* @ngInject */
constructor( constructor($timeout: ng.ITimeoutService, appVersion: string) {
$timeout: ng.ITimeoutService,
appVersion: string,
) {
super($timeout); super($timeout);
this.appVersion = appVersion; this.appVersion = appVersion;
} }
@@ -95,7 +98,9 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
getInitialState() { getInitialState() {
return { return {
appVersion: 'v' + ((window as any).electronAppVersion || this.appVersion), appVersion: 'v' + ((window as any).electronAppVersion || this.appVersion),
passcodeAutoLockOptions: this.application.getAutolockService().getAutoLockIntervalOptions(), passcodeAutoLockOptions: this.application
.getAutolockService()
.getAutoLockIntervalOptions(),
user: this.application.getUser(), user: this.application.getUser(),
formData: { formData: {
mergeLocal: true, mergeLocal: true,
@@ -103,12 +108,14 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
}, },
mutable: {}, mutable: {},
showBetaWarning: false, showBetaWarning: false,
errorReportingEnabled: storage.get(StorageKey.DisableErrorReporting) === false, errorReportingEnabled:
storage.get(StorageKey.DisableErrorReporting) === false,
showSessions: false, showSessions: false,
errorReportingId: errorReportingId(), errorReportingId: errorReportingId(),
keyStorageInfo: Strings.keyStorageInfo(this.application), keyStorageInfo: Strings.keyStorageInfo(this.application),
importData: null, importData: null,
syncInProgress: false, syncInProgress: false,
protectionsDisabledUntil: this.getProtectionsDisabledUntil(),
}; };
} }
@@ -134,14 +141,16 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
user: this.application.getUser(), user: this.application.getUser(),
canAddPasscode: !this.application.isEphemeralSession(), canAddPasscode: !this.application.isEphemeralSession(),
hasPasscode: this.application.hasPasscode(), hasPasscode: this.application.hasPasscode(),
showPasscodeForm: false showPasscodeForm: false,
}; };
} }
async $onInit() { async $onInit() {
super.$onInit(); super.$onInit();
this.setState({ this.setState({
showSessions: this.appState.enableUnfinishedFeatures && await this.application.userCanManageSessions() showSessions:
this.appState.enableUnfinishedFeatures &&
(await this.application.userCanManageSessions()),
}); });
const sync = this.appState.sync; const sync = this.appState.sync;
@@ -153,14 +162,24 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
}); });
this.removeBetaWarningListener = autorun(() => { this.removeBetaWarningListener = autorun(() => {
this.setState({ this.setState({
showBetaWarning: this.appState.showBetaWarning showBetaWarning: this.appState.showBetaWarning,
}); });
}); });
this.removeProtectionLengthObserver = this.application.addEventObserver(
async () => {
this.setState({
protectionsDisabledUntil: this.getProtectionsDisabledUntil(),
});
},
ApplicationEvent.ProtectionSessionExpiryDateChanged
);
} }
deinit() { deinit() {
this.removeSyncObserver?.(); this.removeSyncObserver?.();
this.removeBetaWarningListener?.(); this.removeBetaWarningListener?.();
this.removeProtectionLengthObserver?.();
super.deinit(); super.deinit();
} }
@@ -170,17 +189,46 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
}); });
} }
private getProtectionsDisabledUntil(): string | null {
const protectionExpiry = this.application.getProtectionSessionExpiryDate();
const now = new Date();
if (protectionExpiry > now) {
let f: Intl.DateTimeFormat;
if (isSameDay(protectionExpiry, now)) {
f = new Intl.DateTimeFormat(undefined, {
hour: 'numeric',
minute: 'numeric',
});
} else {
f = new Intl.DateTimeFormat(undefined, {
weekday: 'long',
day: 'numeric',
month: 'short',
hour: 'numeric',
minute: 'numeric',
});
}
return f.format(protectionExpiry);
}
return null;
}
async loadHost() { async loadHost() {
const host = await this.application!.getHost(); const host = await this.application.getHost();
this.setState({ this.setState({
server: host, server: host,
formData: { formData: {
...this.getState().formData, ...this.getState().formData,
url: host url: host,
} },
}); });
} }
enableProtections() {
this.application.clearProtectionSession();
}
onHostInputChange() { onHostInputChange() {
const url = this.getState().formData.url!; const url = this.getState().formData.url!;
this.application!.setHost(url); this.application!.setHost(url);
@@ -195,13 +243,13 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
encryptionStatusString: hasUser encryptionStatusString: hasUser
? STRING_E2E_ENABLED ? STRING_E2E_ENABLED
: hasPasscode : hasPasscode
? STRING_LOCAL_ENC_ENABLED ? STRING_LOCAL_ENC_ENABLED
: STRING_ENC_NOT_ENABLED, : STRING_ENC_NOT_ENABLED,
encryptionEnabled, encryptionEnabled,
mutable: { mutable: {
...this.getState().mutable, ...this.getState().mutable,
backupEncrypted: encryptionEnabled backupEncrypted: encryptionEnabled,
} },
}); });
} }
@@ -213,7 +261,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
const names = [ const names = [
ELEMENT_NAME_AUTH_EMAIL, ELEMENT_NAME_AUTH_EMAIL,
ELEMENT_NAME_AUTH_PASSWORD, ELEMENT_NAME_AUTH_PASSWORD,
ELEMENT_NAME_AUTH_PASSWORD_CONF ELEMENT_NAME_AUTH_PASSWORD_CONF,
]; ];
for (const name of names) { for (const name of names) {
const element = document.getElementsByName(name)[0]; const element = document.getElementsByName(name)[0];
@@ -224,7 +272,10 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
} }
submitAuthForm() { submitAuthForm() {
if (!this.getState().formData.email || !this.getState().formData.user_password) { if (
!this.getState().formData.email ||
!this.getState().formData.user_password
) {
return; return;
} }
this.blurAuthFields(); this.blurAuthFields();
@@ -239,15 +290,15 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
return this.setState({ return this.setState({
formData: { formData: {
...this.getState().formData, ...this.getState().formData,
...formData ...formData,
} },
}); });
} }
async login() { async login() {
await this.setFormDataState({ await this.setFormDataState({
status: STRING_GENERATING_LOGIN_KEYS, status: STRING_GENERATING_LOGIN_KEYS,
authenticating: true authenticating: true,
}); });
const formData = this.getState().formData; const formData = this.getState().formData;
const response = await this.application!.signIn( const response = await this.application!.signIn(
@@ -261,7 +312,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
if (!error) { if (!error) {
await this.setFormDataState({ await this.setFormDataState({
authenticating: false, authenticating: false,
user_password: undefined user_password: undefined,
}); });
this.close(); this.close();
return; return;
@@ -269,28 +320,26 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
await this.setFormDataState({ await this.setFormDataState({
showLogin: true, showLogin: true,
status: undefined, status: undefined,
user_password: undefined user_password: undefined,
}); });
if (error.message) { if (error.message) {
this.application!.alertService!.alert(error.message); this.application!.alertService!.alert(error.message);
} }
await this.setFormDataState({ await this.setFormDataState({
authenticating: false authenticating: false,
}); });
} }
async register() { async register() {
const confirmation = this.getState().formData.password_conf; const confirmation = this.getState().formData.password_conf;
if (confirmation !== this.getState().formData.user_password) { if (confirmation !== this.getState().formData.user_password) {
this.application!.alertService!.alert( this.application!.alertService!.alert(STRING_NON_MATCHING_PASSWORDS);
STRING_NON_MATCHING_PASSWORDS
);
return; return;
} }
await this.setFormDataState({ await this.setFormDataState({
confirmPassword: false, confirmPassword: false,
status: STRING_GENERATING_REGISTER_KEYS, status: STRING_GENERATING_REGISTER_KEYS,
authenticating: true authenticating: true,
}); });
const response = await this.application!.register( const response = await this.application!.register(
this.getState().formData.email!, this.getState().formData.email!,
@@ -301,14 +350,12 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
const error = response.error; const error = response.error;
if (error) { if (error) {
await this.setFormDataState({ await this.setFormDataState({
status: undefined status: undefined,
}); });
await this.setFormDataState({ await this.setFormDataState({
authenticating: false authenticating: false,
}); });
this.application!.alertService!.alert( this.application!.alertService!.alert(error.message);
error.message
);
} else { } else {
await this.setFormDataState({ authenticating: false }); await this.setFormDataState({ authenticating: false });
this.close(); this.close();
@@ -320,8 +367,8 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
this.setFormDataState({ this.setFormDataState({
mergeLocal: !(await confirmDialog({ mergeLocal: !(await confirmDialog({
text: STRING_ACCOUNT_MENU_UNCHECK_MERGE, text: STRING_ACCOUNT_MENU_UNCHECK_MERGE,
confirmButtonStyle: 'danger' confirmButtonStyle: 'danger',
})) })),
}); });
} }
} }
@@ -337,17 +384,19 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
} }
async destroyLocalData() { async destroyLocalData() {
if (await confirmDialog({ if (
text: STRING_SIGN_OUT_CONFIRMATION, await confirmDialog({
confirmButtonStyle: "danger" text: STRING_SIGN_OUT_CONFIRMATION,
})) { confirmButtonStyle: 'danger',
})
) {
this.application.signOut(); this.application.signOut();
} }
} }
showRegister() { showRegister() {
this.setFormDataState({ this.setFormDataState({
showRegister: true showRegister: true,
}); });
} }
@@ -359,9 +408,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
const data = JSON.parse(e.target!.result as string); const data = JSON.parse(e.target!.result as string);
resolve(data); resolve(data);
} catch (e) { } catch (e) {
this.application!.alertService!.alert( this.application!.alertService!.alert(STRING_INVALID_IMPORT_FILE);
STRING_INVALID_IMPORT_FILE
);
} }
}; };
reader.readAsText(file); reader.readAsText(file);
@@ -378,7 +425,8 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
return; return;
} }
if (data.version || data.auth_params || data.keyParams) { if (data.version || data.auth_params || data.keyParams) {
const version = data.version || data.keyParams?.version || data.auth_params?.version; const version =
data.version || data.keyParams?.version || data.auth_params?.version;
if ( if (
this.application.protocolService.supportedVersions().includes(version) this.application.protocolService.supportedVersions().includes(version)
) { ) {
@@ -396,52 +444,50 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
await this.setState({ await this.setState({
importData: { importData: {
...this.getState().importData, ...this.getState().importData,
loading: true loading: true,
} },
}); });
const result = await this.application.importData(data); const result = await this.application.importData(data);
this.setState({ this.setState({
importData: null importData: null,
}); });
if (!result) { if (!result) {
return; return;
} else if ('error' in result) { } else if ('error' in result) {
void alertDialog({ void alertDialog({
text: result.error text: result.error,
}); });
} else if (result.errorCount) { } else if (result.errorCount) {
void alertDialog({ void alertDialog({
text: StringImportError(result.errorCount) text: StringImportError(result.errorCount),
}); });
} else { } else {
void alertDialog({ void alertDialog({
text: STRING_IMPORT_SUCCESS text: STRING_IMPORT_SUCCESS,
}); });
} }
} }
async downloadDataArchive() { async downloadDataArchive() {
this.application.getArchiveService().downloadBackup(this.getState().mutable.backupEncrypted); this.application
.getArchiveService()
.downloadBackup(this.getState().mutable.backupEncrypted);
} }
notesAndTagsCount() { notesAndTagsCount() {
return this.application.getItems( return this.application.getItems([ContentType.Note, ContentType.Tag])
[ .length;
ContentType.Note,
ContentType.Tag
]
).length;
} }
encryptionStatusForNotes() { encryptionStatusForNotes() {
const length = this.notesAndTagsCount(); const length = this.notesAndTagsCount();
return length + "/" + length + " notes and tags encrypted"; return length + '/' + length + ' notes and tags encrypted';
} }
async reloadAutoLockInterval() { async reloadAutoLockInterval() {
const interval = await this.application!.getAutolockService().getAutoLockInterval(); const interval = await this.application!.getAutolockService().getAutoLockInterval();
this.setState({ this.setState({
selectedAutoLockInterval: interval selectedAutoLockInterval: interval,
}); });
} }
@@ -458,7 +504,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
showLogin: false, showLogin: false,
showRegister: false, showRegister: false,
user_password: undefined, user_password: undefined,
password_conf: undefined password_conf: undefined,
}); });
} }
@@ -468,30 +514,31 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
addPasscodeClicked() { addPasscodeClicked() {
this.setFormDataState({ this.setFormDataState({
showPasscodeForm: true showPasscodeForm: true,
}); });
} }
async submitPasscodeForm() { async submitPasscodeForm() {
const passcode = this.getState().formData.passcode!; const passcode = this.getState().formData.passcode!;
if (passcode !== this.getState().formData.confirmPasscode!) { if (passcode !== this.getState().formData.confirmPasscode!) {
this.application!.alertService!.alert( this.application!.alertService!.alert(STRING_NON_MATCHING_PASSCODES);
STRING_NON_MATCHING_PASSCODES
);
return; return;
} }
await preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE, async () => { await preventRefreshing(
if (this.application!.hasPasscode()) { STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE,
await this.application!.changePasscode(passcode); async () => {
} else { if (this.application!.hasPasscode()) {
await this.application!.setPasscode(passcode); await this.application!.changePasscode(passcode);
} else {
await this.application!.setPasscode(passcode);
}
} }
}); );
this.setFormDataState({ this.setFormDataState({
passcode: undefined, passcode: undefined,
confirmPasscode: undefined, confirmPasscode: undefined,
showPasscodeForm: false showPasscodeForm: false,
}); });
this.refreshEncryptionStatus(); this.refreshEncryptionStatus();
} }
@@ -502,13 +549,18 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
} }
async removePasscodePressed() { async removePasscodePressed() {
await preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL, async () => { await preventRefreshing(
if (await this.application!.removePasscode()) { STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL,
await this.application.getAutolockService().deleteAutolockPreference(); async () => {
await this.reloadAutoLockInterval(); if (await this.application!.removePasscode()) {
this.refreshEncryptionStatus(); await this.application
.getAutolockService()
.deleteAutolockPreference();
await this.reloadAutoLockInterval();
this.refreshEncryptionStatus();
}
} }
}); );
} }
openErrorReportingDialog() { openErrorReportingDialog() {
@@ -526,7 +578,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
anonymized. We use error reports to be alerted when something in our anonymized. We use error reports to be alerted when something in our
code is causing unexpected errors and crashes in your application code is causing unexpected errors and crashes in your application
experience. experience.
` `,
}); });
} }
@@ -556,7 +608,7 @@ export class AccountMenu extends WebDirective {
this.bindToController = true; this.bindToController = true;
this.scope = { this.scope = {
closeFunction: '&', closeFunction: '&',
application: '=' application: '=',
}; };
} }
} }

View File

@@ -1,9 +1,9 @@
import { Platform, platformFromString } from "@standardnotes/snjs"; import { Platform, platformFromString } from '@standardnotes/snjs';
declare const process : { declare const process: {
env: { env: {
NODE_ENV: string | null | undefined NODE_ENV: string | null | undefined;
} };
}; };
export const isDev = process.env.NODE_ENV === 'development'; export const isDev = process.env.NODE_ENV === 'development';
@@ -36,11 +36,10 @@ let sharedDateFormatter: Intl.DateTimeFormat;
export function dateToLocalizedString(date: Date) { export function dateToLocalizedString(date: Date) {
if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) { if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
if (!sharedDateFormatter) { if (!sharedDateFormatter) {
const locale = ( const locale =
(navigator.languages && navigator.languages.length) navigator.languages && navigator.languages.length
? navigator.languages[0] ? navigator.languages[0]
: navigator.language : navigator.language;
);
sharedDateFormatter = new Intl.DateTimeFormat(locale, { sharedDateFormatter = new Intl.DateTimeFormat(locale, {
year: 'numeric', year: 'numeric',
month: 'numeric', month: 'numeric',
@@ -58,8 +57,21 @@ export function dateToLocalizedString(date: Date) {
} }
} }
export function isSameDay(dateA: Date, dateB: Date): boolean {
return (
dateA.getFullYear() === dateB.getFullYear() &&
dateA.getMonth() === dateB.getMonth() &&
dateA.getDate() === dateB.getDate()
);
}
/** Via https://davidwalsh.name/javascript-debounce-function */ /** Via https://davidwalsh.name/javascript-debounce-function */
export function debounce(this: any, func: any, wait: number, immediate = false) { export function debounce(
this: any,
func: any,
wait: number,
immediate = false
) {
let timeout: any; let timeout: any;
return () => { return () => {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
@@ -131,7 +143,7 @@ if (!Array.prototype.includes) {
// 8. Return false // 8. Return false
return false; return false;
} },
}); });
} }
@@ -153,7 +165,9 @@ declare const __WEB__: boolean;
declare const __DESKTOP__: boolean; declare const __DESKTOP__: boolean;
if (!__WEB__ && !__DESKTOP__) { if (!__WEB__ && !__DESKTOP__) {
throw Error('Neither __WEB__ nor __DESKTOP__ is true. Check your configuration files.'); throw Error(
'Neither __WEB__ nor __DESKTOP__ is true. Check your configuration files.'
);
} }
export function isDesktopApplication() { export function isDesktopApplication() {

View File

@@ -164,6 +164,19 @@
| {{self.encryptionStatusForNotes()}} | {{self.encryptionStatusForNotes()}}
p.sk-p p.sk-p
| {{self.state.encryptionStatusString}} | {{self.state.encryptionStatusString}}
.sk-panel-section
.sk-panel-section-title Protections
.sk-panel-section-subtitle.info(ng-if="self.state.protectionsDisabledUntil")
| Protections are disabled until {{self.state.protectionsDisabledUntil}}
.sk-panel-section-subtitle.info(ng-if="!self.state.protectionsDisabledUntil")
| Protections are enabled
p.sk-p
| Actions like viewing protected notes, exporting decrypted backups,
| or revoking an active session, require additional authentication
| like entering your account password or application passcode.
.sk-panel-row(ng-if="self.state.protectionsDisabledUntil")
button.sk-button.info(ng-click="self.enableProtections()")
span.sk-label Enable protections
.sk-panel-section .sk-panel-section
.sk-panel-section-title Passcode Lock .sk-panel-section-title Passcode Lock
div(ng-if='!self.state.hasPasscode') div(ng-if='!self.state.hasPasscode')
@@ -206,8 +219,7 @@
ng-click='self.state.formData.showPasscodeForm = false' ng-click='self.state.formData.showPasscodeForm = false'
) Cancel ) Cancel
div(ng-if='self.state.hasPasscode && !self.state.formData.showPasscodeForm') div(ng-if='self.state.hasPasscode && !self.state.formData.showPasscodeForm')
.sk-p .sk-panel-section-subtitle.info Passcode lock is enabled
| Passcode lock is enabled.
.sk-notification.contrast .sk-notification.contrast
.sk-notification-title Options .sk-notification-title Options
.sk-notification-text .sk-notification-text
@@ -273,7 +285,7 @@
.sk-panel-section .sk-panel-section
.sk-panel-section-title Error Reporting .sk-panel-section-title Error Reporting
.sk-panel-section-subtitle.info .sk-panel-section-subtitle.info
| Automatic error reporting is {{ self.state.errorReportingEnabled ? 'enabled.' : 'disabled.' }} | Automatic error reporting is {{ self.state.errorReportingEnabled ? 'enabled' : 'disabled' }}
p.sk-p p.sk-p
| Help us improve Standard Notes by automatically submitting | Help us improve Standard Notes by automatically submitting
| anonymized error reports. | anonymized error reports.

View File

@@ -71,7 +71,7 @@
"@reach/alert-dialog": "^0.13.0", "@reach/alert-dialog": "^0.13.0",
"@reach/dialog": "^0.13.0", "@reach/dialog": "^0.13.0",
"@standardnotes/sncrypto-web": "^1.2.10", "@standardnotes/sncrypto-web": "^1.2.10",
"@standardnotes/snjs": "^2.0.53", "@standardnotes/snjs": "^2.0.54",
"mobx": "^6.1.6", "mobx": "^6.1.6",
"preact": "^10.5.12" "preact": "^10.5.12"
} }

View File

@@ -1845,10 +1845,10 @@
"@standardnotes/sncrypto-common" "^1.2.7" "@standardnotes/sncrypto-common" "^1.2.7"
libsodium-wrappers "^0.7.8" libsodium-wrappers "^0.7.8"
"@standardnotes/snjs@^2.0.53": "@standardnotes/snjs@^2.0.54":
version "2.0.53" version "2.0.54"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.53.tgz#ec89668fef57bf154dc0e145e4bc883cbe6be241" resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.54.tgz#dab1dbf0405c2671aa73e4dbb944863bd434f629"
integrity sha512-9mlSitWXCBnQtMwhHMIV6/BaLIUXzWuQIMKkqWn43XYojnF33avEJteu0ciffZMAW9A2S7ORerRBVBbJxlqtdg== integrity sha512-q1FErsVthiLpOarpKohoZhvXb8BGvgCBpXzbDZ64/15L2lErFUTYbXxyklBTy5DCbULwUh7wBvkm74JF10Ghlg==
dependencies: dependencies:
"@standardnotes/sncrypto-common" "^1.2.9" "@standardnotes/sncrypto-common" "^1.2.9"