add shared computer feature
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { createSuperClient } from '$lib/server/pocketbase';
|
||||
|
||||
// Child shared-device PINs. Superuser-only collection (like `otp`): every
|
||||
// read/write goes through server endpoints with session-role checks, so a
|
||||
// child can never read a sibling's PIN via PB rules.
|
||||
export const PIN_RE = /^\d{3}$/;
|
||||
|
||||
export function generatePin(): string {
|
||||
const n = randomBytes(2).readUIntBE(0, 2) % 1000;
|
||||
return n.toString().padStart(3, '0');
|
||||
}
|
||||
|
||||
async function getPinRow(userId: string) {
|
||||
const pb = await createSuperClient();
|
||||
return pb
|
||||
.collection('pins')
|
||||
.getFirstListItem(`userId='${userId}'`)
|
||||
.catch(() => null);
|
||||
}
|
||||
|
||||
export async function getPin(userId: string): Promise<string | null> {
|
||||
const row = await getPinRow(userId);
|
||||
return row?.pin || null;
|
||||
}
|
||||
|
||||
export async function hasPin(userId: string): Promise<boolean> {
|
||||
return (await getPin(userId)) !== null;
|
||||
}
|
||||
|
||||
export async function setPin(famId: string, userId: string, pin: string): Promise<void> {
|
||||
const pb = await createSuperClient();
|
||||
const row = await getPinRow(userId);
|
||||
if (row) {
|
||||
await pb.collection('pins').update(row.id, { pin });
|
||||
} else {
|
||||
await pb.collection('pins').create({ famId, userId, pin });
|
||||
}
|
||||
}
|
||||
|
||||
export async function resetPin(famId: string, userId: string): Promise<string> {
|
||||
const pin = generatePin();
|
||||
await setPin(famId, userId, pin);
|
||||
return pin;
|
||||
}
|
||||
|
||||
export async function verifyPin(userId: string, pin: string): Promise<boolean> {
|
||||
const row = await getPinRow(userId);
|
||||
return !!row && row.pin === pin;
|
||||
}
|
||||
Reference in New Issue
Block a user