wordpress-plugin/bitfire-admin.php
<?php
namespace BitFirePlugin;
use function BitFire\serve_advanced;
use function BitFire\serve_dashboard;
use function BitFire\serve_database;
use function BitFire\serve_malware;
use function BitFire\serve_settings;
use function BitFire\serve_exceptions;
use function BitFireSvr\doc_root;
use function BitFireSvr\get_wordpress_version;
use BitFire\BitFire;
use BitFire\Config as CFG;
use Exception;
use RuntimeException;
use ThreadFin\Effect as Effect;
use ThreadFin\FileData;
use ThreadFin\FileMod;
use const BitFire\FILE_RW;
use const BitFire\FILE_W;
use const BitFire\WAF_INI;
use const BitFire\WAF_ROOT;
use const BitFire\WAF_SRC;
use const ThreadFin\DAY;
use function BitFireSvr\update_ini_value;
use function ThreadFin\array_filter_modify;
use function ThreadFin\contains;
use function ThreadFin\file_recurse;
use function ThreadFin\dbg;
use function ThreadFin\en_json;
use function ThreadFin\trace;
use function ThreadFin\debug;
use function ThreadFin\ends_with;
use function ThreadFin\error;
use function ThreadFin\get_hidden_file;
use function ThreadFin\partial as BINDL;
use function ThreadFin\partial;
use function ThreadFin\partial_right as BINDR;
// we should have attempted load 2x before here
// 1: for for auto load, 2: plugin load, if it didn't load, something is wrong
if (!defined("BitFire\\WAF_ROOT")) {
die("BitFire did not load correctly. Please re-install.");
}
// since this is an admin page, make sure we have the admin functions loaded
require_once \BitFire\WAF_SRC."dashboard.php";
require_once \BitFire\WAF_SRC."server.php";
require_once \BitFire\WAF_SRC."api.php";
/**
* get the current locale setting
* @return string
*/
function find_locale() : string {
return get_locale();
}
/**
* Create an effect to update the firewall admin status. Admin functions require
* an access token (like nonce), Basic Auth AND CMS admin status (if applicable)
*
* This function should sync the bitfire cookie "wp" value with the current
* admin status.
*
* @return Effect
*/
function bf_auth_effect() : Effect {
if (!defined("BitFire\\WAF_ROOT")) { return Effect::$NULL; } // GUARD
$effect = Effect::new();
$c = BitFire::get_instance()->cookie;
$request = BitFire::get_instance()->_request;
$x = (current_user_can("unfiltered_html")) ? 2 : 0;
$u = (current_user_can("upload_files")) ? 2 : 0;
$a = (\BitFirePlugin\is_admin()) ? 2 : 0;
if (!$c || $c->empty()) {
$cookie = en_json(["ip" => crc32($request->ip), "ua" => crc32($request->agent),
"et" => time() + DAY, "wp" => $a, "u" => $u, "x" => $x]);
return $effect->cookie($cookie);
}
// always allow administrator IPs
$ip = filter_input(INPUT_SERVER, CFG::str_up("ip_header", "REMOTE_ADDR"), FILTER_VALIDATE_IP);
$block_file = \BitFire\BLOCK_DIR . DIRECTORY_SEPARATOR . $ip;
if ($a && !file_exists($block_file)) {
$effect->file(new FileMod($block_file, "allow", FILE_RW, 0, true));
}
$d = $c->value("array");
$updated = false;
// the current admin status needs to be updated
if ($c->extract("wp")->value('int') != $a) {
$updated = true;
$d["wp"] = $a;
}
if ($c->extract("u")->value('int') != $u) {
$updated = true;
$d["u"] = $u;
}
if ($c->extract("x")->value('int') != $x) {
$updated = true;
$d["x"] = $x;
}
if ($updated) {
$effect->cookie(en_json($d));
}
// set the new cookie value
return $effect;
}
/**
* handle the very rare case where administrator moves the wp-content url or directory
* impure
*/
function sync_paths() : void {
return;
require_once ABSPATH . "/wp-admin/includes/file.php";
// sync all paths (make sure we stay up to date if WP_CONTENT_DIR is ever changed)
$home = \get_home_path();
if ($home != CFG::str("cms_root") && contains($home, doc_root())) {
$e = update_ini_value("cms_root", \get_home_path())->run();
debug("sync cms_root [%s] / [%s] - [%d] (%s)", \get_home_path(), CFG::str("cms_root"), $e->read_status(), $e->read_errors());
}
if (defined("WP_CONTENT_DIR") && \WP_CONTENT_DIR != CFG::str("cms_content_dir")) {
$dir = (!contains(\WP_CONTENT_DIR, doc_root())) ? doc_root() . \WP_CONTENT_DIR : \WP_CONTENT_DIR;
$e = update_ini_value("cms_content_dir", $dir)->run();
debug("sync cms_content_dir [%s] / [%s] - [%d] (%s)", \WP_CONTENT_DIR, CFG::str("cms_content_dir"), $e->read_status(), $e->read_errors());
}
if (\content_url() != CFG::str("cms_content_url")) {
update_ini_value("cms_content_url", \content_url())->run();
}
$wp_version = get_wordpress_version(CFG::str("cms_root"));
// update wordpress version
if (CFG::str("wp_version") != $wp_version) {
update_ini_value("wp_version", $wp_version)->run();
}
}
/**
* called on admin page load
*
*
* THIS IS THE ADMIN MAIN
*
*/
function admin_init() {
trace("admin init");
// notify if wp-content dir changes...
// sync_paths();
// the admin function to run
// $page = filter_input(INPUT_GET, "BITFIRE_WP_PAGE", FILTER_SANITIZE_SPECIAL_CHARS);
$rm_path = CFG::str("rm_bitfire");
if ($rm_path) {
// need
debug("PURGE %s", $rm_path);
// remove old bitfire directory, if it exists
// TODO: improve this....
if (ends_with($rm_path, "bitfire") && !contains(ini_get("auto_prepend_file"), $rm_path)) {
if (file_exists($rm_path) && file_exists("{$rm_path}/startup.php")) {
debug("EXEC PURGE %s", $rm_path);
file_recurse($rm_path, function($x) {
if (is_dir($x)) {
$r = chmod($x, 0775);
} else {
chmod($x, 0664);
unlink($x);
}
});
file_recurse($rm_path, function($x) {
if (is_dir($x)) { rmdir($x); }
else { unlink($x); }
});
file_recurse($rm_path, function($x) {
if (is_dir($x)) { rmdir($x); }
else { unlink($x); }
});
chmod($rm_path, 0775);
unlink($rm_path);
if (!file_exists($rm_path)) {
update_ini_value("rm_bitfire", "")->run();
}
}
}
}
// serve the requested page
// TODO: change this to a function map for settings to functions similar to API
/*
if (strtolower($page) === "settings") {
serve_settings();
}
else if (strtolower($page) === "advanced") {
serve_advanced();
}
else if (strtolower($page) === "malwarescan") {
serve_malware();
}
else if (strtolower($page) === "exceptions") {
serve_exceptions();
}
else if (strtolower($page) === "database") {
serve_database();
}
// default to the basic dashboard
else {
serve_dashboard();
}
*/
}
/**
* Register a custom admin menu page.
*/
function bitfire_add_menu() {
$alerts = create_plugin_alerts();
$base_num = count($alerts);
$title = ($base_num > 0) ? "Vulnerable Plugins, " : "";
$base_num += (CFG::disabled("whitelist_enable") || CFG::disabled("require_full_browser")) ? 1 : 0;
$title = ($base_num > 0) ? "Bot Blocking Disabled, " : "";
//$base_num += (CFG::disabled("auto_start")) ? 1 : 0;
//$title = ($base_num > 0) ? "Always On Disabled" : "";
\add_menu_page(
"BitFire Dashboard",
"BitFire <span class='update-plugins count-$base_num' title='$title'><span class='plugin-count'>$base_num</span></span>",
"manage_options",
"bitfire",
"\BitFire\serve_dashboard",
"dashicons-shield",
66
);
\add_submenu_page(
"bitfire",
"BitFire Bot Control",
"Bot Control",
"manage_options",
"bitfire_botlist",
"\BitFire\serve_bot_list",
1
);
\add_submenu_page(
"bitfire",
"BitFire Settings",
"Settings",
"manage_options",
"bitfire_settings",
"\BitFire\serve_settings",
2
);
\add_submenu_page(
"bitfire",
"BitFire Malware Scanner",
"Malware Scan",
"manage_options",
"bitfire_malware",
"\BitFire\serve_malware",
3
);
\add_submenu_page(
"bitfire",
"BitFire RASP Settings",
"RASP Settings",
"manage_options",
"bitfire_advanced",
"\BitFire\serve_advanced",
4
);
\add_submenu_page(
"bitfire",
"BitFire Database",
"Database Recovery",
"manage_options",
"bitfire_database",
"\BitFire\serve_database",
10
);
\add_submenu_page(
"bitfire",
"BitFire Exceptions",
"Rule Exceptions",
"manage_options",
"bitfire_exceptions",
"\BitFire\serve_exceptions",
6
);
}
// helper wrapper for wp_enqueue_script
function add_script_src(string $handle, string $src, string $optional) : string {
if (contains($src, "https")) {
\wp_enqueue_scripts($handle, $src, [], "1.0", true);
}
return "";
}
// helper wrapper for wp_add_inline_script
function add_script_inline(string $handle, string $code) : string {
\wp_add_inline_script($handle, $code);
return "";
}
function bitfire_styles() {
if (stristr($_SERVER['REQUEST_URI'], "wp-admin/plugins.php") !== false) {
\wp_register_script("bitfire", plugin_dir_url(__FILE__) . "public/plugin-monitor.js", ["jquery"], "1.0", true);
\wp_enqueue_script("bitfire", plugin_dir_url(__FILE__) . "public/plugin-monitor.js", "1.0", false);
header("x-plugin: 1");
}
// ONLY ENQUEUE ON BITFIRE PAGES
$page = filter_input(INPUT_GET, "BITFIRE_WP_PAGE", FILTER_SANITIZE_SPECIAL_CHARS);
if (empty($page)) {
$page = filter_input(INPUT_GET, "page", FILTER_SANITIZE_SPECIAL_CHARS);
if (empty($page) || !contains($page, "bitfire")) {
return;
}
}
\wp_register_script("dashkit", plugin_dir_url(__FILE__) . "public/dashkit.min.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-chart", plugin_dir_url(__FILE__) . "public/chart.min.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-diff", plugin_dir_url(__FILE__) . "public/difflib.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-prism", plugin_dir_url(__FILE__) . "public/prism.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-internal", plugin_dir_url(__FILE__) . "public/internal.js", [], "1.0", false);
\wp_register_script("dashkit-vendor", plugin_dir_url(__FILE__) . "public/vendor.bundle.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-theme", plugin_dir_url(__FILE__) . "public/theme.bundle.js", ["jquery"], "1.0", true);
\wp_register_script("dashkit-pako", plugin_dir_url(__FILE__) . "public/pako.js", [], "1.0", true);
\wp_register_script("dashkit-underscore", plugin_dir_url(__FILE__) . "public/underscore.min.js", [], "1.0", false);
\wp_register_style("dashkit-vs2015", plugin_dir_url(__FILE__) . "public/vs2015.min.css", [], "1.0");
\wp_register_style("dashkit-prism", plugin_dir_url(__FILE__) . "public/prism.css", [], "1.0");
//\wp_register_style("dashkit-theme", plugin_dir_url(__FILE__) . "public/theme.min.css", [], "1.0");
\wp_register_style("dashkit-bundle", plugin_dir_url(__FILE__) . "public/theme.bundle.css", [], "1.0");
\wp_register_style("dashkit-feather", plugin_dir_url(__FILE__) . "public/feather.css", [], "1.0");
//\wp_register_script("underscore2", "/wp-includes/js/underscore.min.js", [], false, false);
\wp_enqueue_script("dashkit-underscore", plugin_dir_url(__FILE__) . "public/underscore.min.js", "1.0", false);
\wp_enqueue_script("dashkit-chart", plugin_dir_url(__FILE__) . "public/chart.min.js", ["jquery"], "1.0", false);
\wp_enqueue_script("dashkit-vendor", plugin_dir_url(__FILE__) . "public/vendor.bundle.js", ["jquery"], "1.0", true);
\wp_enqueue_script("dashkit-diff", plugin_dir_url(__FILE__) . "public/difflib.js", ["jquery"], "1.0", true);
\wp_enqueue_script("dashkit-prism", plugin_dir_url(__FILE__) . "public/prism.js", ["jquery"], "1.0", true);
\wp_enqueue_script("dashkit-internal", plugin_dir_url(__FILE__) . "public/internal.js", [], "1.0", false);
\wp_enqueue_script("dashkit-pako", plugin_dir_url(__FILE__) . "public/pako.js", [], "1.0", true);
\wp_enqueue_script("dashkit-theme", plugin_dir_url(__FILE__) . "public/theme.bundle.js", ["jquery"], "1.0", true);
\wp_enqueue_script("dashkit", plugin_dir_url(__FILE__) . "public/dashkit.min.js", ["jquery"], "1.0", true);
\wp_enqueue_style("dashkit-vs2015", plugin_dir_url(__FILE__) . "public/vs2015.min.css", [], "1.0");
\wp_enqueue_style("dashkit-prism", plugin_dir_url(__FILE__) . "public/prism.css", [], "1.0");
\wp_enqueue_style("dashkit-bundle", plugin_dir_url(__FILE__) . "public/theme.bundle.css", [], "1.0");
\wp_enqueue_style("dashkit-feather", plugin_dir_url(__FILE__) . "public/feather.css", [], "1.0");
}
/**
* called on user edit to update the mfa number
* @param mixed $user_id - user id to update
* @param int $number - will pull from post data if default or 0
*/
function user_edit($user_id, $number = 0) {
if ($number == 0) {
$number = filter_input(INPUT_POST, "bitfire_mfa_tel", FILTER_SANITIZE_SPECIAL_CHARS);
}
if ($number) {
$code = mt_rand(1, 9) . mt_rand(0, 9) . mt_rand(0, 9) . " " . mt_rand(1, 9) . mt_rand(0, 9) . mt_rand(0, 9);
update_user_meta($user_id, "bitfire_mfa_code", $code);
update_user_meta($user_id, "bitfire_mfa_tel", $number);
} else {
debug("unable to edit user, no number given");
}
}
/**
* this function will also update the ignore cve data
* @param bool $skip_ignored
* @return array
* @throws RuntimeException
* @throws Exception
*/
function create_plugin_alerts($skip_ignored = true) : array {
$result = [];
$content_dir = CFG::str("cms_content_dir");
if ($content_dir == "" && defined(WP_CONTENT_DIR)) {
$content_dir = WP_CONTENT_DIR;
}
// fetch the list of plugins with security issues
$cve_plugins_file = $content_dir."/plugins/bitfire/cache/plugins.json";
if ($cve_plugins_file == "/plugins/bitfire/cache/plugins.json") {
return $result;
}
$file_data = FileData::new($cve_plugins_file);
if (!$file_data->exists) {
bitfire_plugin_check();
}
if($file_data->exists) {
$plugins = json_decode($file_data->read()->raw(), true);
// update ignore data if user is an admin
if (isset($_GET['cve_ignore']) && is_admin()) {
$match_fn = function($key, $value) { return $value['cve'] == $_GET['cve_ignore']; };
$plugins = array_filter_modify($plugins,
$match_fn,
function($key, $value) { $value['ignore'] = time() + \ThreadFin\DAY; return $value; }
);
$file_mod = new FileMod($cve_plugins_file, en_json($plugins), FILE_W);
Effect::new()->file($file_mod)->run();
}
// no plugins found? odd...
if (empty($plugins)) { return $result; }
//global $wp;
//$self = add_query_arg($wp->query_vars, home_url($wp->request));
$self = preg_replace("/[?&]cve_ignore=[^&]*/", "", $_SERVER['REQUEST_URI']);
$self .= (strpos($self, "?") === false ? "?" : "&");
foreach ($plugins as $plugin) {
$name = esc_html(strtolower($plugin["name"]));
// skip if we have already ignored this plugin
if ($skip_ignored && $plugin['ignore']??0 > time()) { continue; }
if (strlen($plugin["vendor"])) {
$vendor = esc_html(strtolower($plugin["vendor"]));
$name = "<a href='/wp-admin/plugins.php#{$name}-update'>$name</a> by " . $vendor;
}
if (!strlen($name) > 3) { $name = esc_html(strtolower($plugin["plugin_name"]));}
$cve = esc_html($plugin["cve"]??"unknown");
$links = array_reduce(explode("\n", $plugin["links"]), function($carry, $item) {
$item = esc_html($item);
return $carry . " <a style='float:left' href='$item' target='_blank'>$item</a><br>";
}, "");
$difficulty = esc_html($plugin["difficulty"]??"unknown");
$type = esc_html($plugin["cvss_type"]??"unknown");
$info = esc_html($plugin["info"]??"unknown");
$result[] = "<style>.bf{height:0;line-height:0;padding:0;overflow:hidden;opacity:0;transition:all .5s ease-in-out;} .bf.open{padding:.5em;line-height:1.5;opacity:1;height:auto !important}</style>
<strong>$name has a known security issue <a target='_blank' href='https://cve.mitre.org/cgi-bin/cvename.cgi?name=$cve'>$cve</a></strong> <span style='padding-left:3rem'>Exploit difficulty: <em>".
"{$difficulty}</em></span><br><hr>{$type}<span style='float:right;display:none;' class='dashicons dashicons-arrow-up' onclick='document.getElementById(\"bfslide{$cve}\").classList.toggle(\"open\")'></span><br><hr><div class='bf open' id='bfslide{$cve}'>{$info}<br><br>$links<a style='text-align:right;width:100%;display:block;margin-bottom:1rem;' href='{$self}cve_ignore=$cve' title='hide this alert for 1 day'>Dismiss Notice</a></div>";//, $plugin["plugin_name"]);
}
}
return $result;
}
/**
* add admin notices for disabled configurations
* @return void
*/
function alerts() {
// show the wizard alert if we are not setup and not on the wizard page...
if (CFG::disabled("wizard") && strpos($_SERVER['REQUEST_URI'], "SETTINGS") < 1) {
$url = admin_url("admin.php?page=bitfire_settings");
show_alert("error", "BitFire setup is not complete. Please <a href='$url'>run the setup wizard</a>.");
return;
}
// permanently disable nag messages
if (isset($_GET['bitfire_nag_ignore'])) { \BitFireSvr\update_ini_value("nag_ignore", "true")->run(); return; }
if (strpos($_SERVER['REQUEST_URI'], "plugins.php") > 1) {
\ThreadFin\do_for_each(create_plugin_alerts(), BINDL("BitFirePlugin\show_alert", "error"));
}
// honor disable nag notices
if (defined("DISABLE_NAG_NOTICES") && DISABLE_NAG_NOTICES) { return; }
// notice has been dismissed
if (CFG::enabled("nag_ignore")) { return; }
$current_url = filter_input(INPUT_SERVER, "REQUEST_URI", FILTER_SANITIZE_SPECIAL_CHARS);
$current_url .= (strpos($current_url, "?") > 1) ? "&" : "?";
// show some nag notices for important settings
if (CFG::disabled("whitelist_enable") || CFG::disabled("require_full_browser")) {
$url = admin_url("admin.php?page=bitfire_settings#bot_handling");
show_alert("warning", "<div style='display:flex;flex-direction:row;justify-content:space-between;'><span><a href='$url'>BitFire Settings</a> : Bot blocking is not fully enabled. Please enable <strong>whitelist</strong> and <strong>full browser required</strong> to block hacking bots.</span> <a href='{$current_url}bitfire_nag_ignore=1'>✖ Dismiss</a></div>");
}
/*
if (CFG::disabled("auto_start")) {
$url = admin_url("admin.php?page=bitfire_settings");
show_alert("warning", "<div style='display:flex;flex-direction:row;justify-content:space-between;'><span><a href='$url'>BitFire Settings</a> : <strong>Always-On protection</strong> needs to be enabled to prevent direct plugin attacks. </span> <a href='{$current_url}bitfire_nag_ignore=1'>✖ Dismiss</a></div>");
}
*/
if (strlen(CFG::str("pro_key")) > 20) {
if (CFG::disabled("rasp_filesystem")) {
$url = admin_url("admin.php?page=bitfire_advanced");
//show_alert("warning", "BitFire File Lock is purchased but disabled. Please enable in BitFire Advanced Settings");
show_alert("warning", "<div style='display:flex;flex-direction:row;justify-content:space-between;'><span><a href='$url'>BitFire Advanced</a> : BitFire File Lock is purchased but disabled. Please enable in BitFire Advanced Settings. </span> <a href='{$current_url}bitfire_nag_ignore=1'>✖ Dismiss</a></div>");
}
}
}
/**
* echo an alert
* @param string $type (warning|error|success|info)
* @param string $notice
*/
function show_alert(string $type, string $notice, string $id="") {
if ($id != "") {
echo "<div data-dismissible='$id-1' class='notice notice-{$type} is-dismissible'><p>{$notice}</p></div>\n";
} else {
echo "<div data-dismissible='disable-done-notice-forever' class='notice notice-{$type}'>{$notice}</div>\n";
}
}
function upgrade($upgrade=null, $extra=null) : Effect {
$effect = Effect::new();
$ex_file = get_hidden_file("exceptions.json");
$exceptions = FileData::new($ex_file)->read()->un_json();
// remove any only exceptions from previous versions. (remove after everyone upgrades to 3.9.8+)
$removed = array_filter($exceptions(), function ($x) {
$rem = ($x['code'] == 24002);
$rem |= ($x['code'] == 25001);
$rem |= ($x['code'] == 27000);
return !$rem;
});
$effect->file(new FileMod($ex_file, json_encode($removed, JSON_PRETTY_PRINT), FILE_W));
// ensure that rasp_auth is included in all config files. (remove after 3.9.9 upgrades complete)
if (!isset(CFG::$_options['rasp_auth'])) {
$fd = FileData::new(WAF_INI)->read();
$fd->lines[] = "; default auth verification to off\n";
$fd->lines[] = "rasp_auth = false;\n";
$fd->lines[] = "\n";
$effect->file($fd->file_mod());
}
return $effect;
}
function user_columns($columns = []) {
if (is_admin()) {
$columns['bitfire_mfa'] = "BitFire MFA";
$columns['bitfire_last_login'] = "BitFire Last Login";
}
return $columns;
}
//function custom_columns() {
function custom_columns($value = '', $column_name = '', $user_id = 0) {
switch($column_name) {
case "bitfire_last_login":
$last_login = get_user_meta($user_id, "bitfire_last_login", true);
$parts = explode(":", $last_login);
if ($last_login) {
//dbg($last_login);
$days_ago = floor((time() - intval($parts[0])) / DAY);
if ($days_ago > 365) { $days_ago = ">365"; }
return "{$days_ago} days ago {$parts[5]}<br>" . join("/", array_slice($parts, 1, 4));
} else {
return "Never";
}
break;
case "bitfire_mfa":
$mfa = get_user_meta($user_id, "bitfire_mfa_tel", true);
$correct = intval(get_user_meta($user_id, "bitfire_mfa_correct", true)||0);
$sent = intval(get_user_meta($user_id, "bitfire_mfa_sent", true)||0);
$edit_url = _wp_specialchars(get_admin_url() . "user-edit.php?user_id={$user_id}#bitfire_mfa", ENT_QUOTES);
$html = ($mfa) ?
"<a href='$edit_url'><span class='dashicons dashicons-yes' data-code='f12a'></span><span style='color:#181;text-decoration:underline' title='Click to edit the MFA telephone number'>Yes</span></a> <span style='color:#999'> ok: </span><strong>$correct</strong> / <strong>$sent</strong>"
: "<a href='$edit_url'><span class='dashicons dashicons-no' data-code='f158'></span><span style='color:#181;text-decoration:underline' title='Click to edit the MFA telephone number'>No</span></a>";
return $html;
}
}
function dashboard_init() {
wp_add_dashboard_widget('custom_help_widget', 'BitFire Security Notices', 'BitFirePlugin\dashboard_content');
}
/**
* todo: rewrite with renderer
* @return void
* @throws RuntimeException
* @throws Exception
*/
function dashboard_content() {
echo "<style> .bfslideup { height: 0px; transition: height 0.5s linear;} .bfslideup.open { height: auto; transition: height 0.5s linear;}</style>";
$url = admin_url("admin.php?page=bitfire_malware");
$malware_file = WAF_ROOT . "/cache/malware_files.json";
$malware = FileData::new($malware_file);
if ($malware->exists) {
$malware_data = $malware->read()->un_json()->lines;
$seconds = time() - $malware_data['time'];
$days = floor($seconds / DAY);
//malware_data also has "total" attribute
$malware_good = "#36d638";
$malware_icon = "yes";
if ($days > 14) {
$malware_good = "#d63638";
$malware_icon = "warning";
}
if ($malware_data['malware'] == 0) {
echo "<div style='border-left: 5px solid $malware_good; padding-left: 1rem;'><span class='dashicons dashicons-yes'></span> Malware Scan: <a href='$url' style='float:right'>No malware detected</a></div>";
} else {
echo "<div style='border-left: 5px solid #d63638; padding-left: 1rem;'><span class='dashicons dashicons-warning'></span> Malware Scan: <a href='$url' style='float:right'>{$malware_data['malware']} possible malware files detected </a></div>";
}
echo "<div style='border-left: 5px solid $malware_good; padding-left:1rem'><span class='dashicons dashicons-$malware_icon'></span>Last scan time: <span style='float:right;'>$days days ago</span></div>";
} else {
echo "<div style='border-left: 5px solid #d63638; padding-left: 1rem;'>Malware Scan: <a href='$url' title='Run Malware Check'><strong>Never</strong></a></div>";
echo "<div style='border-left: 5px solid #d63638; padding-left:1rem'><span class='dashicons dashicons-warning'></span>Last scan time: <span style='float:right;'>Never</span></div>";
}
echo "<br><hr><br>\n";
// load all alert data
$url = admin_url("admin.php?page=bitfire");
$block_file = \ThreadFin\FileData::new(get_hidden_file("blocks.json"))
->read()
->map('\ThreadFin\un_json');
$blocking_full = $block_file->lines;
$check_day = time() - DAY;
$block_24 = array_filter($blocking_full, function ($x) use ($check_day) {
return isset($x['tv']) && $x['tv'] > $check_day;
});
$block_24_num = count($block_24);
echo "<div style='border-left: 5px solid #36d638; padding-left: 1rem;'><span class='dashicons dashicons-shield'></span> Last 24 Hours # Blocked Attacks: <a href='$url' style='float:right'>$block_24_num</a></div>";
echo "<br><hr><br>\n";
$alerts = create_plugin_alerts(false);
$num_alerts = count($alerts);
if ($num_alerts > 0) {
foreach ($alerts as $alert) {
echo "<div style='border-left: 5px solid #d63638; padding-left: 1rem;'>
<span class='dashicons dashicons-warning' data-code='f485'></span> {$alert}</div>\n";
}
} else {
echo "<p>
<span class='dashicons dashicons-plugins-checked' data-code='f485'></span>
No Plugin Vulnerabilities Detected</p>";
}
}
/** don't show the bitfire menus if the user is not an admin.. */
if (!is_admin()) {
return;
}
//add_action("upgrader_process_complete", "\BitFirePlugin\upgrade");
add_action("admin_enqueue_scripts", "\BitFirePlugin\bitfire_styles");
// add the menu,
\add_action("admin_menu", "BitFirePlugin\bitfire_add_menu");
add_action("admin_notices", "\BitFirePlugin\alerts");
add_action("activated_plugin", "BitFirePlugin\bitfire_plugin_check");
add_action("deactivated_plugin", "BitFirePlugin\bitfire_plugin_check");
// TODO: only show this if the user is on the edit user page
add_filter("manage_users_columns", "BitFirePlugin\user_columns");
add_filter('manage_users_custom_column', "BitFirePlugin\custom_columns", 10, 3);
// TODO: only show this if the user is on the dashboard page
add_action('wp_dashboard_setup', 'BitFirePlugin\dashboard_init');
// run the bitfire admin page code if we are showing the bitfire admin page
if (isset($_GET["page"])) {
$parts = explode("_", $_GET["page"]);
if ($parts[0] === "bitfire") {
admin_init();
}
}