diff --git a/pb_hooks/profile_pin.pb.js b/pb_hooks/profile_pin.pb.js index bd1cf2a..1148c4c 100644 --- a/pb_hooks/profile_pin.pb.js +++ b/pb_hooks/profile_pin.pb.js @@ -67,3 +67,35 @@ routerAdd("POST", "/api/amber/verify-pin", (e) => { } return e.json(200, { ok: ok }) }, $apis.requireAuth("users")) + +// ── POST /api/amber/set-pin ─────────────────────────────────────────────────── +// Auth: account owner. Body: { profileId, pin } — pin "" clears. Exists because +// `pinHash` is hidden and PocketBase **silently drops client writes to hidden +// fields**: the app's old best-effort `PATCH {pinHash}` never landed, so the +// server never held a hash and verify-pin had nothing to compare (the PC's +// local verifier masked this). Hooks run in superuser context, which can write +// hidden fields; the hash shape matches the app + verify-pin: +// sha256(":") hex. +routerAdd("POST", "/api/amber/set-pin", (e) => { + const data = new DynamicModel({ profileId: "", pin: "" }) + e.bindBody(data) + const profileId = (data.profileId || "").trim() + const pin = (data.pin || "").trim() + if (profileId === "" || (pin !== "" && !/^\d{4}$/.test(pin))) { + return e.json(400, { ok: false, error: "profileId and a 4-digit (or empty) pin are required" }) + } + + let rec = null + try { + rec = $app.findRecordById("profiles", profileId) + } catch (_) { + return e.json(404, { ok: false, error: "profile not found" }) + } + if (rec.getString("user") !== e.auth.id) { + return e.json(404, { ok: false, error: "profile not found" }) + } + + rec.set("pinHash", pin === "" ? "" : $security.sha256(profileId + ":" + pin)) + $app.save(rec) + return e.json(200, { ok: true }) +}, $apis.requireAuth("users"))