75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { json, error } from '@sveltejs/kit';
|
|
import type { RequestEvent } from '@sveltejs/kit';
|
|
import { getPin, setPin, verifyPin, hasPin, PIN_RE } from '$lib/server/pins';
|
|
import { createPbClient } from '$lib/server/pocketbase';
|
|
|
|
// PIN status for the shared-device toggle reminders. Never reveals values:
|
|
// - child → whether THEIR OWN pin is set (about self only);
|
|
// - parent → per-child set/unset roster (names + booleans, no PIN values;
|
|
// actual values stay behind the settings revealPin action).
|
|
export async function GET(event: RequestEvent) {
|
|
const u = event.locals.user;
|
|
if (!u || !event.locals.pbToken) throw error(401, 'Unauthorized');
|
|
if (u.role === 'child') {
|
|
return json({ hasPin: await hasPin(u.id) });
|
|
}
|
|
if (u.role !== 'parent') throw error(403, 'Forbidden');
|
|
const pb = createPbClient(event.locals.pbToken);
|
|
const kids: any[] = await pb
|
|
.collection('users')
|
|
.getFullList({ filter: `famId = '${u.famId}' && role = 'child'` })
|
|
.catch(() => []);
|
|
const children = await Promise.all(
|
|
kids.map(async (k: any) => ({
|
|
userId: k.id,
|
|
name: k.name || '?',
|
|
hasPin: await hasPin(k.id)
|
|
}))
|
|
);
|
|
return json({ children });
|
|
}
|
|
|
|
// Child PIN management. Session-role checked here (PB rules are superuser-only
|
|
// on `pins`): only the child themselves can set/change their own PIN.
|
|
export async function POST(event: RequestEvent) {
|
|
const u = event.locals.user;
|
|
if (!u) throw error(401, 'Unauthorized');
|
|
if (u.role !== 'child') throw error(403, 'Only children use PINs');
|
|
|
|
const body = await event.request.json().catch(() => ({}));
|
|
const { action, pin, currentPin } = body as {
|
|
action?: string;
|
|
pin?: string;
|
|
currentPin?: string;
|
|
};
|
|
if (!action || !pin || !PIN_RE.test(pin)) {
|
|
throw error(400, 'PIN must be exactly 3 digits');
|
|
}
|
|
|
|
if (action === 'set') {
|
|
if (await getPin(u.id)) throw error(400, 'PIN already set');
|
|
await setPin(u.famId, u.id, pin);
|
|
return json({ ok: true });
|
|
}
|
|
|
|
// Join wizard: assign the PIN on THIS device without touching an existing
|
|
// one (a kid joining a second shared device already has a PIN — their pin
|
|
// works everywhere; nobody can silently reassign it).
|
|
if (action === 'ensure') {
|
|
if (!(await getPin(u.id))) await setPin(u.famId, u.id, pin);
|
|
return json({ ok: true });
|
|
}
|
|
|
|
if (action === 'change') {
|
|
const existing = await getPin(u.id);
|
|
if (!existing) throw error(400, 'No PIN set yet');
|
|
if (!currentPin || !(await verifyPin(u.id, currentPin))) {
|
|
throw error(401, 'Current PIN is wrong');
|
|
}
|
|
await setPin(u.famId, u.id, pin);
|
|
return json({ ok: true });
|
|
}
|
|
|
|
throw error(400, 'Unknown action');
|
|
}
|