From fb9bd37d72ddd87d5d4dd88eebb16217a929c3e0 Mon Sep 17 00:00:00 2001 From: Mo Date: Thu, 17 Mar 2022 12:19:07 -0500 Subject: [PATCH] feat: privacy prefs (#935) * chore: move all components into Components dir with pascal case * feat: privacy prefs * chore: upgrade deps --- .../javascripts/components/ChallengeModal.tsx | 4 +- .../components/ConfirmSignoutModal.tsx | 2 +- .../components/Preferences/panes/Security.tsx | 4 + .../panes/backups-segments/EmailBackups.tsx | 26 ++- .../cloud-backups/CloudBackupProvider.tsx | 21 ++- .../backups-segments/cloud-backups/index.tsx | 28 +-- .../panes/security-segments/Privacy.tsx | 166 ++++++++++++++++++ .../javascripts/ui_models/application.ts | 2 +- package.json | 14 +- yarn.lock | 94 +++++----- 10 files changed, 273 insertions(+), 88 deletions(-) create mode 100644 app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx diff --git a/app/assets/javascripts/components/ChallengeModal.tsx b/app/assets/javascripts/components/ChallengeModal.tsx index 0eee7d25d..ec98b8426 100644 --- a/app/assets/javascripts/components/ChallengeModal.tsx +++ b/app/assets/javascripts/components/ChallengeModal.tsx @@ -123,13 +123,13 @@ export class ChallengeModal extends PureComponent { }) ) { this.dismiss(); - this.application.signOut(); + this.application.user.signOut(); } }; cancel = () => { if (this.props.challenge.cancelable) { - this.application!.cancelChallenge(this.props.challenge); + this.application.cancelChallenge(this.props.challenge); } }; diff --git a/app/assets/javascripts/components/ConfirmSignoutModal.tsx b/app/assets/javascripts/components/ConfirmSignoutModal.tsx index 62f15b3da..366f27194 100644 --- a/app/assets/javascripts/components/ConfirmSignoutModal.tsx +++ b/app/assets/javascripts/components/ConfirmSignoutModal.tsx @@ -93,7 +93,7 @@ export const ConfirmSignoutModal = observer( if (deleteLocalBackups) { application.signOutAndDeleteLocalBackups(); } else { - application.signOut(); + application.user.signOut(); } closeDialog(); }} diff --git a/app/assets/javascripts/components/Preferences/panes/Security.tsx b/app/assets/javascripts/components/Preferences/panes/Security.tsx index 900940d7a..8c4686310 100644 --- a/app/assets/javascripts/components/Preferences/panes/Security.tsx +++ b/app/assets/javascripts/components/Preferences/panes/Security.tsx @@ -3,6 +3,7 @@ import { AppState } from '@/ui_models/app_state'; import { FunctionComponent } from 'preact'; import { PreferencesPane } from '../components'; import { Encryption, PasscodeLock, Protections } from './security-segments'; +import { Privacy } from './security-segments/Privacy'; import { TwoFactorAuthWrapper } from './two-factor-auth'; import { MfaProps } from './two-factor-auth/MfaProps'; @@ -20,5 +21,8 @@ export const Security: FunctionComponent = (props) => ( userProvider={props.userProvider} /> + {props.appState.enableUnfinishedFeatures && ( + + )} ); diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx index 99e664eb3..58f58e082 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx @@ -13,7 +13,11 @@ import { Text, Title, } from '../../components'; -import { EmailBackupFrequency, SettingName } from '@standardnotes/settings'; +import { + EmailBackupFrequency, + MuteFailedBackupsEmailsOption, + SettingName, +} from '@standardnotes/settings'; import { Dropdown, DropdownItem } from '@/components/Dropdown'; import { Switch } from '@/components/Switch'; import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; @@ -44,14 +48,19 @@ export const EmailBackups = observer(({ application }: Props) => { setIsLoading(true); try { - const userSettings = await application.listSettings(); + const userSettings = await application.settings.listSettings(); setEmailFrequency( - (userSettings.EMAIL_BACKUP_FREQUENCY || - EmailBackupFrequency.Disabled) as EmailBackupFrequency + userSettings.getSettingValue( + SettingName.EmailBackupFrequency, + EmailBackupFrequency.Disabled + ) ); setIsFailedBackupEmailMuted( convertStringifiedBooleanToBoolean( - userSettings[SettingName.MuteFailedBackupsEmails] as string + userSettings.getSettingValue( + SettingName.MuteFailedBackupsEmails, + MuteFailedBackupsEmailsOption.NotMuted + ) ) ); } catch (error) { @@ -75,7 +84,10 @@ export const EmailBackups = observer(({ application }: Props) => { EmailBackupFrequency[frequency as keyof typeof EmailBackupFrequency]; frequencyOptions.push({ value: frequencyValue, - label: application.getEmailBackupFrequencyOptionLabel(frequencyValue), + label: + application.settings.getEmailBackupFrequencyOptionLabel( + frequencyValue + ), }); } setEmailFrequencyOptions(frequencyOptions); @@ -88,7 +100,7 @@ export const EmailBackups = observer(({ application }: Props) => { payload: string ): Promise => { try { - await application.updateSetting(settingName, payload); + await application.settings.updateSetting(settingName, payload, false); return true; } catch (e) { application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING); diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx index 09070c520..b44f521e4 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useCallback, useEffect, useState } from 'preact/hooks'; import { ButtonType, SettingName } from '@standardnotes/snjs'; import { @@ -27,7 +26,9 @@ export const CloudBackupProvider: FunctionComponent = ({ }) => { const [authBegan, setAuthBegan] = useState(false); const [successfullyInstalled, setSuccessfullyInstalled] = useState(false); - const [backupFrequency, setBackupFrequency] = useState(null); + const [backupFrequency, setBackupFrequency] = useState( + undefined + ); const [confirmation, setConfirmation] = useState(''); const disable = async (event: Event) => { @@ -42,10 +43,10 @@ export const CloudBackupProvider: FunctionComponent = ({ 'Cancel' ); if (shouldDisable) { - await application.deleteSetting(backupFrequencySettingName); - await application.deleteSetting(backupTokenSettingName); + await application.settings.deleteSetting(backupFrequencySettingName); + await application.settings.deleteSetting(backupTokenSettingName); - setBackupFrequency(null); + setBackupFrequency(undefined); } } catch (error) { application.alertService.alert(error as string); @@ -66,7 +67,7 @@ export const CloudBackupProvider: FunctionComponent = ({ const performBackupNow = async () => { // A backup is performed anytime the setting is updated with the integration token, so just update it here try { - await application.updateSetting( + await application.settings.updateSetting( backupFrequencySettingName, backupFrequency as string ); @@ -134,11 +135,11 @@ export const CloudBackupProvider: FunctionComponent = ({ if (!cloudProviderToken) { throw new Error(); } - await application.updateSetting( + await application.settings.updateSetting( backupTokenSettingName, cloudProviderToken ); - await application.updateSetting( + await application.settings.updateSetting( backupFrequencySettingName, defaultBackupFrequency ); @@ -166,7 +167,9 @@ export const CloudBackupProvider: FunctionComponent = ({ if (!application.getUser()) { return; } - const frequency = await application.getSetting(backupFrequencySettingName); + const frequency = await application.settings.getSetting( + backupFrequencySettingName + ); setBackupFrequency(frequency); }, [application, backupFrequencySettingName]); diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx index dbc6115d2..77106a07b 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { CloudBackupProvider } from './CloudBackupProvider'; import { useCallback, useEffect, useState } from 'preact/hooks'; import { WebApplication } from '@/ui_models/application'; @@ -13,21 +12,19 @@ import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; import { FeatureIdentifier } from '@standardnotes/features'; import { FeatureStatus } from '@standardnotes/snjs'; import { FunctionComponent } from 'preact'; -import { CloudProvider, SettingName } from '@standardnotes/settings'; +import { + CloudProvider, + MuteFailedCloudBackupsEmailsOption, + SettingName, +} from '@standardnotes/settings'; import { Switch } from '@/components/Switch'; import { convertStringifiedBooleanToBoolean } from '@/utils'; import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/strings'; const providerData = [ - { - name: CloudProvider.Dropbox, - }, - { - name: CloudProvider.Google, - }, - { - name: CloudProvider.OneDrive, - }, + { name: CloudProvider.Dropbox }, + { name: CloudProvider.Google }, + { name: CloudProvider.OneDrive }, ]; type Props = { @@ -51,10 +48,13 @@ export const CloudLink: FunctionComponent = ({ application }) => { setIsLoading(true); try { - const userSettings = await application.listSettings(); + const userSettings = await application.settings.listSettings(); setIsFailedCloudBackupEmailMuted( convertStringifiedBooleanToBoolean( - userSettings[SettingName.MuteFailedCloudBackupsEmails] as string + userSettings.getSettingValue( + SettingName.MuteFailedCloudBackupsEmails, + MuteFailedCloudBackupsEmailsOption.NotMuted + ) ) ); } catch (error) { @@ -89,7 +89,7 @@ export const CloudLink: FunctionComponent = ({ application }) => { payload: string ): Promise => { try { - await application.updateSetting(settingName, payload); + await application.settings.updateSetting(settingName, payload); return true; } catch (e) { application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING); diff --git a/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx b/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx new file mode 100644 index 000000000..78277a96a --- /dev/null +++ b/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx @@ -0,0 +1,166 @@ +import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; +import { Switch } from '@/components/Switch'; +import { + PreferencesGroup, + PreferencesSegment, + Subtitle, + Text, + Title, +} from '@/components/Preferences/components'; +import { WebApplication } from '@/ui_models/application'; +import { + MuteSignInEmailsOption, + LogSessionUserAgentOption, + SettingName, +} from '@standardnotes/settings'; +import { observer } from 'mobx-react-lite'; +import { FunctionalComponent } from 'preact'; +import { useCallback, useEffect, useState } from 'preact/hooks'; +import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/strings'; + +type Props = { + application: WebApplication; +}; + +export const Privacy: FunctionalComponent = observer( + ({ application }: Props) => { + const [signInEmailsMutedValue, setSignInEmailsMutedValue] = + useState(MuteSignInEmailsOption.NotMuted); + const [sessionUaLoggingValue, setSessionUaLoggingValue] = + useState(LogSessionUserAgentOption.Enabled); + const [isLoading, setIsLoading] = useState(false); + + const updateSetting = async ( + settingName: SettingName, + payload: string + ): Promise => { + try { + await application.settings.updateSetting(settingName, payload, false); + return true; + } catch (e) { + application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING); + return false; + } + }; + + const loadSettings = useCallback(async () => { + if (!application.getUser()) { + return; + } + setIsLoading(true); + + try { + const userSettings = await application.settings.listSettings(); + setSignInEmailsMutedValue( + userSettings.getSettingValue( + SettingName.MuteSignInEmails, + MuteSignInEmailsOption.NotMuted + ) + ); + setSessionUaLoggingValue( + userSettings.getSettingValue( + SettingName.LogSessionUserAgent, + LogSessionUserAgentOption.Enabled + ) + ); + } catch (error) { + console.error(error); + } finally { + setIsLoading(false); + } + }, [application]); + + useEffect(() => { + loadSettings(); + }, [loadSettings]); + + const toggleMuteSignInEmails = async () => { + const previousValue = signInEmailsMutedValue; + const newValue = + previousValue === MuteSignInEmailsOption.Muted + ? MuteSignInEmailsOption.NotMuted + : MuteSignInEmailsOption.Muted; + setSignInEmailsMutedValue(newValue); + + const updateResult = await updateSetting( + SettingName.MuteSignInEmails, + newValue + ); + + if (!updateResult) { + setSignInEmailsMutedValue(previousValue); + } + }; + + const toggleSessionLogging = async () => { + const previousValue = sessionUaLoggingValue; + const newValue = + previousValue === LogSessionUserAgentOption.Enabled + ? LogSessionUserAgentOption.Disabled + : LogSessionUserAgentOption.Enabled; + setSessionUaLoggingValue(newValue); + + const updateResult = await updateSetting( + SettingName.LogSessionUserAgent, + newValue + ); + + if (!updateResult) { + setSessionUaLoggingValue(previousValue); + } + }; + + return ( + + + Privacy +
+
+
+ Disable sign-in notification emails + + Disables email notifications when a new sign-in occurs on your + account. (Email notifications are available to paid + subscribers). + +
+ {isLoading ? ( +
+ ) : ( + + )} +
+ +
+
+ Session user agent logging + + User agent logging allows you to identify the devices or + browsers signed into your account. For increased privacy, you + can disable this feature, which will remove all saved user + agent values from our server, and disable future logging of + this value. + +
+ {isLoading ? ( +
+ ) : ( + + )} +
+
+ + + ); + } +); diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index e75cffd3a..8d06cd055 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -149,6 +149,6 @@ export class WebApplication extends SNApplication { async signOutAndDeleteLocalBackups(): Promise { await this.bridge.deleteLocalBackups(); - return this.signOut(); + return this.user.signOut(); } } diff --git a/package.json b/package.json index 3cce0bd38..c7e811a57 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "@babel/preset-typescript": "^7.16.7", "@reach/disclosure": "^0.16.2", "@reach/visually-hidden": "^0.16.0", - "@standardnotes/responses": "1.3.13", - "@standardnotes/services": "1.6.2", + "@standardnotes/responses": "1.3.14", + "@standardnotes/services": "1.6.3", "@standardnotes/stylekit": "5.17.0", "@svgr/webpack": "^6.2.1", "@types/jest": "^27.4.1", @@ -70,13 +70,13 @@ "@reach/listbox": "^0.16.2", "@reach/tooltip": "^0.16.2", "@standardnotes/components": "1.7.12", - "@standardnotes/features": "1.34.12", + "@standardnotes/features": "1.35.0", "@standardnotes/filepicker": "1.10.0", - "@standardnotes/settings": "1.13.0", + "@standardnotes/settings": "1.13.1", "@standardnotes/sncrypto-web": "1.8.0", - "@standardnotes/snjs": "2.85.3", - "@zip.js/zip.js": "^2.4.6", - "mobx": "^6.4.2", + "@standardnotes/snjs": "2.86.2", + "@zip.js/zip.js": "^2.4.7", + "mobx": "^6.5.0", "mobx-react-lite": "^3.3.0", "preact": "^10.6.6", "qrcode.react": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index a650cd8b1..d31fb90de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2363,18 +2363,18 @@ resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.12.tgz#c87c3c8d90c0030b711d4f59aae47e14c745ea2a" integrity sha512-geE3xpBagZFJCucvFymUK4qIWT45nb8OXGW8Ck0EJothVSbz4rF3MJJ/W1pvI6+kYKbT12AaUoGecL6uKxi+1Q== -"@standardnotes/domain-events@^2.24.9": - version "2.24.9" - resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.24.9.tgz#5e68e35894ff396e859d79a98d1282d5d3c67cda" - integrity sha512-k5akmrT0JrcRyt4VP8c+Vo1lBACi73bL3zwF2TR5GoM8mRGRR9kRC/jro8OKIxzHTNUgHv+c50xn1PXvvt6iTw== +"@standardnotes/domain-events@^2.25.0": + version "2.25.0" + resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.25.0.tgz#73d003967cb2b8af8afc6d26360d9af99db928fe" + integrity sha512-o9k07Urfs8u04P9TGS7vA/ol5PQ6pi7BeejHWbWInCQ/kXgHcVHJkWBPsEPRxDboLzhju7ivbzUMYlEBmkj1vw== dependencies: "@standardnotes/auth" "^3.17.7" - "@standardnotes/features" "^1.34.12" + "@standardnotes/features" "^1.35.0" -"@standardnotes/features@1.34.12", "@standardnotes/features@^1.34.12": - version "1.34.12" - resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.34.12.tgz#d900c75318f97457ddbdcf09910f8bf818a2351a" - integrity sha512-QhZsbDoxEHZ93b2u3zWzSk2vQYUlxD/QctmH5csOkMrHVk9HWIku30tt/ZvV/xzCfU9tYVkIT29h6NJuFVaxtQ== +"@standardnotes/features@1.35.0", "@standardnotes/features@^1.35.0": + version "1.35.0" + resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.35.0.tgz#2f3d1f1e7831ec86cf265227f4b61fbf5e245aa2" + integrity sha512-ysibgtv9KoxYsD7f77Vn4DmViDnWeLANGtGwn6uUBnQbKHzuClFmSqBfAB7rmpu+1IRc+dfL8TlkPIwY2xvWqw== dependencies: "@standardnotes/auth" "^3.17.7" "@standardnotes/common" "^1.16.0" @@ -2384,40 +2384,40 @@ resolved "https://registry.yarnpkg.com/@standardnotes/filepicker/-/filepicker-1.10.0.tgz#bd9b283ef2f62989f05913aa79d830e40e073186" integrity sha512-LhWghEm9d9PaUUoE/kqwYfdE5CCPbKTbVEpY+hZXHLeZgubtHROLtzuEc4HDYkL7yG2aU/pcwsAwsKIqdWbs4A== -"@standardnotes/payloads@^1.4.12": - version "1.4.12" - resolved "https://registry.yarnpkg.com/@standardnotes/payloads/-/payloads-1.4.12.tgz#7bf3d53c77b196e8086ce5a4da29ace59bad43af" - integrity sha512-WXYbf1VscV2zGBM7X2kZiUb405X7ZRygLVqJ2q4iNBWU3/h0RWcYwZrMwy9/+FXWMaEgqAYDMh40vKrvTCr/Vw== +"@standardnotes/payloads@^1.4.13": + version "1.4.13" + resolved "https://registry.yarnpkg.com/@standardnotes/payloads/-/payloads-1.4.13.tgz#0a783b88f5f2902e2942a6ed0027e3ad75c26fd6" + integrity sha512-bTBspA/QzZluYUbak09Cg0U9TOA/R4PJ3InehpY+yO4LbtrE0YhegZyoO5pFgI2ftuXPtJTn6d8ilDV+C1PCMQ== dependencies: "@standardnotes/applications" "^1.2.2" "@standardnotes/common" "^1.16.0" - "@standardnotes/features" "^1.34.12" + "@standardnotes/features" "^1.35.0" "@standardnotes/utils" "^1.4.0" -"@standardnotes/responses@1.3.13", "@standardnotes/responses@^1.3.13": - version "1.3.13" - resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.13.tgz#05fa6bc0b68a3df209d0f26475e988d1df097d3a" - integrity sha512-T6iV0eUed+ERYR6RKamHKMmsazAjEBPbYv7r6h7ljhoYR3gyCZelm2lxr8X2gA6hEb4yxXYLbaEPZIJRaNMCSQ== +"@standardnotes/responses@1.3.14", "@standardnotes/responses@^1.3.14": + version "1.3.14" + resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.14.tgz#6a5d34490cb7a26dce0af23da8aa832aac7ca3f7" + integrity sha512-+U2fVoYJiSfJYGnbk2BDJnnSnYhDZx/pV5rRZOreEA/s2xNPw2wiCENdiKHKCAqyuDUdtBuxWA2STfcU6MkpGA== dependencies: "@standardnotes/auth" "^3.17.7" "@standardnotes/common" "^1.16.0" - "@standardnotes/features" "^1.34.12" - "@standardnotes/payloads" "^1.4.12" + "@standardnotes/features" "^1.35.0" + "@standardnotes/payloads" "^1.4.13" -"@standardnotes/services@1.6.2", "@standardnotes/services@^1.6.2": - version "1.6.2" - resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.2.tgz#20e11854341993e619c8755e62c008adc8481242" - integrity sha512-GDvYQxQ7Qrf0sbeMvZqbtARleorXACuxT5mBEQiPQkQwbZoS0OPcBwb7Tx2mVwKCcXitrqOIoclsvtmGj/x2QA== +"@standardnotes/services@1.6.3", "@standardnotes/services@^1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.3.tgz#27223ea7bb28334e3118ba9351c752b3584f3c63" + integrity sha512-p5wjHF0xaInMGQE2wVelboGp+YAYZtIQMOkA++hrIWuwziH+G+Hq2NthHtopx72kGzK8VZ+1Ay+9CRwXx+SMrg== dependencies: "@standardnotes/applications" "^1.2.2" "@standardnotes/common" "^1.16.0" - "@standardnotes/responses" "^1.3.13" + "@standardnotes/responses" "^1.3.14" "@standardnotes/utils" "^1.4.0" -"@standardnotes/settings@1.13.0", "@standardnotes/settings@^1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.0.tgz#dccd585ded6d556144a9063914b80154b79ea6d9" - integrity sha512-IMX9R6Zcnol0Ub6ja/K/v1fD2bIp71OTjDSxHw85vNUpcHqVjv7E2u4Zh6kRb2imPhHIY5E6WGoZ5IBtIdJV+Q== +"@standardnotes/settings@1.13.1", "@standardnotes/settings@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.1.tgz#c0f8558079da178667e7addd569b6953cd5e6bc2" + integrity sha512-oHTJI+R1hLafHraeDmg7Zg1rLwRIT9n0AEe8C4+Qm6iraTYGaUWG1YNJ2xuPrQJRPa2gMxO/E9qMWDl88ZizRQ== "@standardnotes/sncrypto-common@^1.7.3": version "1.7.3" @@ -2433,20 +2433,20 @@ buffer "^6.0.3" libsodium-wrappers "^0.7.9" -"@standardnotes/snjs@2.85.3": - version "2.85.3" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.85.3.tgz#eda6f1928346efc0baf933f4e7580e335c8ac8ae" - integrity sha512-44PC3CtMvK+cw2fqP54Qa+/UlHCLqOxae0F+v5NapSTlJuMT5M7LuQIA72IOILkqzCatC89dA1Q3o2gblKvtAQ== +"@standardnotes/snjs@2.86.2": + version "2.86.2" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.86.2.tgz#8fd238cd49a5a2a47a20a9615d204da609000595" + integrity sha512-tM+QHmnKHf3bNYW5FHZNmW16dpaU43tjzjdD9fGLbBvWXVF+6LrZXkYopNPD3TihoIzmuR3AZddfp99UGDZyNQ== dependencies: "@standardnotes/applications" "^1.2.2" "@standardnotes/auth" "^3.17.7" "@standardnotes/common" "^1.16.0" - "@standardnotes/domain-events" "^2.24.9" - "@standardnotes/features" "^1.34.12" - "@standardnotes/payloads" "^1.4.12" - "@standardnotes/responses" "^1.3.13" - "@standardnotes/services" "^1.6.2" - "@standardnotes/settings" "^1.13.0" + "@standardnotes/domain-events" "^2.25.0" + "@standardnotes/features" "^1.35.0" + "@standardnotes/payloads" "^1.4.13" + "@standardnotes/responses" "^1.3.14" + "@standardnotes/services" "^1.6.3" + "@standardnotes/settings" "^1.13.1" "@standardnotes/sncrypto-common" "^1.7.3" "@standardnotes/utils" "^1.4.0" @@ -3098,10 +3098,10 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -"@zip.js/zip.js@^2.4.6": - version "2.4.6" - resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.4.6.tgz#eb284910f4dcbccb267c5ef76950fb84ee43bb74" - integrity sha512-gP13tvMy1bhaTWw5I/Sm3mJAOU7J8S18e4sAcscGzYY8NVUF8FRirfY17eYq+rZhRBk8SNg5bFzzWgFR47qSyw== +"@zip.js/zip.js@^2.4.7": + version "2.4.7" + resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.4.7.tgz#4f065beb45ea0330000b70cd1eb4068a13fea731" + integrity sha512-IbRUgSsPcnVth4fBljrQDfI6nZO5VqW1/49j9rMAShZ7sB8noRYgQR4nY9jeRw5ZrUM6lZrsuUr8OMF4M3mrsw== abab@^2.0.3, abab@^2.0.5: version "2.0.5" @@ -7138,10 +7138,10 @@ mobx-react-lite@^3.3.0: resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.3.0.tgz#7174e807201943beff6f9d3701492314c9fc0db3" integrity sha512-U/kMSFtV/bNVgY01FuiGWpRkaQVHozBq5CEBZltFvPt4FcV111hEWkgwqVg9GPPZSEuEdV438PEz8mk8mKpYlA== -mobx@^6.4.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.4.2.tgz#d25cd358a46b7a8fe2d8299259bc71008a2aa5b3" - integrity sha512-b4xQJYiH8sb0sEbfq/Ws3N77DEJtSihUFD1moeiz2jNoJ5B+mqJutt54ouO9iEfkp7Wk4jQDsVUOh7DPEW3wEw== +mobx@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.5.0.tgz#dc2d028b1882737f6e813fc92454381e438b7ad3" + integrity sha512-pHZ/cySF00FVENDWIDzJyoObFahK6Eg4d0papqm6d7yMkxWTZ/S/csqJX1A3PsYy4t5k3z2QnlwuCfMW5lSEwA== ms@2.0.0: version "2.0.0"