[READ-ONLY] Mirror of https://github.com/thoda-dev/shhh. Self-hostable zero-knowledge pastebin for secrets that expire on their own
docker end-to-end-encryption nuxt nuxtjs pastebin secrets selft-hosted zero-knowledge
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364import { z } from 'zod'
const settingsSchema = z.object({ max_retention_days_anonymous: z.number().int().positive().nullable(), max_retention_days_authenticated: z.number().int().positive().nullable(), max_text_size_bytes: z.number().int().positive().nullable(), max_upload_size_bytes: z.number().int().positive().nullable(), max_total_storage_bytes: z.number().int().positive().nullable(), rate_limit_anonymous_creates_per_period: z.number().int().positive().nullable(), rate_limit_authenticated_creates_per_period: z.number().int().positive().nullable(), rate_limit_uploads_per_period: z.number().int().positive().nullable(), rate_limit_period_minutes: z.number().int().positive()})
const setupSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(), password: z.string().min(8).max(128), settings: settingsSchema})
// Distinct from the migrator's key: this one serialises the wizard, not the schema.const SETUP_LOCK_KEY = 4_827_302
export default defineEventHandler(async (event) => { const body = await readValidatedBody(event, setupSchema.parse)
// The check and the write have to be one critical section, or two requests both create a super_admin. // Transaction-scoped: a session lock and its unlock are two pool checkouts, and land on different connections. return await db.transaction(async (tx) => { await tx.execute(sql`select pg_advisory_xact_lock(${SETUP_LOCK_KEY})`) return completeSetup(event, body) })})
async function completeSetup(event: Parameters<typeof appendResponseHeader>[0], body: z.infer<typeof setupSchema>) { if (await isSetupComplete()) { throw createError({ statusCode: 409, statusMessage: 'Setup already completed' }) }
const { headers, response } = await auth.api.signUpEmail({ body: { name: body.name, email: body.email, password: body.password }, headers: event.headers, returnHeaders: true })
// Not a signup input (`input: false` in auth.ts), so it is set directly. Auto-verified: completing the wizard proves control of both the instance and this address. await db.update(schema.users).set({ role: 'super_admin', emailVerified: true }).where(eq(schema.users.id, response.user.id))
// A retry after a partially failed setup would otherwise hit the primary key and surface as a // 500 rather than finishing the job. await db .insert(schema.appSettings) .values(Object.entries(body.settings).map(([key, value]) => ({ key, value, updatedBy: response.user.id }))) .onConflictDoNothing({ target: schema.appSettings.key })
for (const cookie of headers.getSetCookie()) { appendResponseHeader(event, 'set-cookie', cookie) }
setResponseStatus(event, 201) return { id: response.user.id, name: response.user.name, email: response.user.email }}