-
Notifications
You must be signed in to change notification settings - Fork 7
feat(medcat-trainer): Clear app storage on start-up to prevent auth state conflicts #316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,51 +1,53 @@ | ||
| import { createRouter, createWebHistory } from 'vue-router' | ||
| import {createRouter, createWebHistory} from 'vue-router' | ||
| import Home from '../views/Home.vue' | ||
| import TrainAnnotations from '../views/TrainAnnotations.vue' | ||
| import Demo from '../views/Demo.vue' | ||
| import Metrics from '../views/Metrics.vue' | ||
| import MetricsHome from '../views/MetricsHome.vue' | ||
| import ConceptDatabase from '../views/ConceptDatabase.vue' | ||
|
|
||
|
|
||
| const router = createRouter({ | ||
| history: createWebHistory(import.meta.env.BASE_URL), | ||
| routes: [ | ||
| const initialiseRouter = () => { | ||
| return createRouter({ | ||
| history: createWebHistory(import.meta.env.BASE_URL), | ||
| routes: [ | ||
| { | ||
| path: '/train-annotations/:projectId/:docId?', | ||
| name: 'train-annotations', | ||
| component: TrainAnnotations, | ||
| props: true, | ||
| // query: true | ||
| path: '/train-annotations/:projectId/:docId?', | ||
| name: 'train-annotations', | ||
| component: TrainAnnotations, | ||
| props: true, | ||
| // query: true | ||
| }, | ||
| { | ||
| path: '/metrics-reports/', | ||
| name: 'metrics-reports', | ||
| component: MetricsHome, | ||
| path: '/metrics-reports/', | ||
| name: 'metrics-reports', | ||
| component: MetricsHome, | ||
| }, | ||
| { | ||
| path: '/metrics/:reportId/', | ||
| name: 'metrics', | ||
| component: Metrics, | ||
| props: router => ({reportId: parseInt(router.params.reportId)}) | ||
| path: '/metrics/:reportId/', | ||
| name: 'metrics', | ||
| component: Metrics, | ||
| props: router => ({reportId: parseInt(router.params.reportId)}) | ||
| }, | ||
| { | ||
| path: '/demo', | ||
| name: 'demo', | ||
| component: Demo | ||
| path: '/demo', | ||
| name: 'demo', | ||
| component: Demo | ||
| }, | ||
| { | ||
| path: '/model-explore', | ||
| name: 'model-explore', | ||
| component: ConceptDatabase | ||
| path: '/model-explore', | ||
| name: 'model-explore', | ||
| component: ConceptDatabase | ||
| }, | ||
| { | ||
| path: '/:pathMatch(.*)', | ||
| name: 'home', | ||
| component: Home | ||
| path: '/:pathMatch(.*)', | ||
| name: 'home', | ||
| component: Home | ||
| } | ||
| ] | ||
| }) | ||
| ] | ||
| }) | ||
| } | ||
|
|
||
|
|
||
| export default router | ||
| export {initialiseRouter} | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,132 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { performStartupCleanup } from '@/utils/storage-cleanup' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe('storageCleanup', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let consoleLogSpy: any | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let localStorageMock: { [key: string]: any } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let sessionStorageMock: { [key: string]: any } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| beforeEach(() => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock console.log | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock localStorage with proper Object.keys() support | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| localStorageMock = {} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const localStorageProxy = new Proxy(localStorageMock, { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| get(target, prop) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'getItem') return (key: string) => target[key] || null | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'setItem') return (key: string, value: string) => { target[key] = value } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'removeItem') return (key: string) => { delete target[key] } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'clear') return () => { Object.keys(target).forEach(k => delete target[k]) } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'key') return (index: number) => Object.keys(target)[index] || null | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop === 'length') return Object.keys(target).length | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return target[prop as string] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ownKeys(target) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Object.keys(target) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getOwnPropertyDescriptor(target, prop) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enumerable: true, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configurable: true, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value: target[prop as string] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.stubGlobal('localStorage', localStorageProxy) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock sessionStorage | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sessionStorageMock = {} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sessionStorageProxy = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getItem: (key: string) => sessionStorageMock[key] || null, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setItem: (key: string, value: string) => { sessionStorageMock[key] = value }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| removeItem: (key: string) => { delete sessionStorageMock[key] }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clear: () => { sessionStorageMock = {} }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key: (index: number) => Object.keys(sessionStorageMock)[index] || null, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| get length() { return Object.keys(sessionStorageMock).length } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } as Storage | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.stubGlobal('sessionStorage', sessionStorageProxy) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock document.cookie | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let cookieStore: string[] = [] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Object.defineProperty(document, 'cookie', { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| get: () => cookieStore.join('; '), | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set: (value: string) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (value.includes('expires=Thu, 01 Jan 1970')) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Cookie deletion | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const name = value.split('=')[0] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cookieStore = cookieStore.filter(c => !c.startsWith(name + '=')) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cookieStore.push(value) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configurable: true | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock window.location and URL | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| delete (window as any).location | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| window.location = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| href: 'https://example.com/', | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hostname: 'example.com' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } as any | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock window.history.replaceState | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| window.history.replaceState = vi.fn() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| afterEach(() => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| consoleLogSpy.mockRestore() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.restoreAllMocks() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.unstubAllGlobals() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe('performStartupCleanup', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should log startup cleanup message', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| performStartupCleanup() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(consoleLogSpy).toHaveBeenCalledWith('[StorageCleanup] Performing startup cleanup') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should clear application cookies', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set some cookies | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'api-token=test123' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'username=testuser' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot AutofixAI 1 day ago Copilot could not generate an autofix suggestion Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'admin=true' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = '_oauth2_proxy=djIuWDI5aGRYUm9NbDl3Y205NGVTMDVaV05sTjJJeE1qUXdZVE0wTWpVNE1UYzBaVEJqWm1KaU1tWXdPR' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot AutofixAI 1 day ago Copilot could not generate an autofix suggestion Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = '_oauth2_proxy_1=mdlsjjsadfhHLFhBLGnbJlhB>j' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot AutofixAI 1 day ago In general, sensitive cookies must be created with the In this specific file, the only problematic code is in the test You only need to edit
Suggested changeset
1
medcat-trainer/webapp/frontend/src/tests/utils/storage-cleanup.spec.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'sessionid=6id701ipjww6rx0gumt0vvz1pnxpy12p' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot AutofixAI 1 day ago In general, sensitive cookies should always be set with the The best way to fix this without changing functionality is to update each cookie assignment in the test to append
Suggested changeset
1
medcat-trainer/webapp/frontend/src/tests/utils/storage-cleanup.spec.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'AUTH_SESSION_ID=OTI4Mzk4NmUtZWJhNi' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot AutofixAI 1 day ago In general, to avoid clear-text transmission of sensitive cookies, you must ensure all security-sensitive cookies are set with the For this specific test file, we should update the cookie strings used in the
Suggested changeset
1
medcat-trainer/webapp/frontend/src/tests/utils/storage-cleanup.spec.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'KC_RESTART=eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4..' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'KEYCLOAK_IDENTITY=eyJhbGciOiJIUzUxMiIsInR5cCI...' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.cookie = 'KEYCLOAK_SESSION=-9rVzyOy1xEA4sktmgSvv8DriM3ZO4kv-zjrhjuYFkA' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| performStartupCleanup() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Cookies should be cleared (setting them with expired date) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // We can't easily verify the exact cookie string, but we can check the function runs | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(consoleLogSpy).toHaveBeenCalled() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should clear all sessionStorage', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add some sessionStorage items | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sessionStorage.setItem('session-key1', 'value1') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sessionStorage.setItem('session-key2', 'value2') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(Object.keys(sessionStorageMock)).toHaveLength(2) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| performStartupCleanup() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(Object.keys(sessionStorageMock)).toHaveLength(0) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should handle localStorage with no Keycloak items', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| localStorage.setItem('normal-key', 'normal-value') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| performStartupCleanup() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Normal key should remain untouched | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(localStorageMock['normal-key']).toBe('normal-value') | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(Object.keys(localStorageMock)).toHaveLength(1) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /** | ||
| * Utility to clear application-specific browser storage on startup to prevent auth state conflicts | ||
| */ | ||
|
|
||
| function clearAuthRelatedCookies() { | ||
| console.debug('[StorageCleanup] Clearing auth-related cookies') | ||
| // Omit keycloak cookies ( 'AUTH_SESSION_ID', 'KC_RESTART', 'KEYCLOAK_IDENTITY', 'KEYCLOAK_SESSION',) as removing them breaks the oauth callback flow when OIDC auth is enabled | ||
| const cookies = [ | ||
| 'api-token', 'username', 'admin', 'user-id', | ||
| 'sessionid', | ||
| '_oauth2_proxy', '_oauth2_proxy_csrf', '_oauth2_proxy_1', '_oauth2_proxy_2' | ||
| ] | ||
| cookies.forEach(name => { | ||
| document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;` | ||
| }) | ||
| } | ||
|
|
||
| function clearSessionStorage() { | ||
| console.debug('[StorageCleanup] Clearing sessionStorage') | ||
| sessionStorage.clear() | ||
| } | ||
|
|
||
|
|
||
| export function performStartupCleanup(): void { | ||
| console.log('[StorageCleanup] Performing startup cleanup') | ||
| clearAuthRelatedCookies(); | ||
| clearSessionStorage(); | ||
| } |
Check warning
Code scanning / CodeQL
Clear text transmission of sensitive cookie Medium test
Copilot Autofix
AI 1 day ago
In general, the way to fix clear-text transmission of sensitive cookies is to ensure that any cookie containing authentication/session data is set with the
Secureattribute (and usuallyHttpOnlyandSameSite), so it is only sent over HTTPS and less exposed to JavaScript.In this specific file, the issue is only in how test cookies are created. The
document.cookiesetter is mocked to store the full cookie string verbatim, so adding attributes likeSecure; HttpOnlyto the cookie strings will not alter the test’s semantics: the cleanup code under test still “sees” the same cookie names/values, and the test only checks that cleanup runs (viaconsoleLogSpy) rather than inspecting cookie contents. The best fix is therefore to update eachdocument.cookie = '...'line in theit('should clear application cookies', ...)test to include; Secure; HttpOnly(and optionallySameSite=Lax) in the cookie string.Concretely:
medcat-trainer/webapp/frontend/src/tests/utils/storage-cleanup.spec.ts, around lines 89–101, update alldocument.cookie = 'name=value'todocument.cookie = 'name=value; Secure; HttpOnly'.