refactor: replace fs with secureFs for improved file handling

This commit updates various modules to utilize the secure file system operations from the secureFs module instead of the native fs module. Key changes include:

- Replaced fs imports with secureFs in multiple route handlers and services to enhance security and consistency in file operations.
- Added centralized validation for working directories in the sdk-options module to ensure all AI model invocations are secure.

These changes aim to improve the security and maintainability of file handling across the application.
This commit is contained in:
Test User
2025-12-21 01:32:26 -05:00
parent 2b5479ae0d
commit 077a63b03b
62 changed files with 4866 additions and 3350 deletions

View File

@@ -1,28 +1,26 @@
import { createRootRoute, Outlet, useLocation, useNavigate } from "@tanstack/react-router";
import { useEffect, useState, useCallback } from "react";
import { Sidebar } from "@/components/layout/sidebar";
import { FileBrowserProvider, useFileBrowser, setGlobalFileBrowser } from "@/contexts/file-browser-context";
import { useAppStore } from "@/store/app-store";
import { useSetupStore } from "@/store/setup-store";
import { getElectronAPI } from "@/lib/electron";
import { Toaster } from "sonner";
import { ThemeOption, themeOptions } from "@/config/theme-options";
import { createRootRoute, Outlet, useLocation, useNavigate } from '@tanstack/react-router';
import { useEffect, useState, useCallback, useDeferredValue } from 'react';
import { Sidebar } from '@/components/layout/sidebar';
import {
FileBrowserProvider,
useFileBrowser,
setGlobalFileBrowser,
} from '@/contexts/file-browser-context';
import { useAppStore } from '@/store/app-store';
import { useSetupStore } from '@/store/setup-store';
import { getElectronAPI } from '@/lib/electron';
import { Toaster } from 'sonner';
import { ThemeOption, themeOptions } from '@/config/theme-options';
function RootLayoutContent() {
const location = useLocation();
const {
setIpcConnected,
theme,
currentProject,
previewTheme,
getEffectiveTheme,
} = useAppStore();
const { setIpcConnected, theme, currentProject, previewTheme, getEffectiveTheme } = useAppStore();
const { setupComplete } = useSetupStore();
const navigate = useNavigate();
const [isMounted, setIsMounted] = useState(false);
const [streamerPanelOpen, setStreamerPanelOpen] = useState(false);
const [setupHydrated, setSetupHydrated] = useState(() =>
useSetupStore.persist?.hasHydrated?.() ?? false
const [setupHydrated, setSetupHydrated] = useState(
() => useSetupStore.persist?.hasHydrated?.() ?? false
);
const { openFileBrowser } = useFileBrowser();
@@ -31,14 +29,14 @@ function RootLayoutContent() {
const activeElement = document.activeElement;
if (activeElement) {
const tagName = activeElement.tagName.toLowerCase();
if (tagName === "input" || tagName === "textarea" || tagName === "select") {
if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') {
return;
}
if (activeElement.getAttribute("contenteditable") === "true") {
if (activeElement.getAttribute('contenteditable') === 'true') {
return;
}
const role = activeElement.getAttribute("role");
if (role === "textbox" || role === "searchbox" || role === "combobox") {
const role = activeElement.getAttribute('role');
if (role === 'textbox' || role === 'searchbox' || role === 'combobox') {
return;
}
}
@@ -47,20 +45,22 @@ function RootLayoutContent() {
return;
}
if (event.key === "\\") {
if (event.key === '\\') {
event.preventDefault();
setStreamerPanelOpen((prev) => !prev);
}
}, []);
useEffect(() => {
window.addEventListener("keydown", handleStreamerPanelShortcut);
window.addEventListener('keydown', handleStreamerPanelShortcut);
return () => {
window.removeEventListener("keydown", handleStreamerPanelShortcut);
window.removeEventListener('keydown', handleStreamerPanelShortcut);
};
}, [handleStreamerPanelShortcut]);
const effectiveTheme = getEffectiveTheme();
// Defer the theme value to keep UI responsive during rapid hover changes
const deferredTheme = useDeferredValue(effectiveTheme);
useEffect(() => {
setIsMounted(true);
@@ -78,7 +78,7 @@ function RootLayoutContent() {
});
return () => {
if (typeof unsubscribe === "function") {
if (typeof unsubscribe === 'function') {
unsubscribe();
}
};
@@ -88,10 +88,10 @@ function RootLayoutContent() {
useEffect(() => {
if (!setupHydrated) return;
if (!setupComplete && location.pathname !== "/setup") {
navigate({ to: "/setup" });
} else if (setupComplete && location.pathname === "/setup") {
navigate({ to: "/" });
if (!setupComplete && location.pathname !== '/setup') {
navigate({ to: '/setup' });
} else if (setupComplete && location.pathname === '/setup') {
navigate({ to: '/' });
}
}, [setupComplete, setupHydrated, location.pathname, navigate]);
@@ -105,9 +105,9 @@ function RootLayoutContent() {
try {
const api = getElectronAPI();
const result = await api.ping();
setIpcConnected(result === "pong");
setIpcConnected(result === 'pong');
} catch (error) {
console.error("IPC connection failed:", error);
console.error('IPC connection failed:', error);
setIpcConnected(false);
}
};
@@ -117,34 +117,34 @@ function RootLayoutContent() {
// Restore to board view if a project was previously open
useEffect(() => {
if (isMounted && currentProject && location.pathname === "/") {
navigate({ to: "/board" });
if (isMounted && currentProject && location.pathname === '/') {
navigate({ to: '/board' });
}
}, [isMounted, currentProject, location.pathname, navigate]);
// Apply theme class to document
// Apply theme class to document - use deferred value to avoid blocking UI
useEffect(() => {
const root = document.documentElement;
// Remove all theme classes dynamically from themeOptions
const themeClasses = themeOptions
.map((option) => option.value)
.filter((theme) => theme !== "system" as ThemeOption['value']);
.filter((theme) => theme !== ('system' as ThemeOption['value']));
root.classList.remove(...themeClasses);
if (effectiveTheme === "dark") {
root.classList.add("dark");
} else if (effectiveTheme === "system") {
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
root.classList.add(isDark ? "dark" : "light");
} else if (effectiveTheme && effectiveTheme !== "light") {
root.classList.add(effectiveTheme);
if (deferredTheme === 'dark') {
root.classList.add('dark');
} else if (deferredTheme === 'system') {
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
root.classList.add(isDark ? 'dark' : 'light');
} else if (deferredTheme && deferredTheme !== 'light') {
root.classList.add(deferredTheme);
} else {
root.classList.add("light");
root.classList.add('light');
}
}, [effectiveTheme, previewTheme, currentProject, theme]);
}, [deferredTheme]);
// Setup view is full-screen without sidebar
const isSetupRoute = location.pathname === "/setup";
const isSetupRoute = location.pathname === '/setup';
if (isSetupRoute) {
return (
@@ -159,7 +159,7 @@ function RootLayoutContent() {
<Sidebar />
<div
className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
style={{ marginRight: streamerPanelOpen ? "250px" : "0" }}
style={{ marginRight: streamerPanelOpen ? '250px' : '0' }}
>
<Outlet />
</div>
@@ -167,7 +167,7 @@ function RootLayoutContent() {
{/* Hidden streamer panel - opens with "\" key, pushes content */}
<div
className={`fixed top-0 right-0 h-full w-[250px] bg-background border-l border-border transition-transform duration-300 ${
streamerPanelOpen ? "translate-x-0" : "translate-x-full"
streamerPanelOpen ? 'translate-x-0' : 'translate-x-full'
}`}
/>
<Toaster richColors position="bottom-right" />