Security hardening: invited user onboarding flow (C1–N7)
- C1: verify.php now filters license='owner' — invite tokens no longer accepted - C1: onboarding API rejects non-owner sessions - C2: Existing-user invite requires explicit acceptance via accept_invite.php - C2: New accept_invite.php page and API engine added - C2: inviteUser() generates token + expiry for existing users; resendInvite() handles active users - C3: session_regenerate_id(true) before writing invite session keys on both invite pages - C4: invited_onboarding API wraps activation in transaction with SELECT FOR UPDATE; rowCount check added; SQLSTATE 23000 caught cleanly - C5: inviteUser() and resendInvite() two-table writes wrapped in transactions - M2: removeUser() wrapped in transaction with FOR UPDATE; clears default_company on active user removal - M4: Logged-in user guard added to invited_onboarding.php and accept_invite.php - M5: manage_users.php uses $server_url instead of HTTP_HOST for invite URLs - M6: Username regex enforces 3-32 chars; reserved name blocklist added - N5: searchUsers() changed from LIKE fuzzy search to exact email match only - N7: resendInvite() rate-limited to once per 60s via invite_resent_at column - Schema: company_map_user gains invite_expires_at and invite_resent_at columns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
1904fea84c
commit
b4b1f5cbec
@@ -15,10 +15,13 @@
|
||||
}
|
||||
|
||||
// ── Look up token ─────────────────────────────────────────────
|
||||
// license='owner' guard: invited users also have verify_token set, but they
|
||||
// must use invited_onboarding.php — never this flow.
|
||||
$sth = $pdo1->prepare("
|
||||
SELECT user_id, name, status, verify_expires_at
|
||||
FROM user
|
||||
WHERE verify_token = :token
|
||||
AND license = 'owner'
|
||||
LIMIT 1
|
||||
");
|
||||
$sth->execute([':token' => $token]);
|
||||
|
||||
Reference in New Issue
Block a user