Add function to enable/disable routing

Wraps the toX() functions of the Router to add a check to only run the
function when it is allowed.

The check is used in the import page to prevent user scripts from
redirecting away to a crime or something else.
This commit is contained in:
Martin Fournier 2022-01-22 10:53:16 -05:00
parent d386528627
commit a47eae8b25
3 changed files with 56 additions and 12 deletions

@ -84,6 +84,9 @@ import { ThemeBrowser } from "../Themes/ui/ThemeBrowser";
import { ImportSaveRoot } from "./React/ImportSaveRoot"; import { ImportSaveRoot } from "./React/ImportSaveRoot";
import { BypassWrapper } from "./React/BypassWrapper"; import { BypassWrapper } from "./React/BypassWrapper";
import _wrap from "lodash/wrap";
import _functions from "lodash/functions";
const htmlLocation = location; const htmlLocation = location;
interface IProps { interface IProps {
@ -111,6 +114,9 @@ export let Router: IRouter = {
page: () => { page: () => {
throw new Error("Router called before initialization"); throw new Error("Router called before initialization");
}, },
allowRouting: () => {
throw new Error("Router called before initialization");
},
toActiveScripts: () => { toActiveScripts: () => {
throw new Error("Router called before initialization"); throw new Error("Router called before initialization");
}, },
@ -238,6 +244,8 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
if (importString === undefined && page === Page.ImportSave) if (importString === undefined && page === Page.ImportSave)
throw new Error("Trying to go to a page without the proper setup"); throw new Error("Trying to go to a page without the proper setup");
const [allowRoutingCalls, setAllowRoutingCalls] = useState(true);
function resetErrorBoundary(): void { function resetErrorBoundary(): void {
setErrorBoundaryKey(errorBoundaryKey + 1); setErrorBoundaryKey(errorBoundaryKey + 1);
} }
@ -259,6 +267,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
Router = { Router = {
page: () => page, page: () => page,
allowRouting: (value: boolean) => setAllowRoutingCalls(value),
toActiveScripts: () => setPage(Page.ActiveScripts), toActiveScripts: () => setPage(Page.ActiveScripts),
toAugmentations: () => setPage(Page.Augmentations), toAugmentations: () => setPage(Page.Augmentations),
toBladeburner: () => setPage(Page.Bladeburner), toBladeburner: () => setPage(Page.Bladeburner),
@ -333,6 +342,26 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
}, },
}; };
useEffect(() => {
// Wrap Router navigate functions to be able to disable the execution
_functions(Router).
filter((fnName) => fnName.startsWith('to')).
forEach((fnName) => {
// @ts-ignore - tslint does not like this, couldn't find a way to make it cooperate
Router[fnName] = _wrap(Router[fnName], (func, ...args) => {
if (!allowRoutingCalls) {
// Let's just log to console.
console.log(`Routing is currently disabled - Attempted router.${fnName}()`);
return;
}
// Call the function normally
return func(...args);
});
});
});
useEffect(() => { useEffect(() => {
if (page !== Page.Terminal) window.scrollTo(0, 0); if (page !== Page.Terminal) window.scrollTo(0, 0);
}); });
@ -539,7 +568,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
<ImportSaveRoot <ImportSaveRoot
importString={importString} importString={importString}
automatic={importAutomatic} automatic={importAutomatic}
onReturning={() => Router.toTerminal()} router={Router}
/> />
); );
withSidebar = false; withSidebar = false;

