Skip to content

Commit b4fef39

Browse files
committed
Harden codebase: fix bugs, remove dead code, improve security and performance
Server: - Fix broken comment update/delete (was querying snippetId=0, added getComment(id)) - Remove insecure /api/test-import endpoint (no auth, hardcoded user) - Add auth + ownership checks to collection GET/list endpoints - Add privacy check to GET /api/snippets/:id (private snippets hidden from non-owners) - Eliminate triple-fallback pattern (simpleStorage → storage → raw SQL) in routes - Remove 400-line dead MemStorage class and simple-storage.ts module - Fix DatabaseStorage: static db import instead of dynamic import in every method - Remove error stack traces from API error responses - Add parseId() helper for numeric route param validation - Cascade snippet deletion to comments table - Add request body size limit (1mb) - Clean up duplicate 404 handlers, excessive debug logging - Remove debug/fix files: db_fix.js, storage_fix.js, debug_storage.ts, winston-test.ts Client: - Fix transformSnippet falsy-value bug (|| → ?? for viewCount:0, isFavorite:false) - Fix CommentSection calling apiRequest with wrong argument order - Fix Tags.tsx using non-existent 'tag' prop instead of 'tags' array - Fix Layout.tsx passing unsupported 'isPublicView' prop to Header - Fix 5 components importing non-existent 'useAuth' export from AuthContext - Fix useAuthenticatedFetch sending uid instead of Firebase ID token - Fix ForgotPasswordForm: wire directly to Firebase sendPasswordResetEmail - Simplify AuthContext: remove DOM notification system, localStorage sync hack - Remove dead components: AdvancedSearch, CreateSnippetModal, FixedLucideIcon, GlobalSVGMonitor, ThemeSelector, TagCloud - Remove dead files: firebase-config.js, all .backup files, SnippetCard.test.tsx - Strip ~200 lines of console.log debug noise across components - Remove window.location.reload() from import success flow Build/deps: - Remove 16 unused npm dependencies (passport, express-session, framer-motion, etc.) - Remove Replit plugin code from vite.config.ts - Remove winston-test.ts from build output, enable tree-shaking - Fix CI workflow: correct script names, update to actions v4 + Node 20 - Fix check-no-hardcode.sh: filename typo and subshell variable bug - Fix server/vite.ts allowedHosts type error - Zero TypeScript errors, clean build Made-with: Cursor
1 parent c0b2a5e commit b4fef39

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3678
-16028
lines changed

.github/workflows/ci.yml

Lines changed: 19 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,29 @@
1-
name: CodePatchwork CI/CD
1+
name: CodePatchwork CI
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [main]
66
pull_request:
7-
branches: [ main ]
7+
branches: [main]
88

99
jobs:
1010
build:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- uses: actions/checkout@v3
15-
16-
- name: Setup Node.js
17-
uses: actions/setup-node@v3
18-
with:
19-
node-version: 18
20-
cache: 'npm'
21-
22-
- name: Install dependencies
23-
run: npm ci
24-
25-
- name: Check types
26-
run: npm run typecheck
27-
28-
- name: Lint code
29-
run: npm run lint
30-
31-
- name: Build project
32-
run: npm run build
33-
34-
- name: Cache build output
35-
uses: actions/cache@v3
36-
with:
37-
path: |
38-
dist
39-
node_modules
40-
key: ${{ runner.os }}-build-${{ github.sha }}
41-
restore-keys: |
42-
${{ runner.os }}-build-
43-
44-
test:
45-
needs: build
46-
runs-on: ubuntu-latest
47-
48-
services:
49-
postgres:
50-
image: postgres:latest
51-
env:
52-
POSTGRES_USER: postgres
53-
POSTGRES_PASSWORD: postgres
54-
POSTGRES_DB: codepatchwork_test
55-
ports:
56-
- 5432:5432
57-
options: >-
58-
--health-cmd pg_isready
59-
--health-interval 10s
60-
--health-timeout 5s
61-
--health-retries 5
62-
63-
steps:
64-
- uses: actions/checkout@v3
65-
66-
- name: Setup Node.js
67-
uses: actions/setup-node@v3
68-
with:
69-
node-version: 18
70-
cache: 'npm'
71-
72-
- name: Restore cached build
73-
uses: actions/cache@v3
74-
with:
75-
path: |
76-
dist
77-
node_modules
78-
key: ${{ runner.os }}-build-${{ github.sha }}
79-
80-
- name: Run database migrations
81-
run: npm run db:push
82-
env:
83-
DATABASE_URL: postgres://postgres:postgres@localhost:5432/codepatchwork_test
84-
85-
- name: Run tests
86-
run: npm test
87-
env:
88-
DATABASE_URL: postgres://postgres:postgres@localhost:5432/codepatchwork_test
89-
90-
deploy:
91-
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
92-
needs: test
93-
runs-on: ubuntu-latest
94-
95-
steps:
96-
- name: Deploy to production
97-
run: echo "Ready for deployment! This step would typically deploy to your hosting provider."
14+
- uses: actions/checkout@v4
15+
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: 20
20+
cache: "npm"
21+
22+
- name: Install dependencies
23+
run: npm ci
24+
25+
- name: Type check
26+
run: npm run check
27+
28+
- name: Build
29+
run: npm run build

