<?php
if (!defined('ABSPATH')) exit;
if (!class_exists('BVSecurityCallback')) :
	class BVSecurityCallback extends BVCallbackBase {
		private $settings;

		public function __construct() {
			$this->settings = new MCWPSettings();
		}

		// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fread
		// Here we need fread as we are using popen which returns a handler
		function getCrontab() {
			$resp = array();

			if (function_exists('exec')) {
				$output = array();
				$retval = -1;
				$execRes = exec('crontab -l', $output, $retval);
				if ($execRes !== false && $execRes !== null) {
					$resp["content"] = implode("\n", $output);
					$resp["status"] = "success";
					$resp["code"] = $retval;
				}
			}
			if (empty($resp) && function_exists('popen')) {
				$handle = popen('crontab -l', 'rb');
				if ($handle) {
					$output = '';
					while (!feof($handle)) {
						$output .= fread($handle, 8192);
					}
					$resp["content"] = $output;
					$resp["status"] = "success";
					pclose($handle);
				} else {
					$resp["status"] = "failed";
				}
			}

			return $resp;
		}
		// phpcs:enable WordPress.WP.AlternativeFunctions.file_system_operations_fread

		public function setupWP2FA($secrets_by_uids, $to_encrypt, $cipher_algo, $enabled) {
			if (!is_array($secrets_by_uids)) {
				return array("status" => false, "message" => "secrets_by_uids is not an array.");
			}

			$result = array();
			foreach ($secrets_by_uids as $user_id => $secret) {
				if (empty($user_id) || !is_string($secret)) {
					continue;
				}

				if ($to_encrypt === true) {
					if (empty($cipher_algo)) {
						$cipher_algo = MCWP2FA::$cipher_algo;
					}

					if (defined('SECURE_AUTH_KEY')) {
						$encryption_result = MCHelper::opensslEncrypt($secret, $cipher_algo, SECURE_AUTH_KEY);
						if ($encryption_result[0] === false) {
							return array("status" => false, "message" => $encryption_result[1]);
						}
						$secret = $encryption_result[1];
					} else {
						return array("status" => false, "message" => "Encryption key not found.");
					}
				}

				$secret_info = array(
					"secret" => base64_encode($secret),
					"is_encrypted" => $to_encrypt
				);

				$result[$user_id][MCWP2FA::SECRET_META_KEY] = update_user_meta($user_id, MCWP2FA::SECRET_META_KEY, $secret_info);
				$result[$user_id][MCWP2FA::FLAG_META_KEY] = update_user_meta($user_id, MCWP2FA::FLAG_META_KEY, true);
			}

			if (is_bool($enabled)) {
				$config = array("enabled" => $enabled);
				$result[MCWP2FA::$wp_2fa_option] = $this->settings->updateOption(MCWP2FA::$wp_2fa_option, $config);
			}

			return array("status" => true, "result" => $result);
		}

		public function verifyWP2FACode($user_id, $code, $cipher_algo = null) {
			$encoded_secret_info = get_user_meta($user_id, MCWP2FA::SECRET_META_KEY, true);

			$secret_info = MCWP2FAUtils::getSecretInfo($encoded_secret_info);
			$secret = $secret_info['secret'];
			$is_secret_encrypted = $secret_info['is_encrypted'];

			if (is_null($secret) || is_null($is_secret_encrypted)) {
				return array("status" => false, "message" => "Secret and encryption status not found.");
			}

			if ($is_secret_encrypted === true) {
				if (empty($cipher_algo)) {
					$cipher_algo = MCWP2FA::$cipher_algo;
				}

				if (defined('SECURE_AUTH_KEY')) {
					$decryption_result = MCHelper::opensslDecrypt($secret, $cipher_algo, SECURE_AUTH_KEY);
					if ($decryption_result[0] === false) {
						return array("status" => false, "message" => $decryption_result[1]);
					}
					$secret = $decryption_result[1];
				} else {
					return array("status" => false, "message" => "Decryption key not found.");
				}
			}

			return array("status" => MCWP2FAAuthenticator::verifyCode($secret, $code, 2));
		}

		public function readWP2FAKeys($user_id) {
			$secret = get_user_meta($user_id, MCWP2FA::SECRET_META_KEY, true);
			$enabled = get_user_meta($user_id, MCWP2FA::FLAG_META_KEY, true);
			return array(
				"secret" => $secret,
				"enabled" => $enabled
			);
		}

		public function deleteWP2FAKeys($user_ids, $is_disable = false) {
			$result = array();

			foreach ($user_ids as $user_id) {
				$secret_deleted = delete_user_meta($user_id, MCWP2FA::SECRET_META_KEY);
				$flag_deleted = delete_user_meta($user_id, MCWP2FA::FLAG_META_KEY);
				$result[$user_id] = array(
					MCWP2FA::SECRET_META_KEY => $secret_deleted,
					MCWP2FA::FLAG_META_KEY => $flag_deleted
				);
			}

			if ($is_disable === true) {
				$result[MCWP2FA::$wp_2fa_option] = $this->settings->deleteOption(MCWP2FA::$wp_2fa_option);
			}

			return array("status" => true, "result" => $result);
		}

		public function process($request) {
			$params = $request->params;

			switch ($request->method) {
			case "gtcrntb":
				$resp = $this->getCrontab();
				break;
			case "stupwp2fa":
				$enable_wp_2fa = null;
				if (array_key_exists('enable_wp_2fa', $request->params)) {
					$enable_wp_2fa = $request->params['enable_wp_2fa'];
				}

				$resp = $this->setupWP2FA($params['secrets_by_uids'], $params['to_encrypt'], $params['cipher_algo'], $enable_wp_2fa);
				break;
			case "vrfywp2fa":
				$resp = $this->verifyWP2FACode($params['user_id'], $params['code'], $params['cipher_algo']);
				break;
			case "rdwp2fa":
				$resp = $this->readWP2FAKeys($params['user_id']);
				break;
			case "dltewp2fa":
				$resp = $this->deleteWP2FAKeys($params['user_ids'], $params['is_disable']);
				break;
			default:
				$resp = false;
			}

			return $resp;
		}
	}
endif;