@ -31,6 +31,7 @@ import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFuncti
import { numeralWrapper } from "../numeralFormat"; import { numeralWrapper } from "../numeralFormat";
import { ConfirmationModal } from "./ConfirmationModal"; import { ConfirmationModal } from "./ConfirmationModal";
import { pushImportResult } from "../../Electron"; import { pushImportResult } from "../../Electron";
import { IRouter } from "../Router";
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
@ -101,28 +102,30 @@ function ComparisonIcon({ isBetter }: { isBetter: boolean }): JSX.Element {
} }
} }
export interface ImportSaveProps { export interface IProps {
importString: string; importString: string;
automatic: boolean; automatic: boolean;
onReturning: () => void; router: IRouter;
} }
let initialAutosave = 0; let initialAutosave = 0;
export function ImportSaveRoot({ importString, automatic, onReturning }: ImportSaveProps): JSX.Element { export function ImportSaveRoot(props: IProps): JSX.Element {
const classes = useStyles(); const classes = useStyles();
const [importData, setImportData] = useState<ImportData | undefined>(); const [importData, setImportData] = useState<ImportData | undefined>();
const [currentData, setCurrentData] = useState<ImportData | undefined>(); const [currentData, setCurrentData] = useState<ImportData | undefined>();
const [importModalOpen, setImportModalOpen] = useState(false); const [importModalOpen, setImportModalOpen] = useState(false);
const [headback, setHeadback] = useState(false);
function handleGoBack(): void { function handleGoBack(): void {
Settings.AutosaveInterval = initialAutosave; Settings.AutosaveInterval = initialAutosave;
pushImportResult(false); pushImportResult(false);
onReturning(); props.router.allowRouting(true);
setHeadback(true)
} }
async function handleImport(): Promise<void> { async function handleImport(): Promise<void> {
await saveObject.importGame(importString, true); await saveObject.importGame(props.importString, true);
pushImportResult(true); pushImportResult(true);
} }
@ -130,11 +133,16 @@ export function ImportSaveRoot({ importString, automatic, onReturning }: ImportS
// We want to disable autosave while we're in this mode // We want to disable autosave while we're in this mode
initialAutosave = Settings.AutosaveInterval; initialAutosave = Settings.AutosaveInterval;
Settings.AutosaveInterval = 0; Settings.AutosaveInterval = 0;
props.router.allowRouting(false);
}, []); }, []);
useEffect(() => {
if (headback) props.router.toTerminal();
}, [headback]);
useEffect(() => { useEffect(() => {
async function fetchData(): Promise<void> { async function fetchData(): Promise<void> {
const dataBeingImported = await saveObject.getImportDataFromString(importString); const dataBeingImported = await saveObject.getImportDataFromString(props.importString);
const dataCurrentlyInGame = await saveObject.getImportDataFromString(saveObject.getSaveString(true)); const dataCurrentlyInGame = await saveObject.getImportDataFromString(saveObject.getSaveString(true));
setImportData(dataBeingImported); setImportData(dataBeingImported);
@ -142,8 +150,8 @@ export function ImportSaveRoot({ importString, automatic, onReturning }: ImportS
return Promise.resolve(); return Promise.resolve();
} }
if (importString) fetchData(); if (props.importString) fetchData();
}, [importString]); }, [props.importString]);
if (!importData || !currentData) return <></>; if (!importData || !currentData) return <></>;
return ( return (
@ -151,7 +159,7 @@ export function ImportSaveRoot({ importString, automatic, onReturning }: ImportS
<Typography variant="h4" sx={{ mb: 2 }}> <Typography variant="h4" sx={{ mb: 2 }}>
Import Save Comparison Import Save Comparison
</Typography> </Typography>
{automatic && ( {props.automatic && (
<Typography sx={{ mb: 2 }}> <Typography sx={{ mb: 2 }}>
We've found a <b>NEWER save</b> that you may want to use instead. We've found a <b>NEWER save</b> that you may want to use instead.
</Typography> </Typography>
@ -202,8 +210,14 @@ export function ImportSaveRoot({ importString, automatic, onReturning }: ImportS
<TableRow> <TableRow>
<TableCell>Saved On</TableCell> <TableCell>Saved On</TableCell>
<TableCell>{new Date(currentData.playerData?.lastSave ?? 0).toLocaleString()}</TableCell> <TableCell>
<TableCell>{new Date(importData.playerData?.lastSave ?? 0).toLocaleString()}</TableCell> {(currentData.playerData?.lastSave ?? 0) > 0 ?
new Date(currentData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
</TableCell>
<TableCell>
{(importData.playerData?.lastSave ?? 0) > 0 ?
new Date(importData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
</TableCell>
<TableCell> <TableCell>
{importData.playerData?.lastSave !== currentData.playerData?.lastSave && ( {importData.playerData?.lastSave !== currentData.playerData?.lastSave && (
<ComparisonIcon <ComparisonIcon

@ -55,6 +55,7 @@ export interface IRouter {
// toRedPill(): void; // toRedPill(): void;
// toworkInProgress(): void; // toworkInProgress(): void;
page(): Page; page(): Page;
allowRouting(value: boolean): void;
toActiveScripts(): void; toActiveScripts(): void;
toAugmentations(): void; toAugmentations(): void;
toBitVerse(flume: boolean, quick: boolean): void; toBitVerse(flume: boolean, quick: boolean): void;