client/src/App.tsx

Lines changed: 17 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
// client/src/App.tsx
2-
3-
import React, { useEffect, useState, lazy, Suspense } from "react";
4-
import { Redirect, Switch, Route } from "wouter"; // Added Redirect
1+
import React, { useEffect, lazy, Suspense } from "react";
2+
import { Redirect, Switch, Route } from "wouter";
53
import { TooltipProvider } from "@/components/ui/tooltip";
64
import { ThemeProvider } from "@/contexts/ThemeContext";
75
import { CodeThemeProvider } from "@/contexts/CodeThemeContext";
86
import { SnippetProvider } from "@/contexts/SnippetContext";
97
import { CollectionProvider } from "@/contexts/CollectionContext";
108
import { useAuthContext } from "@/contexts/AuthContext";
119

12-
// Lazy load pages for better performance
1310
const NotFound = lazy(() => import("@/pages/not-found"));
1411
const Home = lazy(() => import("@/pages/Home"));
1512
const PublicHome = lazy(() => import("@/pages/PublicHome"));
@@ -20,26 +17,24 @@ const Tags = lazy(() => import("@/pages/Tags"));
2017
const Settings = lazy(() => import("@/pages/Settings"));
2118
const SharedSnippet = lazy(() => import("@/pages/SharedSnippet"));
2219

23-
// Loading spinner for lazy-loaded pages
2420
const PageLoader = () => (
2521
<div className="h-screen flex items-center justify-center">
2622
<div className="animate-spin h-8 w-8 border-t-2 border-b-2 border-blue-500 rounded-full"></div>
2723
</div>
2824
);
2925

