Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Warn users on possible risks on installing third party unvetted plugins #600

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
29d651b
fix: get rid of title view jank on latest beta
AAGaming00 Nov 9, 2023
8f26fde
Count the number of installs for each plugin (#557)
PartyWumpus Nov 10, 2023
479a16c
Bump aiohttp from 3.8.4 to 3.8.5 in /backend (#558)
dependabot[bot] Nov 10, 2023
75ad98a
Check if Linux service is running before trying to start or stop it (…
Jan200101 Nov 11, 2023
7c3ae9b
replace chmod implementation with os.chmod (#541)
Jan200101 Nov 11, 2023
91186da
bump dfl
PartyWumpus Nov 24, 2023
80a00a0
fix: Adjust tabs and toaster hooks to work on react 18, also half-fix…
AAGaming00 Dec 13, 2023
e21a5d5
fix: idiotic formatting error i should have noticed
AAGaming00 Dec 13, 2023
3489fd7
fix(developer): add back valve internal on beta
AAGaming00 Dec 14, 2023
39f4f28
Call plugin unload function after stopping event loop (#539)
Jan200101 Dec 16, 2023
e3d72b6
Translations update from Weblate (#553)
WerWolvTranslationBot Dec 16, 2023
12a99b8
Bump tj-actions/changed-files to 41.0.0 in /.github/workflows (#575)
dependabot[bot] Jan 3, 2024
f9a07da
fix: Fix on Chromium 109 beta (#576)
beebls Jan 20, 2024
9295e4b
Bump aiohttp from 3.8.5 to 3.9.0 in /backend (#577)
dependabot[bot] Jan 23, 2024
3146ebf
[Bugfix] Toaster changed name again (#581)
RodoMa92 Jan 25, 2024
647f3fe
Translations update from Weblate (#580)
WerWolvTranslationBot Jan 26, 2024
6b4a56c
fix the tasks
AAGaming00 Feb 3, 2024
7f2caa3
fix: use findInReactTree to find correct errorboundary for toaster
AAGaming00 Feb 3, 2024
62e3128
fix: bump dfl to fix error on latest steam beta
AAGaming00 Feb 3, 2024
3e4c255
Specify catthehacker/ubuntu:act-22.04 as container for act
PartyWumpus Feb 6, 2024
fd4ed81
Refactor plugin store and add sorting by downloads and release date (…
PartyWumpus Feb 7, 2024
2500b74
Revert "Call plugin unload function after stopping event loop (#539)"…
PartyWumpus Feb 9, 2024
435dfa7
fix(filepicker_ls): use case insensitive matching for file exts (#585)
doZennn Feb 10, 2024
9503d5c
Testing PRs from within decky (#496)
PartyWumpus Feb 15, 2024
0dce3a8
Get plugin name for development ZIP during installation (#578)
eXhumer Feb 15, 2024
7d6b880
[Feature] Freeze updates for devs (#582)
FineWolf Feb 15, 2024
ecf4800
fix finding qam root node for feb 14th beta
PartyWumpus Feb 15, 2024
922d0c4
Appease prettier
PartyWumpus Feb 15, 2024
49d1e33
Translations update from Weblate (#587)
WerWolvTranslationBot Feb 22, 2024
55a95e0
Update bug_report.yml
TrainDoctor Feb 24, 2024
8e8e6a2
Update bug_report.yml
TrainDoctor Feb 24, 2024
4a7e9a5
fix: support new minified class names
AAGaming00 Mar 9, 2024
056f921
Initial implementation to warn users of potential dangers from third …
RodoMa92 Mar 13, 2024
a1b4040
Fixing spelling mistakes
RodoMa92 Mar 13, 2024
05f9a3b
Added a wait time only for the first popup message on both warnings.
RodoMa92 Mar 13, 2024
314e812
Simplified and cleared up text warnings
RodoMa92 Mar 14, 2024
cfd4f40
Merge branch 'main' into warn_third_party
Aug 6, 2024
2bd47cf
Adapt commits to latest changes
Aug 6, 2024
b3f26d9
Readapt class parameters to main
Aug 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ MANIFEST
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
backend/dist/
backend/static/

# Installer logs
pip-log.txt
Expand Down
4 changes: 3 additions & 1 deletion backend/decky_loader/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@
"update_all_many": "Aggiorna {{count}} plugins",
"update_all_one": "Aggiorna un plugin",
"update_all_other": "Aggiorna {{count}} plugins",
"update_to": "Aggiorna a {{name}}"
"update_to": "Aggiorna a {{name}}",
"unfreeze": "Permetti aggiornamenti",
"freeze": "Congela aggiornamenti"
},
"PluginListLabel": {
"hidden": "Nascosto dal menu di accesso rapido"
Expand Down
4 changes: 4 additions & 0 deletions backend/decky_loader/locales/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,5 +286,9 @@
"reloading": "Recarregando",
"updating": "Atualizando"
}
},
"TitleView": {
"decky_store_desc": "Abrir Loja Decky",
"settings_desc": "Abrir Definições Decky"
}
}
21 changes: 21 additions & 0 deletions backend/decky_loader/locales/pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@
},
"updates": {
"header": "Actualizações"
},
"notifications": {
"decky_updates_label": "Atualização Decky disponível",
"header": "Notificações",
"plugin_updates_label": "Atualizações de plugins disponíveis"
}
},
"SettingsIndex": {
Expand Down Expand Up @@ -263,5 +268,21 @@
"reloading": "Recarregar",
"updating": "Actualização em curso"
}
},
"FilePickerError": {
"errors": {
"perm_denied": "Não tem acesso ao diretório especificado. Por favor, verifique se o seu utilizador (deck na Steam Deck) possui as permissões correspondentes para aceder à pasta/ficheiro especificado.",
"unknown": "Ocorreu um erro desconhecido. O erro é: {{raw_error}}",
"file_not_found": "O caminho especificado não é válido. Por favor, verifique e insira-o corretamente."
}
},
"TitleView": {
"decky_store_desc": "Abrir a Loja Decky",
"settings_desc": "Abrir as Definições Decky"
},
"DropdownMultiselect": {
"button": {
"back": "Voltar"
}
}
}
28 changes: 14 additions & 14 deletions frontend/src/components/modals/PluginInstallModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({
strTitle={
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', width: '100%' }}>
<TranslationHelper
transClass={TranslationClass.PLUGIN_INSTALL_MODAL}
transText="title"
i18nArgs={{ artifact: artifact }}
installType={installType}
trans_class={TranslationClass.PLUGIN_INSTALL_MODAL}
trans_text="title"
i18n_args={{ artifact: artifact }}
install_type={installType}
/>
{loading && (
<div style={{ marginLeft: 'auto' }}>
Expand All @@ -81,31 +81,31 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({
loading ? (
<div>
<TranslationHelper
transClass={TranslationClass.PLUGIN_INSTALL_MODAL}
transText="button_processing"
installType={installType}
trans_class={TranslationClass.PLUGIN_INSTALL_MODAL}
trans_text="button_processing"
install_type={installType}
/>
</div>
) : (
<div>
<TranslationHelper
transClass={TranslationClass.PLUGIN_INSTALL_MODAL}
transText="button_idle"
installType={installType}
trans_class={TranslationClass.PLUGIN_INSTALL_MODAL}
trans_text="button_idle"
install_type={installType}
/>
</div>
)
}
>
<div>
<TranslationHelper
transClass={TranslationClass.PLUGIN_INSTALL_MODAL}
transText="desc"
i18nArgs={{
trans_class={TranslationClass.PLUGIN_INSTALL_MODAL}
trans_text="desc"
i18n_args={{
artifact: artifact,
version: version,
}}
installType={installType}
install_type={installType}
/>
</div>
{hash == 'False' && <span style={{ color: 'red' }}>{t('PluginInstallModal.no_hash')}</span>}
Expand Down
82 changes: 82 additions & 0 deletions frontend/src/components/modals/WarnThirdParty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { ConfirmModal } from '@decky/ui';
import { FC, useEffect, useState } from 'react';
import { FaExclamationTriangle } from 'react-icons/fa';

import TranslationHelper, { TranslationClass } from '../../utils/TranslationHelper';

interface WarnThirdPartyProps {
seconds?: number;
type: WarnThirdPartyType;
onOK(): void;
onCancel(): void;
closeModal?(): void;
}

export enum WarnThirdPartyType {
REPO = 0,
ZIP = 1,
}

const WarnThirdParty: FC<WarnThirdPartyProps> = ({ seconds = 5, type, onOK, onCancel, closeModal }) => {
const [waitTimer, setWaitTimer] = useState(seconds);

useEffect(() => {
// exit early when we reach 0
if (waitTimer <= 0) return;

// save intervalId to clear the interval when the
// component re-renders
const intervalId = setInterval(() => {
setWaitTimer(waitTimer - 1);
}, 1000);

// clear interval on re-render to avoid memory leaks
return () => clearInterval(intervalId);
// add waitTimer as a dependency to re-rerun the effect
// when we update it
}, [waitTimer]);

return (
<ConfirmModal
bOKDisabled={waitTimer > 0}
closeModal={closeModal}
onOK={async () => {
await onOK();
}}
onCancel={async () => {
await onCancel();
}}
strTitle={
<div>
<FaExclamationTriangle />
<TranslationHelper trans_class={TranslationClass.WARN_THIRD_PARTY} trans_text="title" warn_type={type} />
</div>
}
strOKButtonText={
waitTimer > 0 ? (
<div>
<TranslationHelper
trans_class={TranslationClass.WARN_THIRD_PARTY}
trans_text="button_processing"
i18n_args={{
timer: waitTimer,
}}
/>
</div>
) : (
<div>
<TranslationHelper trans_class={TranslationClass.WARN_THIRD_PARTY} trans_text="button_idle" />
</div>
)
}
>
<span style={{ color: 'red' }}>
<div>
<TranslationHelper trans_class={TranslationClass.WARN_THIRD_PARTY} trans_text="desc" warn_type={type} />
</div>
</span>
</ConfirmModal>
);
};

export default WarnThirdParty;
21 changes: 20 additions & 1 deletion frontend/src/components/settings/pages/developer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Navigation,
TextField,
Toggle,
showModal,
} from '@decky/ui';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
Expand All @@ -18,6 +19,7 @@ import { installFromURL } from '../../../../store';
import { useSetting } from '../../../../utils/hooks/useSetting';
import { getSetting } from '../../../../utils/settings';
import { FileSelectionType } from '../../../modals/filepicker';
import WarnThirdParty, { WarnThirdPartyType } from '../../../modals/WarnThirdParty';
import RemoteDebuggingSettings from '../general/RemoteDebugging';

const logger = new Logger('DeveloperIndex');
Expand All @@ -43,6 +45,8 @@ export default function DeveloperSettings() {
const [enableValveInternal, setEnableValveInternal] = useSetting<boolean>('developer.valve_internal', false);
const [reactDevtoolsEnabled, setReactDevtoolsEnabled] = useSetting<boolean>('developer.rdt.enabled', false);
const [reactDevtoolsIP, setReactDevtoolsIP] = useSetting<string>('developer.rdt.ip', '');
const [acceptedWarning, setAcceptedWarning] = useSetting<boolean>('developer.warn.third_party', false);
const waitTime = acceptedWarning ? 0 : 5;
const [pluginURL, setPluginURL] = useState('');
const textRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation();
Expand Down Expand Up @@ -72,7 +76,22 @@ export default function DeveloperSettings() {
}
icon={<FaLink style={{ display: 'block' }} />}
>
<DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}>
<DialogButton
disabled={pluginURL.length == 0}
onClick={() =>
showModal(
<WarnThirdParty
type={WarnThirdPartyType.ZIP}
onOK={() => {
setAcceptedWarning(true);
installFromURL(pluginURL);
}}
onCancel={() => {}}
seconds={waitTime}
/>,
)
}
>
{t('SettingsDeveloperIndex.third_party_plugins.button_install')}
</DialogButton>
</Field>
Expand Down
43 changes: 28 additions & 15 deletions frontend/src/components/settings/pages/general/StoreSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Dropdown, Field, TextField } from '@decky/ui';
import { Dropdown, Field, TextField, showModal } from '@decky/ui';
import { FunctionComponent } from 'react';
import { useTranslation } from 'react-i18next';
import { FaShapes } from 'react-icons/fa';

import Logger from '../../../../logger';
import { Store } from '../../../../store';
import { useSetting } from '../../../../utils/hooks/useSetting';
import WarnThirdParty, { WarnThirdPartyType } from '../../../modals/WarnThirdParty';

const logger = new Logger('StoreSelect');

const StoreSelect: FunctionComponent<{}> = () => {
const [selectedStore, setSelectedStore] = useSetting<Store>('store', Store.Default);
const [selectedStoreURL, setSelectedStoreURL] = useSetting<string | null>('store-url', null);
const [acceptedWarning, setAcceptedWarning] = useSetting<boolean>('store_select.warn.third_party', false);
const waitTime = acceptedWarning ? 0 : 5;
const { t } = useTranslation();
const tStores = [
t('StoreSelect.store_channel.default'),
Expand All @@ -38,20 +41,30 @@ const StoreSelect: FunctionComponent<{}> = () => {
}}
/>
</Field>
{selectedStore == Store.Custom && (
<Field
label={t('StoreSelect.custom_store.label')}
indentLevel={1}
description={
<TextField
label={t('StoreSelect.custom_store.url_label')}
value={selectedStoreURL || undefined}
onChange={(e) => setSelectedStoreURL(e?.target.value || null)}
/>
}
icon={<FaShapes style={{ display: 'block' }} />}
></Field>
)}
{selectedStore == Store.Custom &&
showModal(
<WarnThirdParty
type={WarnThirdPartyType.REPO}
seconds={waitTime}
onOK={() => {
setAcceptedWarning(true);
}}
onCancel={() => setSelectedStore(Store.Default)}
/>,
) && (
<Field
label={t('StoreSelect.custom_store.label')}
indentLevel={1}
description={
<TextField
label={t('StoreSelect.custom_store.url_label')}
value={selectedStoreURL || undefined}
onChange={(e) => setSelectedStoreURL(e?.target.value || null)}
/>
}
icon={<FaShapes style={{ display: 'block' }} />}
></Field>
)}
</>
);
};
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/developer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ export async function setShowValveInternal(show: boolean) {
export async function setShouldConnectToReactDevTools(enable: boolean) {
DeckyPluginLoader.toaster.toast({
title: enable ? (
<TranslationHelper transClass={TranslationClass.DEVELOPER} transText={'enabling'} />
<TranslationHelper trans_class={TranslationClass.DEVELOPER} trans_text={'enabling'} />
) : (
<TranslationHelper transClass={TranslationClass.DEVELOPER} transText={'disabling'} />
<TranslationHelper trans_class={TranslationClass.DEVELOPER} trans_text={'disabling'} />
),
body: <TranslationHelper transClass={TranslationClass.DEVELOPER} transText={'5secreload'} />,
body: <TranslationHelper trans_class={TranslationClass.DEVELOPER} trans_text={'5secreload'} />,
icon: <FaReact />,
});
await sleep(5000);
Expand Down
Loading
Loading