@empline/preflight 1.1.33 → 1.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/client-only-protected-pages";
3
+ export declare const name = "Client Only Protected Pages";
4
+ export declare const description = "Detects protected pages marked 'use client' bypassing server auth";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=client-only-protected-pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-protected-pages.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/client-only-protected-pages.ts"],"names":[],"mappings":";AA2BA,eAAO,MAAM,EAAE,qCAAqC,CAAC;AACrD,eAAO,MAAM,IAAI,gCAAgC,CAAC;AAClD,eAAO,MAAM,WAAW,sEAAsE,CAAC;AAC/F,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAA8D,CAAC;AAChF,eAAO,MAAM,QAAQ,UAA0B,CAAC;AAgDhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmH3F"}
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Client Only Protected Pages Preflight
11
+ *
12
+ * Detects when pages in protected routes are marked "use client" which
13
+ * bypasses server-side authentication. This is a CRITICAL security issue.
14
+ *
15
+ * The problem:
16
+ * - Server Components can check auth before rendering
17
+ * - Client Components render first, THEN check auth
18
+ * - This creates a flash of protected content before redirect
19
+ * - Attacker can intercept the initial HTML with sensitive data
20
+ *
21
+ * DANGEROUS: 'use client' in app/store/[storeId]/page.tsx
22
+ * DANGEROUS: 'use client' in app/admin/page.tsx
23
+ * DANGEROUS: 'use client' in app/(protected)/page.tsx
24
+ *
25
+ * SAFE: Server Component that checks auth, then renders client child
26
+ * SAFE: Layout does auth check, page can be client component
27
+ */
28
+ const fs_1 = __importDefault(require("fs"));
29
+ const path_1 = __importDefault(require("path"));
30
+ const glob_1 = require("glob");
31
+ const console_chars_1 = require("../../utils/console-chars");
32
+ // METADATA - Required for plugin loader discovery
33
+ exports.id = "auth/client-only-protected-pages";
34
+ exports.name = "Client Only Protected Pages";
35
+ exports.description = "Detects protected pages marked 'use client' bypassing server auth";
36
+ exports.category = "auth";
37
+ exports.blocking = true; // Critical security check
38
+ exports.tags = ["auth", "security", "client", "server", "rsc", "critical"];
39
+ exports.requires = ["trading-card-system"];
40
+ /**
41
+ * Protected route patterns that MUST have server-side auth
42
+ */
43
+ const PROTECTED_ROUTE_PATTERNS = [
44
+ "app/store/**/page.tsx",
45
+ "app/admin/**/page.tsx",
46
+ "app/(protected)/**/page.tsx",
47
+ "app/(authenticated)/**/page.tsx",
48
+ "app/dashboard/**/page.tsx",
49
+ "app/settings/**/page.tsx",
50
+ "app/account/**/page.tsx",
51
+ "app/seller/**/page.tsx",
52
+ ];
53
+ /**
54
+ * These files MUST check auth server-side in the route
55
+ */
56
+ const LAYOUT_FILES = [
57
+ "app/store/layout.tsx",
58
+ "app/store/[storeId]/layout.tsx",
59
+ "app/admin/layout.tsx",
60
+ "app/(protected)/layout.tsx",
61
+ "app/dashboard/layout.tsx",
62
+ ];
63
+ function hasUseClientDirective(content) {
64
+ // Check first 500 chars for 'use client' directive
65
+ const header = content.substring(0, 500);
66
+ return /['"]use client['"]/.test(header);
67
+ }
68
+ function hasServerAuthCheck(content) {
69
+ // Check for server-side auth patterns
70
+ return (/getServerSession|auth\s*\(\s*\)|requireAuth/.test(content) &&
71
+ /redirect|notFound|throw/.test(content));
72
+ }
73
+ async function run() {
74
+ console.log(`\n${console_chars_1.emoji.shield} CLIENT ONLY PROTECTED PAGES CHECK`);
75
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
76
+ const issues = [];
77
+ const filesChecked = [];
78
+ // First, check if protected route layouts have server auth
79
+ console.log(`\n${console_chars_1.emoji.search} Checking protected route layouts...`);
80
+ const layoutsWithAuth = new Set();
81
+ for (const layoutPattern of LAYOUT_FILES) {
82
+ const matches = await (0, glob_1.glob)(layoutPattern, { cwd: process.cwd() });
83
+ for (const relativePath of matches) {
84
+ const filePath = path_1.default.join(process.cwd(), relativePath);
85
+ if (!fs_1.default.existsSync(filePath))
86
+ continue;
87
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
88
+ if (hasServerAuthCheck(content)) {
89
+ layoutsWithAuth.add(path_1.default.dirname(relativePath));
90
+ console.log(` ${console_chars_1.emoji.success} ${relativePath} has server-side auth`);
91
+ }
92
+ else if (!hasUseClientDirective(content)) {
93
+ // Server component layout without auth check
94
+ console.log(` ${console_chars_1.emoji.warning} ${relativePath} is server component but no auth check found`);
95
+ }
96
+ }
97
+ }
98
+ // Now check protected pages
99
+ console.log(`\n${console_chars_1.emoji.search} Checking protected pages...`);
100
+ const allFiles = [];
101
+ for (const pattern of PROTECTED_ROUTE_PATTERNS) {
102
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
103
+ allFiles.push(...matches);
104
+ }
105
+ const uniqueFiles = [...new Set(allFiles)];
106
+ for (const relativePath of uniqueFiles) {
107
+ const filePath = path_1.default.join(process.cwd(), relativePath);
108
+ if (!fs_1.default.existsSync(filePath))
109
+ continue;
110
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
111
+ filesChecked.push(relativePath);
112
+ const isClientComponent = hasUseClientDirective(content);
113
+ const pageDir = path_1.default.dirname(relativePath);
114
+ // Check if this page's parent layout has auth
115
+ const hasParentLayoutAuth = [...layoutsWithAuth].some((layoutDir) => pageDir.startsWith(layoutDir));
116
+ if (isClientComponent) {
117
+ if (!hasParentLayoutAuth) {
118
+ issues.push({
119
+ file: relativePath,
120
+ type: "client-protected-page",
121
+ description: `Protected page uses 'use client' without server auth in parent layout`,
122
+ critical: true,
123
+ });
124
+ console.log(` ${console_chars_1.emoji.error} ${relativePath}: Client component in protected route without parent layout auth`);
125
+ }
126
+ else {
127
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Client component but parent layout has auth`);
128
+ }
129
+ }
130
+ else {
131
+ // Server component - check if it has its own auth
132
+ if (hasServerAuthCheck(content)) {
133
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Server component with auth check`);
134
+ }
135
+ else if (hasParentLayoutAuth) {
136
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Server component, parent layout has auth`);
137
+ }
138
+ else {
139
+ console.log(` ${console_chars_1.emoji.warning} ${relativePath}: Server component but no visible auth check`);
140
+ }
141
+ }
142
+ }
143
+ // Summary
144
+ const criticalIssues = issues.filter((i) => i.critical);
145
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
146
+ console.log(` Protected pages checked: ${filesChecked.length}`);
147
+ console.log(` Layouts with server auth: ${layoutsWithAuth.size}`);
148
+ console.log(` Security issues: ${criticalIssues.length}`);
149
+ if (issues.length === 0) {
150
+ console.log(`\n${console_chars_1.emoji.success} CLIENT ONLY PROTECTED PAGES CHECK PASSED`);
151
+ console.log(`\nAll protected pages have proper server-side authentication.`);
152
+ return { success: true, errors: 0, warnings: 0 };
153
+ }
154
+ console.log(`\n${console_chars_1.emoji.error} Security issues found:`);
155
+ for (const issue of issues) {
156
+ console.log(` ${issue.file}: ${issue.description}`);
157
+ }
158
+ console.log(`\n${console_chars_1.emoji.info} To fix client-only protected pages:`);
159
+ console.log(` Option 1: Remove 'use client' and do auth in the page itself`);
160
+ console.log(` Option 2: Add auth check to parent layout.tsx (recommended)`);
161
+ console.log(` Option 3: Create a Server Component wrapper that checks auth`);
162
+ console.log(`\n Layout auth pattern:`);
163
+ console.log(` export default async function Layout({children}) {`);
164
+ console.log(` const session = await auth();`);
165
+ console.log(` if (!session) redirect('/login');`);
166
+ console.log(` return children;`);
167
+ console.log(` }`);
168
+ console.log(`\n${console_chars_1.emoji.error} CLIENT ONLY PROTECTED PAGES CHECK FAILED`);
169
+ return { success: false, errors: criticalIssues.length, warnings: 0 };
170
+ }
171
+ // Allow direct execution
172
+ if (require.main === module) {
173
+ run()
174
+ .then((result) => {
175
+ process.exit(result.success ? 0 : 1);
176
+ })
177
+ .catch((err) => {
178
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
179
+ process.exit(1);
180
+ });
181
+ }
182
+ //# sourceMappingURL=client-only-protected-pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-protected-pages.js","sourceRoot":"","sources":["../../../src/checks/auth/client-only-protected-pages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/empty-data-instead-of-redirect";
3
+ export declare const name = "Empty Data Instead of Redirect";
4
+ export declare const description = "Detects pages returning empty data instead of redirecting on access failure";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=empty-data-instead-of-redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-data-instead-of-redirect.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/empty-data-instead-of-redirect.ts"],"names":[],"mappings":";AA4BA,eAAO,MAAM,EAAE,wCAAwC,CAAC;AACxD,eAAO,MAAM,IAAI,mCAAmC,CAAC;AACrD,eAAO,MAAM,WAAW,gFAAgF,CAAC;AACzG,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAAqD,CAAC;AACvE,eAAO,MAAM,QAAQ,UAA0B,CAAC;AAiFhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuG3F"}
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Empty Data Instead of Redirect Preflight
11
+ *
12
+ * Detects when pages return empty arrays/objects instead of redirecting
13
+ * on access failure. This is a security anti-pattern because:
14
+ *
15
+ * BAD: if (!hasAccess) return { data: [] } // Hides access failure
16
+ * BAD: if (!session) return [] // Silent auth failure
17
+ * BAD: if (!store) return null // Doesn't tell user they need to login
18
+ *
19
+ * GOOD: if (!hasAccess) redirect('/unauthorized')
20
+ * GOOD: if (!session) redirect('/login')
21
+ * GOOD: if (!store) notFound()
22
+ *
23
+ * Problems with returning empty data:
24
+ * - User sees blank page with no explanation
25
+ * - Masks authorization failures
26
+ * - Makes debugging harder
27
+ * - May expose that resource exists (information leak)
28
+ */
29
+ const fs_1 = __importDefault(require("fs"));
30
+ const path_1 = __importDefault(require("path"));
31
+ const glob_1 = require("glob");
32
+ const console_chars_1 = require("../../utils/console-chars");
33
+ // METADATA - Required for plugin loader discovery
34
+ exports.id = "auth/empty-data-instead-of-redirect";
35
+ exports.name = "Empty Data Instead of Redirect";
36
+ exports.description = "Detects pages returning empty data instead of redirecting on access failure";
37
+ exports.category = "auth";
38
+ exports.blocking = true;
39
+ exports.tags = ["auth", "security", "redirect", "ux", "critical"];
40
+ exports.requires = ["trading-card-system"];
41
+ /**
42
+ * File patterns to check
43
+ */
44
+ const FILE_PATTERNS = [
45
+ "app/**/page.tsx",
46
+ "app/**/layout.tsx",
47
+ "app/api/**/route.ts",
48
+ ];
49
+ /**
50
+ * Dangerous patterns - returning empty on auth/access failure
51
+ */
52
+ const DANGEROUS_PATTERNS = {
53
+ // Return empty array on !session
54
+ emptyArrayNoSession: {
55
+ pattern: /if\s*\(\s*!session\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null|undefined)/,
56
+ description: "Returns empty data when session missing (should redirect to login)",
57
+ critical: true,
58
+ },
59
+ // Return empty array on !hasAccess
60
+ emptyArrayNoAccess: {
61
+ pattern: /if\s*\(\s*!(?:hasAccess|canAccess|isAuthorized|hasPermission)\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null)/,
62
+ description: "Returns empty data on access failure (should redirect or show error)",
63
+ critical: true,
64
+ },
65
+ // Return empty on !store
66
+ emptyArrayNoStore: {
67
+ pattern: /if\s*\(\s*!store\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null)/,
68
+ description: "Returns empty data when store not found (should use notFound())",
69
+ critical: true,
70
+ },
71
+ // Return empty data prop
72
+ emptyDataProp: {
73
+ pattern: /return\s*\{[^}]*(?:data|items|results):\s*\[\s*\][^}]*\}(?:(?!redirect|notFound).)*$/m,
74
+ description: "Returns object with empty data array (may mask access failure)",
75
+ critical: false,
76
+ },
77
+ // Early return empty in RSC
78
+ earlyReturnEmpty: {
79
+ pattern: /(?:async\s+)?function\s+(?:Page|Layout)\s*\([^)]*\)[^{]*\{[^}]*if\s*\([^)]*\)\s*return\s*(?:null|\[\]|\{\})/s,
80
+ description: "Page/Layout returns empty early (should redirect instead)",
81
+ critical: false,
82
+ },
83
+ // Return NextResponse with empty body on auth failure
84
+ nextResponseEmpty: {
85
+ pattern: /if\s*\(\s*!(?:session|auth|user)\s*\)[^{]*return\s*NextResponse\.json\s*\(\s*(?:\[\]|\{\}|null)\s*\)/,
86
+ description: "API returns empty response on auth failure (should return 401)",
87
+ critical: true,
88
+ },
89
+ };
90
+ /**
91
+ * Safe patterns that indicate proper handling
92
+ */
93
+ const SAFE_PATTERNS = [
94
+ // Redirect on failure
95
+ /if\s*\(\s*!session\s*\)[^{]*redirect/,
96
+ /if\s*\(\s*!hasAccess\s*\)[^{]*redirect/,
97
+ // notFound() call
98
+ /if\s*\(\s*!(?:store|data|item)\s*\)[^{]*notFound\s*\(\)/,
99
+ // Proper error response
100
+ /if\s*\(\s*!session\s*\)[^{]*return\s*(?:NextResponse\.json\s*\([^)]*,\s*\{\s*status:\s*401|new\s*Response\s*\([^)]*,\s*\{\s*status:\s*401)/,
101
+ // Throw error
102
+ /if\s*\(\s*!(?:session|hasAccess)\s*\)[^{]*throw/,
103
+ ];
104
+ function getLineNumber(content, position) {
105
+ return content.substring(0, position).split("\n").length;
106
+ }
107
+ async function run() {
108
+ console.log(`\n${console_chars_1.emoji.shield} EMPTY DATA INSTEAD OF REDIRECT CHECK`);
109
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
110
+ const issues = [];
111
+ const filesChecked = [];
112
+ // Find files
113
+ const allFiles = [];
114
+ for (const pattern of FILE_PATTERNS) {
115
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
116
+ allFiles.push(...matches);
117
+ }
118
+ const uniqueFiles = [...new Set(allFiles)];
119
+ console.log(`\n${console_chars_1.emoji.search} Scanning ${uniqueFiles.length} page/route files...`);
120
+ for (const relativePath of uniqueFiles) {
121
+ const filePath = path_1.default.join(process.cwd(), relativePath);
122
+ if (!fs_1.default.existsSync(filePath))
123
+ continue;
124
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
125
+ filesChecked.push(relativePath);
126
+ // Skip if file has proper redirect/notFound handling
127
+ const hasSafePattern = SAFE_PATTERNS.some((pattern) => pattern.test(content));
128
+ // Check for dangerous patterns
129
+ for (const [name, check] of Object.entries(DANGEROUS_PATTERNS)) {
130
+ const regex = new RegExp(check.pattern.source, "g");
131
+ let match;
132
+ while ((match = regex.exec(content)) !== null) {
133
+ // Check if there's a safe pattern nearby
134
+ const nearbyCode = content.substring(Math.max(0, match.index - 100), Math.min(content.length, match.index + 300));
135
+ if (SAFE_PATTERNS.some((pattern) => pattern.test(nearbyCode))) {
136
+ continue;
137
+ }
138
+ const lineNum = getLineNumber(content, match.index);
139
+ issues.push({
140
+ file: relativePath,
141
+ type: "empty-data-return",
142
+ pattern: name,
143
+ description: check.description,
144
+ critical: check.critical,
145
+ line: lineNum,
146
+ });
147
+ }
148
+ }
149
+ }
150
+ // Summary
151
+ const criticalIssues = issues.filter((i) => i.critical);
152
+ const warningIssues = issues.filter((i) => !i.critical);
153
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
154
+ console.log(` Files checked: ${filesChecked.length}`);
155
+ console.log(` Critical issues: ${criticalIssues.length}`);
156
+ console.log(` Warning issues: ${warningIssues.length}`);
157
+ if (issues.length === 0) {
158
+ console.log(`\n${console_chars_1.emoji.success} EMPTY DATA INSTEAD OF REDIRECT CHECK PASSED`);
159
+ console.log(`\nAll pages properly redirect or show errors on access failure.`);
160
+ return { success: true, errors: 0, warnings: 0 };
161
+ }
162
+ // Group by file
163
+ const issuesByFile = new Map();
164
+ for (const issue of issues) {
165
+ const existing = issuesByFile.get(issue.file) || [];
166
+ existing.push(issue);
167
+ issuesByFile.set(issue.file, existing);
168
+ }
169
+ console.log(`\n${console_chars_1.emoji.error} Issues found:`);
170
+ for (const [file, fileIssues] of issuesByFile) {
171
+ console.log(`\n ${file}:`);
172
+ for (const issue of fileIssues) {
173
+ const icon = issue.critical ? console_chars_1.emoji.error : console_chars_1.emoji.warning;
174
+ console.log(` ${icon} Line ${issue.line}: ${issue.description}`);
175
+ }
176
+ }
177
+ console.log(`\n${console_chars_1.emoji.info} To fix empty data returns:`);
178
+ console.log(` 1. On missing session: redirect('/login') or redirect('/auth/signin')`);
179
+ console.log(` 2. On access denied: redirect('/unauthorized') or return 403`);
180
+ console.log(` 3. On missing resource: notFound() to show 404 page`);
181
+ console.log(` 4. API routes: return NextResponse.json({error}, {status: 401/403})`);
182
+ if (criticalIssues.length > 0) {
183
+ console.log(`\n${console_chars_1.emoji.error} EMPTY DATA INSTEAD OF REDIRECT CHECK FAILED`);
184
+ return { success: false, errors: criticalIssues.length, warnings: warningIssues.length };
185
+ }
186
+ console.log(`\n${console_chars_1.emoji.warning} EMPTY DATA INSTEAD OF REDIRECT CHECK PASSED WITH WARNINGS`);
187
+ return { success: true, errors: 0, warnings: warningIssues.length };
188
+ }
189
+ // Allow direct execution
190
+ if (require.main === module) {
191
+ run()
192
+ .then((result) => {
193
+ process.exit(result.success ? 0 : 1);
194
+ })
195
+ .catch((err) => {
196
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
197
+ process.exit(1);
198
+ });
199
+ }
200
+ //# sourceMappingURL=empty-data-instead-of-redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-data-instead-of-redirect.js","sourceRoot":"","sources":["../../../src/checks/auth/empty-data-instead-of-redirect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/store-id-fallback";
3
+ export declare const name = "Store ID Fallback Detection";
4
+ export declare const description = "Detects risky patterns where storeId falls back to userId";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=store-id-fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-id-fallback.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/store-id-fallback.ts"],"names":[],"mappings":";AA4BA,eAAO,MAAM,EAAE,2BAA2B,CAAC;AAC3C,eAAO,MAAM,IAAI,gCAAgC,CAAC;AAClD,eAAO,MAAM,WAAW,8DAA8D,CAAC;AACvF,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAAwD,CAAC;AAC1E,eAAO,MAAM,QAAQ,UAA0B,CAAC;AA4FhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgH3F"}
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Store ID Fallback Preflight
11
+ *
12
+ * Detects risky patterns where storeId falls back to userId or other values.
13
+ * This pattern can cause security issues and data leakage:
14
+ *
15
+ * DANGEROUS: storeId || userId - Falls back to userId if storeId missing
16
+ * DANGEROUS: storeId ?? session.user.id - Silently uses userId as storeId
17
+ * DANGEROUS: params.storeId || defaultStoreId - May expose wrong store
18
+ *
19
+ * These patterns often indicate:
20
+ * - Missing store context in the request
21
+ * - Assumption that userId === storeId (only true for store owners)
22
+ * - Logic errors that expose other users' stores
23
+ *
24
+ * Correct patterns:
25
+ * - Always require explicit storeId
26
+ * - Validate storeId against user's accessible stores
27
+ * - Return error if storeId is missing, don't fallback
28
+ */
29
+ const fs_1 = __importDefault(require("fs"));
30
+ const path_1 = __importDefault(require("path"));
31
+ const glob_1 = require("glob");
32
+ const console_chars_1 = require("../../utils/console-chars");
33
+ // METADATA - Required for plugin loader discovery
34
+ exports.id = "auth/store-id-fallback";
35
+ exports.name = "Store ID Fallback Detection";
36
+ exports.description = "Detects risky patterns where storeId falls back to userId";
37
+ exports.category = "auth";
38
+ exports.blocking = true; // Critical security check
39
+ exports.tags = ["auth", "security", "store", "fallback", "critical"];
40
+ exports.requires = ["trading-card-system"];
41
+ /**
42
+ * File patterns to check
43
+ */
44
+ const FILE_PATTERNS = [
45
+ "app/store/**/*.tsx",
46
+ "app/store/**/*.ts",
47
+ "app/api/store/**/*.ts",
48
+ "app/(store)/**/*.tsx",
49
+ "app/(store)/**/*.ts",
50
+ "lib/store*.ts",
51
+ "hooks/useStore*.ts",
52
+ "hooks/useStore*.tsx",
53
+ ];
54
+ /**
55
+ * Dangerous fallback patterns
56
+ */
57
+ const DANGEROUS_PATTERNS = {
58
+ // storeId || userId fallback
59
+ storeIdOrUserId: {
60
+ pattern: /storeId\s*\|\|\s*(?:userId|session\.user\.id|user\.id)/,
61
+ description: "storeId falls back to userId (dangerous - userId !== storeId for non-owners)",
62
+ critical: true,
63
+ },
64
+ // storeId ?? userId fallback
65
+ storeIdNullishUserId: {
66
+ pattern: /storeId\s*\?\?\s*(?:userId|session\.user\.id|user\.id)/,
67
+ description: "storeId nullish coalesces to userId",
68
+ critical: true,
69
+ },
70
+ // params.storeId || default
71
+ paramsStoreIdFallback: {
72
+ pattern: /params\.storeId\s*\|\|\s*(?!null|undefined|throw|redirect)/,
73
+ description: "params.storeId falls back to another value instead of erroring",
74
+ critical: true,
75
+ },
76
+ // Default storeId assignment
77
+ defaultStoreId: {
78
+ pattern: /storeId\s*=\s*storeId\s*\|\|\s*|storeId\s*\?\?=\s*(?!null)/,
79
+ description: "storeId assigned a default value instead of requiring explicit value",
80
+ critical: true,
81
+ },
82
+ // userId as storeId directly
83
+ userIdAsStoreId: {
84
+ pattern: /storeId:\s*(?:userId|session\.user\.id|user\.id)(?!\s*\|\||[^,}\s])/,
85
+ description: "userId used directly as storeId (only valid for store owners)",
86
+ critical: false, // Warning - might be intentional for owner operations
87
+ },
88
+ // Ternary fallback to userId
89
+ ternaryFallbackUserId: {
90
+ pattern: /storeId\s*\?\s*storeId\s*:\s*(?:userId|session\.user\.id)/,
91
+ description: "Ternary expression falls back to userId when storeId missing",
92
+ critical: true,
93
+ },
94
+ };
95
+ /**
96
+ * Acceptable patterns (used for context - don't flag these)
97
+ */
98
+ const SAFE_PATTERNS = [
99
+ // Explicit error on missing storeId
100
+ /if\s*\(\s*!storeId\s*\)\s*(?:throw|return.*error|redirect)/,
101
+ // Required storeId validation
102
+ /storeId.*required|require.*storeId/i,
103
+ // Lookup user's default store (intentional)
104
+ /getUserDefaultStore|getDefaultStoreForUser/i,
105
+ ];
106
+ function getLineNumber(content, position) {
107
+ return content.substring(0, position).split("\n").length;
108
+ }
109
+ function getCodeContext(content, position) {
110
+ const lines = content.split("\n");
111
+ const lineNum = getLineNumber(content, position);
112
+ const start = Math.max(0, lineNum - 2);
113
+ const end = Math.min(lines.length, lineNum + 1);
114
+ return lines.slice(start, end).join("\n").trim();
115
+ }
116
+ async function run() {
117
+ console.log(`\n${console_chars_1.emoji.shield} STORE ID FALLBACK DETECTION`);
118
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
119
+ const issues = [];
120
+ const filesChecked = [];
121
+ // Find files
122
+ const allFiles = [];
123
+ for (const pattern of FILE_PATTERNS) {
124
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
125
+ allFiles.push(...matches);
126
+ }
127
+ const uniqueFiles = [...new Set(allFiles)];
128
+ console.log(`\n${console_chars_1.emoji.search} Scanning ${uniqueFiles.length} store-related files...`);
129
+ if (uniqueFiles.length === 0) {
130
+ console.log(`\n${console_chars_1.emoji.warning} No store files found - skipping check`);
131
+ return { success: true, errors: 0, warnings: 1 };
132
+ }
133
+ for (const relativePath of uniqueFiles) {
134
+ const filePath = path_1.default.join(process.cwd(), relativePath);
135
+ if (!fs_1.default.existsSync(filePath))
136
+ continue;
137
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
138
+ filesChecked.push(relativePath);
139
+ // Skip if file has safe patterns indicating proper handling
140
+ const hasSafePattern = SAFE_PATTERNS.some((pattern) => pattern.test(content));
141
+ // Check for dangerous patterns
142
+ for (const [name, check] of Object.entries(DANGEROUS_PATTERNS)) {
143
+ const regex = new RegExp(check.pattern.source, "g");
144
+ let match;
145
+ while ((match = regex.exec(content)) !== null) {
146
+ // Skip if nearby code has safe pattern
147
+ const nearbyCode = content.substring(Math.max(0, match.index - 200), Math.min(content.length, match.index + 200));
148
+ if (SAFE_PATTERNS.some((pattern) => pattern.test(nearbyCode))) {
149
+ continue;
150
+ }
151
+ const lineNum = getLineNumber(content, match.index);
152
+ issues.push({
153
+ file: relativePath,
154
+ type: "dangerous-fallback",
155
+ pattern: name,
156
+ description: check.description,
157
+ critical: check.critical,
158
+ line: lineNum,
159
+ code: getCodeContext(content, match.index),
160
+ });
161
+ }
162
+ }
163
+ }
164
+ // Summary
165
+ const criticalIssues = issues.filter((i) => i.critical);
166
+ const warningIssues = issues.filter((i) => !i.critical);
167
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
168
+ console.log(` Files checked: ${filesChecked.length}`);
169
+ console.log(` Critical issues: ${criticalIssues.length}`);
170
+ console.log(` Warning issues: ${warningIssues.length}`);
171
+ if (issues.length === 0) {
172
+ console.log(`\n${console_chars_1.emoji.success} STORE ID FALLBACK DETECTION PASSED`);
173
+ console.log(`\nNo dangerous storeId fallback patterns found.`);
174
+ return { success: true, errors: 0, warnings: 0 };
175
+ }
176
+ // Display issues
177
+ if (criticalIssues.length > 0) {
178
+ console.log(`\n${console_chars_1.emoji.error} Critical issues:`);
179
+ for (const issue of criticalIssues) {
180
+ console.log(`\n ${issue.file}:${issue.line}`);
181
+ console.log(` ${issue.description}`);
182
+ if (issue.code) {
183
+ const indented = issue.code.split("\n").map((l) => ` ${l}`).join("\n");
184
+ console.log(indented);
185
+ }
186
+ }
187
+ }
188
+ if (warningIssues.length > 0) {
189
+ console.log(`\n${console_chars_1.emoji.warning} Warning issues:`);
190
+ for (const issue of warningIssues) {
191
+ console.log(` ${issue.file}:${issue.line}: ${issue.description}`);
192
+ }
193
+ }
194
+ console.log(`\n${console_chars_1.emoji.info} To fix storeId fallback issues:`);
195
+ console.log(` 1. Never use: storeId || userId (userId !== storeId for delegated users)`);
196
+ console.log(` 2. Always require explicit storeId from route params or context`);
197
+ console.log(` 3. Validate storeId against user's accessible stores`);
198
+ console.log(` 4. Return error/redirect if storeId is missing, don't fallback`);
199
+ if (criticalIssues.length > 0) {
200
+ console.log(`\n${console_chars_1.emoji.error} STORE ID FALLBACK DETECTION FAILED`);
201
+ return { success: false, errors: criticalIssues.length, warnings: warningIssues.length };
202
+ }
203
+ console.log(`\n${console_chars_1.emoji.warning} STORE ID FALLBACK DETECTION PASSED WITH WARNINGS`);
204
+ return { success: true, errors: 0, warnings: warningIssues.length };
205
+ }
206
+ // Allow direct execution
207
+ if (require.main === module) {
208
+ run()
209
+ .then((result) => {
210
+ process.exit(result.success ? 0 : 1);
211
+ })
212
+ .catch((err) => {
213
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
214
+ process.exit(1);
215
+ });
216
+ }
217
+ //# sourceMappingURL=store-id-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-id-fallback.js","sourceRoot":"","sources":["../../../src/checks/auth/store-id-fallback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/store-page-auth-guard";
3
+ export declare const name = "Store Page Auth Guard";
4
+ export declare const description = "Detects store pages missing auth or store access verification";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=store-page-auth-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-page-auth-guard.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/store-page-auth-guard.ts"],"names":[],"mappings":";AA2BA,eAAO,MAAM,EAAE,+BAA+B,CAAC;AAC/C,eAAO,MAAM,IAAI,0BAA0B,CAAC;AAC5C,eAAO,MAAM,WAAW,kEAAkE,CAAC;AAC3F,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAA8D,CAAC;AAChF,eAAO,MAAM,QAAQ,UAA0B,CAAC;AAgFhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0G3F"}
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Store Page Auth Guard Preflight
11
+ *
12
+ * Detects store pages that are missing authentication or store access verification.
13
+ * This is CRITICAL for security - store pages must verify:
14
+ * 1. User is authenticated (session exists)
15
+ * 2. User has access to the specific store (ownership or delegation)
16
+ * 3. Store exists and is not deleted
17
+ *
18
+ * Common vulnerable patterns:
19
+ * - Store pages without getServerSession or auth() call
20
+ * - Store API routes without checkPermission or store access check
21
+ * - Pages that fetch store data without verifying user access
22
+ *
23
+ * Prevents:
24
+ * - Unauthorized access to store data
25
+ * - Store data leakage between users
26
+ * - IDOR vulnerabilities
27
+ */
28
+ const fs_1 = __importDefault(require("fs"));
29
+ const path_1 = __importDefault(require("path"));
30
+ const glob_1 = require("glob");
31
+ const console_chars_1 = require("../../utils/console-chars");
32
+ // METADATA - Required for plugin loader discovery
33
+ exports.id = "auth/store-page-auth-guard";
34
+ exports.name = "Store Page Auth Guard";
35
+ exports.description = "Detects store pages missing auth or store access verification";
36
+ exports.category = "auth";
37
+ exports.blocking = true; // Critical security check
38
+ exports.tags = ["auth", "security", "store", "access-control", "critical"];
39
+ exports.requires = ["trading-card-system"];
40
+ /**
41
+ * Store page patterns to check
42
+ */
43
+ const STORE_PAGE_PATTERNS = [
44
+ "app/store/**/page.tsx",
45
+ "app/store/**/layout.tsx",
46
+ "app/api/store/**/route.ts",
47
+ "app/(store)/**/page.tsx",
48
+ "app/(store)/**/layout.tsx",
49
+ ];
50
+ /**
51
+ * Required auth patterns for store pages
52
+ */
53
+ const REQUIRED_AUTH_PATTERNS = {
54
+ // Session/auth check
55
+ sessionCheck: {
56
+ pattern: /getServerSession|auth\s*\(\s*\)|requireAuth|getSession/,
57
+ description: "Session/authentication check",
58
+ critical: true,
59
+ },
60
+ // Store access verification
61
+ storeAccessCheck: {
62
+ pattern: /checkPermission|getUserStoreAccess|verifyStoreAccess|storeId.*session|hasStoreAccess/i,
63
+ description: "Store access verification",
64
+ critical: true,
65
+ },
66
+ // Store ownership or delegation check
67
+ ownershipCheck: {
68
+ pattern: /store\.ownerId|ownerId.*===.*userId|userId.*===.*ownerId|delegatedAccess|storeAccess/i,
69
+ description: "Store ownership or delegation check",
70
+ critical: true,
71
+ },
72
+ };
73
+ /**
74
+ * Patterns that indicate store data access (requires auth)
75
+ */
76
+ const STORE_DATA_PATTERNS = [
77
+ /findUnique.*store|findFirst.*store|prisma\.authStores/i,
78
+ /store\.listings|store\.orders|store\.products/i,
79
+ /getStoreData|fetchStore|loadStore/i,
80
+ /params\.storeId|storeId.*params/i,
81
+ ];
82
+ /**
83
+ * Anti-patterns - dangerous code patterns
84
+ */
85
+ const ANTI_PATTERNS = {
86
+ // Fetch store without auth
87
+ fetchStoreNoAuth: {
88
+ pattern: /(?:findUnique|findFirst)[\s\S]{0,100}authStores(?:(?!session|auth|checkPermission).)*\}/s,
89
+ description: "Store data fetched without authentication check nearby",
90
+ },
91
+ // Direct storeId from params without verification
92
+ directStoreIdUsage: {
93
+ pattern: /params\.storeId(?:(?!checkPermission|verifyAccess|hasAccess).){0,200}prisma/s,
94
+ description: "storeId from params used directly without access verification",
95
+ },
96
+ // Return store data without auth check
97
+ returnStoreDataNoAuth: {
98
+ pattern: /return\s*(?:NextResponse\.json|Response\.json)[\s\S]{0,50}store(?:(?!session|auth).){0,100}\}/s,
99
+ description: "Store data returned without visible auth check",
100
+ },
101
+ };
102
+ function hasStoreDataAccess(content) {
103
+ return STORE_DATA_PATTERNS.some((pattern) => pattern.test(content));
104
+ }
105
+ async function run() {
106
+ console.log(`\n${console_chars_1.emoji.shield} STORE PAGE AUTH GUARD CHECK`);
107
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
108
+ const issues = [];
109
+ const filesChecked = [];
110
+ // Find all store pages/routes
111
+ const allFiles = [];
112
+ for (const pattern of STORE_PAGE_PATTERNS) {
113
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
114
+ allFiles.push(...matches);
115
+ }
116
+ const uniqueFiles = [...new Set(allFiles)];
117
+ console.log(`\n${console_chars_1.emoji.search} Scanning ${uniqueFiles.length} store pages/routes...`);
118
+ if (uniqueFiles.length === 0) {
119
+ console.log(`\n${console_chars_1.emoji.warning} No store pages found - skipping check`);
120
+ return { success: true, errors: 0, warnings: 1 };
121
+ }
122
+ for (const relativePath of uniqueFiles) {
123
+ const filePath = path_1.default.join(process.cwd(), relativePath);
124
+ if (!fs_1.default.existsSync(filePath))
125
+ continue;
126
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
127
+ filesChecked.push(relativePath);
128
+ // Skip if file doesn't access store data
129
+ if (!hasStoreDataAccess(content)) {
130
+ continue;
131
+ }
132
+ console.log(`\n${console_chars_1.emoji.file} ${relativePath} (accesses store data)`);
133
+ // Check for required auth patterns
134
+ const hasSessionCheck = REQUIRED_AUTH_PATTERNS.sessionCheck.pattern.test(content);
135
+ const hasStoreAccessCheck = REQUIRED_AUTH_PATTERNS.storeAccessCheck.pattern.test(content);
136
+ const hasOwnershipCheck = REQUIRED_AUTH_PATTERNS.ownershipCheck.pattern.test(content);
137
+ if (!hasSessionCheck) {
138
+ issues.push({
139
+ file: relativePath,
140
+ type: "missing-auth",
141
+ description: "Missing session/authentication check",
142
+ critical: true,
143
+ });
144
+ console.log(` ${console_chars_1.emoji.error} Missing: Session/authentication check`);
145
+ }
146
+ else {
147
+ console.log(` ${console_chars_1.emoji.success} Found: Session check`);
148
+ }
149
+ if (!hasStoreAccessCheck && !hasOwnershipCheck) {
150
+ issues.push({
151
+ file: relativePath,
152
+ type: "missing-store-access",
153
+ description: "Missing store access verification",
154
+ critical: true,
155
+ });
156
+ console.log(` ${console_chars_1.emoji.error} Missing: Store access verification`);
157
+ }
158
+ else {
159
+ console.log(` ${console_chars_1.emoji.success} Found: Store access check`);
160
+ }
161
+ // Check for anti-patterns
162
+ for (const [name, check] of Object.entries(ANTI_PATTERNS)) {
163
+ if (check.pattern.test(content)) {
164
+ issues.push({
165
+ file: relativePath,
166
+ type: "anti-pattern",
167
+ description: check.description,
168
+ critical: true,
169
+ });
170
+ console.log(` ${console_chars_1.emoji.error} Anti-pattern: ${check.description}`);
171
+ }
172
+ }
173
+ }
174
+ // Summary
175
+ const criticalIssues = issues.filter((i) => i.critical);
176
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
177
+ console.log(` Store pages checked: ${filesChecked.length}`);
178
+ console.log(` Security issues: ${criticalIssues.length}`);
179
+ if (issues.length === 0) {
180
+ console.log(`\n${console_chars_1.emoji.success} STORE PAGE AUTH GUARD CHECK PASSED`);
181
+ console.log(`\nAll store pages have proper authentication and access control.`);
182
+ return { success: true, errors: 0, warnings: 0 };
183
+ }
184
+ console.log(`\n${console_chars_1.emoji.error} Security issues found:`);
185
+ for (const issue of issues) {
186
+ console.log(` ${issue.file}: ${issue.description}`);
187
+ }
188
+ console.log(`\n${console_chars_1.emoji.info} Store page auth requirements:`);
189
+ console.log(` 1. Call getServerSession() or auth() to verify authentication`);
190
+ console.log(` 2. Call checkPermission() or getUserStoreAccess() to verify store access`);
191
+ console.log(` 3. Verify store ownership or delegation before returning data`);
192
+ console.log(` 4. Redirect or return 403 on access failure (don't return empty data)`);
193
+ console.log(`\n${console_chars_1.emoji.error} STORE PAGE AUTH GUARD CHECK FAILED`);
194
+ return { success: false, errors: criticalIssues.length, warnings: 0 };
195
+ }
196
+ // Allow direct execution
197
+ if (require.main === module) {
198
+ run()
199
+ .then((result) => {
200
+ process.exit(result.success ? 0 : 1);
201
+ })
202
+ .catch((err) => {
203
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
204
+ process.exit(1);
205
+ });
206
+ }
207
+ //# sourceMappingURL=store-page-auth-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-page-auth-guard.js","sourceRoot":"","sources":["../../../src/checks/auth/store-page-auth-guard.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empline/preflight",
3
- "version": "1.1.33",
3
+ "version": "1.1.34",
4
4
  "description": "Distributable preflight validation system with app-specific plugin support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",