ID, wp_hash($code), 600); // 10 mins
// Send email
/* translators: 1: Blog name */
$subject = sprintf(__('[%1$s] Your Two-Factor Authentication Code', 'admin-login-guard-branding'), wp_specialchars_decode(get_option('blogname'), ENT_QUOTES));
$site_url = get_bloginfo('url');
$logo_url = admilogu_URL . 'assets/images/admin-login-guard-branding-logo.png';
$message = sprintf('
Hi %1$s,
This is your one-time verification code to securely access the admin area.
%2$s
This code is only active for the next 10 minutes. Once the code expires you will have to resubmit a request for a new code.
If you did not attempt to log in, please reset your password immediately.
For any further questions, please contact the site administrator.
Secured by Admin Login Guard & Branding
|
', $user->display_name, $code, $site_url, $logo_url);
$headers = array('Content-Type: text/html; charset=UTF-8');
wp_mail($user->user_email, $subject, $message, $headers);
}
/**
* Intercept Login Process
*
* Runs after WP validates the password. Logs the user back out, sets a pending token,
* and redirects to the 2FA form.
*/
function admilogu_intercept_login_for_2fa($user_login, $user)
{
if (!get_option('admilogu_enable_2fa', 0)) {
return;
}
// Check if user has 2FA enabled
$user_2fa_enabled = get_user_meta($user->ID, 'admilogu_2fa_enabled', true);
// Default to ON if it has never been set
if ($user_2fa_enabled === '') {
$user_2fa_enabled = '1';
}
// If not enabled for this user, let them pass normally
if (!$user_2fa_enabled || $user_2fa_enabled === '0') {
return;
}
// They need 2FA. Generate code and send email.
admilogu_send_2fa_email($user);
// Logout the user (since wp_login fires after auth cookie is set)
wp_logout();
// Set a temporary cookie to identify them for the 2FA step
$temp_token = wp_generate_password(32, false);
set_transient('admilogu_2fa_pending_' . $temp_token, $user->ID, 600);
setcookie('admilogu_2fa_token', $temp_token, time() + 600, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
// Redirect to 2FA form
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$redirect_to = isset($_REQUEST['redirect_to']) ? sanitize_text_field(wp_unslash($_REQUEST['redirect_to'])) : admin_url();
$login_url = wp_login_url();
$url = add_query_arg(array('action' => 'admilogu_2fa', 'redirect_to' => urlencode($redirect_to)), $login_url);
wp_safe_redirect($url);
exit;
}
// Run early (priority 5) to intercept before other plugins redirect
add_action('wp_login', 'admilogu_intercept_login_for_2fa', 5, 2);
/**
* Render the 2FA Form on the wp-login.php page
*/
function admilogu_render_2fa_form()
{
$token = isset($_COOKIE['admilogu_2fa_token']) ? sanitize_text_field(wp_unslash($_COOKIE['admilogu_2fa_token'])) : '';
if (!$token) {
wp_safe_redirect(wp_login_url());
exit;
}
$uid = get_transient('admilogu_2fa_pending_' . $token);
if (!$uid) {
wp_safe_redirect(wp_login_url());
exit;
}
$error = '';
$form_message = __('Please enter the 6-digit code sent to your email address.', 'admin-login-guard-branding');
// Handle form submission
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['admilogu_2fa_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['admilogu_2fa_nonce'])), 'admilogu_2fa_action')) {
$error = __('Invalid security token. Please try again.', 'admin-login-guard-branding');
} elseif (isset($_POST['admilogu_resend_2fa'])) {
// Handle Resend action
$user = get_user_by('id', $uid);
if ($user) {
admilogu_send_2fa_email($user);
$form_message = __('A new code has been sent to your email address.', 'admin-login-guard-branding');
} else {
$error = __('User not found. Please try logging in again.', 'admin-login-guard-branding');
}
} elseif (isset($_POST['admilogu_2fa_code'])) {
// Handle Verification action
$code = sanitize_text_field(wp_unslash($_POST['admilogu_2fa_code']));
$stored_hash = get_transient('admilogu_2fa_code_' . $uid);
if ($stored_hash && hash_equals($stored_hash, wp_hash($code))) {
// Success!
delete_transient('admilogu_2fa_code_' . $uid);
delete_transient('admilogu_2fa_pending_' . $token);
setcookie('admilogu_2fa_token', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN);
// Set real auth cookie
wp_set_auth_cookie($uid, true);
$user = get_user_by('id', $uid);
if ($user) {
remove_action('wp_login', 'admilogu_intercept_login_for_2fa', 5);
do_action('wp_login', $user->user_login, $user);
}
$redirect_to = isset($_POST['redirect_to']) ? sanitize_text_field(wp_unslash($_POST['redirect_to'])) : admin_url();
wp_safe_redirect($redirect_to);
exit;
} else {
$error = __('Invalid or expired code. Please check your email and try again.', 'admin-login-guard-branding');
}
}
}
// Render standard WP login header
$error_html = $error ? '' . esc_html($error) . '
' : '';
$message_html = !$error && $form_message ? '' . esc_html($form_message) . '
' : '';
login_header(
__('Two-Factor Authentication', 'admin-login-guard-branding'),
$error_html . $message_html
);
?>
ID, 'admilogu_2fa_enabled', true);
// Default to ON if it has never been set
if ($enabled === '') {
$enabled = '1';
}
?>