modify classed and comments
This commit is contained in:
@@ -1,114 +1,152 @@
|
||||
<?php
|
||||
require '../../../session.php';
|
||||
require '../../../config.php';
|
||||
require '../../../preset.php';
|
||||
require '../../../assets/utils/db_auth.php';
|
||||
<?php
|
||||
/**
|
||||
* request_new_otp.php — Resend OTP during the 2-factor login flow
|
||||
*
|
||||
* Called by: login page AJAX "Resend OTP" button on the OTP input screen.
|
||||
* Input: All data sourced from $_SESSION (written by login_otp.php).
|
||||
* No new user input is accepted — credentials are re-read from session
|
||||
* to avoid re-exposing the password in a second HTTP request.
|
||||
*
|
||||
* This endpoint regenerates a fresh TOTP and resends the OTP email without
|
||||
* requiring the user to re-enter their username and password. It is only
|
||||
* reachable after login_otp.php has successfully validated credentials and
|
||||
* written the login session state.
|
||||
*
|
||||
* Full flow:
|
||||
* 1. Reload username, password, and user_id from session.
|
||||
* 2. Fetch the full user row (need the password hash to regenerate OTP
|
||||
* and the email address to resend to).
|
||||
* 3. Re-verify the stored password against the session-stored hash.
|
||||
* This is a safety re-check — the session could theoretically have been
|
||||
* tampered with between login_otp.php and this call.
|
||||
* 4. On password mismatch → clear cookies, return "Incorrect Password".
|
||||
* 5. On success:
|
||||
* a. Generate a fresh 6-digit TOTP (new timestamp → new OTP).
|
||||
* b. Generate a new 6-letter reference number.
|
||||
* c. Send the OTP email via system SMTP ($SMTP from config.php).
|
||||
* Note: uses system-level SMTP unconditionally (unlike login_otp.php
|
||||
* which tries the company SMTP first). The if(true) wrapper is a
|
||||
* placeholder left from the original — email always sends.
|
||||
* d. Clear session and repopulate with new OTP state.
|
||||
* 6. Return { success: 1, message: "Login Complete!" }.
|
||||
*
|
||||
* Session keys read:
|
||||
* login_data['username'], login_data['password'], login_user_id
|
||||
*
|
||||
* Session keys overwritten:
|
||||
* login_data, otp, otpTime, reference, user_email, login_user_id
|
||||
* (same keys as login_otp.php — login_confirm.php reads the same structure)
|
||||
*
|
||||
* Response JSON:
|
||||
* On success: { "success": 1, "message": "Login Complete!" }
|
||||
* On failure: { "message": "Incorrect Password" }
|
||||
*/
|
||||
|
||||
$data["username"] = $_SESSION["login_data"]['username'];
|
||||
$data["password"] = $_SESSION["login_data"]['password'];
|
||||
$user_id = (int)$_SESSION["login_user_id"];
|
||||
require '../../../session.php';
|
||||
require '../../../config.php';
|
||||
require '../../../preset.php';
|
||||
require '../../../assets/utils/db_auth.php';
|
||||
|
||||
// get password
|
||||
$sth = $pdo1->prepare("select * from user where user_id = :user_id limit 1;");
|
||||
$sth->execute([
|
||||
":user_id" => $user_id
|
||||
]);
|
||||
$temp = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
// ── Step 1: Reload credentials from session ───────────────────────────────────
|
||||
// These were stored by login_otp.php so the user doesn't have to retype them.
|
||||
$data["username"] = $_SESSION["login_data"]['username'];
|
||||
$data["password"] = $_SESSION["login_data"]['password'];
|
||||
$user_id = (int)$_SESSION["login_user_id"];
|
||||
|
||||
// user email
|
||||
$user_email = $temp["email"];
|
||||
// ── Step 2: Fetch user record ─────────────────────────────────────────────────
|
||||
$sth = $pdo1->prepare("select * from user where user_id = :user_id limit 1;");
|
||||
$sth->execute([":user_id" => $user_id]);
|
||||
$temp = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
/**
|
||||
* validate password
|
||||
*/
|
||||
if(password_verify(trim($data["password"]), $temp["password"])) {
|
||||
$user_email = $temp["email"];
|
||||
|
||||
/**
|
||||
* Generate OTP
|
||||
*/
|
||||
function generateOTP($sercet_key, $time_step = 180, $length = 6){
|
||||
// ── Step 3–4: Re-verify password ─────────────────────────────────────────────
|
||||
// Safety check — ensures the session hasn't been tampered with between
|
||||
// login_otp.php and this resend call.
|
||||
if (password_verify(trim($data["password"]), $temp["password"])) {
|
||||
|
||||
global $otpTime;
|
||||
// ── Step 5a: Generate fresh 6-digit TOTP ──────────────────────────────────
|
||||
// Same HMAC-SHA1 algorithm as login_otp.php and login_confirm.php.
|
||||
// A new $otpTime is captured so the OTP window resets from this moment.
|
||||
function generateOTP($sercet_key, $time_step = 180, $length = 6) {
|
||||
|
||||
$otpTime = time();
|
||||
global $otpTime;
|
||||
|
||||
$counter = floor($otpTime / $time_step);
|
||||
$data = pack("NN", 0, $counter);
|
||||
$hash = hash_hmac('sha1', $data, $sercet_key, true);
|
||||
$offset = ord(substr($hash, -1)) & 0x0F;
|
||||
$value = unpack("N", substr($hash, $offset, 4));
|
||||
$otp = ($value[1] & 0x7FFFFFFF) % pow(10, $length);
|
||||
$otpTime = time(); // new timestamp — extends the 5-minute validity window
|
||||
|
||||
return str_pad(strval($otp), $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$counter = floor($otpTime / $time_step);
|
||||
$data = pack("NN", 0, $counter);
|
||||
$hash = hash_hmac('sha1', $data, $sercet_key, true);
|
||||
$offset = ord(substr($hash, -1)) & 0x0F;
|
||||
$value = unpack("N", substr($hash, $offset, 4));
|
||||
$otp = ($value[1] & 0x7FFFFFFF) % pow(10, $length);
|
||||
|
||||
return str_pad(strval($otp), $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
function numberToLetters($num) {
|
||||
$result = '';
|
||||
while ($num > 0) {
|
||||
$mod = ($num - 1) % 26;
|
||||
$result = chr(65 + $mod) . $result;
|
||||
$num = intval(($num - $mod) / 26);
|
||||
}
|
||||
return str_pad($result, 6, 'A', STR_PAD_LEFT);
|
||||
}
|
||||
// ── Step 5b: Generate 6-letter reference number ───────────────────────────
|
||||
// Converts a second TOTP (derived from the first OTP as the key) to a
|
||||
// base-26 uppercase letter string shown on the OTP input screen.
|
||||
function numberToLetters($num) {
|
||||
$result = '';
|
||||
while ($num > 0) {
|
||||
$mod = ($num - 1) % 26;
|
||||
$result = chr(65 + $mod) . $result;
|
||||
$num = intval(($num - $mod) / 26);
|
||||
}
|
||||
return str_pad($result, 6, 'A', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$otp = generateOTP($temp["password"]);
|
||||
$otp = generateOTP($temp["password"]);
|
||||
$reference_number = numberToLetters(generateOTP($otp));
|
||||
|
||||
$reference_number = numberToLetters(generateOTP($otp));
|
||||
// ── Step 5c: Send OTP email ───────────────────────────────────────────────
|
||||
// Uses the system-level $SMTP config from config.php.
|
||||
// The if(true) wrapper is a no-op placeholder from the original code —
|
||||
// the email block always executes.
|
||||
require "../../../assets/utils/module/mailer.php";
|
||||
|
||||
/**
|
||||
* Sent Email With OTP
|
||||
*/
|
||||
require "../../../assets/utils/module/mailer.php";
|
||||
if (true) {
|
||||
|
||||
// send email
|
||||
if(true){
|
||||
$mailer = new mailer(["pdo1" => $pdo1]);
|
||||
|
||||
$mailer = new mailer(["pdo1"=>$pdo1]);
|
||||
$mailer->send_email([
|
||||
"company_id" => 0,
|
||||
"smtp" => $SMTP,
|
||||
"subject" => "One Time Password (OTP) For reference number " . $reference_number,
|
||||
"message" => "Your OTP is " . $otp . " for reference number " . $reference_number,
|
||||
"channel_name" => "WMS LOGIN OTP ",
|
||||
"to" => $user_email,
|
||||
"key" => $pinkey,
|
||||
]);
|
||||
}
|
||||
|
||||
$mailer->send_email([
|
||||
"company_id" => 0,
|
||||
"smtp" => $SMTP,
|
||||
"subject" => "One Time Password (OTP) For reference number ".$reference_number,
|
||||
"message" => "Your OTP is ".$otp." for reference number ".$reference_number,
|
||||
"channel_name" => "WMS LOGIN OTP ",
|
||||
"to" => $user_email,
|
||||
"key" => $pinkey,
|
||||
]);
|
||||
// ── Step 5d: Reset session with new OTP state ─────────────────────────────
|
||||
// Full session is cleared before repopulating to avoid stale state
|
||||
// from the previous OTP attempt leaking into this one.
|
||||
$_SESSION = [];
|
||||
|
||||
}
|
||||
$_SESSION["login_data"] = $data;
|
||||
$_SESSION["otp"] = $otp;
|
||||
$_SESSION["otpTime"] = $otpTime; // new timestamp — login_confirm.php uses this
|
||||
$_SESSION["reference"] = $reference_number;
|
||||
$_SESSION["user_email"] = $user_email;
|
||||
$_SESSION["login_user_id"] = $user_id;
|
||||
|
||||
// ── Step 6: Respond ───────────────────────────────────────────────────────
|
||||
$answer["success"] = 1;
|
||||
$answer["message"] = "Login Complete!";
|
||||
exit(json_encode($answer));
|
||||
|
||||
$_SESSION = [];
|
||||
} else {
|
||||
|
||||
$_SESSION["login_data"] = $data; // store variables
|
||||
// ── Password mismatch — clear cookies and reject ──────────────────────────
|
||||
$answer["message"] = "Incorrect Password";
|
||||
setcookie("u", "", time() - 1, "/");
|
||||
setcookie("h1", "", time() - 1, "/");
|
||||
setcookie("h2", "", time() - 1, "/");
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
|
||||
$_SESSION["otp"] = $otp;
|
||||
|
||||
$_SESSION["otpTime"] = $otpTime;
|
||||
|
||||
$_SESSION["reference"] = $reference_number;
|
||||
|
||||
$_SESSION["user_email"] = $user_email;
|
||||
|
||||
$_SESSION["login_user_id"] = $user_id;
|
||||
|
||||
|
||||
$answer["success"] = 1;
|
||||
$answer["message"] = "Login Complete!";
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
else
|
||||
{
|
||||
$answer["message"] = "Incorrect Password";
|
||||
setcookie("u", "", time()-1, "/");
|
||||
setcookie("h1", "", time()-1, "/");
|
||||
setcookie("h2", "", time()-1, "/");
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
|
||||
$answer["success"] = 1;
|
||||
exit(json_encode($answer));
|
||||
|
||||
?>
|
||||
$answer["success"] = 1;
|
||||
exit(json_encode($answer));
|
||||
Reference in New Issue
Block a user