Server : Apache
System : Linux p3plmcpnl504569.prod.phx3.secureserver.net 4.18.0-553.141.2.lve.el8.x86_64 #1 SMP Wed Jul 8 16:10:02 UTC 2026 x86_64
User : vvx4wizpbi9m ( 10307748)
PHP Version : 8.3.32
Disable Function : NONE
Directory :  /home/vvx4wizpbi9m/public_html/wp-content/plugins/malcare-security/wp_2fa/

📁 Create New:
⬆️ Upload File:
Current Dir [ Writable ] Root [ Writable ]


OR Upload from URL:
URL: Save as:

📄 File: email_otp.php

Path: /home/vvx4wizpbi9m/public_html/wp-content/plugins/malcare-security/wp_2fa/email_otp.php

Size: 5.72 KB

Permissions: 0644

<?php
if (!defined('ABSPATH')) exit;
if (!class_exists('MCWP2FAEmailOTP')) :

class MCWP2FAEmailOTP {
	const DIGITS = 8;
	const LIFETIME = 600;
	const TRIES = 3;
	const SEND_COOLDOWN = 60;
	const SEND_WINDOW = 900;
	const SENDS_PER_WINDOW = 5;
	const SITE_SECRET_CONSTANT = 'AUTH_SALT';

	public static function hasSiteSecret() {
		return self::siteSecret() !== null;
	}

	public static function secondsUntilNextSend($user_id) {
		$rate = self::loadRate($user_id);
		$now = time();

		if ($now - $rate['window_at'] >= self::SEND_WINDOW) {
			return 0;
		}

		if ($rate['sends'] >= self::SENDS_PER_WINDOW) {
			return $rate['window_at'] + self::SEND_WINDOW - $now;
		}

		return max(0, $rate['last_sent_at'] + self::SEND_COOLDOWN - $now);
	}

	public static function hasLiveCode($user_id) {
		$challenge = self::loadChallenge($user_id);

		return $challenge !== null && intval($challenge['expires_at']) > time();
	}

	public static function issue($user) {
		$secret = self::siteSecret();
		if ($secret === null) {
			return null;
		}

		if (self::secondsUntilNextSend($user->ID) > 0) {
			return null;
		}

		try {
			$number = random_int(0, pow(10, self::DIGITS) - 1);
		} catch (Exception $error) {
			return null;
		}

		$code = str_pad(strval($number), self::DIGITS, '0', STR_PAD_LEFT);

		$challenge = array(
			'code_hash' => self::codeHash($user->ID, $code, $secret),
			'expires_at' => time() + self::LIFETIME,
			'tries_left' => self::TRIES
		);

		if (!self::recordSend($user->ID)) {
			return null;
		}

		if (!self::storeChallenge($user->ID, $challenge)) {
			return null;
		}

		return $code;
	}

	public static function redeem($user, $code) {
		$secret = self::siteSecret();
		if ($secret === null) {
			return false;
		}

		$code = self::parseCode($code);
		if ($code === null) {
			return false;
		}

		$challenge = self::loadChallenge($user->ID);
		if ($challenge === null) {
			return false;
		}

		if (intval($challenge['expires_at']) <= time()) {
			self::claim($user->ID, $challenge);
			return false;
		}

		if (!hash_equals($challenge['code_hash'], self::codeHash($user->ID, $code, $secret))) {
			self::spendTry($user->ID, $challenge);
			return false;
		}

		self::discard($user->ID);
		self::clearSendCount($user->ID);

		return true;
	}

	public static function revoke($user_id) {
		delete_user_meta($user_id, MCWP2FA::EMAIL_RATE_META_KEY);

		return self::discard($user_id);
	}

	public static function discard($user_id) {
		delete_user_meta($user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY);

		return !metadata_exists('user', $user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY);
	}

	private static function spendTry($user_id, $challenge) {
		if (intval($challenge['tries_left']) <= 1) {
			self::claim($user_id, $challenge);
			return;
		}

		$spent = $challenge;
		$spent['tries_left'] = intval($challenge['tries_left']) - 1;

		if (update_user_meta($user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY, $spent, $challenge) === false) {
			self::claim($user_id, $challenge);
		}
	}

	# Proving inbox control clears the window cap, so logging in repeatedly does
	# not lock someone out. The cooldown is kept so codes still cannot be pulled
	# back to back, and a failed write only means the budget is not returned.
	private static function clearSendCount($user_id) {
		$current = self::loadRate($user_id);
		$next = array(
			'sends' => 0,
			'window_at' => time(),
			'last_sent_at' => $current['last_sent_at']
		);

		update_user_meta($user_id, MCWP2FA::EMAIL_RATE_META_KEY, $next, $current);
	}

	private static function loadRate($user_id) {
		$blank = array('sends' => 0, 'window_at' => 0, 'last_sent_at' => 0);
		$rate = get_user_meta($user_id, MCWP2FA::EMAIL_RATE_META_KEY, true);

		if (!self::validRate($rate, $blank)) {
			delete_user_meta($user_id, MCWP2FA::EMAIL_RATE_META_KEY);
			return $blank;
		}

		return $rate;
	}

	private static function validRate($rate, $blank) {
		if (!is_array($rate)) {
			return false;
		}

		foreach ($blank as $field => $default) {
			if (!isset($rate[$field]) || !is_int($rate[$field]) || $rate[$field] < 0) {
				return false;
			}
		}

		return true;
	}

	private static function recordSend($user_id) {
		$now = time();
		$current = self::loadRate($user_id);

		$window_at = $current['window_at'];
		$sends = $current['sends'];
		if ($now - $window_at >= self::SEND_WINDOW) {
			$window_at = $now;
			$sends = 0;
		}

		$next = array(
			'sends' => $sends + 1,
			'window_at' => $window_at,
			'last_sent_at' => $now
		);

		# $current is left untouched: it is the value the update guards on.
		return update_user_meta($user_id, MCWP2FA::EMAIL_RATE_META_KEY, $next, $current) !== false;
	}

	private static function claim($user_id, $challenge) {
		return delete_user_meta($user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY, $challenge) === true;
	}

	private static function loadChallenge($user_id) {
		$challenge = get_user_meta($user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY, true);

		if (!is_array($challenge) || !isset($challenge['code_hash'], $challenge['expires_at'], $challenge['tries_left'])) {
			return null;
		}

		if (!is_string($challenge['code_hash']) || !is_int($challenge['expires_at']) || !is_int($challenge['tries_left'])) {
			return null;
		}

		return $challenge;
	}

	private static function storeChallenge($user_id, $challenge) {
		return update_user_meta($user_id, MCWP2FA::EMAIL_CHALLENGE_META_KEY, $challenge) !== false;
	}

	private static function codeHash($user_id, $code, $secret) {
		return hash_hmac('sha256', intval($user_id) . "\0" . $code, $secret);
	}

	private static function siteSecret() {
		return MCHelper::configSalt(self::SITE_SECRET_CONSTANT);
	}

	private static function parseCode($code) {
		if (!is_string($code)) {
			return null;
		}

		$code = trim($code);

		return MCHelper::safePregMatch('/^\d{' . self::DIGITS . '}$/D', $code) === 1 ? $code : null;
	}
}
endif;

← Back to Directory Edit File 🔒 Chmod

WP File Manager