159 auth user active sessions#242
Conversation
…InfinityBowman/corates into 159-auth---user-active-sessions
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughWalkthroughThis PR introduces an ESLint rule enforcing correct Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant SM as SessionManagement UI
participant Store as Better Auth Store
participant Client as Auth Client
participant API as Backend API
User->>SM: Click revoke session
SM->>SM: Show confirmation (if revokeAll)
SM->>SM: Set revoking state
alt Revoke Single Session
SM->>Store: revokeSessionByToken(token)
else Revoke All Others
SM->>Store: revokeAllOtherSessions()
else Revoke All (Sign out everywhere)
SM->>Store: revokeAllSessions()
end
Store->>Client: Call _revokeSession(s)
Client->>API: POST revoke endpoint
API-->>Client: Success/Error response
Client-->>Store: Return result
alt Error
Store->>Store: Set authError
Store-->>SM: Throw error
SM->>SM: Catch & show error toast
else Success
alt Revoke All Sessions
Store->>Store: Clear cached user/avatar/auth
end
Store-->>SM: Return success
SM->>SM: Refetch active sessions
SM->>Store: listActiveSessions()
Store->>Client: _listSessions()
Client->>API: Fetch sessions
API-->>Client: Sessions list
Client-->>Store: Return sessions
Store-->>SM: Return sessions
SM->>SM: Update UI with new list
end
SM->>SM: Clear revoking state
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom Pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
corates | c293aa2 | Commit Preview URL | Jan 07 2026, 07:50 AM |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @packages/docs/audits/security-audit-2026-01.md:
- Around line 1122-1155: The audit claims a working isBlockedHost-based SSRF
defense (blocking hostnames like "localhost" and "metadata.google.internal",
regexes for 127/10/172.16-31/192.168/169.254 and IPv6, numeric-decimal IPs, and
redirect validation) but the pdf-proxy handler actually lacks these checks;
either implement the protections in the pdf-proxy endpoint handler (add an
isBlockedHost(hostname) utility used before fetching and when following
redirects to check parsedUrl.hostname and redirectUrl.hostname, implement
numeric-decimal IP detection/resolution, the listed regex/IP ranges and explicit
blocked hostnames, and ensure redirect validation increments redirect count and
rechecks targets) or update the audit doc to remove the false claims and
document the real current behavior (keep references to isBlockedHost,
parsedUrl.hostname, redirectUrl.hostname and the pdf-proxy handler to locate
where to add or remove the described protections).
In @packages/web/src/api/better-auth-store.js:
- Around line 676-687: The revokeAllSessions function currently calls
_revokeSessions and clears local in-memory state (saveCachedAuth, setCachedUser,
setCachedAvatarUrl) but does not perform the full signout cleanup; update
revokeAllSessions to mirror signout(): after successful _revokeSessions() call
invoke clearAvatarCache(), call queryClient.clear(), call
clearPersistedQueryCache(), trigger a refetch of the session (e.g.,
refetchSession()) to immediately reset state, and then clear in-memory caches
and avatar like existing saveCachedAuth(null), setCachedUser(null),
setCachedAvatarUrl(null); keep the existing error handling that sets
setAuthError(err.message) and rethrows from the catch that references
_revokeSessions.
🧹 Nitpick comments (3)
packages/web/src/components/settings/SettingsLayout.jsx (1)
69-69: Remove commented-out code or document intent.The
toggleMobileSidebarfunction is commented out but not removed. If this is a temporary change pending future mobile UI work, add a TODO comment explaining the intent. Otherwise, remove it to reduce code clutter.🔎 Proposed fix
- // const toggleMobileSidebar = () => setMobileSidebarOpen(open => !open); const closeMobileSidebar = () => setMobileSidebarOpen(false);eslint.config.js (1)
244-250: Consider removing redundant pattern.The
patternsarray with@ark-ui/solid/*is redundant since all specific subpaths are already listed in thepathsarray above. ESLint will match the specific paths first, and the generic pattern provides no additional coverage.🔎 Proposed fix
}, ], - patterns: [ - { - group: ['@ark-ui/solid/*'], - message: - 'Import from @corates/ui instead. Use ComponentName for prestyled or ComponentNamePrimitive for the Ark UI primitive.', - }, - ], }, ],packages/web/src/components/settings/pages/SessionManagement.jsx (1)
56-72: Consider handling edge case for invalid dates.The function could return unexpected results if
dateis an invalid date string (resulting inNaNfrom date arithmetic).🔎 Proposed fix
function formatRelativeTime(date) { if (!date) return 'Unknown'; const now = new Date(); const then = new Date(date); + if (isNaN(then.getTime())) return 'Unknown'; + const diffMs = now - then; + if (diffMs < 0) return 'Just now'; // Handle future dates gracefully + const diffMins = Math.floor(diffMs / 60000);
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
eslint-rules/corates-ui-imports.jseslint-rules/index.jseslint.config.jspackages/docs/audits/security-audit-2026-01.mdpackages/web/src/api/auth-client.jspackages/web/src/api/better-auth-store.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsx
🧰 Additional context used
📓 Path-based instructions (18)
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from @/lib/formStatePersistence.js
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
packages/web/src/**/*.{js,jsx,ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Use import aliases from jsconfig.json (see ui-components.mdc)
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/{web,ui}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
packages/{web,ui}/**/*.{js,jsx,ts,tsx}: Import UI components from '@corates/ui' package instead of local components directories
Use solid-icons library for icons instead of emojis or other icon sources
Use Tailwind CSS classes for styling UI components
Apply responsive design using mobile-first approach with Tailwind CSS
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/web/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Use import aliases from jsconfig.json (e.g., @/, @components/, @auth-ui/, @checklist-ui/, @project-ui/, @routes/, @primitives/, @api/, @config/, @lib/) instead of relative paths
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
**/*.{js,jsx,ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Prefer modern ES6+ syntax and features
Use import aliases from jsconfig.json (see ui-components.mdc)
Group related components in subdirectories with barrel exports
Use Ark UI components from@corates/uipackage, NOT local components
Usesolid-iconsicon library (e.g.,solid-icons/bi,solid-icons/fi) for icons
Comments should explain WHY something is being done, not narrate what the code does
Use comments to explain why a particular approach or workaround was chosen
Use comments to clarify intent when code could be misread or misunderstood
Use comments to provide context from external systems, specs, or requirements
Use comments to document assumptions, edge cases, or limitations
Do NOT narrate what the code is doing in comments
Do NOT duplicate function or variable names in plain English in comments
Do NOT leave stale comments that contradict the code
Do NOT reference removed or obsolete code paths in comments
**/*.{js,jsx,ts,tsx}: Prefer modern ES6+ syntax and features
Comments should not repeat what the code is saying. Rese...
Files:
packages/web/src/api/auth-client.jseslint.config.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxeslint-rules/corates-ui-imports.jspackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxeslint-rules/index.jspackages/web/src/api/better-auth-store.js
**/*.{js,jsx,ts,tsx,css,scss}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Ensure browser compatibility (Safari is usually problematic)
Files:
packages/web/src/api/auth-client.jseslint.config.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxeslint-rules/corates-ui-imports.jspackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxeslint-rules/index.jspackages/web/src/api/better-auth-store.js
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/{web,ui}/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Group related components in subdirectories with barrel exports
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/{workers,web}/src/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Better-Auth for authentication and user management
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/web/src/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/web/src/**/*.{js,ts,jsx,tsx}: UsecreateStorefor complex state objects
UsecreateMemofor derived values
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/api/auth-client.jspackages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsxpackages/web/src/api/better-auth-store.js
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
packages/web/src/**/*.{jsx,tsx}: Do NOT prop-drill application state - Import stores directly where needed
Do NOT destructure props - Accessprops.fielddirectly or wrap in function:() => props.field
Components should receive at most 1-5 props (local config only, not shared state)
Move business logic to stores, utilities, or primitives (not components)
Files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS components
Files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
packages/web/**/*.{jsx,tsx}: Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure props in SolidJS - accessprops.fielddirectly or wrap in function:() => props.field
Shared state lives in external stores underpackages/web/src/stores/
SolidJS components should receive at most 1-5 props (local config only, not shared state)
UsecreateStorefor complex state objects in SolidJS
UsecreateMemofor derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readabilityUse
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsx
packages/{web,landing,docs}/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/{web,landing,docs}/src/**/*.{jsx,tsx}: Use Ark UI components from@corates/uipackage, NOT local components
Usesolid-iconsfor icon imports (e.g.,solid-icons/bi,solid-icons/fi)
Files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/components/settings/pages/SecuritySettings.jsxpackages/web/src/components/settings/pages/SessionManagement.jsxpackages/web/src/components/settings/SettingsLayout.jsx
packages/docs/audits/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place plans/audits in
packages/docs/audits/directory
Files:
packages/docs/audits/security-audit-2026-01.md
🧠 Learnings (37)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/{web,ui}/**/*.{js,jsx,ts,tsx} : Import UI components from 'corates/ui' package instead of local components directories
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use Ark UI components from `corates/ui` package, NOT local components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{workers,web}/src/**/*.{js,ts,jsx,tsx} : Use Better-Auth for authentication and user management
📚 Learning: 2025-12-27T03:02:33.023Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/{web,ui}/**/*.{js,jsx,ts,tsx} : Import UI components from 'corates/ui' package instead of local components directories
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use Ark UI components from `corates/ui` package, NOT local components
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2025-12-27T03:02:33.023Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/web/**/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (e.g., @/, components/, auth-ui/, checklist-ui/, project-ui/, routes/, primitives/, api/, config/, lib/) instead of relative paths
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (see ui-components.mdc)
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (see ui-components.mdc)
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use Ark UI components from `corates/ui` package, NOT local components
Applied to files:
eslint.config.jseslint-rules/corates-ui-imports.jseslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Prefer modern ES6+ syntax and features
Applied to files:
eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use `solid-icons` icon library (e.g., `solid-icons/bi`, `solid-icons/fi`) for icons
Applied to files:
eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx,css,scss} : Ensure browser compatibility (Safari is usually problematic)
Applied to files:
eslint.config.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use `solid-icons` for icon imports (e.g., `solid-icons/bi`, `solid-icons/fi`)
Applied to files:
eslint.config.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : For UI icons, use `solid-icons` library or SVGs only (never emojis)
Applied to files:
eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : For UI icons, use `solid-icons` library or SVGs only (never emojis)
Applied to files:
eslint.config.js
📚 Learning: 2026-01-06T23:56:57.343Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2026-01-06T23:56:57.343Z
Learning: Applies to packages/workers/**/*.{js,ts} : Use predefined error constants from `corates/shared` (PROJECT_ERRORS, AUTH_ERRORS, VALIDATION_ERRORS, SYSTEM_ERRORS, USER_ERRORS) instead of arbitrary error strings
Applied to files:
eslint.config.jseslint-rules/index.js
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from @/ROBINS-I/checklist.js to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : Use scoreChecklist utility from @/AMSTAR2/checklist.js to determine quality assessment rating: 'High' | 'Moderate' | 'Low' | 'Critically Low'
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use shouldStopAssessment utility from @/ROBINS-I/checklist.js to check if Section B indicates critical risk of bias requiring assessment termination
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from @/lib/checklist-domain.js to determine current checklist status before performing operations
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Checklist status transitions follow sequence: in_progress → completed (when all questions answered) → reconciled (after reconciliation complete)
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Maintain separate answer format implementations for each checklist type (AMSTAR2, ROBINS-I, Generic) to prevent data corruption
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/lib/checklist-domain.js : Register and retrieve checklists using checklist-registry: getChecklistType and getChecklistComponent functions
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsxpackages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Multi-part answers (q9a, q9b, q11a, q11b) should be stored as objects with answer matrix and critical flag properties
Applied to files:
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Applied to files:
eslint-rules/corates-ui-imports.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/*.{js,ts} : Track active WebSocket sessions in a Map with session structure { user, awarenessClientId }
Applied to files:
packages/web/src/components/settings/pages/SessionManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Applied to files:
packages/web/src/components/settings/pages/SessionManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use the children helper when manipulating props.children in SolidJS components
Applied to files:
packages/web/src/components/settings/SettingsLayout.jsx
📚 Learning: 2026-01-01T23:31:43.756Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/api-routes.mdc:0-0
Timestamp: 2026-01-01T23:31:43.756Z
Learning: Applies to packages/workers/src/routes/**/*.js : Use error constants from `corates/shared` (`PROJECT_ERRORS.*`, `AUTH_ERRORS.*`, `VALIDATION_ERRORS.*`, `SYSTEM_ERRORS.*`, `USER_ERRORS.*`) instead of creating error objects manually
Applied to files:
eslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{workers,web}/src/**/*.{js,ts,jsx,tsx} : Use Better-Auth for authentication and user management
Applied to files:
packages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
Applied to files:
packages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/*.{js,ts} : Do not expose internal sync endpoints (/sync, /sync-member, /sync-pdf, /disconnect-all) publicly without X-Internal-Request verification
Applied to files:
packages/docs/audits/security-audit-2026-01.md
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
Applied to files:
packages/docs/audits/security-audit-2026-01.md
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Verify authentication before WebSocket upgrade in ProjectDoc
Applied to files:
packages/docs/audits/security-audit-2026-01.md
🧬 Code graph analysis (1)
packages/web/src/components/settings/pages/SecuritySettings.jsx (1)
packages/web/src/components/settings/pages/SessionManagement.jsx (1)
SessionManagement(165-384)
🪛 LanguageTool
packages/docs/audits/security-audit-2026-01.md
[grammar] ~1032-~1032: Ensure spelling is correct
Context: ...xcept current - revokeSessions() - Logout everywhere 2. Frontend: - Added...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~1032-~1032: Ensure spelling is correct
Context: ...- revokeSessions() - Logout everywhere 2. Frontend: - Added session methods t...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Workers Builds: corates
🔇 Additional comments (22)
packages/web/src/components/settings/SettingsLayout.jsx (1)
82-82: LGTM!The inline children rendering is functionally equivalent to the previous implementation and slightly more concise.
eslint-rules/index.js (1)
1-13: LGTM!The ESLint plugin entry point follows standard conventions and correctly exports the custom rule for consumption by the ESLint configuration.
packages/web/src/components/settings/pages/SecuritySettings.jsx (3)
3-3: LGTM!The updated comment accurately reflects the expanded scope of the SecuritySettings component.
7-11: LGTM!The import changes correctly add the new SessionManagement component and update the icon to
FiMonitor, which is semantically appropriate for representing active sessions/devices.
272-284: LGTM!The Active Sessions section integration follows the established pattern used by other sections in this component. The structure is consistent, and the SessionManagement component is properly integrated.
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx (1)
4-4: Import pattern aligns with ESLint rule and requires no changes.The import
import { DialogPrimitive as Dialog } from '@corates/ui'correctly uses the primitive variant with the alias pattern shown in the ESLint rule's own error message template. The rule identifiesDialogPrimitiveas a primitive component (by thePrimitivesuffix) and allows it to be imported and aliased. Since the component applies custom styling, using the primitive variant is the correct approach per the rule design.packages/web/src/api/auth-client.js (1)
49-53: No action required. Better Auth provides all four session management methods (listSessions,revokeSession,revokeOtherSessions,revokeSessions) viaauthClienton the client side, confirming the implementation is correct.eslint.config.js (2)
4-4: LGTM! Well-structured ESLint plugin integration.The custom
coratesplugin is correctly registered and thecorates-ui-importsrule properly enforces the prestyled vs primitive component distinction. This aligns with the project's coding guidelines to import UI components from@corates/ui.Also applies to: 17-19, 121-125
255-260: Good override for the UI package.Correctly disables
no-restricted-importsforpackages/ui/**since the UI package legitimately wraps Ark UI primitives.packages/web/src/components/settings/pages/SessionManagement.jsx (5)
6-10: Correct import pattern for primitive Dialog usage.Using
DialogPrimitive as Dialogis the correct approach since the component uses primitive patterns (.Root,.Content,.Backdrop, etc.) as required by the new ESLint rule. This follows the@corates/uicomponent guidelines.
94-163: Well-implemented SessionCard component following SolidJS patterns.The component correctly:
- Uses
props.sessiondirectly without destructuring (SolidJS reactivity)- Wraps derived values in functions (
deviceInfo = () => ...)- Uses
Showfor conditional rendering- Uses
solid-icons/fifor icons as per coding guidelines
187-229: Solid deduplication logic with proper current-session handling.The deduplication correctly prioritizes the current session and keeps the most recent session per device fingerprint. The sorting ensures the current session appears first.
265-280: Intentional asymmetric error handling in handleRevokeAll.The function correctly does not call
setRevokingAll(false)in the success path because the user will be redirected after all sessions are revoked. The state reset only happens in the error path. Good pattern.
352-381: Correct primitive Dialog usage with proper accessibility structure.The Dialog uses all required primitive subcomponents (
.Root,.Backdrop,.Positioner,.Content,.Title,.Description,.CloseTrigger) which aligns with the Ark UI primitive pattern and the new ESLint rule.packages/web/src/api/better-auth-store.js (2)
33-40: Good import convention with underscore prefix for internal helpers.Using
_listSessions,_revokeSession, etc. for the imported auth-client functions clearly distinguishes them from the public API methods defined in the store. This follows established patterns in the codebase.
872-876: Clean public API extension for session management.The new methods are properly grouped under a clear comment and follow the existing return object structure.
eslint-rules/corates-ui-imports.js (4)
73-89: Clear and actionable error messages.The
usePrimitivemessage provides excellent guidance: it names the component, the subcomponent being incorrectly used, and suggests the correct primitive import. This will help developers quickly fix violations.
131-164: Good handling of MemberExpression vs JSXMemberExpression.Line 134 correctly skips nodes with JSX parent types to avoid duplicate reports, since JSXMemberExpression handles those cases. This prevents the same violation from being reported twice.
198-213: Reasonable decision to disable the "unused primitive" warning.The commented-out
Program:exitcheck would warn when importing a primitive but not using subcomponent patterns. Keeping this disabled reduces noise since there are legitimate use cases (e.g., passing the primitive to a wrapper component).
11-42: Comprehensive component mapping.The map correctly covers all Ark UI components that have both prestyled and primitive variants in
@corates/ui, includingPasswordInputwhich is properly exported with its primitive version.packages/docs/audits/security-audit-2026-01.md (2)
1018-1051: Accurate documentation of M1 Session Revocation implementation.The audit correctly reflects the implementation details:
- Backend leverages Better Auth's built-in session APIs
- Frontend additions match the files in this PR (
auth-client.js,better-auth-store.js,SessionManagement.jsx,SecuritySettings.jsx)- Feature description matches the actual UI implementation
Note: "Logout" (lines 1032) is acceptable American English usage and not a spelling error as flagged by static analysis.
1326-1328: Updated security posture score reflects resolved items.The score update to 8.8/10 and the narrative change appropriately reflect that short-term security items are resolved.
| **Location:** `packages/workers/src/index.js` - `/api/pdf-proxy` endpoint | ||
|
|
||
| **Impact:** | ||
|
|
||
| - SSRF to internal services (metadata endpoints, databases) | ||
| - Port scanning via proxy | ||
| - SSRF to localhost (127.0.0.1, ::1) | ||
|
|
||
| **Recommendation:** | ||
| **Status:** RESOLVED | ||
|
|
||
| ```javascript | ||
| const BLOCKED_IPS = [ | ||
| '127.0.0.1', | ||
| '::1', // Localhost | ||
| '169.254.169.254', // AWS metadata | ||
| '::ffff:169.254.169.254', // IPv6-mapped AWS metadata | ||
| ]; | ||
| **Original Issue:** PDF proxy accepted user-provided URLs without validation, allowing SSRF attacks to internal services. | ||
|
|
||
| const BLOCKED_RANGES = [ | ||
| '10.0.0.0/8', // Private | ||
| '172.16.0.0/12', // Private | ||
| '192.168.0.0/16', // Private | ||
| ]; | ||
| **Implementation:** Added comprehensive SSRF protection with: | ||
|
|
||
| async function validateProxyUrl(urlString) { | ||
| const url = new URL(urlString); | ||
| 1. **Blocked hostnames:** `localhost`, `metadata.google.internal`, `metadata.google` | ||
| 2. **Blocked IP patterns (regex):** | ||
| - `127.x.x.x` (loopback) | ||
| - `10.x.x.x` (private Class A) | ||
| - `172.16-31.x.x` (private Class B) | ||
| - `192.168.x.x` (private Class C) | ||
| - `169.254.x.x` (link-local / cloud metadata) | ||
| - IPv6 loopback, link-local, unique local | ||
| 3. **Numeric IP blocking:** Blocks decimal IP representations like `2130706433` (127.0.0.1) | ||
| 4. **Redirect validation:** Also validates redirect destinations to prevent SSRF via open redirects | ||
|
|
||
| // Only allow HTTP(S) | ||
| if (!['http:', 'https:'].includes(url.protocol)) { | ||
| throw new Error('Invalid protocol'); | ||
| } | ||
| **Code:** | ||
|
|
||
| // Resolve hostname to IP | ||
| const ip = await dns.resolve(url.hostname); | ||
| ```javascript | ||
| // Initial URL validation | ||
| if (isBlockedHost(parsedUrl.hostname)) { | ||
| console.warn('PDF proxy SSRF attempt blocked:', { hostname: parsedUrl.hostname }); | ||
| return c.json({ error: 'Access to internal resources is not allowed' }, 403); | ||
| } | ||
|
|
||
| // Check against blocked IPs/ranges | ||
| if (BLOCKED_IPS.includes(ip) || isPrivateIP(ip)) { | ||
| throw new Error('Access denied'); | ||
| } | ||
| // Redirect validation | ||
| if (isBlockedHost(redirectUrl.hostname)) { | ||
| console.warn('PDF proxy SSRF redirect blocked:', { hostname: redirectUrl.hostname }); | ||
| return c.json({ error: 'Redirect to internal resources is not allowed' }, 403); | ||
| } | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for isBlockedHost function in the codebase
rg -n 'isBlockedHost' packages/workers/src --type js -A 5 -B 2Repository: InfinityBowman/corates
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check if the file mentioned exists
echo "=== Checking if packages/workers/src/index.js exists ==="
ls -la packages/workers/src/index.js 2>&1
echo -e "\n=== Searching for pdf-proxy endpoint ==="
rg -n 'pdf-proxy' packages/workers --type js
echo -e "\n=== Searching for any SSRF blocking logic ==="
rg -n 'blocked.*host|SSRF|internal.*resource' packages/workers --type js -i
echo -e "\n=== Listing packages/workers structure ==="
find packages/workers/src -type f -name "*.js" -o -name "*.ts" | head -20Repository: InfinityBowman/corates
Length of output: 1603
🏁 Script executed:
#!/bin/bash
# Read the pdf-proxy endpoint implementation
sed -n '219,280p' packages/workers/src/index.jsRepository: InfinityBowman/corates
Length of output: 1922
🏁 Script executed:
#!/bin/bash
# Read more of the pdf-proxy endpoint
sed -n '280,320p' packages/workers/src/index.jsRepository: InfinityBowman/corates
Length of output: 1309
The documented SSRF protections do not exist in the actual implementation. The audit file describes comprehensive protections including hostname blocking (localhost, metadata.google.internal), IP pattern blocking (127.x.x.x, 10.x.x.x, 192.168.x.x, etc.), and an isBlockedHost function—none of which are present in packages/workers/src/index.js.
The actual pdf-proxy endpoint implementation (lines 219–320) contains only basic protocol validation, redirect counting, auth redirect detection, and content-type checking. It lacks all documented SSRF mitigations, leaving the endpoint vulnerable to attacks via private IPs, cloud metadata endpoints, and internal hosts.
Update the audit document to accurately reflect the actual implementation, and either implement the documented protections or remove the false claims of comprehensive SSRF protection.
🤖 Prompt for AI Agents
In @packages/docs/audits/security-audit-2026-01.md around lines 1122 - 1155, The
audit claims a working isBlockedHost-based SSRF defense (blocking hostnames like
"localhost" and "metadata.google.internal", regexes for
127/10/172.16-31/192.168/169.254 and IPv6, numeric-decimal IPs, and redirect
validation) but the pdf-proxy handler actually lacks these checks; either
implement the protections in the pdf-proxy endpoint handler (add an
isBlockedHost(hostname) utility used before fetching and when following
redirects to check parsedUrl.hostname and redirectUrl.hostname, implement
numeric-decimal IP detection/resolution, the listed regex/IP ranges and explicit
blocked hostnames, and ensure redirect validation increments redirect count and
rechecks targets) or update the audit doc to remove the false claims and
document the real current behavior (keep references to isBlockedHost,
parsedUrl.hostname, redirectUrl.hostname and the pdf-proxy handler to locate
where to add or remove the described protections).
| async function revokeAllSessions() { | ||
| try { | ||
| await _revokeSessions(); | ||
| // Clear local state after revoking all sessions | ||
| saveCachedAuth(null); | ||
| setCachedUser(null); | ||
| setCachedAvatarUrl(null); | ||
| } catch (err) { | ||
| setAuthError(err.message); | ||
| throw err; | ||
| } | ||
| } |
There was a problem hiding this comment.
Consider mirroring full signout cleanup in revokeAllSessions.
When revoking all sessions (including current), the user is effectively logged out. However, unlike signout() (lines 432-466), this function doesn't:
- Clear the avatar cache from IndexedDB (
clearAvatarCache()) - Clear the query cache (
queryClient.clear()) - Clear persisted query cache (
clearPersistedQueryCache()) - Refetch session to immediately clear state
This could leave stale data in caches if the user logs back in as a different user.
🔎 Proposed fix
async function revokeAllSessions() {
try {
await _revokeSessions();
// Clear local state after revoking all sessions
saveCachedAuth(null);
setCachedUser(null);
setCachedAvatarUrl(null);
+
+ // Mirror signout() cleanup for full cache clearing
+ clearAvatarCache();
+ queryClient.clear();
+ await clearPersistedQueryCache();
} catch (err) {
setAuthError(err.message);
throw err;
}
}🤖 Prompt for AI Agents
In @packages/web/src/api/better-auth-store.js around lines 676 - 687, The
revokeAllSessions function currently calls _revokeSessions and clears local
in-memory state (saveCachedAuth, setCachedUser, setCachedAvatarUrl) but does not
perform the full signout cleanup; update revokeAllSessions to mirror signout():
after successful _revokeSessions() call invoke clearAvatarCache(), call
queryClient.clear(), call clearPersistedQueryCache(), trigger a refetch of the
session (e.g., refetchSession()) to immediately reset state, and then clear
in-memory caches and avatar like existing saveCachedAuth(null),
setCachedUser(null), setCachedAvatarUrl(null); keep the existing error handling
that sets setAuthError(err.message) and rethrows from the catch that references
_revokeSessions.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.