Skip to content

Commit cdbe5d5

Browse files
committed
Fix schema page loading
1 parent 718cfcb commit cdbe5d5

3 files changed

Lines changed: 16 additions & 6 deletions

File tree

src/api/auth.server.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import crypto from 'node:crypto'
2+
13
import bcrypt from 'bcrypt'
24
import { eq } from 'drizzle-orm'
35
import type { Context, MiddlewareHandler } from 'hono'
@@ -21,17 +23,22 @@ const internalToken = process.env.INTERNAL_API_TOKEN ?? 'internal-dev-token'
2123
const authInternalApiKey = process.env.AUTH_INTERNAL_API_KEY ?? ''
2224
const sessionSecret = process.env.SESSION_SECRET ?? 'dev-secret-change-me'
2325

26+
function timingSafeEquals(a: string, b: string): boolean {
27+
if (a.length !== b.length) return false
28+
return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
29+
}
30+
2431
export const authMiddleware = createMiddleware<AuthEnv>(async (c, next) => {
2532
// Internal service calls (legacy header)
2633
const internalHeader = c.req.header('x-internal-token')
27-
if (internalHeader === internalToken) {
34+
if (internalHeader && timingSafeEquals(internalHeader, internalToken)) {
2835
c.set('apiKeyScope', 'read')
2936
return next()
3037
}
3138

3239
// Auth provider internal API key (used by /api/kf/* endpoints)
3340
const auth = c.req.header('authorization')
34-
if (authInternalApiKey && auth === `Bearer ${authInternalApiKey}`) {
41+
if (authInternalApiKey && auth && timingSafeEquals(auth, `Bearer ${authInternalApiKey}`)) {
3542
c.set('apiKeyScope', 'admin')
3643
return next()
3744
}

src/api/kf-auth.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,11 @@ export async function callback(c: Context<AuthEnv>) {
162162

163163
setSessionCookie(c, sessionId)
164164

165-
// Redirect to saved return URL
166-
const returnTo = getCookie(c, RETURN_COOKIE) ?? '/dashboard'
165+
// Redirect to saved return URL (validate it's a safe relative path)
166+
const rawReturn = getCookie(c, RETURN_COOKIE) ?? '/dashboard'
167167
deleteCookie(c, RETURN_COOKIE, { path: '/' })
168+
const returnTo =
169+
rawReturn.startsWith('/') && !rawReturn.startsWith('//') ? rawReturn : '/dashboard'
168170

169171
return c.redirect(returnTo)
170172
}

src/routes/schemas/[id].tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect, useState } from 'react'
2-
import { Link } from 'react-router'
2+
import { Link, useParams } from 'react-router'
33

44
import BaseLayout from '~/components/BaseLayout'
55
import SchemaLabelManager from '~/components/SchemaLabelManager'
@@ -15,7 +15,8 @@ interface SchemaData {
1515
}
1616

1717
export default function SchemaDetailPage() {
18-
const schemaId = useSSRData<string>('schemaId')
18+
const params = useParams()
19+
const schemaId = useSSRData<string>('schemaId') ?? params.id
1920
const [schema, setSchema] = useState<SchemaData | null>(null)
2021
const [loading, setLoading] = useState(true)
2122
const [error, setError] = useState('')

0 commit comments

Comments
 (0)