login: block concurrent login, single-factor auth for staff/viewer
This commit is contained in:
@@ -253,6 +253,31 @@ if (password_verify(trim($data["password"]), $temp["password"])) {
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
|
||||
// ── Step 5g: Role check — staff/viewer skip OTP entirely ─────────────────
|
||||
// Owners always require 2FA. Invited users (license='user') require 2FA only
|
||||
// if their role in this company is admin or owner; staff/viewer go straight in.
|
||||
$requires_otp = true;
|
||||
if (($r['license'] ?? 'owner') !== 'owner') {
|
||||
$sth_role = $pdo1->prepare(
|
||||
"SELECT role FROM company_map_user WHERE company_id = :cid AND user_id = :uid LIMIT 1"
|
||||
);
|
||||
$sth_role->execute([':cid' => (int)($r['default_company'] ?? 0), ':uid' => (int)$r['user_id']]);
|
||||
$role_for_otp = ($sth_role->fetch(PDO::FETCH_ASSOC))['role'] ?? 'viewer';
|
||||
$requires_otp = in_array($role_for_otp, ['admin', 'owner'], true);
|
||||
}
|
||||
|
||||
if (!$requires_otp) {
|
||||
$_SESSION = [];
|
||||
$_SESSION['login_data'] = $data;
|
||||
$_SESSION['login_user_id'] = $user_id;
|
||||
$_SESSION['otpTime'] = time();
|
||||
$_SESSION['skip_otp'] = true;
|
||||
$answer['success'] = 1;
|
||||
$answer['skip_otp'] = true;
|
||||
$answer['message'] = 'Login Complete!';
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
|
||||
// ── Step 6: Generate 6-digit TOTP ────────────────────────────────────────
|
||||
// The secret key is the user's current password hash, so the OTP is unique
|
||||
// per user and automatically invalidated if the password changes.
|
||||
|
||||
Reference in New Issue
Block a user