Add OTP_REQUIRED switch for email OTP login

This commit is contained in:
Thanakorn
2026-09-14 15:03:16 +07:00
parent 2f290ddb26
commit 9afcf072b0
11 changed files with 133 additions and 9 deletions
+9 -2
View File
@@ -58,6 +58,7 @@ require_once '../../../config.php';
require_once '../../../preset.php';
define('UNAUTHENTICATED_ROUTE', true);
require_once '../../../assets/utils/db_auth.php';
require_once '../../../assets/utils/otp_policy.php';
// ── Step 1: Load session state written by login_otp.php ───────────────────────
$data["username"] = $_SESSION["login_data"]['username'];
@@ -100,9 +101,15 @@ $_SESSION["diff"] = $otp_diff_minutes;
// ── Step 4: Validate OTP value and expiry ─────────────────────────────────────
// Skipped for staff/viewer roles — login_otp.php sets skip_otp=true in session
// so they never receive or enter an OTP. Admin/owner always go through this check.
// so they never receive or enter an OTP. Admin/owner always go through this check,
// unless OTP_REQUIRED=false in config.php: that also covers a user who was already
// on the OTP screen when the switch was turned off.
if (empty($_SESSION['skip_otp'])) {
if ($data["otp"] != $otp || $otp_diff_minutes > 5) {
if (!otp_required()) {
if (!empty($user_id)) {
otp_log_bypass($user_id, 'login_confirm');
}
} elseif ($data["otp"] != $otp || $otp_diff_minutes > 5) {
$answer["message"] = "Wrong OTP! Please try again. (Our OTP is valid for 5 minute)";
exit(json_encode($answer));
}
+9 -4
View File
@@ -62,6 +62,7 @@ require_once '../../../config.php';
require_once '../../../preset.php';
define('UNAUTHENTICATED_ROUTE', true);
require_once '../../../assets/utils/db_auth.php';
require_once '../../../assets/utils/otp_policy.php';
// ── Step 1: Resolve user_id from username or email (case-insensitive) ────────
$sth = $pdo1->prepare("select user_id from user where ? in (username,email) ");
@@ -253,11 +254,15 @@ 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
// ── Step 5g: OTP policy, then role check — staff/viewer skip OTP entirely ─
// OTP_REQUIRED=false in config.php turns the email OTP off for everyone and
// logs the sign-in as a bypass (see assets/utils/otp_policy.php).
// Otherwise 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') {
$requires_otp = otp_required();
if (!$requires_otp) {
otp_log_bypass($user_id, 'login_otp');
} elseif (($r['license'] ?? 'owner') !== 'owner') {
$sth_role = $pdo1->prepare(
"SELECT role FROM company_map_user WHERE company_id = :cid AND user_id = :uid LIMIT 1"
);