refactor: move auth.ts into a shared location rather than importing across workspace boundaries (#11)

This commit is contained in:
2026-04-25 14:37:28 +02:00
committed by GitHub
parent 6d53729b70
commit 298feb574e
8 changed files with 7 additions and 17 deletions
+1 -3
View File
@@ -37,6 +37,4 @@ jobs:
run: npm run build:pages run: npm run build:pages
- name: Run tests - name: Run tests
run: | run: npm run test
npm run test
npm run test:pages
+3 -1
View File
@@ -30,7 +30,7 @@ vitest run src/path/to.test.ts # single test (no npx needed)
```bash ```bash
npm run dev:pages # astro dev npm run dev:pages # astro dev
npm run build:pages # astro build → status-page/dist/ npm run build:pages # astro build → status-page/dist/
npm run test:pages # vitest run (auth tests)
npm run check:pages # astro check + tsc --noEmit npm run check:pages # astro check + tsc --noEmit
npm run lint:pages # eslint (astro plugin) npm run lint:pages # eslint (astro plugin)
``` ```
@@ -39,6 +39,8 @@ npm run lint:pages # eslint (astro plugin)
Before commit: `npm run check && npm run test && npm run build:pages && npm run check:pages` Before commit: `npm run check && npm run test && npm run build:pages && npm run check:pages`
## Verification order
`npm run check` = typecheck + Oxlint (worker) + ESLint (dedup via `eslint-plugin-oxlint`). Pages uses `eslint-plugin-astro`. `npm run check` = typecheck + Oxlint (worker) + ESLint (dedup via `eslint-plugin-oxlint`). Pages uses `eslint-plugin-astro`.
## Gotchas ## Gotchas
-3
View File
@@ -387,9 +387,6 @@ npm run build:pages
# Worker tests # Worker tests
npm run test npm run test
# Status page tests
npm run test:pages
# Type checking and linting # Type checking and linting
npm run check # worker npm run check # worker
npm run check:pages # pages (astro check + tsc) npm run check:pages # pages (astro check + tsc)
-1
View File
@@ -20,7 +20,6 @@
"check:fix": "npm run lint:fix && npm run format", "check:fix": "npm run lint:fix && npm run format",
"dev:pages": "npm run dev --workspace=status-page", "dev:pages": "npm run dev --workspace=status-page",
"build:pages": "npm run build --workspace=status-page", "build:pages": "npm run build --workspace=status-page",
"test:pages": "npm run test --workspace=status-page",
"check:pages": "npm run typecheck --workspace=status-page && npm run lint:pages && npm run format:pages:check", "check:pages": "npm run typecheck --workspace=status-page && npm run lint:pages && npm run format:pages:check",
"lint:pages": "npm run lint --workspace=status-page", "lint:pages": "npm run lint --workspace=status-page",
"lint:pages:fix": "npm run lint:fix --workspace=status-page", "lint:pages:fix": "npm run lint:fix --workspace=status-page",
+2 -2
View File
@@ -11,7 +11,7 @@ vi.mock('cloudflare:workers', () => ({
})); }));
// Mock the auth module // Mock the auth module
vi.mock('../status-page/src/lib/auth.js', () => ({ vi.mock('./lib/auth.js', () => ({
checkAuth: vi.fn().mockResolvedValue(undefined), checkAuth: vi.fn().mockResolvedValue(undefined),
})); }));
@@ -62,7 +62,7 @@ describe('worker fetch handler', () => {
}); });
it('should return 401 when auth fails', async () => { it('should return 401 when auth fails', async () => {
const { checkAuth } = await import('../status-page/src/lib/auth.js'); const { checkAuth } = await import('./lib/auth.js');
vi.mocked(checkAuth).mockResolvedValueOnce( vi.mocked(checkAuth).mockResolvedValueOnce(
new Response('Unauthorized', { new Response('Unauthorized', {
status: 401, status: 401,
+1 -1
View File
@@ -1,4 +1,4 @@
import { checkAuth } from '../status-page/src/lib/auth.js'; import { checkAuth } from './lib/auth.js';
import { handleAggregation } from './aggregation.js'; import { handleAggregation } from './aggregation.js';
import { executeDnsCheck } from './checks/dns.js'; import { executeDnsCheck } from './checks/dns.js';
import { executeHttpCheck } from './checks/http.js'; import { executeHttpCheck } from './checks/http.js';
@@ -10,11 +10,6 @@ const unauthorizedResponse = (): Response =>
headers: { 'WWW-Authenticate': 'Basic realm="Status Page"' }, headers: { 'WWW-Authenticate': 'Basic realm="Status Page"' },
}); });
/**
* Timing-safe string comparison using SHA-256 hashing.
* Hashing both values to a fixed size prevents leaking length information.
* Uses constant-time byte comparison to prevent timing side-channel attacks.
*/
async function timingSafeCompare(a: string, b: string): Promise<boolean> { async function timingSafeCompare(a: string, b: string): Promise<boolean> {
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const [hashA, hashB] = await Promise.all([ const [hashA, hashB] = await Promise.all([
@@ -25,7 +20,6 @@ async function timingSafeCompare(a: string, b: string): Promise<boolean> {
const viewA = new Uint8Array(hashA); const viewA = new Uint8Array(hashA);
const viewB = new Uint8Array(hashB); const viewB = new Uint8Array(hashB);
// Constant-time comparison: always check every byte
let mismatch = 0; let mismatch = 0;
for (let i = 0; i < viewA.length; i++) { for (let i = 0; i < viewA.length; i++) {
mismatch |= viewA[i] ^ viewB[i]; mismatch |= viewA[i] ^ viewB[i];