diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/.gitignore b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/.gitignore
new file mode 100644
index 00000000..591254b0
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/.gitignore
@@ -0,0 +1 @@
+env.php
diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/CHANGELOG b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/CHANGELOG
new file mode 100644
index 00000000..c9d8e4b2
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/CHANGELOG
@@ -0,0 +1,8 @@
+ Cleanup with pbcbf
+ Change style to PSR2
+ Automatically log users in if they have an Okta session already
+ Use promises for sign-out
+ Remove templating from sign-in page
+ Log users out of Okta when they log out of Wordpress
+ Remove all hardcoded values
+ Validate OIDC tokens via /token endpoint
diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/README.md b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/README.md
new file mode 100644
index 00000000..d59f314a
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/README.md
@@ -0,0 +1,41 @@
+# WordPress Okta Sign-In Widget
+
+This plugin replaces the WordPress login screen with the Okta sign-in widget.
+
+🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
+
+This plugin was created to demonstrate the capability of replacing the WordPress login screen with the Okta sign-in widget for [this 2018 blog post](https://developer.okta.com/blog/2018/10/30/wordpress-authentication-with-okta).
+
+🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
+
+This plugin is not supported by Okta, and not updated regularly.
+
+🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
+
+If you would like to use an officially supported Okta WordPress integration, please see [this guide](https://plugins.miniorange.com/okta-single-sign-on-wordpress-sso-oauth-openid-connect) to configuring the [miniOrange WordPress SSO Plugin](https://www.okta.com/integrations/wordpress-oauth-single-sign-on-sso-by-miniorange/) with Okta.
+
+🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
+
+
+## Setup Instructions
+
+After dropping this folder into the WordPress plugins folder and activating the plugin, you should see a new Settings menu where you can configure your Okta settings to enable the plugin.
+
+Make sure your admin user in WordPress has an email address that matches an Okta user, or enable native WordPress logins, otherwise you'll be locked out of your WordPress after configuring the plugin.
+
+TODO:
+
+* Clean up the UX around installing the plugin, like making sure the admin user can still log in after the plugin is activated
+* Handle errors better (or at all really)
+
+## Development Environment
+
+### Manual
+
+Install WordPress and move plugin to `wp-content/plugins` directory
+
+### Docker
+
+Install Docker and docker-compose and run `docker-compose up`
+
+Navigate to http://localhost:8080
diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/docker-compose.yml b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/docker-compose.yml
new file mode 100644
index 00000000..e614de12
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/docker-compose.yml
@@ -0,0 +1,18 @@
+version: '3.1'
+
+services:
+ wordpress:
+ image: wordpress
+ depends_on:
+ - mysql
+ ports:
+ - 8080:80
+ environment:
+ WORDPRESS_DB_PASSWORD: password
+ volumes:
+ - .:/var/www/html/wp-content/plugins/okta-wordpress-sign-in-widget
+
+ mysql:
+ image: mysql:5.7
+ environment:
+ MYSQL_ROOT_PASSWORD: password
diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/initialize-widget.js.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/initialize-widget.js.php
new file mode 100644
index 00000000..65df41c2
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/initialize-widget.js.php
@@ -0,0 +1,9 @@
+ var oktaSignIn = new OktaSignIn({
+ baseUrl: '',
+ redirectUri: '',
+ clientId: '',
+ scopes: ''.split(' '),
+ authParams: {
+ issuer: ''
+ }
+ });
diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/okta-admin.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/okta-admin.php
new file mode 100644
index 00000000..b4f0f2b6
--- /dev/null
+++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/okta-admin.php
@@ -0,0 +1,104 @@
+ 'string',
+ 'show_in_rest' => false,
+ ));
+ add_settings_field(
+ 'okta-issuer-url',
+ 'Okta Issuer URI',
+ function() { $this->optionsPageTextInputAction('okta-issuer-url', 'text', 'e.g. https://youroktadomain.okta.com/oauth2/default', 'Find your Issuer URI in the Admin console under Security -> API, or in the Developer console under API -> Authorization Servers'); },
+ 'okta-sign-in-widget',
+ 'okta-sign-in-widget-options-section'
+ );
+
+ register_setting('okta-sign-in-widget', 'okta-widget-client-id', array(
+ 'type' => 'string',
+ 'show_in_rest' => false,
+ ));
+ add_settings_field(
+ 'okta-widget-client-id',
+ 'Sign-In Widget Client ID',
+ function() { $this->optionsPageTextInputAction('okta-widget-client-id', 'text', null, 'Register a "SPA" app in Okta and provide its Client ID here. Set the Login redirect URI in Okta to '.wp_login_url().', and set the Logout redirect URI to '.home_url().''); },
+ 'okta-sign-in-widget',
+ 'okta-sign-in-widget-options-section'
+ );
+
+ register_setting('okta-sign-in-widget', 'okta-allow-wordpress-login', array(
+ 'type' => 'boolean',
+ 'show_in_rest' => false,
+ ));
+ add_settings_field(
+ 'okta-allow-wordpress-login',
+ 'Allow Native WordPress Login',
+ function() { $this->optionsPageCheckboxInputAction('okta-allow-wordpress-login', 'checkbox', 'Check this to allow local WordPress users to log in with a password. When unchecked, Okta will be the only way users can log in. Make sure you have a WordPress admin user with an email address matching an Okta user already.'); },
+ 'okta-sign-in-widget',
+ 'okta-sign-in-widget-options-section'
+ );
+ }
+
+ public function optionsMenuAction() {
+ add_options_page(
+ 'Okta Sign-In Widget Options',
+ 'Okta Sign-In Widget',
+ 'manage_options',
+ 'okta-sign-in-widget',
+ array($this, 'optionsPageAction')
+ );
+ }
+
+ public function optionsPageAction() {
+ if (current_user_can('manage_options')) {
+ include(plugin_dir_path(__FILE__)."../templates/options-form.php");
+ } else {
+ wp_die( 'You do not have sufficient permissions to access this page.' );
+ }
+ }
+
+ public function optionsPageTextInputAction($option_name, $type, $placeholder=false, $description=false) {
+ $option_value = get_option($option_name, '');
+ printf(
+ '',
+ esc_attr($type),
+ esc_attr($option_name),
+ esc_attr($option_name),
+ esc_attr($option_value),
+ esc_attr($placeholder)
+ );
+ if($description)
+ echo '
'.$description.'
'; + } + + public function optionsPageCheckboxInputAction($option_name, $type, $description=false) { + $option_value = get_option($option_name, false); + printf( + '', + esc_attr($type), + esc_attr($option_name), + esc_attr($option_name), + $option_value ? 'checked="checked"' : '' + ); + if($description) + echo ''.$description.'
'; + } + +} diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/widget.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/widget.php new file mode 100644 index 00000000..903cb03e --- /dev/null +++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/includes/widget.php @@ -0,0 +1,2 @@ + + diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/okta-widget.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/okta-widget.php new file mode 100644 index 00000000..5b2b52ed --- /dev/null +++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/okta-widget.php @@ -0,0 +1,226 @@ +OktaAdmin = new OktaAdmin; + + $this->setBaseUrl(); + + // https://developer.wordpress.org/reference/hooks/login_init/ + add_action('login_init', array($this, 'loginAction')); + + // This runs on every pageload to insert content into the HTML section + // https://codex.wordpress.org/Plugin_API/Action_Reference/wp_head + add_action('wp_head', array($this, 'addLogInExistingSessionAction')); + + add_action('init', array($this, 'startSessionAction')); + } + + private function setBaseUrl() + { + if($issuer = get_option('okta-issuer-url')) { + $this->base_url = parse_url($issuer, PHP_URL_SCHEME).'://'.parse_url($issuer, PHP_URL_HOST); + } + } + + private function getIntrospectionEndpoint() { + if($this->introspection_endpoint) + return $this->introspection_endpoint; + + if(!$this->base_url) + return false; + + $response = wp_remote_get(get_option('okta-issuer-url').'/.well-known/openid-configuration'); + if(!$response) + return false; + + $metadata = json_decode($response['body'], true); + if(!$metadata) + return false; + + if(!isset($metadata['introspection_endpoint'])) + return false; + + return $this->introspection_endpoint = $metadata['introspection_endpoint']; + } + + public function startSessionAction() + { + if (session_status() != PHP_SESSION_ACTIVE) { + session_start(); + } + } + + public function addLogInExistingSessionAction() + { + if (!is_user_logged_in()) { + $this->startSessionAction(); + $_SESSION['redirect_to'] = $_SERVER['REQUEST_URI']; + include("templates/log-in-existing-session.php"); + } + } + + private function httpPost($url, $body) + { + $args = array( + 'headers' => array( + 'Accept' => 'application/json', + 'Content-Type' => 'application/x-www-form-urlencoded', + ), + 'body' => $body, + ); + return wp_remote_post($url, $args); + } + + public function loginAction() + { + // Support redirecting back to the page the user was on before they clicked log in + $redirect_to = false; + if (isset($_GET['redirect_to'])) { + $redirect_to = $_GET['redirect_to']; + $_SESSION['redirect_to'] = $_GET['redirect_to']; + } + + // When signing out of WordPress, tell the Okta JS library to log out of Okta as well + if (isset($_GET["action"]) && $_GET["action"] === "logout") { + $this->logUserOutOfOkta(); + } + + if (isset($_GET['log_in_from_id_token'])) { + $this->logUserIntoWordPressWithIDToken($_GET['log_in_from_id_token'], $redirect_to); + exit; + } + + if($this->useWordpressLogin()) { + return; + } + + // If there is no code in the query string, show the Okta sign-in widget + $template = plugin_dir_path(__FILE__) . 'templates/sign-in-form.php'; + load_template($template); + exit; + } + + private function useWordpressLogin() + { + // Always skip showing the Okta widget on POST requests + if($_SERVER['REQUEST_METHOD'] === 'POST') + return true; + + // If the plugin isn't configured yet, don't show the Okta widget + if(!$this->base_url) + return true; + + // null when plugin is not configured, "1"/"0" after + if(get_option('okta-allow-wordpress-login') === null || get_option('okta-allow-wordpress-login') === "1") + { + if(isset($_GET['wordpress_login']) && $_GET['wordpress_login'] == 'true') + return true; + + if(isset($_GET['action']) && $_GET['action'] == 'lostpassword') + return true; + + if(isset($_GET['checkemail'])) + return true; + } + + return false; + } + + private function logUserOutOfOkta() { + $user = wp_get_current_user(); + + wp_clear_auth_cookie(); + + $template = plugin_dir_path(__FILE__) . 'templates/sign-out.php'; + load_template($template); + exit; + } + + private function logUserIntoWordPressWithIDToken($id_token, $redirect_to) + { + $introspection_endpoint = $this->getIntrospectionEndpoint(); + + if(!$this->introspection_endpoint) + die("The plugin is not configured properly. Please double check the Issuer URI in the configuration."); + + /********************************************/ + // [jpf] TODO: Implement client-side id_token validation to speed up the verification process + // (~300ms for /introspect endpoint v. ~5ms for client-side validation) + $payload = array( + 'client_id' => get_option('okta-widget-client-id'), + 'token' => $id_token, + 'token_type_hint' => 'id_token' + ); + $response = $this->httpPost($this->introspection_endpoint, $payload); + if ($response === false) { + die("Invalid id_token received from Okta"); + } + $claims = json_decode($response['body'], true); + if (!$claims['active']) { + die("Okta reports that id_token is not active or client authentication failed:" . $claims['error_description']); + } + /********************************************/ + + $this->logUserIntoWordPressFromEmail($claims, $redirect_to); + } + + private function logUserIntoWordPressFromEmail($claims, $redirect_to) + { + $email = $claims['email']; + + // Find or create the WordPress user for this email address + $user = get_user_by('email', $email); + if (!$user) { + $random_password = wp_generate_password($length = 64, $include_standard_special_chars = false); + $user_id = wp_create_user($email, $random_password, $email); + $user = get_user_by('id', $user_id); + } else { + $user_id = $user->ID; + } + + do_action('okta_widget_before_login', $claims, $user); + + // Actually log the user in now + wp_set_current_user($user_id); + wp_set_auth_cookie($user_id); + error_log("Logging in WordPress user with ID of: " . $user_id); + + // See also: https://developer.wordpress.org/reference/functions/do_action/ + // Run the wp_login actions now that the user is logged in + do_action('wp_login', $user->user_login, $user); + + if (isset($_SESSION['redirect_to'])) { + $redirect_uri = $_SESSION['redirect_to']; + unset($_SESSION['redirect_to']); + } else { + $redirect_uri = home_url(); + } + wp_redirect($redirect_uri); + } +} + +$okta = new OktaSignIn(); diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/log-in-existing-session.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/log-in-existing-session.php new file mode 100644 index 00000000..bad1cc28 --- /dev/null +++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/log-in-existing-session.php @@ -0,0 +1,17 @@ + + + diff --git a/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/options-form.php b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/options-form.php new file mode 100644 index 00000000..d7014c3b --- /dev/null +++ b/wp/wp-content/plugins/okta-wordpress-sign-in-widget-main/templates/options-form.php @@ -0,0 +1,9 @@ +" + body + "
", settings]); - this.colorboxServiceQueue(); - }, - colorboxModalHTML: function(width, heading, body, settings) { - if (typeof settings === 'undefined') { - settings = {}; - } - - var prompt = $.tmpl(WordfenceAdminVars.modalHTMLTemplate, {title: heading, message: body}); - var promptHTML = $("").append(prompt).html(); - var callback = settings.onComplete; - settings.overlayClose = false; - settings.closeButton = false; - settings.className = 'wf-modal'; - settings.onComplete = function() { - $('#wf-generic-modal-close').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.colorboxClose(); - }); - - typeof callback === 'function' && callback(); - }; - this.colorboxHTML(width, promptHTML, settings) - }, - colorboxModal: function(width, heading, body, settings) { - if (typeof settings === 'undefined') { - settings = {}; - } - - var prompt = $.tmpl(WordfenceAdminVars.modalTemplate, {title: heading, message: body}); - var promptHTML = $("").append(prompt).html(); - var callback = settings.onComplete; - settings.overlayClose = false; - settings.closeButton = false; - settings.className = 'wf-modal'; - settings.onComplete = function() { - $('#wf-generic-modal-close').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.colorboxClose(); - }); - - typeof callback === 'function' && callback(); - }; - this.colorboxHTML(width, promptHTML, settings) - }, - colorboxError: function(errorMsg, isTokenError) { - var callback = false; - if (isTokenError) { - if (WFAD.tokenErrorShowing) { - return; - } - - callback = function() { - setTimeout(function() { - WFAD.tokenErrorShowing = false; - }, 30000); - }; - - WFAD.tokenErrorShowing = true; - } - - var prompt = $.tmpl(WordfenceAdminVars.tokenInvalidTemplate, {title: __('An error occurred'), message: errorMsg}); - var promptHTML = $("").append(prompt).html(); - var settings = {}; - settings.overlayClose = false; - settings.closeButton = false; - settings.className = 'wf-modal'; - settings.onComplete = function() { - $('#wf-token-invalid-modal-reload').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - window.location.reload(true); - }); - - typeof callback === 'function' && callback(); - }; - WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '400px'), promptHTML, settings); - }, - colorboxHTML: function(width, html, settings) { - if (typeof settings === 'undefined') { - settings = {}; - } - this.colorboxQueue.push([width, html, settings]); - this.colorboxServiceQueue(); - }, - colorboxServiceQueue: function() { - if (this.colorboxIsOpen) { - return; - } - if (this.colorboxQueue.length < 1) { - return; - } - var elem = this.colorboxQueue.shift(); - this.colorboxOpen(elem[0], elem[1], elem[2]); - }, - colorboxOpen: function(width, html, settings) { - var self = this; - this.colorboxIsOpen = true; - var onClosed = settings.onClosed || null; - jQuery.extend(settings, { - width: width, - html: html, - onClosed: function() { - self.colorboxClose(); - if (onClosed) - onClosed(); - } - }); - jQuery.wfcolorbox(settings); - }, - colorboxClose: function() { - this.colorboxIsOpen = false; - jQuery.wfcolorbox.close(); - }, - bulkOperationConfirmed: function(op) { - WFAD.colorboxClose(); - this.ajax('wordfence_bulkOperation', { - op: op - }, function(res) { - if (res.ok) { - for (var i = 0; i < res.idsRemoved.length; i++) { - $('.wf-issue[data-issue-id="' + res.idsRemoved[i] + '"]').remove(); - } - - WFAD.updateIssueCounts(res.issueCounts); - WFAD.repositionSiteCleaningCallout(); - WFAD.updateBulkButtons(); - setTimeout(function() { - WFAD.colorboxModalHTML((WFAD.isSmallScreen ? '300px' : '400px'), res.bulkHeading, res.bulkBody); - }, 500); - } - }); - }, - deleteFile: function(issueID, force, callback) { - this.ajax('wordfence_deleteFile', { - issueID: issueID, - forceDelete: force - }, function(res) { - if (res.needsCredentials) { - document.location.href = res.redirect; - } else { - typeof callback === 'function' && callback(res); - } - }); - }, - promptToRepairFile: function(issueID, data) { - if (window.localStorage) { - var sudoExpiration = window.localStorage.getItem('wf-repair-file-sudo'); - if (sudoExpiration && parseInt(sudoExpiration, 10) > new Date().getTime()) { - this.repairFile(issueID); - return; - } - } - WFAD.colorboxModalHTML((WFAD.isSmallScreen ? '300px' : '400px'), __("Download Backup File"), __('Please make a backup of this file before proceeding. If you need to restore this backup file, you can copy it to the following path from your site\'s root:') + '' + data.file + '
' + - '' + - '' + - '
' + - '' - ); - }, - promptToRepairFileDone: function(issueID, dontPromptAgain) { - if (dontPromptAgain) { - if (window.localStorage) { - window.localStorage.setItem('wf-repair-file-sudo', (new Date().getTime() + 86400000)); - } - } - this.repairFile(issueID); - }, - repairFile: function(issueID) { - var self = this; - self.colorboxClose(); - this.restoreFile(issueID, function(res) { - if (res.ok) { - var issueElement = $('.wf-issue[data-issue-id=' + parseInt(issueID, 10) + ']'); - issueElement.remove(); - self.updateIssueCounts(res.issueCounts); - self.repositionSiteCleaningCallout(); - self.updateBulkButtons(); - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success restoring file"), sprintf(__("The file %s was successfully restored."), res.file)); - } - else if (res.errorMsg) { - self.colorboxError(res.errorMsg, res.tokenInvalid); - } - }); - }, - deleteDatabaseOption: function(issueID) { - var self = this; - this.ajax('wordfence_deleteDatabaseOption', { - issueID: issueID - }, function(res) { - self.doneDeleteDatabaseOption(res); - }); - }, - doneDeleteDatabaseOption: function(res) { - var cb = false; - var self = this; - if (res.ok) { - this.loadIssues(function() { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success removing option"), sprintf(__("The option %s was successfully removed."), res.option_name)); - }); - } else if (res.cerrorMsg) { - this.loadIssues(function() { - WFAD.colorboxError(res.cerrorMsg, res.tokenInvalid); - }); - } - }, - useRecommendedHowGetIPs: function(issueID) { - var self = this; - this.ajax('wordfence_misconfiguredHowGetIPsChoice', { - issueID: issueID, - choice: 'yes' - }, function(res) { - if (res.ok) { - jQuery('#wordfenceMisconfiguredHowGetIPsNotice').fadeOut(); - - self.loadIssues(function() { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success updating option"), __("The 'How does Wordfence get IPs' option was successfully updated to the recommended value.")); - }); - } else if (res.cerrorMsg) { - self.loadIssues(function() { - WFAD.colorboxError(res.cerrorMsg, res.tokenInvalid); - }); - } - }); - }, - fixFPD: function(issueID) { - var self = this; - var title = __("Full Path Disclosure"); - issueID = parseInt(issueID); - - this.ajax('wordfence_checkHtaccess', {}, function(res) { - if (res.ok) { - self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), title, __('We are about to change your .htaccess file. Please make a backup of this file before proceeding.') - + '" + __('No activity to report yet. Please complete your first scan.') + "
"); - } - }); - }, - emailActivityLog: function() { - this.colorboxModalHTML((this.isSmallScreen ? '300px' : '400px'), __('Email Wordfence Activity Log'), __("Enter the email address you would like to send the Wordfence activity log to. Note that the activity log may contain thousands of lines of data. This log is usually only sent to a member of the Wordfence support team. It also contains your PHP configuration from the phpinfo() function for diagnostic data.") + "" + sprintf(__("Use one of these %s codes to log in if you lose access to your authenticator device. Codes are 16 characters long, plus optional spaces. Each one may be used only once."), res.recoveryCodes.length) + "
" + __("This will be shown only once. Keep these codes somewhere safe.") + "
"; - - self.colorboxModalHTML((self.isSmallScreen ? '300px' : '440px'), __("Authentication Code"), message, {onComplete: function() { - jQuery('#wfTwoFactorQRCodeTable').qrcode({text: totpURL, width: (self.isSmallScreen ? 175 : 256), height: (self.isSmallScreen ? 175 : 256)}); - jQuery('#wfTwoFactorDownload').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - saveAs(new Blob([recoveryCodeFileContents], {type: "text/plain;charset=" + document.characterSet}), self.htmlEscape(res.homeurl) + "_" + self.htmlEscape(res.username) + "_recoverycodes.txt"); - }); - }}); - } - else { - if (res.recoveryCodes.length > 0) { - var message = "" + sprintf(__("Use one of these %s codes to log in if you are unable to access your phone. Codes are 16 characters long, plus optional spaces. Each one may be used only once."), res.recoveryCodes.length) + "
" + __("This will be shown only once. Keep these codes somewhere safe.") + "
"; - - self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __("Recovery Codes"), message, {onComplete: function() { - jQuery('#wfTwoFactorDownload').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - saveAs(new Blob([recoveryCodeFileContents], {type: "text/plain;charset=" + document.characterSet}), self.htmlEscape(res.homeurl) + "_" + self.htmlEscape(res.username) + "_recoverycodes.txt"); - }); - }}); - } - } - - var updatedTwoFac = jQuery('#wfTwoFacUserTmpl').tmpl({users: [res]}); - jQuery('#twoFactorUser-none').remove(); - jQuery('#wfTwoFacUsers > table > tbody:last-child').append(updatedTwoFac.find('tbody > tr')); - } - }); - }, - twoFacActivate: function(userID, code) { - var self = this; - this.ajax('wordfence_twoFacActivate', { - userID: userID, - code: code - }, function(res) { - if (res.ok) { - var updatedTwoFac = jQuery('#wfTwoFacUserTmpl').tmpl({users: [res]}); - updatedTwoFac.find('tbody > tr').each(function(index, element) { - jQuery('#' + jQuery(element).attr('id')).replaceWith(element); - }); - self.twoFacStatus(__('Cellphone Sign-in activated for user.')); - } - }); - }, - delTwoFac: function(userID) { - this.ajax('wordfence_twoFacDel', { - userID: userID - }, function(res) { - if (res.ok) { - jQuery('#twoFactorUser-' + res.userID).fadeOut(function() { - jQuery(this).remove(); - - if (jQuery('#wfTwoFacUsers > table > tbody:last-child').children().length == 0) { - jQuery('#wfTwoFacUsers').html(jQuery('#wfTwoFacUserTmpl').tmpl({users: []})); - } - }); - } - }); - }, - loadTwoFactor: function() { - this.ajax('wordfence_loadTwoFactor', {}, function(res) { - jQuery('#wfTwoFacUsers').html(jQuery('#wfTwoFacUserTmpl').tmpl(res)); - }); - }, - getQueryParam: function(name) { - name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); - var regexS = "[\\?&]" + name + "=([^]*)"; - var regex = new RegExp(regexS); - var results = regex.exec(window.location.search); - if (results == null) { - return ""; - } else { - return decodeURIComponent(results[1].replace(/\+/g, " ")); - } - }, - inet_aton: function(dot) { - var d = dot.split('.'); - return ((((((+d[0]) * 256) + (+d[1])) * 256) + (+d[2])) * 256) + (+d[3]); - }, - inet_ntoa: function(num) { - var d = num % 256; - for (var i = 3; i > 0; i--) { - num = Math.floor(num / 256); - d = num % 256 + '.' + d; - } - return d; - }, - - inet_pton: function(a) { - // discuss at: http://phpjs.org/functions/inet_pton/ - // original by: Theriault - // example 1: inet_pton('::'); - // returns 1: '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' - // example 2: inet_pton('127.0.0.1'); - // returns 2: '\x7F\x00\x00\x01' - - var r, m, x, i, j, f = String.fromCharCode; - m = a.match(/^(?:\d{1,3}(?:\.|$)){4}/); // IPv4 - if (m) { - m = m[0].split('.'); - m = f(m[0]) + f(m[1]) + f(m[2]) + f(m[3]); - // Return if 4 bytes, otherwise false. - return m.length === 4 ? m : false; - } - r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i; - m = a.match(r); // IPv6 - if (m) { - if (a == '::') { - return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - } - - var colonCount = a.split(':').length - 1; - var doubleColonPos = a.indexOf('::'); - if (doubleColonPos > -1) { - var expansionLength = ((doubleColonPos == 0 || doubleColonPos == a.length - 2) ? 9 : 8) - colonCount; - var expansion = ''; - for (i = 0; i < expansionLength; i++) { - expansion += ':0000'; - } - a = a.replace('::', expansion + ':'); - a = a.replace(/(?:^\:|\:$)/, '', a); - } - - var ipGroups = a.split(':'); - var ipBin = ''; - for (i = 0; i < ipGroups.length; i++) { - var group = ipGroups[i]; - if (group.length > 4) { - return false; - } - group = ("0000" + group).slice(-4); - var b1 = parseInt(group.slice(0, 2), 16); - var b2 = parseInt(group.slice(-2), 16); - if (isNaN(b1) || isNaN(b2)) { - return false; - } - ipBin += f(b1) + f(b2); - } - - return ipBin.length == 16 ? ipBin : false; - } - return false; // Invalid IP. - }, - inet_ntop: function(a) { - // discuss at: http://phpjs.org/functions/inet_ntop/ - // original by: Theriault - // example 1: inet_ntop('\x7F\x00\x00\x01'); - // returns 1: '127.0.0.1' - // example 2: inet_ntop('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1'); - // returns 2: '::1' - - var i = 0, - m = '', - c = []; - a += ''; - if (a.length === 4) { // IPv4 - return [ - a.charCodeAt(0), a.charCodeAt(1), a.charCodeAt(2), a.charCodeAt(3)].join('.'); - } else if (a.length === 16) { // IPv6 - for (i = 0; i < 16; i++) { - c.push(((a.charCodeAt(i++) << 8) + a.charCodeAt(i)) - .toString(16)); - } - return c.join(':') - .replace(/((^|:)0(?=:|$))+:?/g, function(t) { - m = (t.length > m.length) ? t : m; - return t; - }) - .replace(m || ' ', '::'); - } else { // Invalid length - return false; - } - }, - - deleteAdminUser: function(issueID) { - var self = this; - this.ajax('wordfence_deleteAdminUser', { - issueID: issueID - }, function(res) { - if (res.ok) { - self.loadIssues(function() { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully deleted admin"), sprintf(__("The admin user %s was successfully deleted."), res.user_login)); - }); - } else if (res.errorMsg) { - self.loadIssues(function() { - WFAD.colorboxError(res.errorMsg, res.tokenInvalid); - }); - } - }); - }, - - revokeAdminUser: function(issueID) { - var self = this; - this.ajax('wordfence_revokeAdminUser', { - issueID: issueID - }, function(res) { - if (res.ok) { - self.loadIssues(function() { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully revoked admin"), sprintf(__("All capabilties of admin user %s were successfully revoked."), res.user_login)); - }); - } else if (res.errorMsg) { - self.loadIssues(function() { - WFAD.colorboxError(res.errorMsg, res.tokenInvalid); - }); - } - }); - }, - - acknowledgeAdminUser: function (issueID) { - var self = this; - this.ajax('wordfence_acknowledgeAdminUser', { - issueID: issueID - }, function(res) { - if (res.ok) { - self.loadIssues(function() { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully acknowledged admin"), sprintf(__("The admin user %s will no longer show up in future scans."), res.user_login)); - }); - } else if (res.errorMsg) { - self.loadIssues(function() { - WFAD.colorboxError(res.errorMsg, res.tokenInvalid); - }); - } - }); - }, - - windowHasFocus: function() { - if (typeof document.hasFocus === 'function') { - return document.hasFocus(); - } - // Older versions of Opera - return this._windowHasFocus; - }, - - htmlEscape: function(html) { - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); - }, - - permanentlyBlockAllIPs: function(type) { - var self = this; - this.ajax('wordfence_permanentlyBlockAllIPs', { - type: type - }, function(res) { - $('#wfTabs').find('.wfTab1').eq(0).trigger('click'); - }); - }, - - showTimestamp: function(timestamp, serverTime, format) { - serverTime = serverTime === undefined ? new Date().getTime() / 1000 : serverTime; - format = format === undefined ? '${dateTime} (${timeAgo} ago)' : format; - var date = new Date(timestamp * 1000); - - return jQuery.tmpl(format, { - dateTime: date.toLocaleDateString() + ' ' + date.toLocaleTimeString(), - timeAgo: this.makeTimeAgo(serverTime - timestamp) - }); - }, - - updateTimeAgo: function() { - var self = this; - jQuery('.wfTimeAgo-timestamp').each(function(idx, elem) { - var el = jQuery(elem); - var testEl = el; - if (typeof jQuery === "function" && testEl instanceof jQuery) { - testEl = testEl[0]; - } - - var rect = testEl.getBoundingClientRect(); - if (!(rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth))) { - return; - } - - var timestamp = el.data('wfctime'); - if (!timestamp) { - timestamp = el.attr('data-timestamp'); - } - var serverTime = self.serverMicrotime; - var format = el.data('wfformat'); - if (!format) { - format = el.attr('data-format'); - } - el.html(self.showTimestamp(timestamp, serverTime, format)); - }); - }, - - wafData: { - whitelistedURLParams: [] - }, - restoreWAFData: { - whitelistedURLParams: [] - }, - - wafWhitelistedBulkChangeEnabled: function(enabled) { - $('.wf-whitelist-table-bulk-checkbox.wf-option-checkbox.wf-checked').each(function() { - $(this).closest('tr').find('.wf-whitelist-item-enabled.wf-option-checkbox').each(function() { - if (($(this).hasClass('wf-checked') && !enabled) || (!$(this).hasClass('wf-checked') && enabled)) { - var tr = $(this).closest('tr'); - if (tr.is(':visible')) { - WFAD.wafWhitelistedChangeEnabled(tr.data('key'), enabled); - } - } - }); - }) - }, - - wafWhitelistedChangeEnabled: function(key, enabled) { - $('#waf-whitelisted-urls-wrapper .whitelist-table > tbody > tr[data-key="' + key + '"]').each(function() { - var adding = !!$(this).data('adding'); - if (adding) { - WFAD.pendingChanges['whitelistedURLParams']['add'][key]['data']['disabled'] = !enabled ? 1 : 0; - } - else { - if (!(WFAD.pendingChanges['whitelistedURLParams'] instanceof Object)) { - WFAD.pendingChanges['whitelistedURLParams'] = {}; - } - - if (!(WFAD.pendingChanges['whitelistedURLParams']['enabled'] instanceof Object)) { - WFAD.pendingChanges['whitelistedURLParams']['enabled'] = {}; - } - - WFAD.pendingChanges['whitelistedURLParams']['enabled'][key] = !!enabled ? 1 : 0; - } - $(this).find('.wf-whitelist-item-enabled.wf-option-checkbox').toggleClass('wf-checked', !!enabled); - }); - }, - - wafWhitelistedBulkDelete: function() { - $('.wf-whitelist-table-bulk-checkbox.wf-option-checkbox.wf-checked').each(function() { - $(this).closest('tr').find('.wf-whitelist-item-enabled.wf-option-checkbox').each(function() { - var tr = $(this).closest('tr'); - if (tr.is(':visible')) { - WFAD.wafWhitelistedDelete(tr.data('key')); - } - }); - }); - }, - - wafWhitelistedDelete: function(key) { - $('#waf-whitelisted-urls-wrapper .whitelist-table > tbody > tr[data-key="' + key + '"]').each(function() { - var adding = !!$(this).data('adding'); - if (adding) { - delete WFAD.pendingChanges['whitelistedURLParams']['add'][key]; - } - else { - if (!(WFAD.pendingChanges['whitelistedURLParams'] instanceof Object)) { - WFAD.pendingChanges['whitelistedURLParams'] = {}; - } - - if (!(WFAD.pendingChanges['whitelistedURLParams']['delete'] instanceof Object)) { - WFAD.pendingChanges['whitelistedURLParams']['delete'] = {}; - } - - WFAD.pendingChanges['whitelistedURLParams']['delete'][key] = 1; - } - - for (var i = 0; i < WFAD.wafData.whitelistedURLParams.length; i++) { - var testKey = WFAD.wafData.whitelistedURLParams[i].path + '|' + WFAD.wafData.whitelistedURLParams[i].paramKey; - if (testKey == key) { - WFAD.wafData.whitelistedURLParams.splice(i, 1); - break; - } - } - }); - }, - - wafConfigPageRender: function() { - WFAD.wafData.ruleCount = 0; - if (WFAD.wafData.rules) { - WFAD.wafData.ruleCount = Object.keys(WFAD.wafData.rules).length; - } - - var whitelistedIPsEl = $('#waf-whitelisted-urls-tmpl').tmpl(WFAD.wafData); - $('#waf-whitelisted-urls-wrapper').html(whitelistedIPsEl); - - var rulesEl = $('#waf-rules-tmpl').tmpl(WFAD.wafData); - $('#waf-rules-wrapper').html(rulesEl); - - $('#waf-show-all-rules-button').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - $('#waf-rules-wrapper').addClass('wf-show-all'); - }); - - if (WFAD.wafData['rulesLastUpdated']) { - var date = new Date(WFAD.wafData['rulesLastUpdated'] * 1000); - WFAD.renderWAFRulesLastUpdated(date); - } - $(window).trigger('wordfenceWAFConfigPageRender'); - }, - - renderWAFRulesLastUpdated: function(date) { - var dateString = date.toString(); - if (date.toLocaleString) { - dateString = date.toLocaleString(); - } - $('#waf-rules-last-updated').text(sprintf(__('Last Updated: %s'), dateString)) - .css({ - 'opacity': 0 - }) - .animate({ - 'opacity': 1 - }, 500); - }, - - renderWAFRulesNextUpdate: function(date) { - var dateString = date.toString(); - if (date.toLocaleString) { - dateString = date.toLocaleString(); - } - $('#waf-rules-next-update').text(sprintf(__('Next Update Check: %s'), dateString)) - .css({ - 'opacity': 0 - }) - .animate({ - 'opacity': 1 - }, 500); - }, - - wafUpdateRules: function(onSuccess) { - var self = this; - this.ajax('wordfence_updateWAFRules', {}, function(res) { - self.wafData = res; - self.restoreWAFData.rules = res.rules; - self.restoreWAFData.rulesLastUpdated = res.rulesLastUpdated; - self.wafConfigPageRender(); - if (self.wafData['updated']) { - if (!self.wafData['isPaid']) { - self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __('Rules Updated'), __('Your rules have been updated successfully. You are currently using the free version of Wordfence. Upgrade to Wordfence premium to have your rules updated automatically as new threats emerge. Click here to purchase a premium license. Note: Your rules will still update every 30 days as a free user.')); - } else { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rules Updated'), __('Your rules have been updated successfully.')); - } - } - else { - if (self.wafData['failure'] == 'ratelimit') { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Your website has reached the maximum number of rule update requests. Please try again later.')); - } - else if (self.wafData['failure'] == 'unreachable') { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Please verify your website can reach the Wordfence servers.')); - } - else { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Please verify you have permissions to write to the /wp-content/wflogs directory.')); - } - } - if (typeof onSuccess === 'function') { - return onSuccess.apply(this, arguments); - } - }); - }, - - dateFormat: function(date) { - if (date instanceof Date) { - if (date.toLocaleString) { - return date.toLocaleString(); - } - return date.toString(); - } - return date; - }, - - confirmWAFConfigureAutoPrepend: function() { - var self = this; - this.ajax('wordfence_wafConfigureAutoPrepend', {}, function(res) { - self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('.htaccess Updated'), __("Your .htaccess has been updated successfully. Please verify your site is functioning normally.")); - }); - }, - - updatePendingChanges: function() { - $(window).off('beforeunload', WFAD._unsavedOptionsHandler); - if (Object.keys(WFAD.pendingChanges).length) { - $('#wf-cancel-changes').removeClass('wf-disabled'); - $('#wf-save-changes').removeClass('wf-disabled'); - $(window).on('beforeunload', WFAD._unsavedOptionsHandler); - } - else { - $('#wf-cancel-changes').addClass('wf-disabled'); - $('#wf-save-changes').addClass('wf-disabled'); - } - }, - - _unsavedOptionsHandler: function(e) { - var message = __("You have unsaved changes to your options. If you leave this page, those changes will be lost."); //Only shows on older browsers, newer browsers don't allow message customization - e = e || window.event; - if (e) { - e.returnValue = message; //IE and Firefox - } - return message; //Others - }, - - setOption: function(key, value, successCallback, failureCallback, failureAfterModal) { - var changes = {}; - changes[key] = value; - this.ajax('wordfence_saveOptions', {changes: JSON.stringify(changes), page: WFAD.getParameterByName('page')}, function(res) { - if (res.success) { - typeof successCallback == 'function' && successCallback(res); - } - else { - failureAfterModal = typeof failureAfterModal !== 'undefined' && failureAfterModal; - var modalSettings = {}; - if (failureAfterModal) - modalSettings.onClosed = failureCallback; - WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Saving Option'), res.error, modalSettings); - if (!failureAfterModal) - typeof failureCallback == 'function' && failureCallback(res); - } - }); - }, - - saveOptions: function(successCallback, failureCallback) { - if (!Object.keys(WFAD.pendingChanges).length) { - return; - } - var self = this; - - this.ajax('wordfence_saveOptions', {changes: JSON.stringify(WFAD.pendingChanges), page: WFAD.getParameterByName('page')}, function(res) { - if (res.success) { - typeof successCallback == 'function' && successCallback(res); - } - else { - WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Saving Options'), res.error); - typeof failureCallback == 'function' && failureCallback - } - }); - }, - - enableAllOptionsPage: function() { - this.ajax('wordfence_enableAllOptionsPage', {}, function(res) { - if (res.redirect) { - window.location.href = res.redirect; - } - else { - WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Enabling All Options Page'), res.error); - } - }); - }, - - getParameterByName: function(name, url) { - if (!url) url = window.location.href; - name = name.replace(/[\[\]]/g, "\\$&"); - var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)"), - results = regex.exec(url); - if (!results) return null; - if (!results[2]) return ''; - return decodeURIComponent(results[2].replace(/\+/g, " ")); - }, - - base64_decode: function(s) { - var e = {}, i, b = 0, c, x, l = 0, a, r = '', w = String.fromCharCode, L = s.length; - var A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - for (i = 0; i < 64; i++) { - e[A.charAt(i)] = i; - } - for (x = 0; x < L; x++) { - c = e[s.charAt(x)]; - b = (b << 6) + c; - l += 6; - while (l >= 8) { - ((a = (b >>> (l -= 8)) & 0xff) || (x < (L - 2))) && (r += w(a)); - } - } - return r; - }, - - base64_encode: function (input) { - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - while (i < input.length) { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } - else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + chars.charAt(enc1) + chars.charAt(enc2) + chars.charAt(enc3) + chars.charAt(enc4); - } - - return output; - } - }; - - window['WFAD'] = window['wordfenceAdmin']; - setInterval(function() { - WFAD.updateTimeAgo(); - }, 1000); - } - - __ = window.wfi18n.__; - sprintf = window.wfi18n.sprintf; - - jQuery(function() { - wordfenceAdmin.init(); - jQuery(window).on('focus', function() { - if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) { - jQuery('body').removeClass('wordfenceLiveActivityPaused'); - } - }); - }); - - $(function() { - $('#wf-mobile-controls').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - $.wfMobileMenu({ - menuItems: [ - {title: __('Save Changes'), primary: true, disabled: $('#wf-save-changes').hasClass('wf-disabled'), action: function() { $('#wf-save-changes').trigger('click'); }}, - {title: __('Cancel Changes'), primary: false, disabled: $('#wf-cancel-changes').hasClass('wf-disabled'), action: function() { $('#wf-cancel-changes').trigger('click'); }}, - {title: __('Restore Defaults'), primary: false, disabled: $('#wf-restore-defaults').hasClass('wf-disabled'), action: function() { $('#wf-restore-defaults').trigger('click'); }} - ] - }); - }); - - $('#wf-restore-defaults').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - var restoreDefaultsSection = $(this).data('restoreDefaultsSection'); - var prompt = $('#wfTmpl_restoreDefaultsPrompt').tmpl(); - var promptHTML = $("").append(prompt).html(); - WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '400px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() { - $('#wf-restore-defaults-prompt-cancel').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.colorboxClose(); - }); - - $('#wf-restore-defaults-prompt-confirm').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.ajax('wordfence_restoreDefaults', {section: restoreDefaultsSection}, function(res) { - if (res.success) { - window.location.reload(true); - } - else { - WFAD.colorboxClose(); - WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __('Error Restoring Defaults'), res.error); - } - }); - }); - }}); - }); - - $('#wf-save-changes').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.saveOptions(function(res) { - WFAD.pendingChanges = {}; - WFAD.updatePendingChanges(); - - if (res.redirect) { - window.location.href = res.redirect; - } - else { - window.location.reload(true); - } - }); - }); - - $('#wf-cancel-changes').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - WFAD.pendingChanges = {}; - - WFAD.updatePendingChanges(); - - //On/Off options - $('.wf-option.wf-option-toggled').each(function() { - var enabledValue = $(this).data('enabledValue'); - var disabledValue = $(this).data('disabledValue'); - var originalValue = $(this).data('originalValue'); - if (enabledValue == originalValue) { - $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true'); - } - else { - $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false'); - } - $(this).trigger('change', [true]); - }); - - $('.wf-option-toggled-boolean-switch').each(function() { - var enabledValue = $(this).data('enabledValue'); - var disabledValue = $(this).data('disabledValue'); - var originalValue = $(this).data('originalValue'); - if (enabledValue == originalValue) { - $(this).find('.wf-boolean-switch').addClass('wf-active').attr('aria-checked', 'true'); - } - else { - $(this).find('.wf-boolean-switch').removeClass('wf-active').attr('aria-checked', 'false'); - } - $(this).trigger('change', [true]); - }); - - $('.wf-option.wf-option-toggled-segmented').each(function() { - var originalValue = $(this).data('originalValue'); - $(this).find('[type=radio]').each(function() { - if (this.value == originalValue) { - this.checked = true; - return false; - } - }); - $(this).trigger('change', [true]); - }); - - //On/Off multiple options - $('.wf-option.wf-option-toggled-multiple').each(function() { - $(this).find('.wf-option-checkboxes > ul').each(function() { - var enabledValue = $(this).data('enabledValue'); - var disabledValue = $(this).data('disabledValue'); - var originalValue = $(this).data('originalValue'); - if (enabledValue == originalValue) { - $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true'); - } - else { - $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false'); - } - }); - $(this).trigger('change', [true]); - }); - - //On/Off options with menu - $('.wf-option.wf-option-toggled-select').each(function() { - var selectElement = $(this).find('.wf-option-select select'); - var enabledToggleValue = $(this).data('enabledToggleValue'); - var disabledToggleValue = $(this).data('disabledToggleValue'); - var originalToggleValue = $(this).data('originalToggleValue'); - if (enabledToggleValue == originalToggleValue) { - $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true'); - selectElement.attr('disabled', false); - } - else { - $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false'); - selectElement.attr('disabled', true); - } - - var originalSelectValue = $(this).data('originalSelectValue'); - $(this).find('.wf-option-select select').val(originalSelectValue).trigger('change'); - $(this).trigger('change', [true]); - }); - - //Menu options - $('.wf-option.wf-option-select').each(function() { - var originalSelectValue = $(this).data('originalSelectValue'); - $(this).find('.wf-option-select select').val(originalSelectValue).trigger('change'); - $(this).trigger('change', [true]); - }); - - //Text options - $('.wf-option.wf-option-text').each(function() { - var originalTextValue = $(this).data('originalTextValue'); - if (typeof originalTextValue !== 'undefined') { - $(this).find('.wf-option-text input').val(originalTextValue); - } - $(this).trigger('change', [true]); - }); - - //Text area options - $('.wf-option.wf-option-textarea').each(function() { - var originalTextValue = $(this).data('originalTextValue'); - $(this).find('.wf-option-textarea textarea').val(originalTextValue); - $(this).trigger('change', [true]); - }); - - //Token options - $('.wf-option.wf-option-token').each(function() { - var originalTokenValue = $(this).data('originalTokenValue'); - $(this).find('select').val(originalTokenValue).trigger('change'); - $(this).trigger('change', [true]); - }); - - //Switch options - $('.wf-option.wf-option-switch').each(function() { - var originalValue = $(this).data('originalValue'); - $(this).find('.wf-switch > li').each(function() { - $(this).toggleClass('wf-active', originalValue == $(this).data('optionValue')).attr('aria-checked', originalValue == $(this).data('optionValue') ? 'true' : 'false'); - }); - $(this).trigger('change', [true]); - }); - - //Other options - $(window).trigger('wfOptionsReset'); - }); - - var select2s = $('.wf-select2'); - if (select2s.length && $.fn.wfselect2) { - select2s.wfselect2({ - minimumResultsForSearch: 5 - }); - } - - - if ($.fn.tooltip) { - $('.wf-status-circular').each(function() { - var circle = $(this); - var tmplID = 'tooltip-' + this.id + '-tmpl'; - var circleTmpl = $('#' + tmplID); - if (circleTmpl.length) { - circle.tooltip({ - tooltipClass: "wf-circle-tooltip", - position: { - my: "left-40 bottom", - at: "center top", - using: function(obj, info) { - var el = $(this); - el.removeClass('wf-tooltip-vertical-top wf-tooltip-vertical-bottom ' + - 'wf-tooltip-horizontal-left wf-tooltip-horizontal-right') - .addClass('wf-tooltip-vertical-' + info.vertical) - .addClass('wf-tooltip-horizontal-' + info.horizontal); - - $(this).css({ - left: obj.left + 'px', - top: obj.top + 'px' - }); - } - }, - items: this, - close: function (event, ui) { - ui.tooltip.hover( - function () { - $(this).stop(true).fadeTo(400, 1); - }, - function () { - $(this).fadeOut("400", function () { - $(this).remove(); - }) - }); - }, - content: function() { - var circleClone = $(this).clone(); - circleClone.find('svg, .wf-status-circular-text').css('opacity', 1.0); - var circleHTML = $(circleClone).html(); - return circleTmpl.tmpl({ - statusCircle: circleHTML - }); - } - }) - // .tooltip('open'); - } - }); - } - }); -})(jQuery); - -//wfCircularProgress -jQuery.fn.wfCircularProgress = function(options) { - var __ = window.wfi18n.__; - var sprintf = window.wfi18n.sprintf; - - jQuery(this).each(function() { - var creationOptions; - try { - creationOptions = JSON.parse(jQuery(this).data('wfCircularProgressOptions')); - } - catch (e) { /* Ignore */ } - if (typeof creationOptions !== 'object') { - creationOptions = {}; - } - var opts = jQuery.extend({}, jQuery.fn.wfCircularProgress.defaults, creationOptions, options); - - var center = Math.floor(opts.diameter / 2); - var insetRadius = center - opts.strokeWidth * 2; - - var circumference = 2 * insetRadius * Math.PI; - var finalOffset = -(circumference * (1 - opts.endPercent)); - var initialOffset = -(circumference); - - var terminatorRadius = Math.floor(opts.strokeWidth * 1.5); - var terminatorDiameter = 2 * terminatorRadius; - var finalTerminatorX = center - insetRadius * Math.cos(Math.PI * 2 * (opts.endPercent - 0.25)); - var finalTerminatorY = center + insetRadius * Math.sin(Math.PI * 2 * (opts.endPercent - 0.25)); - var initialTerminatorX = center - insetRadius * Math.cos(Math.PI * 2 * (opts.startPercent - 0.25)); - var initialTerminatorY = center + insetRadius * Math.sin(Math.PI * 2 * (opts.startPercent - 0.25)); - - var terminatorSVG = "m 0,-" + terminatorRadius + " a " + terminatorRadius + "," + terminatorRadius + " 0 1 1 0," + terminatorDiameter + " a " + terminatorRadius + "," + terminatorRadius + " 0 1 1 0,-" + terminatorDiameter; - - jQuery(this).data('wfCircularProgressOptions', JSON.stringify(opts)); - - jQuery(this).css('width', opts.diameter + 'px'); - jQuery(this).css('height', opts.diameter + 'px'); - - var svg = jQuery(this).find('svg'); - if (svg.length == 0) { svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); jQuery(this).append(svg); } - var inactivePath = jQuery(this).find('.wf-status-circular-inactive-path'); - if (inactivePath.length == 0) { inactivePath = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(inactivePath).addClass('wf-status-circular-inactive-path'); jQuery(svg).append(inactivePath); } - var activePath = jQuery(this).find('.wf-status-circular-active-path'); - if (activePath.length == 0) { activePath = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(activePath).addClass('wf-status-circular-active-path'); jQuery(svg).append(activePath); } - var terminator = jQuery(this).find('.wf-status-circular-terminator'); - if (terminator.length == 0) { terminator = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(terminator).addClass('wf-status-circular-terminator'); jQuery(svg).append(terminator); } - var text = jQuery(this).find('.wf-status-circular-text'); - if (text.length == 0) { text = jQuery(''); jQuery(this).append(text); } - var pendingOverlay = jQuery(this).find('.wf-status-overlay-text'); - if (pendingOverlay.length == 0) { pendingOverlay = jQuery(''); jQuery(this).append(pendingOverlay); } - - jQuery(svg).attr('viewBox', '0 0 ' + opts.diameter + ' ' + opts.diameter); - jQuery(svg).css('display', 'block'); - jQuery(svg).css('width', opts.diameter + 'px'); - jQuery(svg).css('height', opts.diameter + 'px'); - jQuery(inactivePath).attr('d', 'M ' + center + ',' + center + ' m 0,-' + insetRadius + ' a ' + insetRadius + ',' +insetRadius + ' 0 1 1 0,' + (2 * insetRadius) + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,-' + (2 * insetRadius)); - jQuery(inactivePath).attr('stroke', opts.inactiveColor); - jQuery(inactivePath).attr('stroke-width', opts.strokeWidth); - jQuery(inactivePath).attr('fill-opacity', 0); - jQuery(activePath).attr('d', 'M ' + center + ',' + center + ' m 0,-' + insetRadius + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,' + (2 * insetRadius) + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,-' + (2 * insetRadius)); - jQuery(activePath).attr('stroke', opts.color); - jQuery(activePath).attr('stroke-width', opts.strokeWidth); - jQuery(activePath).attr('stroke-dasharray', circumference + ',' + circumference); - jQuery(activePath).attr('stroke-dashoffset', initialOffset); - jQuery(activePath).attr('fill-opacity', 0); - jQuery(terminator).attr('d', 'M ' + initialTerminatorX + ',' + initialTerminatorY + ' ' + terminatorSVG); - jQuery(terminator).attr('stroke', opts.color); - jQuery(terminator).attr('stroke-width', opts.strokeWidth); - jQuery(terminator).attr('fill', '#ffffff'); - jQuery(pendingOverlay).html(opts.pendingMessage); - - jQuery(pendingOverlay).animate({ - opacity: opts.pendingOverlay ? 1.0 : 0.0, - }, { - duration: 500, - step: function(value) { - var opacity = 1.0 - (value * 0.8); - jQuery(svg).css('opacity', opacity); - jQuery(text).css('opacity', opacity); - }, - complete: function() { - jQuery(svg).css('opacity', opts.pendingOverlay ? 0.2 : 1.0); - jQuery(text).css('opacity', opts.pendingOverlay ? 0.2 : 1.0); - } - }); - - jQuery(activePath).animate({ - "stroke-dashoffset": finalOffset + 'px' - }, { - duration: 500, - step: function(value) { - var percentage = 1 + value / circumference; - var x = center - insetRadius * Math.cos(Math.PI * 2 * (percentage - 0.25)); - var y = center + insetRadius * Math.sin(Math.PI * 2 * (percentage - 0.25)); - jQuery(terminator).attr('d', 'M ' + x + ',' + y + ' ' + terminatorSVG); - text.html(Math.round(percentage * 100) + '%'); - }, - complete: function() { - text.html(Math.round(opts.endPercent * 100) + '%'); - } - }); - }); -}; - -(function() { - var __ = window.wfi18n.__; - var sprintf = window.wfi18n.sprintf; - - jQuery.fn.wfCircularProgress.defaults = { - startPercent: 0, - endPercent: 1, - color: '#16bc9b', - inactiveColor: '#ececec', - strokeWidth: 3, - diameter: 100, - pendingOverlay: false, - pendingMessage: __('Note: Status will update when changes are saved'), - }; -})(); - -//wfDrawer -(function ($, document, window) { - var __ = window.wfi18n.__; - var sprintf = window.wfi18n.sprintf; - - var defaults = { - width: '600px', - clickOverlayDismiss: false, - content: false, - onComplete: false, - }; - - var publicMethod = $.fn['wfDrawer'] = $['wfDrawer'] = function (options) { - var opts = $.extend({}, defaults, options); - - var overlay = $('').css('opacity', 0); - if (opts.clickOverlayDismiss) { - overlay.on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - $.wfDrawer.close(); - }); - } - $('body').append(overlay); - - var drawer = $('').css('width', opts.width).css('right', '-' + opts.width); - if (opts.content) { - drawer.append(opts.content); - } - $('body').append(drawer); - - overlay.animate({ - "opacity": 1 - }); - drawer.animate({ - "right": '0px' - }, - { - complete: function() { - typeof opts.onComplete === 'function' && opts.onComplete(); - } - }); - }; - - publicMethod.close = function() { - var overlay = $('.wf-drawer-overlay'); - overlay.animate({ - "opacity": 0 - }, - { - complete: function() { - overlay.remove(); - } - }); - - var drawer = $('.wf-drawer'); - drawer.animate({ - "right": '-' + drawer.css('width') - }, - { - complete: function() { - drawer.remove(); - } - }); - }; -}(jQuery, document, window)); - -//wfMobileMenu -(function ($, document, window) { - var __ = window.wfi18n.__; - var sprintf = window.wfi18n.sprintf; - - var defaults = { - width: '280px', - clickOverlayDismiss: true, - menuItems: [], - onDismiss: false, - }; - - var publicMethod = $.fn['wfMobileMenu'] = $['wfMobileMenu'] = function (options) { - var opts = $.extend({}, defaults, options); - - var overlay = $('').css('opacity', 0); - if (opts.clickOverlayDismiss) { - overlay.on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - typeof opts.onDismiss === 'function' && opts.onDismiss(false); - $.wfMobileMenu.close(); - }); - } - $('body').append(overlay); - - var menu = $('').css('width', opts.width).css('bottom', '-9999px'); - var itemsWrapper = menu.find('.wf-mobile-menu-items'); - for (var i = 0; i < opts.menuItems.length; i++) { - var button = $('" + sprintf(__("Wordfence Firewall blocked a background request to WordPress for the URL %s. If this occurred as a result of an intentional action, you may consider allowlisting the request to allow it in the future."), "" + requestURLEscaped + "") + "
" + __("Add action to allowlist") + " " + __("Dismiss") + "
", - onComplete: function() { - $('#background-block-dismiss').click(function(event) { - event.preventDefault(); - event.stopPropagation(); - $.wordfenceBox.close(); - }); - - $('#background-block-whitelist').click(function(event) { - event.preventDefault(); - event.stopPropagation(); - - if (confirm(__('Are you sure you want to allowlist this action?'))) { - $.ajax({ - method: 'POST', - url: formAction, - data: queryParams, - global: false, - success: function() { - alert(__('The request has been allowlisted. Please try it again.')); - $.wordfenceBox.close(); - }, - error: function() { - alert(__('An error occurred when adding the request to the allowlist.')); - $.wordfenceBox.close(); - } - }); - } - }); - }, - onClosed: function() { - wordfenceAJAXWatcher.blockWarningOpen = false; - } - }); - } - } - }); - } - } - } - $(function() { - wordfenceAJAXWatcher.init(); - $('#wfboxPrevious, #wfboxNext, #wfboxSlideshow').remove(); - }); - -}(jQuery, document, window)); diff --git a/wp/wp-content/plugins/wordfence/js/admin.liveTraffic.1704213472.js b/wp/wp-content/plugins/wordfence/js/admin.liveTraffic.1704213472.js deleted file mode 100644 index a87fcf75..00000000 --- a/wp/wp-content/plugins/wordfence/js/admin.liveTraffic.1704213472.js +++ /dev/null @@ -1,924 +0,0 @@ -(function($) { - var __ = window.wfi18n.__; - var sprintf = window.wfi18n.sprintf; - - var LISTING_LIMIT = 50; - - LiveTrafficViewModel = function(listings, filters) { - var self = this; - var listingIDTable = {}; - self.listings = ko.observableArray(listings); - self.listings.subscribe(function(items) { - listingIDTable = {}; - for (var i = 0; i < items.length; i++) { - listingIDTable[items[i].id()] = 1; - } - //console.log(items); - }); - self.hasListing = function(id) { - return id in listingIDTable; - }; - self.filters = ko.observableArray(filters); - - var urlGroupBy = new GroupByModel('url', __('URL')); - var groupBys = [ - new GroupByModel('type', __('Type')), - new GroupByModel('user_login', __('Username')), - new GroupByModel('statusCode', __('HTTP Response Code')), - new GroupByModel('action', __('Firewall Response'), 'enum', ['ok', 'throttled', 'lockedOut', 'blocked', 'blocked:waf']), - new GroupByModel('ip', __('IP')), - urlGroupBy - ]; - - self.presetFiltersOptions = ko.observableArray([ - new PresetFilterModel(__('All Hits'), "all", []), - new PresetFilterModel(__('Humans'), "humans", [new ListingsFilterModel(self, 'type', 'human')]), - new PresetFilterModel(__('Registered Users'), "users", [new ListingsFilterModel(self, 'userID', '0', '!=')]), - new PresetFilterModel(__('Crawlers'), "crawlers", [new ListingsFilterModel(self, 'type', 'bot')]), - new PresetFilterModel(__('Google Crawlers'), "google", [new ListingsFilterModel(self, 'isGoogle', '1')]), - new PresetFilterModel(__('Pages Not Found'), "404s", [new ListingsFilterModel(self, 'statusCode', '404')]), - new PresetFilterModel(__('Logins and Logouts'), "logins", [ - new ListingsFilterModel(self, 'action', 'login', 'contains'), - new ListingsFilterModel(self, 'action', 'logout', 'contains') - ]), - //new PresetFilterModel('Top Consumers', "top_consumers", [new ListingsFilterModel(self, 'statusCode', '200')], urlGroupBy), - //new PresetFilterModel('Top 404s', "top_404s", [new ListingsFilterModel(self, 'statusCode', '404')], urlGroupBy), - new PresetFilterModel(__('Locked Out'), "lockedOut", [new ListingsFilterModel(self, 'action', 'lockedOut')]), - new PresetFilterModel(__('Blocked'), "blocked", [new ListingsFilterModel(self, 'action', 'blocked', 'contains')]), - new PresetFilterModel(__('Blocked By Firewall'), "blocked:waf", [new ListingsFilterModel(self, 'action', 'blocked:waf')]) - ]); - - self.showAdvancedFilters = ko.observable(false); - self.showAdvancedFilters.subscribe(function(val) { - if (val && self.filters().length == 0) { - self.addFilter(); - } - }); - - self.presetFiltersOptionsText = function(item) { - return item.text(); - }; - - self.selectedPresetFilter = ko.observable(); - self.selectedPresetFilter.subscribe(function(item) { - var clonedFilters = ko.toJS(item.filters()); - var newFilters = []; - for (var i = 0; i < clonedFilters.length; i++) { - newFilters.push(new ListingsFilterModel(self, clonedFilters[i].param, clonedFilters[i].value, clonedFilters[i].operator)); - } - self.filters(newFilters); - self.groupBy(item.groupBy()); - }); - - self.filters.subscribe(function() { - self.checkQueryAndReloadListings(); - }); - - self.addFilter = function() { - self.filters.push(new ListingsFilterModel(self)); - }; - - self.removeFilter = function(item) { - self.filters.remove(item); - }; - - var currentFilterQuery = ''; - var getURLEncodedFilters = function() { - var dataString = ''; - ko.utils.arrayForEach(self.filters(), function(filter) { - if (filter.getValue() !== false) { - dataString += filter.urlEncoded() + '&'; - } - }); - var groupBy = self.groupBy(); - if (groupBy) { - dataString += 'groupby=' + encodeURIComponent(groupBy.param()) + '&'; - } - var startDate = self.startDate(); - if (startDate) { - dataString += 'startDate=' + encodeURIComponent(startDate) + '&'; - } - var endDate = self.endDate(); - if (endDate) { - dataString += 'endDate=' + encodeURIComponent(endDate) + '&'; - } - if (dataString.length > 1) { - return dataString.substring(0, dataString.length - 1); - } - return ''; - }; - - self.filterGroupByOptions = ko.observableArray(groupBys); - - self.filterGroupByOptionsText = function(item) { - return item.text() || item.param(); - }; - - self.groupBy = ko.observable(); - self.groupBy.subscribe(function() { - self.checkQueryAndReloadListings(); - }); - - self.startDate = ko.observable(); - self.startDate.subscribe(function() { - // console.log('start date change ' + self.startDate()); - self.checkQueryAndReloadListings(); - }); - - self.endDate = ko.observable(); - self.endDate.subscribe(function() { - // console.log('end date change ' + self.endDate()); - self.checkQueryAndReloadListings(); - }); - - /** - * Pulls down fresh traffic data and resets the list. - * - * @param options - */ - self.checkQueryAndReloadListings = function(options) { - if (currentFilterQuery !== getURLEncodedFilters()) { - self.reloadListings(options); - } - }; - self.reloadListings = function(options) { - pullDownListings(options, function(listings) { - var groupByKO = self.groupBy(); - var groupBy = ''; - if (groupByKO) { - groupBy = groupByKO.param(); - WFAD.mode = 'liveTraffic_paused'; - } - else { - WFAD.mode = 'liveTraffic'; - } - - var newListings = []; - for (var i = 0; i < listings.length; i++) { - newListings.push(new ListingModel(listings[i], groupBy)); - } - self.listings(newListings); - }) - }; - - /** - * Used in the infinite scroll - */ - self.loadNextListings = function(callback) { - var lastTimestamp = self.filters[0]; - pullDownListings({ - since: lastTimestamp, - limit: LISTING_LIMIT, - offset: self.listings().length - }, function() { - self.appendListings.apply(this, arguments); - typeof callback === 'function' && callback.apply(this, arguments); - }); - }; - - self.getCurrentQueryString = function(options) { - var queryOptions = { - since: null, - limit: LISTING_LIMIT, - offset: 0 - }; - for (var prop in queryOptions) { - if (queryOptions.hasOwnProperty(prop) && options && prop in options) { - queryOptions[prop] = options[prop]; - } - } - currentFilterQuery = getURLEncodedFilters(); - var data = currentFilterQuery; - for (prop in queryOptions) { - if (queryOptions.hasOwnProperty(prop)) { - var val = queryOptions[prop]; - if (val === null || val === undefined) { - val = ''; - } - data += '&' + encodeURIComponent(prop) + '=' + encodeURIComponent(val); - } - } - return data; - }; - - var pullDownListings = function(options, callback) { - var data = self.getCurrentQueryString(options); - - WFAD.ajax('wordfence_loadLiveTraffic', data, function(response) { - if (!response || !response.success) { - return; - } - callback && callback(response.data, response); - self.sql(response.sql); - }); - }; - - self.prependListings = function(listings, response) { - for (var i = listings.length - 1; i >= 0; i--) { - // Prevent duplicates - if (self.hasListing(listings[i].id)) { - continue; - } - var listing = new ListingModel(listings[i]); - listing.highlighted(true); - self.listings.unshift(listing); - } - - //self.listings.sort(function(a, b) { - // if (a.ctime() < b.ctime()) { - // return 1; - // } else if (a.ctime() > b.ctime()) { - // return -1; - // } - // return 0; - //}); - }; - - self.appendListings = function(listings, response) { - var highlight = 3; - for (var i = 0; i < listings.length; i++) { - // Prevent duplicates - if (self.hasListing(listings[i].id)) { - continue; - } - var listing = new ListingModel(listings[i]); - listing.highlighted(highlight-- > 0); - self.listings.push(listing); - } - - //self.listings.sort(function(a, b) { - // if (a.ctime() < b.ctime()) { - // return 1; - // } else if (a.ctime() > b.ctime()) { - // return -1; - // } - // return 0; - //}); - }; - - self.whitelistWAFParamKey = function(path, paramKey, failedRules) { - WFAD.ajax('wordfence_whitelistWAFParamKey', { - path: path, - paramKey: paramKey, - failedRules: failedRules - }, function(response) { - - }); - }; - - self.trimIP = function(ip) { - if (ip && ip.length > 16) { - return ip.substring(0, 16) + "\u2026"; - } - return ip; - }; - - $(window).on('wf-live-traffic-ip-blocked', function(e, ip) { - ko.utils.arrayForEach(self.listings(), function(listing) { - if (listing.IP() === ip) { - listing.blocked(true); - } - }); - }).on('wf-live-traffic-ip-unblocked', function(e, ip) { - ko.utils.arrayForEach(self.listings(), function(listing) { - if (listing.IP() === ip) { - listing.blocked(false); - } - }); - }); - - // For debuggering-a-ding - self.sql = ko.observable(''); - }; - - LiveTrafficViewModel.truncateText = function(text, maxLength) { - maxLength = maxLength || 100; - if (text && text.length > maxLength) { - return text.substring(0, Math.round(maxLength)) + "\u2026"; - // return text.substring(0, Math.round(maxLength / 2)) + " ... " + text.substring(text.length - Math.round(maxLength / 2)); - } - return text; - }; - - var ListingModel = function(data, groupBy) { - var self = this; - - self.id = ko.observable(0); - self.ctime = ko.observable(0); - self.IP = ko.observable(''); - self.jsRun = ko.observable(0); - self.statusCode = ko.observable(200); - self.isGoogle = ko.observable(0); - self.userID = ko.observable(0); - self.URL = ko.observable(''); - self.referer = ko.observable(''); - self.UA = ko.observable(''); - self.loc = ko.observable(); - self.type = ko.observable(''); - self.blocked = ko.observable(false); - self.rangeBlocked = ko.observable(false); - self.ipRangeID = ko.observable(-1); - self.extReferer = ko.observable(); - self.browser = ko.observable(); - self.user = ko.observable(); - self.hitCount = ko.observable(); - self.username = ko.observable(''); - - // New fields/columns - self.action = ko.observable(''); - self.actionDescription = ko.observable(false); - self.actionData = ko.observable(); - - self.highlighted = ko.observable(false); - self.showDetails = ko.observable(false); - self.toggleDetails = function() { - self.showDetails(!self.showDetails()); - }; - //self.highlighted.subscribe(function(val) { - // if (val) { - // _classes += ' highlighted'; - // self.cssClasses(_classes); - // } else { - // _classes.replace(/ highlighted(\s*|$)/, ' '); - // self.cssClasses(_classes); - // } - //}); - - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - if (prop === 'blocked' || prop === 'rangeBlocked') { - data[prop] = !!data[prop]; - } - self[prop] !== undefined && self[prop](data[prop]); - } - } - - if (data['lastHit'] !== undefined) { - self['ctime'](data['lastHit']); - } - - self.timestamp = ko.pureComputed(function() { - var date = new Date(self.ctime() * 1000); - return date.toLocaleDateString() + ' ' + date.toLocaleTimeString(); - }, self); - - // Use the same format as these update. - self.timeAgo = ko.pureComputed(function() { - var serverTime = WFAD.serverMicrotime; - return $(WFAD.showTimestamp(this.ctime(), serverTime)).text(); - }, self); - - self.displayURL = ko.pureComputed(function() { - return LiveTrafficViewModel.truncateText(self.URL(), 105); - }); - - self.displayURLShort = ko.pureComputed(function() { - var a = document.createElement('a'); - if (!self.URL()) { - return ''; - } - a.href = self.URL(); - if (a.host !== location.host) { - return LiveTrafficViewModel.truncateText(self.URL(), 30); - } - var url = a.pathname + (typeof a.search === 'string' ? a.search : ''); - return LiveTrafficViewModel.truncateText(url, 30); - }); - - self.firewallAction = ko.pureComputed(function() { - //Grouped by firewall action listing - if (groupBy == 'action') { - switch (self.action()) { - case 'lockedOut': - return __('Locked out from logging in'); - case 'blocked:waf-always': - return __('Blocked by the Wordfence Application Firewall and plugin settings'); - case 'blocked:wordfence': - return __('Blocked by Wordfence plugin settings'); - case 'blocked:wfsnrepeat': - case 'blocked:wfsn': - return __('Blocked by the Wordfence Security Network'); - case 'blocked:waf': - return __('Blocked by the Wordfence Web Application Firewall'); - case 'cbl:redirect': - return __('Redirected by Country Blocking bypass URL'); - default: - return __('Blocked by Wordfence'); - } - } - - //Standard listing - var desc = ''; - switch (self.action()) { - case 'lockedOut': - return __('locked out from logging in'); - - case 'blocked:waf-always': - case 'blocked:wordfence': - case 'blocked:wfsnrepeat': - desc = self.actionDescription(); - if (desc && desc.toLowerCase().indexOf('block') === 0) { - return 'b' + desc.substring(1); - } - return sprintf(__('blocked for %s'), desc); - - case 'blocked:wfsn': - return __('blocked by the Wordfence Security Network'); - - case 'blocked:waf': - var data = self.actionData(); - if (typeof data === 'object') { - var paramKey = data.paramKey ? WFAD.base64_decode(data.paramKey) : null; - var paramValue = data.paramKey ? WFAD.base64_decode(data.paramValue) : null; - // var category = data.category; - - var matches = paramKey !== null && paramKey.match(/([a-z0-9_]+\.[a-z0-9_]+)(?:\[(.+?)\](.*))?/i); - desc = self.actionDescription(); - if (matches) { - switch (matches[1]) { - case 'request.queryString': - desc = sprintf(__('%s in query string: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue))); - break; - case 'request.body': - desc = sprintf(__('%s in POST body: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue))); - break; - case 'request.cookie': - desc = sprintf(__('%s in cookie: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue))); - break; - case 'request.fileNames': - desc = sprintf(__('%s in file: %s'), self.actionDescription(), matches[2] + '=' + LiveTrafficViewModel.truncateText(encodeURIComponent(paramValue))); - break; - } - } - if (desc) { - return sprintf(__('blocked by firewall for %s'), desc); - } - if (data.failedRules == 'blocked') { - return __('blocked by real-time IP blocklist'); - } - return __('blocked by firewall'); - } - return sprintf(__('blocked by firewall for %s'), self.actionDescription()); - case 'cbl:redirect': - desc = self.actionDescription(); - return desc; - } - return desc; - }); - - self.cssClasses = ko.pureComputed(function() { - var classes = 'wf-live-traffic-hit-type'; - if (self.statusCode() == 403 || self.statusCode() == 503) { - classes += ' wfActionBlocked'; - } - if (self.statusCode() == 404) { - classes += ' wf404'; - } - if (self.jsRun() == 1) { - classes += ' wfHuman'; - } - if (self.actionData() && self.actionData().learningMode) { - classes += ' wfWAFLearningMode'; - } - if (self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') { - classes += ' wfFailedLogin'; - } - // if (self.highlighted()) { - // classes += ' highlighted'; - // } - return classes; - }); - - self.typeIconClass = ko.pureComputed(function() { - var classes = 'wf-live-traffic-type-icon'; - if (self.statusCode() == 403 || self.statusCode() == 503) { - classes += ' wf-icon-blocked wf-ion-android-cancel'; - } else if (self.statusCode() == 404 || self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') { - classes += ' wf-icon-warning wf-ion-alert-circled'; - } else if (self.jsRun() == 1) { - classes += ' wf-icon-human wf-ion-ios-person'; - } else { - // classes += ' wf-ion-soup-can'; - classes += ' wf-ion-bug'; - } - return classes; - }); - - self.typeText = ko.pureComputed(function() { - var type = ''; - if (self.action() == 'loginFailValidUsername' || self.action() == 'loginFailInvalidUsername') { - type = __('Failed Login'); - } else if (self.statusCode() == 403 || self.statusCode() == 503) { - type = __('Blocked'); - } else if (self.statusCode() == 404) { - type = __('404 Not Found'); - } else if (self.statusCode() == 302) { - type = __('Redirected'); - } else if (self.jsRun() == 1) { - type = __('Human'); - } else { - type = __('Bot'); - } - return sprintf(__('Type: %s'), type); - }); - - function slideInDrawer() { - overlayWrapper.fadeIn(400); - overlay.css({ - right: '-800px' - }) - .stop() - .animate({ - right: 0 - }, 500); - } - - self.showWhoisOverlay = function() { - slideInDrawer(); - overlayHeader.html($('#wfActEvent_' + self.id()).html()); - overlayBody.html('').css('opacity', 0); - - WFAD.ajax('wordfence_whois', { - val: self.IP() - }, function(result) { - var whoisHTML = WFAD.completeWhois(result, true); - overlayBody.stop() - .animate({ - opacity: 1 - }, 200) - .html('| ' + tmph + ' | '; - } - } - else { - for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) { - gridSize[litem]++; - html += '' + ((m < 10) ? '0' : '') + m + ' | '; - } - } - - html += '