initial commit
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
// M20 — users.onRecordCreateRequest role guard.
|
||||
//
|
||||
// Closes the self-signup role-escalation hole: a client can no longer
|
||||
// POST { role: 'technician', shopUserId: '<someone>' } to /api/collections/users
|
||||
// to land inside another shop's technician list.
|
||||
//
|
||||
// Rule: role defaults to 'advisor' and shopUserId is cleared, UNLESS the
|
||||
// email being registered matches a pending, unexpired technicianInvites
|
||||
// record — in which case role='technician' and shopUserId comes from the
|
||||
// invite (not the client).
|
||||
//
|
||||
// Idempotent: re-applying is safe because we only set values on create.
|
||||
|
||||
migrate(
|
||||
(app) => {
|
||||
app.onRecordCreateRequest((e) => {
|
||||
if (e.collection.name !== 'users') return;
|
||||
|
||||
const record = e.record;
|
||||
const email = (record.get('email') || '').toString().trim().toLowerCase();
|
||||
if (!email) return;
|
||||
|
||||
// Look for a matching pending, unexpired invite.
|
||||
let invite = null;
|
||||
try {
|
||||
invite = e.dao.findFirstRecordByFilter(
|
||||
'technicianInvites',
|
||||
`email = "${email.replace(/"/g, '')}" && status = "pending" && expiresAt >= @now`,
|
||||
);
|
||||
} catch {
|
||||
invite = null;
|
||||
}
|
||||
|
||||
if (invite) {
|
||||
// Authorized technician signup — pin values from the invite.
|
||||
record.set('role', 'technician');
|
||||
record.set('shopUserId', invite.get('shopUserId') || '');
|
||||
console.log(`[M20] technician signup authorized for ${email}`);
|
||||
} else {
|
||||
// Regular owner signup — force advisor, clear shop link.
|
||||
record.set('role', 'advisor');
|
||||
record.set('shopUserId', '');
|
||||
console.log(`[M20] owner signup: role forced to advisor for ${email}`);
|
||||
}
|
||||
});
|
||||
console.log('[M20] users create role guard installed');
|
||||
},
|
||||
(app) => {
|
||||
// Best-effort rollback: we cannot easily unregister a JS hook in 0.39
|
||||
// without restarting PB. Document that rolling this back requires a
|
||||
// PB restart after removing the file. The down-migration is a no-op
|
||||
// that logs the intent.
|
||||
console.log('[M20] rollback requested — remove this migration file and restart PocketBase');
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user