@oculum/scanner 1.0.0
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.
- package/dist/formatters/cli-terminal.d.ts +27 -0
- package/dist/formatters/cli-terminal.d.ts.map +1 -0
- package/dist/formatters/cli-terminal.js +412 -0
- package/dist/formatters/cli-terminal.js.map +1 -0
- package/dist/formatters/github-comment.d.ts +41 -0
- package/dist/formatters/github-comment.d.ts.map +1 -0
- package/dist/formatters/github-comment.js +306 -0
- package/dist/formatters/github-comment.js.map +1 -0
- package/dist/formatters/grouping.d.ts +52 -0
- package/dist/formatters/grouping.d.ts.map +1 -0
- package/dist/formatters/grouping.js +152 -0
- package/dist/formatters/grouping.js.map +1 -0
- package/dist/formatters/index.d.ts +9 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +35 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/vscode-diagnostic.d.ts +103 -0
- package/dist/formatters/vscode-diagnostic.d.ts.map +1 -0
- package/dist/formatters/vscode-diagnostic.js +151 -0
- package/dist/formatters/vscode-diagnostic.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +648 -0
- package/dist/index.js.map +1 -0
- package/dist/layer1/comments.d.ts +8 -0
- package/dist/layer1/comments.d.ts.map +1 -0
- package/dist/layer1/comments.js +203 -0
- package/dist/layer1/comments.js.map +1 -0
- package/dist/layer1/config-audit.d.ts +8 -0
- package/dist/layer1/config-audit.d.ts.map +1 -0
- package/dist/layer1/config-audit.js +252 -0
- package/dist/layer1/config-audit.js.map +1 -0
- package/dist/layer1/entropy.d.ts +8 -0
- package/dist/layer1/entropy.d.ts.map +1 -0
- package/dist/layer1/entropy.js +500 -0
- package/dist/layer1/entropy.js.map +1 -0
- package/dist/layer1/file-flags.d.ts +7 -0
- package/dist/layer1/file-flags.d.ts.map +1 -0
- package/dist/layer1/file-flags.js +112 -0
- package/dist/layer1/file-flags.js.map +1 -0
- package/dist/layer1/index.d.ts +36 -0
- package/dist/layer1/index.d.ts.map +1 -0
- package/dist/layer1/index.js +132 -0
- package/dist/layer1/index.js.map +1 -0
- package/dist/layer1/patterns.d.ts +8 -0
- package/dist/layer1/patterns.d.ts.map +1 -0
- package/dist/layer1/patterns.js +482 -0
- package/dist/layer1/patterns.js.map +1 -0
- package/dist/layer1/urls.d.ts +8 -0
- package/dist/layer1/urls.d.ts.map +1 -0
- package/dist/layer1/urls.js +296 -0
- package/dist/layer1/urls.js.map +1 -0
- package/dist/layer1/weak-crypto.d.ts +7 -0
- package/dist/layer1/weak-crypto.d.ts.map +1 -0
- package/dist/layer1/weak-crypto.js +291 -0
- package/dist/layer1/weak-crypto.js.map +1 -0
- package/dist/layer2/ai-agent-tools.d.ts +19 -0
- package/dist/layer2/ai-agent-tools.d.ts.map +1 -0
- package/dist/layer2/ai-agent-tools.js +528 -0
- package/dist/layer2/ai-agent-tools.js.map +1 -0
- package/dist/layer2/ai-endpoint-protection.d.ts +36 -0
- package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -0
- package/dist/layer2/ai-endpoint-protection.js +332 -0
- package/dist/layer2/ai-endpoint-protection.js.map +1 -0
- package/dist/layer2/ai-execution-sinks.d.ts +18 -0
- package/dist/layer2/ai-execution-sinks.d.ts.map +1 -0
- package/dist/layer2/ai-execution-sinks.js +496 -0
- package/dist/layer2/ai-execution-sinks.js.map +1 -0
- package/dist/layer2/ai-fingerprinting.d.ts +7 -0
- package/dist/layer2/ai-fingerprinting.d.ts.map +1 -0
- package/dist/layer2/ai-fingerprinting.js +654 -0
- package/dist/layer2/ai-fingerprinting.js.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts +19 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.js +356 -0
- package/dist/layer2/ai-prompt-hygiene.js.map +1 -0
- package/dist/layer2/ai-rag-safety.d.ts +21 -0
- package/dist/layer2/ai-rag-safety.d.ts.map +1 -0
- package/dist/layer2/ai-rag-safety.js +459 -0
- package/dist/layer2/ai-rag-safety.js.map +1 -0
- package/dist/layer2/ai-schema-validation.d.ts +25 -0
- package/dist/layer2/ai-schema-validation.d.ts.map +1 -0
- package/dist/layer2/ai-schema-validation.js +375 -0
- package/dist/layer2/ai-schema-validation.js.map +1 -0
- package/dist/layer2/auth-antipatterns.d.ts +20 -0
- package/dist/layer2/auth-antipatterns.d.ts.map +1 -0
- package/dist/layer2/auth-antipatterns.js +333 -0
- package/dist/layer2/auth-antipatterns.js.map +1 -0
- package/dist/layer2/byok-patterns.d.ts +12 -0
- package/dist/layer2/byok-patterns.d.ts.map +1 -0
- package/dist/layer2/byok-patterns.js +299 -0
- package/dist/layer2/byok-patterns.js.map +1 -0
- package/dist/layer2/dangerous-functions.d.ts +7 -0
- package/dist/layer2/dangerous-functions.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions.js +1375 -0
- package/dist/layer2/dangerous-functions.js.map +1 -0
- package/dist/layer2/data-exposure.d.ts +16 -0
- package/dist/layer2/data-exposure.d.ts.map +1 -0
- package/dist/layer2/data-exposure.js +279 -0
- package/dist/layer2/data-exposure.js.map +1 -0
- package/dist/layer2/framework-checks.d.ts +7 -0
- package/dist/layer2/framework-checks.d.ts.map +1 -0
- package/dist/layer2/framework-checks.js +388 -0
- package/dist/layer2/framework-checks.js.map +1 -0
- package/dist/layer2/index.d.ts +58 -0
- package/dist/layer2/index.d.ts.map +1 -0
- package/dist/layer2/index.js +380 -0
- package/dist/layer2/index.js.map +1 -0
- package/dist/layer2/logic-gates.d.ts +7 -0
- package/dist/layer2/logic-gates.d.ts.map +1 -0
- package/dist/layer2/logic-gates.js +182 -0
- package/dist/layer2/logic-gates.js.map +1 -0
- package/dist/layer2/risky-imports.d.ts +7 -0
- package/dist/layer2/risky-imports.d.ts.map +1 -0
- package/dist/layer2/risky-imports.js +161 -0
- package/dist/layer2/risky-imports.js.map +1 -0
- package/dist/layer2/variables.d.ts +8 -0
- package/dist/layer2/variables.d.ts.map +1 -0
- package/dist/layer2/variables.js +152 -0
- package/dist/layer2/variables.js.map +1 -0
- package/dist/layer3/anthropic.d.ts +83 -0
- package/dist/layer3/anthropic.d.ts.map +1 -0
- package/dist/layer3/anthropic.js +1745 -0
- package/dist/layer3/anthropic.js.map +1 -0
- package/dist/layer3/index.d.ts +24 -0
- package/dist/layer3/index.d.ts.map +1 -0
- package/dist/layer3/index.js +119 -0
- package/dist/layer3/index.js.map +1 -0
- package/dist/layer3/openai.d.ts +25 -0
- package/dist/layer3/openai.d.ts.map +1 -0
- package/dist/layer3/openai.js +238 -0
- package/dist/layer3/openai.js.map +1 -0
- package/dist/layer3/package-check.d.ts +63 -0
- package/dist/layer3/package-check.d.ts.map +1 -0
- package/dist/layer3/package-check.js +508 -0
- package/dist/layer3/package-check.js.map +1 -0
- package/dist/modes/incremental.d.ts +66 -0
- package/dist/modes/incremental.d.ts.map +1 -0
- package/dist/modes/incremental.js +200 -0
- package/dist/modes/incremental.js.map +1 -0
- package/dist/tiers.d.ts +125 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +234 -0
- package/dist/tiers.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +50 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-helper-detector.d.ts +56 -0
- package/dist/utils/auth-helper-detector.d.ts.map +1 -0
- package/dist/utils/auth-helper-detector.js +360 -0
- package/dist/utils/auth-helper-detector.js.map +1 -0
- package/dist/utils/context-helpers.d.ts +96 -0
- package/dist/utils/context-helpers.d.ts.map +1 -0
- package/dist/utils/context-helpers.js +493 -0
- package/dist/utils/context-helpers.js.map +1 -0
- package/dist/utils/diff-detector.d.ts +53 -0
- package/dist/utils/diff-detector.d.ts.map +1 -0
- package/dist/utils/diff-detector.js +104 -0
- package/dist/utils/diff-detector.js.map +1 -0
- package/dist/utils/diff-parser.d.ts +80 -0
- package/dist/utils/diff-parser.d.ts.map +1 -0
- package/dist/utils/diff-parser.js +202 -0
- package/dist/utils/diff-parser.js.map +1 -0
- package/dist/utils/imported-auth-detector.d.ts +37 -0
- package/dist/utils/imported-auth-detector.d.ts.map +1 -0
- package/dist/utils/imported-auth-detector.js +251 -0
- package/dist/utils/imported-auth-detector.js.map +1 -0
- package/dist/utils/middleware-detector.d.ts +55 -0
- package/dist/utils/middleware-detector.d.ts.map +1 -0
- package/dist/utils/middleware-detector.js +260 -0
- package/dist/utils/middleware-detector.js.map +1 -0
- package/dist/utils/oauth-flow-detector.d.ts +41 -0
- package/dist/utils/oauth-flow-detector.d.ts.map +1 -0
- package/dist/utils/oauth-flow-detector.js +202 -0
- package/dist/utils/oauth-flow-detector.js.map +1 -0
- package/dist/utils/path-exclusions.d.ts +55 -0
- package/dist/utils/path-exclusions.d.ts.map +1 -0
- package/dist/utils/path-exclusions.js +222 -0
- package/dist/utils/path-exclusions.js.map +1 -0
- package/dist/utils/project-context-builder.d.ts +119 -0
- package/dist/utils/project-context-builder.d.ts.map +1 -0
- package/dist/utils/project-context-builder.js +534 -0
- package/dist/utils/project-context-builder.js.map +1 -0
- package/dist/utils/registry-clients.d.ts +93 -0
- package/dist/utils/registry-clients.d.ts.map +1 -0
- package/dist/utils/registry-clients.js +273 -0
- package/dist/utils/registry-clients.js.map +1 -0
- package/dist/utils/trpc-analyzer.d.ts +78 -0
- package/dist/utils/trpc-analyzer.d.ts.map +1 -0
- package/dist/utils/trpc-analyzer.js +297 -0
- package/dist/utils/trpc-analyzer.js.map +1 -0
- package/package.json +45 -0
- package/src/__tests__/benchmark/fixtures/false-positives.ts +227 -0
- package/src/__tests__/benchmark/fixtures/index.ts +68 -0
- package/src/__tests__/benchmark/fixtures/layer1/config-audit.ts +364 -0
- package/src/__tests__/benchmark/fixtures/layer1/hardcoded-secrets.ts +173 -0
- package/src/__tests__/benchmark/fixtures/layer1/high-entropy.ts +234 -0
- package/src/__tests__/benchmark/fixtures/layer1/index.ts +31 -0
- package/src/__tests__/benchmark/fixtures/layer1/sensitive-urls.ts +90 -0
- package/src/__tests__/benchmark/fixtures/layer1/weak-crypto.ts +197 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-agent-tools.ts +170 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-endpoint-protection.ts +418 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +189 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-fingerprinting.ts +316 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +178 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +184 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-schema-validation.ts +434 -0
- package/src/__tests__/benchmark/fixtures/layer2/auth-antipatterns.ts +159 -0
- package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +112 -0
- package/src/__tests__/benchmark/fixtures/layer2/dangerous-functions.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +168 -0
- package/src/__tests__/benchmark/fixtures/layer2/framework-checks.ts +346 -0
- package/src/__tests__/benchmark/fixtures/layer2/index.ts +67 -0
- package/src/__tests__/benchmark/fixtures/layer2/injection-vulnerabilities.ts +239 -0
- package/src/__tests__/benchmark/fixtures/layer2/logic-gates.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/risky-imports.ts +231 -0
- package/src/__tests__/benchmark/fixtures/layer2/variables.ts +167 -0
- package/src/__tests__/benchmark/index.ts +29 -0
- package/src/__tests__/benchmark/run-benchmark.ts +144 -0
- package/src/__tests__/benchmark/run-depth-validation.ts +206 -0
- package/src/__tests__/benchmark/run-real-world-test.ts +243 -0
- package/src/__tests__/benchmark/security-benchmark-script.ts +1737 -0
- package/src/__tests__/benchmark/tier-integration-script.ts +177 -0
- package/src/__tests__/benchmark/types.ts +144 -0
- package/src/__tests__/benchmark/utils/test-runner.ts +475 -0
- package/src/__tests__/regression/known-false-positives.test.ts +467 -0
- package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +178 -0
- package/src/__tests__/snapshots/scan-depth.test.ts +258 -0
- package/src/__tests__/validation/analyze-results.ts +542 -0
- package/src/__tests__/validation/extract-for-triage.ts +146 -0
- package/src/__tests__/validation/fp-deep-analysis.ts +327 -0
- package/src/__tests__/validation/run-validation.ts +364 -0
- package/src/__tests__/validation/triage-template.md +132 -0
- package/src/formatters/cli-terminal.ts +446 -0
- package/src/formatters/github-comment.ts +382 -0
- package/src/formatters/grouping.ts +190 -0
- package/src/formatters/index.ts +47 -0
- package/src/formatters/vscode-diagnostic.ts +243 -0
- package/src/index.ts +823 -0
- package/src/layer1/comments.ts +218 -0
- package/src/layer1/config-audit.ts +289 -0
- package/src/layer1/entropy.ts +583 -0
- package/src/layer1/file-flags.ts +127 -0
- package/src/layer1/index.ts +181 -0
- package/src/layer1/patterns.ts +516 -0
- package/src/layer1/urls.ts +334 -0
- package/src/layer1/weak-crypto.ts +328 -0
- package/src/layer2/ai-agent-tools.ts +601 -0
- package/src/layer2/ai-endpoint-protection.ts +387 -0
- package/src/layer2/ai-execution-sinks.ts +580 -0
- package/src/layer2/ai-fingerprinting.ts +758 -0
- package/src/layer2/ai-prompt-hygiene.ts +411 -0
- package/src/layer2/ai-rag-safety.ts +511 -0
- package/src/layer2/ai-schema-validation.ts +421 -0
- package/src/layer2/auth-antipatterns.ts +394 -0
- package/src/layer2/byok-patterns.ts +336 -0
- package/src/layer2/dangerous-functions.ts +1563 -0
- package/src/layer2/data-exposure.ts +315 -0
- package/src/layer2/framework-checks.ts +433 -0
- package/src/layer2/index.ts +473 -0
- package/src/layer2/logic-gates.ts +206 -0
- package/src/layer2/risky-imports.ts +186 -0
- package/src/layer2/variables.ts +166 -0
- package/src/layer3/anthropic.ts +2030 -0
- package/src/layer3/index.ts +130 -0
- package/src/layer3/package-check.ts +604 -0
- package/src/modes/incremental.ts +293 -0
- package/src/tiers.ts +318 -0
- package/src/types.ts +284 -0
- package/src/utils/auth-helper-detector.ts +443 -0
- package/src/utils/context-helpers.ts +535 -0
- package/src/utils/diff-detector.ts +135 -0
- package/src/utils/diff-parser.ts +272 -0
- package/src/utils/imported-auth-detector.ts +320 -0
- package/src/utils/middleware-detector.ts +333 -0
- package/src/utils/oauth-flow-detector.ts +246 -0
- package/src/utils/path-exclusions.ts +266 -0
- package/src/utils/project-context-builder.ts +707 -0
- package/src/utils/registry-clients.ts +351 -0
- package/src/utils/trpc-analyzer.ts +382 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tRPC Router Analyzer
|
|
3
|
+
* Analyzes tRPC router definitions to understand which procedures are protected
|
|
4
|
+
* by middleware (e.g., adminProcedure, protectedProcedure).
|
|
5
|
+
*
|
|
6
|
+
* This helps prevent false positives when frontend code calls protected tRPC
|
|
7
|
+
* procedures - the backend already handles authorization.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ScanFile } from '../types'
|
|
11
|
+
|
|
12
|
+
export interface TRPCMiddleware {
|
|
13
|
+
/** Name of the middleware/procedure base */
|
|
14
|
+
name: string
|
|
15
|
+
/** Type of protection */
|
|
16
|
+
type: 'admin' | 'authenticated' | 'public' | 'unknown'
|
|
17
|
+
/** File where defined */
|
|
18
|
+
definedIn?: string
|
|
19
|
+
/** Line number where defined */
|
|
20
|
+
lineNumber?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TRPCProcedure {
|
|
24
|
+
/** Procedure name (e.g., 'getUsers', 'createPost') */
|
|
25
|
+
name: string
|
|
26
|
+
/** Router this procedure belongs to */
|
|
27
|
+
router: string
|
|
28
|
+
/** Whether this procedure has auth middleware */
|
|
29
|
+
hasAuthMiddleware: boolean
|
|
30
|
+
/** Type of middleware protection */
|
|
31
|
+
middlewareType?: 'admin' | 'authenticated' | 'public'
|
|
32
|
+
/** File where defined */
|
|
33
|
+
definedIn?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TRPCRouter {
|
|
37
|
+
/** Router name (e.g., 'admin', 'user', 'post') */
|
|
38
|
+
name: string
|
|
39
|
+
/** File where router is defined */
|
|
40
|
+
file: string
|
|
41
|
+
/** Procedures in this router */
|
|
42
|
+
procedures: string[]
|
|
43
|
+
/** Default middleware for this router (if any) */
|
|
44
|
+
defaultMiddleware?: string
|
|
45
|
+
/** Whether all procedures in this router are protected */
|
|
46
|
+
isProtected: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface TRPCRouterContext {
|
|
50
|
+
/** All detected routers */
|
|
51
|
+
routers: Map<string, TRPCRouter>
|
|
52
|
+
/** All detected procedures with their protection status */
|
|
53
|
+
procedures: Map<string, TRPCProcedure>
|
|
54
|
+
/** All detected middleware definitions */
|
|
55
|
+
middlewares: Map<string, TRPCMiddleware>
|
|
56
|
+
/** Whether tRPC is detected in the project */
|
|
57
|
+
hasTRPC: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Patterns that indicate admin-level middleware
|
|
62
|
+
*/
|
|
63
|
+
const ADMIN_MIDDLEWARE_PATTERNS = [
|
|
64
|
+
/adminProcedure/i,
|
|
65
|
+
/adminMiddleware/i,
|
|
66
|
+
/requireAdmin/i,
|
|
67
|
+
/isAdmin\s*:\s*true/i,
|
|
68
|
+
/role\s*===?\s*['"]admin['"]/i,
|
|
69
|
+
/\.admin\s*\(/i,
|
|
70
|
+
/adminRouter/i,
|
|
71
|
+
/superAdminProcedure/i,
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Patterns that indicate authenticated middleware
|
|
76
|
+
*/
|
|
77
|
+
const AUTH_MIDDLEWARE_PATTERNS = [
|
|
78
|
+
/protectedProcedure/i,
|
|
79
|
+
/authenticatedProcedure/i,
|
|
80
|
+
/requireAuth/i,
|
|
81
|
+
/isAuthenticated/i,
|
|
82
|
+
/privateProcedure/i,
|
|
83
|
+
/authedProcedure/i,
|
|
84
|
+
/userProcedure/i,
|
|
85
|
+
/loggedInProcedure/i,
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Patterns that indicate public/unprotected procedures
|
|
90
|
+
*/
|
|
91
|
+
const PUBLIC_MIDDLEWARE_PATTERNS = [
|
|
92
|
+
/publicProcedure/i,
|
|
93
|
+
/guestProcedure/i,
|
|
94
|
+
/unauthenticatedProcedure/i,
|
|
95
|
+
/openProcedure/i,
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Detect tRPC usage in files
|
|
100
|
+
*/
|
|
101
|
+
function detectTRPCUsage(content: string): boolean {
|
|
102
|
+
const trpcPatterns = [
|
|
103
|
+
/@trpc\/server/i,
|
|
104
|
+
/@trpc\/client/i,
|
|
105
|
+
/@trpc\/react-query/i,
|
|
106
|
+
/@trpc\/next/i,
|
|
107
|
+
/createTRPCRouter/i,
|
|
108
|
+
/initTRPC/i,
|
|
109
|
+
/trpc\.router/i,
|
|
110
|
+
/t\.router\s*\(/i,
|
|
111
|
+
/t\.procedure/i,
|
|
112
|
+
]
|
|
113
|
+
return trpcPatterns.some(p => p.test(content))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Extract middleware definitions from a file
|
|
118
|
+
*/
|
|
119
|
+
function extractMiddlewares(content: string, filePath: string): TRPCMiddleware[] {
|
|
120
|
+
const middlewares: TRPCMiddleware[] = []
|
|
121
|
+
const lines = content.split('\n')
|
|
122
|
+
|
|
123
|
+
// Look for procedure definitions with middleware
|
|
124
|
+
const procedureDefPatterns = [
|
|
125
|
+
/export\s+const\s+(\w+Procedure)\s*=\s*t\.procedure\.use/i,
|
|
126
|
+
/const\s+(\w+Procedure)\s*=\s*t\.procedure\.use/i,
|
|
127
|
+
/(\w+Procedure)\s*=\s*publicProcedure\.use/i,
|
|
128
|
+
/export\s+const\s+(\w+Procedure)\s*=/i,
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < lines.length; i++) {
|
|
132
|
+
const line = lines[i]
|
|
133
|
+
|
|
134
|
+
for (const pattern of procedureDefPatterns) {
|
|
135
|
+
const match = line.match(pattern)
|
|
136
|
+
if (match) {
|
|
137
|
+
const name = match[1]
|
|
138
|
+
let type: 'admin' | 'authenticated' | 'public' | 'unknown' = 'unknown'
|
|
139
|
+
|
|
140
|
+
// Determine type based on name and context
|
|
141
|
+
if (ADMIN_MIDDLEWARE_PATTERNS.some(p => p.test(name) || p.test(line))) {
|
|
142
|
+
type = 'admin'
|
|
143
|
+
} else if (AUTH_MIDDLEWARE_PATTERNS.some(p => p.test(name) || p.test(line))) {
|
|
144
|
+
type = 'authenticated'
|
|
145
|
+
} else if (PUBLIC_MIDDLEWARE_PATTERNS.some(p => p.test(name) || p.test(line))) {
|
|
146
|
+
type = 'public'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
middlewares.push({
|
|
150
|
+
name,
|
|
151
|
+
type,
|
|
152
|
+
definedIn: filePath,
|
|
153
|
+
lineNumber: i + 1,
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return middlewares
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Extract router definitions from a file
|
|
164
|
+
*/
|
|
165
|
+
function extractRouters(content: string, filePath: string, middlewares: Map<string, TRPCMiddleware>): TRPCRouter[] {
|
|
166
|
+
const routers: TRPCRouter[] = []
|
|
167
|
+
const lines = content.split('\n')
|
|
168
|
+
|
|
169
|
+
// Pattern to find router definitions
|
|
170
|
+
const routerDefPatterns = [
|
|
171
|
+
/export\s+const\s+(\w+Router)\s*=\s*(?:createTRPCRouter|t\.router)\s*\(\s*\{/i,
|
|
172
|
+
/const\s+(\w+Router)\s*=\s*(?:createTRPCRouter|t\.router)\s*\(\s*\{/i,
|
|
173
|
+
/(\w+):\s*(?:createTRPCRouter|t\.router)\s*\(\s*\{/i,
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < lines.length; i++) {
|
|
177
|
+
const line = lines[i]
|
|
178
|
+
|
|
179
|
+
for (const pattern of routerDefPatterns) {
|
|
180
|
+
const match = line.match(pattern)
|
|
181
|
+
if (match) {
|
|
182
|
+
const name = match[1].replace(/Router$/i, '').toLowerCase()
|
|
183
|
+
|
|
184
|
+
// Look ahead to find procedures in this router
|
|
185
|
+
const procedures: string[] = []
|
|
186
|
+
let isProtected = false
|
|
187
|
+
let defaultMiddleware: string | undefined
|
|
188
|
+
|
|
189
|
+
// Check if router name suggests admin protection
|
|
190
|
+
if (/admin/i.test(name)) {
|
|
191
|
+
isProtected = true
|
|
192
|
+
defaultMiddleware = 'adminProcedure'
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Scan the router body for procedures
|
|
196
|
+
let braceDepth = 0
|
|
197
|
+
let inRouter = false
|
|
198
|
+
for (let j = i; j < Math.min(i + 100, lines.length); j++) {
|
|
199
|
+
const routerLine = lines[j]
|
|
200
|
+
|
|
201
|
+
if (routerLine.includes('{')) {
|
|
202
|
+
braceDepth += (routerLine.match(/\{/g) || []).length
|
|
203
|
+
inRouter = true
|
|
204
|
+
}
|
|
205
|
+
if (routerLine.includes('}')) {
|
|
206
|
+
braceDepth -= (routerLine.match(/\}/g) || []).length
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (inRouter && braceDepth === 0) break
|
|
210
|
+
|
|
211
|
+
// Look for procedure definitions
|
|
212
|
+
const procMatch = routerLine.match(/(\w+)\s*:\s*(\w+Procedure)\./i)
|
|
213
|
+
if (procMatch) {
|
|
214
|
+
procedures.push(procMatch[1])
|
|
215
|
+
const middlewareName = procMatch[2]
|
|
216
|
+
const middleware = middlewares.get(middlewareName)
|
|
217
|
+
if (middleware && (middleware.type === 'admin' || middleware.type === 'authenticated')) {
|
|
218
|
+
isProtected = true
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check for admin/protected procedure usage
|
|
223
|
+
if (ADMIN_MIDDLEWARE_PATTERNS.some(p => p.test(routerLine))) {
|
|
224
|
+
isProtected = true
|
|
225
|
+
} else if (AUTH_MIDDLEWARE_PATTERNS.some(p => p.test(routerLine))) {
|
|
226
|
+
isProtected = true
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
routers.push({
|
|
231
|
+
name,
|
|
232
|
+
file: filePath,
|
|
233
|
+
procedures,
|
|
234
|
+
defaultMiddleware,
|
|
235
|
+
isProtected,
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return routers
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Analyze tRPC routers across all files
|
|
246
|
+
*/
|
|
247
|
+
export function analyzeTRPCRouters(files: ScanFile[]): TRPCRouterContext {
|
|
248
|
+
const context: TRPCRouterContext = {
|
|
249
|
+
routers: new Map(),
|
|
250
|
+
procedures: new Map(),
|
|
251
|
+
middlewares: new Map(),
|
|
252
|
+
hasTRPC: false,
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// First pass: detect if tRPC is used
|
|
256
|
+
for (const file of files) {
|
|
257
|
+
if (detectTRPCUsage(file.content)) {
|
|
258
|
+
context.hasTRPC = true
|
|
259
|
+
break
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!context.hasTRPC) {
|
|
264
|
+
return context
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Second pass: extract middlewares
|
|
268
|
+
for (const file of files) {
|
|
269
|
+
const middlewares = extractMiddlewares(file.content, file.path)
|
|
270
|
+
for (const middleware of middlewares) {
|
|
271
|
+
context.middlewares.set(middleware.name, middleware)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Third pass: extract routers
|
|
276
|
+
for (const file of files) {
|
|
277
|
+
const routers = extractRouters(file.content, file.path, context.middlewares)
|
|
278
|
+
for (const router of routers) {
|
|
279
|
+
context.routers.set(router.name, router)
|
|
280
|
+
|
|
281
|
+
// Add procedures to the procedures map
|
|
282
|
+
for (const procName of router.procedures) {
|
|
283
|
+
context.procedures.set(`${router.name}.${procName}`, {
|
|
284
|
+
name: procName,
|
|
285
|
+
router: router.name,
|
|
286
|
+
hasAuthMiddleware: router.isProtected,
|
|
287
|
+
middlewareType: router.isProtected ? 'authenticated' : 'public',
|
|
288
|
+
definedIn: router.file,
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return context
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Check if a tRPC procedure is protected by middleware
|
|
299
|
+
*/
|
|
300
|
+
export function isProcedureProtected(
|
|
301
|
+
context: TRPCRouterContext,
|
|
302
|
+
routerName: string,
|
|
303
|
+
procedureName?: string
|
|
304
|
+
): boolean {
|
|
305
|
+
// Check if the router itself is protected
|
|
306
|
+
const router = context.routers.get(routerName.toLowerCase())
|
|
307
|
+
if (router?.isProtected) {
|
|
308
|
+
return true
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Check specific procedure if provided
|
|
312
|
+
if (procedureName) {
|
|
313
|
+
const procedure = context.procedures.get(`${routerName.toLowerCase()}.${procedureName}`)
|
|
314
|
+
if (procedure?.hasAuthMiddleware) {
|
|
315
|
+
return true
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Check if router name suggests admin protection
|
|
320
|
+
if (/admin/i.test(routerName)) {
|
|
321
|
+
return true
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return false
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Parse a tRPC client call to extract router and procedure names
|
|
329
|
+
* e.g., trpc.admin.getUsers.useQuery() -> { router: 'admin', procedure: 'getUsers' }
|
|
330
|
+
*/
|
|
331
|
+
export function parseTRPCCall(lineContent: string): { router: string; procedure: string } | null {
|
|
332
|
+
// Pattern: trpc.routerName.procedureName
|
|
333
|
+
const patterns = [
|
|
334
|
+
/trpc\.(\w+)\.(\w+)\./i,
|
|
335
|
+
/api\.(\w+)\.(\w+)\./i,
|
|
336
|
+
/client\.(\w+)\.(\w+)\./i,
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
for (const pattern of patterns) {
|
|
340
|
+
const match = lineContent.match(pattern)
|
|
341
|
+
if (match) {
|
|
342
|
+
return {
|
|
343
|
+
router: match[1],
|
|
344
|
+
procedure: match[2],
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return null
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Check if a line contains a tRPC client call
|
|
354
|
+
*/
|
|
355
|
+
export function isTRPCClientCall(lineContent: string): boolean {
|
|
356
|
+
const patterns = [
|
|
357
|
+
/trpc\.\w+\.\w+\.(useQuery|useMutation|useInfiniteQuery)/i,
|
|
358
|
+
/api\.\w+\.\w+\.(useQuery|useMutation|useInfiniteQuery)/i,
|
|
359
|
+
/trpc\.\w+\.\w+\.query\(/i,
|
|
360
|
+
/trpc\.\w+\.\w+\.mutate\(/i,
|
|
361
|
+
]
|
|
362
|
+
return patterns.some(p => p.test(lineContent))
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get a summary of tRPC context for logging
|
|
367
|
+
*/
|
|
368
|
+
export function getTRPCSummary(context: TRPCRouterContext): string {
|
|
369
|
+
if (!context.hasTRPC) {
|
|
370
|
+
return 'No tRPC detected'
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const parts: string[] = []
|
|
374
|
+
parts.push(`tRPC detected: ${context.routers.size} routers, ${context.procedures.size} procedures`)
|
|
375
|
+
|
|
376
|
+
const protectedRouters = Array.from(context.routers.values()).filter(r => r.isProtected)
|
|
377
|
+
if (protectedRouters.length > 0) {
|
|
378
|
+
parts.push(`Protected routers: ${protectedRouters.map(r => r.name).join(', ')}`)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return parts.join('; ')
|
|
382
|
+
}
|