30-
// Renamed from Router to AuthenticatedRouter
3126
function AuthenticatedRouter() {
3227
return (
3328
<Suspense fallback={<PageLoader />}>
3429
<Switch>
35-
<Route path="/" component={Home} /> {/* Authenticated home/dashboard */}
30+
<Route path="/" component={Home} />
3631
<Route path="/snippets" component={Snippets} />
3732
<Route path="/collections" component={Collections} />
3833
<Route path="/collections/:id" component={CollectionDetail} />
3934
<Route path="/tags" component={Tags} />
4035
<Route path="/settings" component={Settings} />
4136
<Route path="/shared/:shareId" component={SharedSnippet} />
42-
<Route path="/login"><Redirect to="/" /></Route> {/* Added for authenticated users */}
37+
<Route path="/login"><Redirect to="/" /></Route>
4338
<Route component={NotFound} />
4439
</Switch>
4540
</Suspense>
@@ -51,131 +46,60 @@ function PublicRouter() {
5146
<Suspense fallback={<PageLoader />}>
5247
<Switch>
5348
<Route path="/" component={PublicHome} />
54-
<Route path="/login" component={SignInTriggerPage} /> {/* Added for unauthenticated users */}
49+
<Route path="/login" component={SignInTriggerPage} />
5550
<Route path="/shared/:shareId" component={SharedSnippet} />
56-
{/* For non-matched routes, redirect to PublicHome */}
5751
<Route component={PublicHome} />
5852
</Switch>
5953
</Suspense>
6054
);
6155
}
6256

63-
// SignInTriggerPage Helper Component
6457
const SignInTriggerPage: React.FC = () => {
65-
const { signIn, user, loading } = useAuthContext(); // useAuthContext is already imported
58+
const { signIn, user, loading } = useAuthContext();
59+
6660
useEffect(() => {
67-
// Only attempt to sign in if not already authenticated and not loading
6861
if (!user && !loading) {
6962
signIn();
7063
}
7164
}, [signIn, user, loading]);
7265

73-
// If already logged in (e.g., due to fast auth resolution), redirect to home.
7466
if (user) {
7567
return <Redirect to="/" />;
7668
}
77-
// If still loading auth state
78-
if (loading) {
79-
return (
80-
<div className="h-screen flex flex-col items-center justify-center">
81-
<div className="mb-4">Loading authentication...</div>
82-
<div className="animate-spin h-8 w-8 border-t-2 border-b-2 border-blue-500 rounded-full"></div>
83-
</div>
84-
);
85-
}
86-
// Default state while sign-in is being triggered or if user backs out of Google prompt
87-
return (
88-
<div className="h-screen flex flex-col items-center justify-center">
89-
<p>Redirecting to sign-in...</p>
90-
{/* Or redirect to PublicHome if sign-in is not immediate / user needs to click again */}
91-
{/* For now, this message is fine as signIn() should overlay Google prompt */}
92-
</div>
93-
);
94-
};
9569

96-
// Added debug component to show authentication state
97-
function AuthDebug({ user, loading }: { user: any, loading: boolean }) {
9870
return (
99-
<div className="fixed bottom-4 right-4 bg-gray-800 text-white p-2 rounded text-xs opacity-80 z-50">
100-
<div>Auth Status: {loading ? "Loading" : user ? "Authenticated" : "Not Authenticated"}</div>
101-
{user && (
102-
<div>
103-
User: {user.email || "No email"}<br />
104-
ID: {user.id?.substring(0, 8) || "No ID"}
105-
</div>
71+
<div className="h-screen flex flex-col items-center justify-center">
72+
<div className="mb-4">{loading ? "Loading authentication..." : "Redirecting to sign-in..."}</div>
73+
{loading && (
74+
<div className="animate-spin h-8 w-8 border-t-2 border-b-2 border-blue-500 rounded-full"></div>
10675
)}
10776
</div>
10877
);
109-
}
78+
};
11079

11180
export default function App() {
112-
const { user, loading } = useAuthContext(); // Removed signIn from here as it's not used directly for button anymore
113-
const [showDebug, setShowDebug] = useState(false);
114-
115-
// Add explicit debugging to track auth state
116-
useEffect(() => {
117-
console.log("[App] Auth state in App.tsx:", {
118-
user: user ? { id: user.id, email: user.email } : null,
119-
loading
120-
});
121-
console.log("[App] Is user null?", user === null);
122-
console.log("[App] Authentication state:", loading ? "loading" : user ? "authenticated" : "not authenticated");
123-
}, [user, loading]);
81+
const { user, loading } = useAuthContext();
12482

125-
// Setup keyboard shortcuts (theme is now handled by ThemeContext)
126-
useEffect(() => {
127-
// Toggle debug panel with key press (Alt+D)
128-
const handleKeyDown = (e: KeyboardEvent) => {
129-
if (e.altKey && e.key === 'd') {
130-
setShowDebug(prev => !prev);
131-
}
132-
};
133-
134-
window.addEventListener('keydown', handleKeyDown);
135-
return () => window.removeEventListener('keydown', handleKeyDown);
136-
}, []);
137-
138-
// Try to restore from localStorage if no user but we have a saved one
139-
useEffect(() => {
140-
if (!loading && !user) {
141-
try {
142-
const savedUser = localStorage.getItem('auth_user');
143-
if (savedUser) {
144-
console.log("[App] Found saved user in localStorage, but not reflected in context");
145-
}
146-
} catch (e) {
147-
console.error("[App] localStorage error:", e);
148-
}
149-
}
150-
}, [user, loading]);
151-
152-
// 1) Still waiting for Firebase → show spinner or placeholder
15383
if (loading) {
154-
console.log("[App] Currently loading, showing loading state");
15584
return (
15685
<div className="h-screen flex flex-col items-center justify-center">
157-
<div className="mb-4">Loading authentication...</div>
86+
<div className="mb-4">Loading...</div>
15887
<div className="animate-spin h-8 w-8 border-t-2 border-b-2 border-blue-500 rounded-full"></div>
159-
{showDebug && <AuthDebug user={user} loading={loading} />}
16088
</div>
16189
);
16290
}
16391

164-
// 2) Routing logic based on authentication state
165-
// PublicHome will now handle the sign-in prompt.
166-
console.log(`[App] Rendering routers. User: ${user ? user.id : 'null'}, Loading: ${loading}`);
16792
return (
16893
<ThemeProvider>
16994
<CodeThemeProvider>
170-
<SnippetProvider> {/* SnippetProvider might be needed by SharedSnippet too */}
171-
<CollectionProvider> {/* CollectionProvider might be needed by SharedSnippet too */}
95+
<SnippetProvider>
96+
<CollectionProvider>
17297
<TooltipProvider>
17398
{user ? <AuthenticatedRouter /> : <PublicRouter />}
174-
{showDebug && <AuthDebug user={user} loading={loading} />}
17599
</TooltipProvider>
176100
</CollectionProvider>
177101
</SnippetProvider>
178102
</CodeThemeProvider>
179103
</ThemeProvider>
180104
);
181-
}
105+
}

client/src/components/AddSnippetDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export default function AddSnippetDialog({
108108
snippet
109109
);
110110

111-
console.log(isEditing ? "Snippet updated successfully:" : "Snippet created successfully:", result);
111+
// Success
112112

113113
toast({
114114
title: "Success",

0 commit comments

Comments
 (0)