<?php
 /**
 * CV Monitor
 *
 * @package   CV_Monitor_Admin
 * @author    Gabriel Mariani <gabriel@coursevector.com>
 * @license   GPL-2.0+
 * @link      http://coursevector.com
 * @copyright 2019 CourseVector
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) die;

//if ( ! current_user_can( 'view_site_health_checks' ) ) { // only exists in v5+
if ( ! current_user_can( 'manage_options' ) ) {
	wp_die( __( 'Sorry, you are not allowed to access the debug data.' ), '', 403 );
}

if ( ! function_exists( 'get_plugins' ) ) {
	require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

function get_vuln_links( $vuln ) {
	$html = '';
	if ( isset($vuln['references']) ) {
		$html .= '<ul>';

		if ( isset($vuln["references"]["url"]) && count($vuln["references"]["url"]) > 0 ) {
			foreach ( $vuln["references"]["url"] as $url ) {
				$html .= '<li><a href="' . $url . '" target="_blank">' . $url . '</a></li>';
			}
		}

		// CVE
		if ( isset($vuln["references"]["cve"]) && count($vuln["references"]["cve"]) > 0 ) {
			foreach ( $vuln["references"]["cve"] as $cve_id ) {
				$html .= '<li><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=' . $cve_id . '" target="_blank">CVE ' . $cve_id . '</a></li>';
			}
		}

		// Secunia
		if ( isset($vuln["references"]["secunia"]) && count($vuln["references"]["secunia"]) > 0 ) {
			foreach ( $vuln["references"]["secunia"] as $secunia_id ) {
				$html .= '<li><a href="http://secunia.com/advisories/' . $secunia_id . '" target="_blank">Secunia Advisory #' . $secunia_id . '</a></li>';
			}
		}

		// OSVDB shut down
		// $vuln["references"]["osvdb"]
		$html .= '</ul>';
		return  $html;
	} else {
		return $html;
	}
}

?>
<div class="wrap">
	<?php
	$vuln_count = 0;
	$api_token = 'QeVWRMTrM3SGH11dkG7r033zJN3JizjyvjgnhiRoOXE';
	global $wp_version;
	if ( version_compare( $wp_version, '3.8', '<' ) ) {
		screen_icon();
		echo '<h2>' . esc_html( get_admin_page_title() ) . '</h2>';
	} else {
		echo '<h1>' . esc_html( get_admin_page_title() ) . '</h1>';
	}
	?>
	<div class="wrap-body">
		<?php
		$clean_version = preg_replace( "/[^0-9]/","", $wp_version );
		$version = preg_replace( "/[^0-9\.]/","", $wp_version );
		$json = get_transient( "cv_monitor_vuln_wordpress" );

		if ( false === $json ) {
			// Can only use 50 times a day
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, "https://wpvulndb.com/api/v3/wordpresses/" . $clean_version);
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Token token={$api_token}"));
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			$output = curl_exec($ch);
			curl_close($ch);
			$json = json_decode($output, true);

			//$output = wp_remote_get( "https://wpvulndb.com/api/v2/wordpresses/" . $clean_version );
			//$json = json_decode($output, true);
			if ( null === $json ) $json = "UNAVAILABLE";
			set_transient( "cv_monitor_vuln_wordpress", $json, DAY_IN_SECONDS );
		}

		$is_vuln = false;
		$vuln_html = '';
		if ( isset($json["$version"]) ) {
			foreach ( $json["$version"]["vulnerabilities"] as $vuln ) {
				if ( true === version_compare( $version, trim($vuln["fixed_in"]), '<') ) {
					$is_vuln = true;
					$vuln_count++;

					$vuln_html .= '<div class="col"><div class="vuln-container">';
					$vuln_html .= '<h3 class="title ' . ($is_vuln ? 'vulnerable' : '') . '">' . $vuln["title"] . '</h3>';
					$vuln_html .= '<p class="meta">Fixed in ' . $vuln["fixed_in"] . ' @ <abbr title="' . date("Y-m-d H:i:s", strtotime($vuln["created_at"]))  . '">' . $this->plugin->parse_mysql_timestamp($vuln["created_at"]) . '</abbr></p>';
					$vuln_html .= get_vuln_links($vuln);
					$vuln_html .= '</div></div>';
				}
				$is_vuln = false;
			}
		}
		if ( isset($json["$version"]) && count($json["$version"]["vulnerabilities"]) > 0 ) {
			echo "<h2>WordPress {$version} Vulnerabilities</h2><div class='row'>" . $vuln_html . '</div>';
		} else {
			echo "<h2>WordPress {$version} Vulnerabilities</h2><p>No known vulnerabilities at this time.</p>";
		}

		$is_vuln = false;
		$vuln_html = '';
		$all_themes = wp_get_themes();
		//$current_theme = function_exists( 'wp_get_theme' ) ? wp_get_theme()->get( 'Name' ) : get_current_theme();
		foreach ( $all_themes as $slug => $theme ) {
			$json = get_transient( "cv_monitor_vuln_theme_{$slug}" );

			if ( false === $json ) {
				$ch = curl_init();
				curl_setopt($ch, CURLOPT_URL, "https://wpvulndb.com/api/v3/themes/" . $slug);
				curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Token token={$api_token}"));
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
				$output = curl_exec($ch);
				curl_close($ch);
				$json = json_decode($output, true);

				//$output = wp_remote_get( "https://wpvulndb.com/api/v2/themes/" . $slug );
				//$json = json_decode($output, true);
				if ( null === $json ) $json = "UNAVAILABLE";
				set_transient( "cv_monitor_vuln_theme_{$slug}", $json, DAY_IN_SECONDS );
			}

			if ( "UNAVAILABLE" === $json || "Not found" === $json["error"] ) {
				// Not in WP database
				continue;
			}

			$is_theme_vuln = false;
			$vuln_detail_html = '<div class="col"><div class="vuln-container">';
			$vuln_detail_list_html = '<ul class="striped">';
			foreach ( $json[$slug]["vulnerabilities"] as $vuln ) {
				if ( true === version_compare( $theme["Version"], trim($vuln["fixed_in"]), '<') ) {
					$is_vuln = true;
					$is_theme_vuln = true;
					$vuln_count++;

					$vuln_detail_list_html .= '<li>';
					$vuln_detail_list_html .= '<h4 class="' . ($is_vuln ? 'vulnerable' : '') . '">' . $vuln["title"] . '</h4>';
					$vuln_detail_list_html .= '<p class="vuln-meta">Fixed in ' . $vuln["fixed_in"] . ' @ <abbr title="' . date("Y-m-d H:i:s", strtotime($vuln["created_at"]))  . '">' . $this->plugin->parse_mysql_timestamp($vuln["created_at"]) . '</abbr></p>';
					$vuln_detail_list_html .= get_vuln_links($vuln);
					$vuln_detail_list_html .= '</li>';
				}
				$is_vuln = false;
			}
			$vuln_detail_list_html .= '</ul>';

			$vuln_detail_html .= '<h3 class="title ' . ($is_theme_vuln ? 'vulnerable' : '') . '">' . $slug . ' - ' . $theme["Version"] . '</h3>';
			$vuln_detail_html .= '<div class="meta">Latest Version: ' . $json[$slug]["latest_version"] . ' @ <abbr title="' . date("Y-m-d H:i:s", strtotime($json[$slug]["last_updated"]))  . '">' . $this->plugin->parse_mysql_timestamp($json[$slug]["last_updated"]) . '</abbr></div>';
			$vuln_detail_html .= $vuln_detail_list_html;
			$vuln_detail_html .= '</div></div>';
			if ( count($json[$slug]["vulnerabilities"]) > 0 && $is_theme_vuln ) {
				$vuln_html .= $vuln_detail_html;
			}
		}
		if ( '' != $vuln_html ) {
			echo "<h2>Theme Vulnerabilities</h2><div class='row'>" . $vuln_html . '</div>';
		} else {
			echo "<h2>Theme Vulnerabilities</h2><p>No known vulnerabilities at this time.</p>";
		}

		$is_vuln = false;
		$vuln_html = '';
		$all_plugins = get_plugins();
		foreach ( $all_plugins as $plugin_path => $plugin ) {
			$arr_path = explode('/', $plugin_path);
			$slug = $arr_path[0];
			$transient_name = "cv_monitor_vuln_plugin_{$slug}";

			// Transient name can't be longer than 64 characters for old versions of WordPress
			// https://core.trac.wordpress.org/ticket/13310
			// this includes '_transient_timeout_' which is prefixed
			if ( strlen($transient_name) > 44 ) $transient_name = substr( $transient_name, 0, 44 );

			$json = get_transient( $transient_name );
			if ( false === $json ) {
				$ch = curl_init();
				curl_setopt($ch, CURLOPT_URL, "https://wpvulndb.com/api/v3/plugins/" . $slug);
				curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Token token={$api_token}"));
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
				$output = curl_exec($ch);
				curl_close($ch);
				$json = json_decode($output, true);

				//$output = wp_remote_get( "https://wpvulndb.com/api/v2/plugins/" . $slug );
				//$json = json_decode($output, true);
				if ( null === $json ) $json = "UNAVAILABLE";
				set_transient( $transient_name, $json, DAY_IN_SECONDS );
			}

			if ( "UNAVAILABLE" === $json || "Not found" === $json["error"] ) {
				// Not in WP database
				continue;
			}

			$is_plugin_vuln = false;
			$vuln_detail_html = '<div class="col"><div class="vuln-container">';
			$vuln_detail_list_html = '<ul class="striped">';
			foreach ( $json[$slug]["vulnerabilities"] as $vuln ) {
				if ( true === version_compare( $plugin["Version"], trim($vuln["fixed_in"]), '<') ) {
					$is_vuln = true;
					$is_plugin_vuln = true;
					$vuln_count++;

					$vuln_detail_list_html .= '<li>';
					//$vuln_detail_html .= "<pre>'{$plugin["Version"]}' &lt; '{$vuln["fixed_in"]}' = " . (version_compare( $plugin["Version"], trim($vuln["fixed_in"]), '<') ? 'true' : 'false') . "</pre>";
					$vuln_detail_list_html .= '<h4 class="' . ($is_vuln ? 'vulnerable' : '') . '">' . $vuln["title"] . '</h4>';
					$vuln_detail_list_html .= '<p class="vuln-meta">Fixed in ' . $vuln["fixed_in"] . ' @ <abbr title="' . date("Y-m-d H:i:s", strtotime($vuln["created_at"]))  . '">' . $this->plugin->parse_mysql_timestamp($vuln["created_at"]) . '</abbr></p>';
					$vuln_detail_list_html .= get_vuln_links($vuln);
					$vuln_detail_list_html .= '</li>';
				}
				$is_vuln = false;

			}
			$vuln_detail_list_html .= '</ul>';

			$vuln_detail_html .= '<h3 class="title ' . ($is_plugin_vuln ? 'vulnerable' : '') . '">' . $slug . ' - ' . $plugin["Version"] . '</h3>';
			$vuln_detail_html .= '<div class="meta">Latest Version: ' . $json[$slug]["latest_version"] . ' @ <abbr title="' . date("Y-m-d H:i:s", strtotime($json[$slug]["last_updated"]))  . '">' . $this->plugin->parse_mysql_timestamp($json[$slug]["last_updated"]) . '</abbr></div>';
			$vuln_detail_html .= $vuln_detail_list_html;
			$vuln_detail_html .= '</div></div>';
			if ( count($json[$slug]["vulnerabilities"]) > 0 && $is_plugin_vuln ) {
				$vuln_html .= $vuln_detail_html;
			}
		}
		if ( '' != $vuln_html ) {
			echo "<h2>Plugin Vulnerabilities</h2><div class='row'>" . $vuln_html . '</div>';
		} else {
			echo "<h2>Plugin Vulnerabilities</h2><p>No known vulnerabilities at this time.</p>";
		}

		set_transient( "cv_monitor_vuln_count", $vuln_count, DAY_IN_SECONDS * 30 );
		?>
	</div>
</div> <!-- End Wrap -->