import { fail, redirect } from '@sveltejs/kit'; import { getDb } from '$lib/server/db'; import { createCertificate, createP12 } from '$lib/server/step'; import { logAudit } from '$lib/server/audit'; import crypto from 'crypto'; export const actions = { default: async (event: import('@sveltejs/kit').RequestEvent) => { const data = await event.request.formData(); const deviceName = data.get('device_name')?.toString() || ''; const subject = data.get('subject')?.toString() || ''; const hours = parseInt(data.get('hours')?.toString() || '8760', 10); const exportP12 = data.get('export_p12') === 'on'; const p12Password = data.get('p12_password')?.toString() || ''; if (!deviceName || !subject || isNaN(hours)) { return fail(400, { error: 'Missing required fields' }); } if (exportP12 && !p12Password) { return fail(400, { error: 'p12 password required if exporting p12' }); } try { // generate serial number roughly matching the cert if step output differs, or just a unique ID. // step ca doesn't easily output the exact serial in simple exec without inspect command, // so we will just create a unique internal reference for our DB tracking if necessary, // or parse it from `step certificate inspect` // For this basic MVP, we generate a UUID for the db relation to file. const serialNumber = crypto.randomUUID(); const { crtFile } = await createCertificate(deviceName, subject, hours); if (exportP12) { await createP12(deviceName, p12Password); } const db = getDb(); const expiresAt = new Date(); expiresAt.setHours(expiresAt.getHours() + hours); const stmt = db.prepare(` INSERT INTO certificates (device_name, subject, serial_number, status, expires_at, file_path, created_by) VALUES (?, ?, ?, 'active', ?, ?, 'admin') `); stmt.run(deviceName, subject, serialNumber, expiresAt.toISOString(), crtFile); logAudit('create_cert', `Created device cert ${deviceName}`, 'admin', event.getClientAddress()); } catch (err: any) { return fail(500, { error: err.message || 'Failed to create certificate' }); } throw redirect(303, '/certificates'); } };