feat: privacy prefs (#935)

* chore: move all components into Components dir with pascal case

* feat: privacy prefs

* chore: upgrade deps
This commit is contained in:
Mo
2022-03-17 12:19:07 -05:00
committed by GitHub
parent c29e45795d
commit fb9bd37d72
10 changed files with 273 additions and 88 deletions

View File

@@ -123,13 +123,13 @@ export class ChallengeModal extends PureComponent<Props, State> {
})
) {
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);
}
};

View File

@@ -93,7 +93,7 @@ export const ConfirmSignoutModal = observer(
if (deleteLocalBackups) {
application.signOutAndDeleteLocalBackups();
} else {
application.signOut();
application.user.signOut();
}
closeDialog();
}}

View File

@@ -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<SecurityProps> = (props) => (
userProvider={props.userProvider}
/>
<PasscodeLock appState={props.appState} application={props.application} />
{props.appState.enableUnfinishedFeatures && (
<Privacy application={props.application} />
)}
</PreferencesPane>
);

View File

@@ -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<EmailBackupFrequency>(
SettingName.EmailBackupFrequency,
EmailBackupFrequency.Disabled
)
);
setIsFailedBackupEmailMuted(
convertStringifiedBooleanToBoolean(
userSettings[SettingName.MuteFailedBackupsEmails] as string
userSettings.getSettingValue<MuteFailedBackupsEmailsOption>(
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<boolean> => {
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);

View File

@@ -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<Props> = ({
}) => {
const [authBegan, setAuthBegan] = useState(false);
const [successfullyInstalled, setSuccessfullyInstalled] = useState(false);
const [backupFrequency, setBackupFrequency] = useState<string | null>(null);
const [backupFrequency, setBackupFrequency] = useState<string | undefined>(
undefined
);
const [confirmation, setConfirmation] = useState('');
const disable = async (event: Event) => {
@@ -42,10 +43,10 @@ export const CloudBackupProvider: FunctionComponent<Props> = ({
'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<Props> = ({
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<Props> = ({
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<Props> = ({
if (!application.getUser()) {
return;
}
const frequency = await application.getSetting(backupFrequencySettingName);
const frequency = await application.settings.getSetting(
backupFrequencySettingName
);
setBackupFrequency(frequency);
}, [application, backupFrequencySettingName]);

View File

@@ -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<Props> = ({ 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<Props> = ({ application }) => {
payload: string
): Promise<boolean> => {
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);

View File

@@ -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<Props> = observer(
({ application }: Props) => {
const [signInEmailsMutedValue, setSignInEmailsMutedValue] =
useState<MuteSignInEmailsOption>(MuteSignInEmailsOption.NotMuted);
const [sessionUaLoggingValue, setSessionUaLoggingValue] =
useState<LogSessionUserAgentOption>(LogSessionUserAgentOption.Enabled);
const [isLoading, setIsLoading] = useState(false);
const updateSetting = async (
settingName: SettingName,
payload: string
): Promise<boolean> => {
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<MuteSignInEmailsOption>(
SettingName.MuteSignInEmails,
MuteSignInEmailsOption.NotMuted
)
);
setSessionUaLoggingValue(
userSettings.getSettingValue<LogSessionUserAgentOption>(
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 (
<PreferencesGroup>
<PreferencesSegment>
<Title>Privacy</Title>
<div>
<div className="flex items-center justify-between">
<div className="flex flex-col">
<Subtitle>Disable sign-in notification emails</Subtitle>
<Text>
Disables email notifications when a new sign-in occurs on your
account. (Email notifications are available to paid
subscribers).
</Text>
</div>
{isLoading ? (
<div className={'sk-spinner info small'} />
) : (
<Switch
onChange={toggleMuteSignInEmails}
checked={
signInEmailsMutedValue === MuteSignInEmailsOption.Muted
}
/>
)}
</div>
<HorizontalSeparator classes="mt-5 mb-3" />
<div className="flex items-center justify-between">
<div className="flex flex-col">
<Subtitle>Session user agent logging</Subtitle>
<Text>
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.
</Text>
</div>
{isLoading ? (
<div className={'sk-spinner info small'} />
) : (
<Switch
onChange={toggleSessionLogging}
checked={
sessionUaLoggingValue === LogSessionUserAgentOption.Enabled
}
/>
)}
</div>
</div>
</PreferencesSegment>
</PreferencesGroup>
);
}
);

View File

@@ -149,6 +149,6 @@ export class WebApplication extends SNApplication {
async signOutAndDeleteLocalBackups(): Promise<void> {
await this.bridge.deleteLocalBackups();
return this.signOut();
return this.user.signOut();
}
}

View File

@@ -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",

View File

@@ -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"