Files
ysj7705andCursor 0fd00bfa37 Add Docker Registry AIO with Nuxt Token Auth and admin UI.
Compose brings up registry:3 plus a Prisma/SQLite Nuxt app for docker login, ACL management, and image browsing with shadcn-vue.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 16:12:12 +09:00

81 lines
2.1 KiB
TypeScript

import type { H3Event } from 'h3'
import { SignJWT, jwtVerify } from 'jose'
import type { Role } from '../../generated/prisma/client'
export type SessionUser = {
id: string
username: string
role: Role
}
const COOKIE_NAME = 'registry_aio_session'
function getSecret(): Uint8Array {
const secret = process.env.SESSION_SECRET || 'dev-session-secret-change-me'
return new TextEncoder().encode(secret)
}
export async function createSessionToken(user: SessionUser): Promise<string> {
return new SignJWT({
id: user.id,
username: user.username,
role: user.role,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('7d')
.sign(getSecret())
}
export async function readSessionUser(event: H3Event): Promise<SessionUser | null> {
const token = getCookie(event, COOKIE_NAME)
if (!token) return null
try {
const { payload } = await jwtVerify(token, getSecret())
if (
typeof payload.id !== 'string' ||
typeof payload.username !== 'string' ||
(payload.role !== 'ADMIN' && payload.role !== 'USER')
) {
return null
}
return {
id: payload.id,
username: payload.username,
role: payload.role,
}
} catch {
return null
}
}
export function setSessionCookie(event: H3Event, token: string) {
setCookie(event, COOKIE_NAME, token, {
httpOnly: true,
sameSite: 'lax',
path: '/',
maxAge: 60 * 60 * 24 * 7,
secure: process.env.AUTH_PUBLIC_URL?.startsWith('https://') ?? false,
})
}
export function clearSessionCookie(event: H3Event) {
deleteCookie(event, COOKIE_NAME, { path: '/' })
}
export async function requireSession(event: H3Event): Promise<SessionUser> {
const user = await readSessionUser(event)
if (!user) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
}
return user
}
export async function requireAdmin(event: H3Event): Promise<SessionUser> {
const user = await requireSession(event)
if (user.role !== 'ADMIN') {
throw createError({ statusCode: 403, statusMessage: 'Forbidden' })
}
return user
}