Files
ysj7705andCursor 3fa4ae2b66 Add everyone system user for anonymous registry pull.
Reserved PUBLIC ACLs can grant unauthenticated pull while blocking login, deletion, and anonymous push/delete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 17:12:27 +09:00

88 lines
2.5 KiB
TypeScript

import { z } from 'zod'
const aclSchema = z.object({
repository: z.string().min(1),
canPull: z.boolean().default(true),
canPush: z.boolean().default(false),
canDelete: z.boolean().default(false),
})
const bodySchema = z.object({
password: z.string().min(6).optional(),
role: z.enum(['ADMIN', 'USER']).optional(),
active: z.boolean().optional(),
acls: z.array(aclSchema).optional(),
})
export default defineEventHandler(async (event) => {
const session = await requireAdmin(event)
await ensureBootstrap()
const id = getRouterParam(event, 'id')
if (!id) {
throw createError({ statusCode: 400, statusMessage: 'Missing id' })
}
const existing = await prisma.user.findUnique({ where: { id } })
if (!existing) {
throw createError({ statusCode: 404, statusMessage: 'User not found' })
}
const body = bodySchema.parse(await readBody(event))
const isEveryone = isEveryoneUsername(existing.username)
if (isEveryone && (body.password || body.role)) {
throw createError({
statusCode: 400,
statusMessage: 'Cannot change password or role for system user "everyone"',
})
}
if (existing.username === (process.env.ADMIN_USERNAME || 'admin') && body.active === false) {
throw createError({ statusCode: 400, statusMessage: 'Cannot deactivate bootstrap admin' })
}
if (session.id === id && body.role && body.role !== 'ADMIN') {
throw createError({ statusCode: 400, statusMessage: 'Cannot demote yourself' })
}
const user = await prisma.$transaction(async (tx) => {
if (body.acls) {
await tx.acl.deleteMany({ where: { userId: id } })
await tx.acl.createMany({
data: body.acls
.filter((acl) => !isEveryone || acl.canPull)
.map((acl) => ({
userId: id,
repository: acl.repository,
canPull: isEveryone ? true : acl.canPull,
canPush: isEveryone ? false : acl.canPush,
canDelete: isEveryone ? false : acl.canDelete,
})),
})
}
return tx.user.update({
where: { id },
data: {
...(body.role ? { role: body.role } : {}),
...(typeof body.active === 'boolean' ? { active: body.active } : {}),
...(body.password ? { passwordHash: await hashPassword(body.password) } : {}),
},
include: { acls: true },
})
})
return {
user: {
id: user.id,
username: user.username,
role: user.role,
active: user.active,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
acls: user.acls,
},
}
})