diff --git a/contract/Contracts/WordPress-Website/_scratch/site_analysis/IMPLEMENTATION-PLAN.md b/contract/Contracts/WordPress-Website/_scratch/site_analysis/IMPLEMENTATION-PLAN.md index 05c2d079..dd03a4cb 100644 --- a/contract/Contracts/WordPress-Website/_scratch/site_analysis/IMPLEMENTATION-PLAN.md +++ b/contract/Contracts/WordPress-Website/_scratch/site_analysis/IMPLEMENTATION-PLAN.md @@ -808,11 +808,31 @@ This implementation plan is a draft for review. Please confirm: - Site icon/favicon managed via WordPress Customizer (Appearance > Customize > Site Identity) - Theme color set to #0A0A0A (background dark) for mobile browser chrome -### Phase 6: Performance & Security - PENDING +### Phase 6: Performance & Security - COMPLETED (Partial) +- [x] WebP image conversion via "Converter for Media" plugin +- [x] Nginx rewrite rules for serving WebP to supported browsers +- [x] Server dependencies documented in DEPENDENCIES.md +- [ ] Caching plugin - SKIPPED (not requested) +- [ ] Security plugin - SKIPPED (not requested) +- [ ] Backups plugin - SKIPPED (not requested) + +**Technical Details:** +- Plugin: Converter for Media v6.3.2 +- Conversion method: PHP GD/Imagick (both available, WebP supported) +- WebP files stored in: `/wp-content/uploads-webpc/` +- Nginx serves WebP when browser sends `Accept: image/webp` header +- No external APIs or services used (fully local processing) + +**Files Created:** +- /var/www/html/DEPENDENCIES.md (server dependency documentation) + +**Files Modified:** +- /etc/nginx/sites-available/default (WebP rewrite rules added) + ### Phase 7: Testing & Launch - PENDING --- -*Document Version: 1.4* +*Document Version: 1.5* *Last Updated: November 28, 2025* *Prepared by: Hanson.xyz Development Team* diff --git a/db-snapshots/db-snapshot.sql b/db-snapshots/db-snapshot.sql index 869c10b0..afbe73f5 100644 --- a/db-snapshots/db-snapshot.sql +++ b/db-snapshots/db-snapshot.sql @@ -15,6 +15,261 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- +-- Table structure for table `wp_aiowps_audit_log` +-- + +DROP TABLE IF EXISTS `wp_aiowps_audit_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_audit_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `network_id` bigint NOT NULL DEFAULT '0', + `site_id` bigint NOT NULL DEFAULT '0', + `username` varchar(60) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `ip` varchar(45) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `level` varchar(25) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `event_type` varchar(25) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `details` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `stacktrace` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `created` int unsigned DEFAULT NULL, + `country_code` varchar(50) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `username` (`username`), + KEY `ip` (`ip`), + KEY `level` (`level`), + KEY `event_type` (`event_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_audit_log` +-- + +LOCK TABLES `wp_aiowps_audit_log` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_audit_log` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_audit_log` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_debug_log` +-- + +DROP TABLE IF EXISTS `wp_aiowps_debug_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_debug_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `created` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `logtime` int unsigned DEFAULT NULL, + `level` varchar(25) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `network_id` bigint NOT NULL DEFAULT '0', + `site_id` bigint NOT NULL DEFAULT '0', + `message` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `type` varchar(25) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_debug_log` +-- + +LOCK TABLES `wp_aiowps_debug_log` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_debug_log` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_debug_log` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_events` +-- + +DROP TABLE IF EXISTS `wp_aiowps_events`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_events` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `event_type` varchar(150) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `username` varchar(150) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + `user_id` bigint DEFAULT NULL, + `event_date` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `created` int unsigned DEFAULT NULL, + `ip_or_host` varchar(100) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + `referer_info` varchar(255) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + `url` varchar(255) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + `country_code` varchar(50) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL, + `event_data` longtext COLLATE utf8mb4_unicode_520_ci, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_events` +-- + +LOCK TABLES `wp_aiowps_events` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_events` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_events` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_global_meta` +-- + +DROP TABLE IF EXISTS `wp_aiowps_global_meta`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_global_meta` ( + `meta_id` bigint NOT NULL AUTO_INCREMENT, + `date_time` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `created` int unsigned DEFAULT NULL, + `meta_key1` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_key2` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_key3` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_key4` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_key5` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_value1` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_value2` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_value3` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_value4` longtext COLLATE utf8mb4_unicode_520_ci NOT NULL, + `meta_value5` longtext COLLATE utf8mb4_unicode_520_ci NOT NULL, + PRIMARY KEY (`meta_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_global_meta` +-- + +LOCK TABLES `wp_aiowps_global_meta` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_global_meta` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_global_meta` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_logged_in_users` +-- + +DROP TABLE IF EXISTS `wp_aiowps_logged_in_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_logged_in_users` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `username` varchar(60) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `ip_address` varchar(45) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `site_id` bigint NOT NULL, + `created` int unsigned DEFAULT NULL, + `expires` int unsigned DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `unique_user_id` (`user_id`), + KEY `created` (`created`), + KEY `expires` (`expires`), + KEY `user_id` (`user_id`), + KEY `site_id` (`site_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_logged_in_users` +-- + +LOCK TABLES `wp_aiowps_logged_in_users` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_logged_in_users` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_logged_in_users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_login_lockdown` +-- + +DROP TABLE IF EXISTS `wp_aiowps_login_lockdown`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_login_lockdown` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `user_login` varchar(150) COLLATE utf8mb4_unicode_520_ci NOT NULL, + `lockdown_date` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `created` int unsigned DEFAULT NULL, + `release_date` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `released` int unsigned DEFAULT NULL, + `failed_login_ip` varchar(100) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `lock_reason` varchar(128) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `unlock_key` varchar(128) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `is_lockout_email_sent` tinyint(1) NOT NULL DEFAULT '1', + `backtrace_log` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `ip_lookup_result` longtext COLLATE utf8mb4_unicode_520_ci, + PRIMARY KEY (`id`), + KEY `failed_login_ip` (`failed_login_ip`), + KEY `is_lockout_email_sent` (`is_lockout_email_sent`), + KEY `unlock_key` (`unlock_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_login_lockdown` +-- + +LOCK TABLES `wp_aiowps_login_lockdown` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_login_lockdown` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_login_lockdown` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_message_store` +-- + +DROP TABLE IF EXISTS `wp_aiowps_message_store`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_message_store` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `message_key` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `message_value` text COLLATE utf8mb4_unicode_520_ci NOT NULL, + `created` int unsigned DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_message_store` +-- + +LOCK TABLES `wp_aiowps_message_store` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_message_store` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_message_store` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `wp_aiowps_permanent_block` +-- + +DROP TABLE IF EXISTS `wp_aiowps_permanent_block`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `wp_aiowps_permanent_block` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `blocked_ip` varchar(100) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `block_reason` varchar(128) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `country_origin` varchar(50) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '', + `blocked_date` datetime NOT NULL DEFAULT '1000-10-10 10:00:00', + `created` int unsigned DEFAULT NULL, + `unblock` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `blocked_ip` (`blocked_ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `wp_aiowps_permanent_block` +-- + +LOCK TABLES `wp_aiowps_permanent_block` WRITE; +/*!40000 ALTER TABLE `wp_aiowps_permanent_block` DISABLE KEYS */; +/*!40000 ALTER TABLE `wp_aiowps_permanent_block` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `wp_commentmeta` -- @@ -134,7 +389,7 @@ CREATE TABLE `wp_options` ( PRIMARY KEY (`option_id`), UNIQUE KEY `option_name` (`option_name`), KEY `autoload` (`autoload`) -) ENGINE=InnoDB AUTO_INCREMENT=179 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +) ENGINE=InnoDB AUTO_INCREMENT=185 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -143,7 +398,7 @@ CREATE TABLE `wp_options` ( LOCK TABLES `wp_options` WRITE; /*!40000 ALTER TABLE `wp_options` DISABLE KEYS */; -INSERT INTO `wp_options` VALUES (1,'cron','a:10:{i:1764363747;a:1:{s:32:\"recovery_mode_clean_expired_keys\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:5:\"daily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:86400;}}}i:1764363748;a:1:{s:34:\"wp_privacy_delete_old_export_files\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"hourly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:3600;}}}i:1764367344;a:1:{s:16:\"wp_version_check\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:10:\"twicedaily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:43200;}}}i:1764369115;a:1:{s:30:\"wp_delete_temp_updater_backups\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"weekly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:604800;}}}i:1764369116;a:1:{s:27:\"acf_update_site_health_data\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"weekly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:604800;}}}i:1764369144;a:1:{s:17:\"wp_update_plugins\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:10:\"twicedaily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:43200;}}}i:1764370944;a:1:{s:16:\"wp_update_themes\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:10:\"twicedaily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:43200;}}}i:1764371307;a:1:{s:31:\"wpseo_permalink_structure_check\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:5:\"daily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:86400;}}}i:1764450148;a:1:{s:30:\"wp_site_health_scheduled_check\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"weekly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:604800;}}}s:7:\"version\";i:2;}','on'),(2,'siteurl','https://homeproz.dev.hanson.xyz','on'),(3,'home','https://homeproz.dev.hanson.xyz','on'),(4,'blogname','HomeProz','on'),(5,'blogdescription','','on'),(6,'users_can_register','0','on'),(7,'admin_email','brian@hanson.xyz','on'),(8,'start_of_week','1','on'),(9,'use_balanceTags','0','on'),(10,'use_smilies','1','on'),(11,'require_name_email','1','on'),(12,'comments_notify','1','on'),(13,'posts_per_rss','10','on'),(14,'rss_use_excerpt','0','on'),(15,'mailserver_url','mail.example.com','on'),(16,'mailserver_login','login@example.com','on'),(17,'mailserver_pass','','on'),(18,'mailserver_port','110','on'),(19,'default_category','1','on'),(20,'default_comment_status','open','on'),(21,'default_ping_status','open','on'),(22,'default_pingback_flag','1','on'),(23,'posts_per_page','10','on'),(24,'date_format','F j, Y','on'),(25,'time_format','g:i a','on'),(26,'links_updated_date_format','F j, Y g:i a','on'),(27,'comment_moderation','0','on'),(28,'moderation_notify','1','on'),(29,'permalink_structure','/%postname%/','on'),(30,'rewrite_rules','a:133:{s:11:\"^wp-json/?$\";s:22:\"index.php?rest_route=/\";s:14:\"^wp-json/(.*)?\";s:33:\"index.php?rest_route=/$matches[1]\";s:21:\"^index.php/wp-json/?$\";s:22:\"index.php?rest_route=/\";s:24:\"^index.php/wp-json/(.*)?\";s:33:\"index.php?rest_route=/$matches[1]\";s:17:\"^wp-sitemap\\.xml$\";s:23:\"index.php?sitemap=index\";s:17:\"^wp-sitemap\\.xsl$\";s:36:\"index.php?sitemap-stylesheet=sitemap\";s:23:\"^wp-sitemap-index\\.xsl$\";s:34:\"index.php?sitemap-stylesheet=index\";s:48:\"^wp-sitemap-([a-z]+?)-([a-z\\d_-]+?)-(\\d+?)\\.xml$\";s:75:\"index.php?sitemap=$matches[1]&sitemap-subtype=$matches[2]&paged=$matches[3]\";s:34:\"^wp-sitemap-([a-z]+?)-(\\d+?)\\.xml$\";s:47:\"index.php?sitemap=$matches[1]&paged=$matches[2]\";s:13:\"properties/?$\";s:28:\"index.php?post_type=property\";s:43:\"properties/feed/(feed|rdf|rss|rss2|atom)/?$\";s:45:\"index.php?post_type=property&feed=$matches[1]\";s:38:\"properties/(feed|rdf|rss|rss2|atom)/?$\";s:45:\"index.php?post_type=property&feed=$matches[1]\";s:30:\"properties/page/([0-9]{1,})/?$\";s:46:\"index.php?post_type=property&paged=$matches[1]\";s:47:\"category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:52:\"index.php?category_name=$matches[1]&feed=$matches[2]\";s:42:\"category/(.+?)/(feed|rdf|rss|rss2|atom)/?$\";s:52:\"index.php?category_name=$matches[1]&feed=$matches[2]\";s:23:\"category/(.+?)/embed/?$\";s:46:\"index.php?category_name=$matches[1]&embed=true\";s:35:\"category/(.+?)/page/?([0-9]{1,})/?$\";s:53:\"index.php?category_name=$matches[1]&paged=$matches[2]\";s:17:\"category/(.+?)/?$\";s:35:\"index.php?category_name=$matches[1]\";s:44:\"tag/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:42:\"index.php?tag=$matches[1]&feed=$matches[2]\";s:39:\"tag/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:42:\"index.php?tag=$matches[1]&feed=$matches[2]\";s:20:\"tag/([^/]+)/embed/?$\";s:36:\"index.php?tag=$matches[1]&embed=true\";s:32:\"tag/([^/]+)/page/?([0-9]{1,})/?$\";s:43:\"index.php?tag=$matches[1]&paged=$matches[2]\";s:14:\"tag/([^/]+)/?$\";s:25:\"index.php?tag=$matches[1]\";s:45:\"type/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:50:\"index.php?post_format=$matches[1]&feed=$matches[2]\";s:40:\"type/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:50:\"index.php?post_format=$matches[1]&feed=$matches[2]\";s:21:\"type/([^/]+)/embed/?$\";s:44:\"index.php?post_format=$matches[1]&embed=true\";s:33:\"type/([^/]+)/page/?([0-9]{1,})/?$\";s:51:\"index.php?post_format=$matches[1]&paged=$matches[2]\";s:15:\"type/([^/]+)/?$\";s:33:\"index.php?post_format=$matches[1]\";s:38:\"properties/[^/]+/attachment/([^/]+)/?$\";s:32:\"index.php?attachment=$matches[1]\";s:48:\"properties/[^/]+/attachment/([^/]+)/trackback/?$\";s:37:\"index.php?attachment=$matches[1]&tb=1\";s:68:\"properties/[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:63:\"properties/[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:63:\"properties/[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$\";s:50:\"index.php?attachment=$matches[1]&cpage=$matches[2]\";s:44:\"properties/[^/]+/attachment/([^/]+)/embed/?$\";s:43:\"index.php?attachment=$matches[1]&embed=true\";s:27:\"properties/([^/]+)/embed/?$\";s:41:\"index.php?property=$matches[1]&embed=true\";s:31:\"properties/([^/]+)/trackback/?$\";s:35:\"index.php?property=$matches[1]&tb=1\";s:51:\"properties/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:47:\"index.php?property=$matches[1]&feed=$matches[2]\";s:46:\"properties/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:47:\"index.php?property=$matches[1]&feed=$matches[2]\";s:39:\"properties/([^/]+)/page/?([0-9]{1,})/?$\";s:48:\"index.php?property=$matches[1]&paged=$matches[2]\";s:46:\"properties/([^/]+)/comment-page-([0-9]{1,})/?$\";s:48:\"index.php?property=$matches[1]&cpage=$matches[2]\";s:35:\"properties/([^/]+)(?:/([0-9]+))?/?$\";s:47:\"index.php?property=$matches[1]&page=$matches[2]\";s:27:\"properties/[^/]+/([^/]+)/?$\";s:32:\"index.php?attachment=$matches[1]\";s:37:\"properties/[^/]+/([^/]+)/trackback/?$\";s:37:\"index.php?attachment=$matches[1]&tb=1\";s:57:\"properties/[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\"properties/[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\"properties/[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$\";s:50:\"index.php?attachment=$matches[1]&cpage=$matches[2]\";s:33:\"properties/[^/]+/([^/]+)/embed/?$\";s:43:\"index.php?attachment=$matches[1]&embed=true\";s:54:\"property-type/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:52:\"index.php?property_type=$matches[1]&feed=$matches[2]\";s:49:\"property-type/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:52:\"index.php?property_type=$matches[1]&feed=$matches[2]\";s:30:\"property-type/([^/]+)/embed/?$\";s:46:\"index.php?property_type=$matches[1]&embed=true\";s:42:\"property-type/([^/]+)/page/?([0-9]{1,})/?$\";s:53:\"index.php?property_type=$matches[1]&paged=$matches[2]\";s:24:\"property-type/([^/]+)/?$\";s:35:\"index.php?property_type=$matches[1]\";s:56:\"property-status/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:54:\"index.php?property_status=$matches[1]&feed=$matches[2]\";s:51:\"property-status/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:54:\"index.php?property_status=$matches[1]&feed=$matches[2]\";s:32:\"property-status/([^/]+)/embed/?$\";s:48:\"index.php?property_status=$matches[1]&embed=true\";s:44:\"property-status/([^/]+)/page/?([0-9]{1,})/?$\";s:55:\"index.php?property_status=$matches[1]&paged=$matches[2]\";s:26:\"property-status/([^/]+)/?$\";s:37:\"index.php?property_status=$matches[1]\";s:49:\"location/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:56:\"index.php?property_location=$matches[1]&feed=$matches[2]\";s:44:\"location/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:56:\"index.php?property_location=$matches[1]&feed=$matches[2]\";s:25:\"location/([^/]+)/embed/?$\";s:50:\"index.php?property_location=$matches[1]&embed=true\";s:37:\"location/([^/]+)/page/?([0-9]{1,})/?$\";s:57:\"index.php?property_location=$matches[1]&paged=$matches[2]\";s:19:\"location/([^/]+)/?$\";s:39:\"index.php?property_location=$matches[1]\";s:12:\"robots\\.txt$\";s:18:\"index.php?robots=1\";s:13:\"favicon\\.ico$\";s:19:\"index.php?favicon=1\";s:12:\"sitemap\\.xml\";s:24:\"index.php??sitemap=index\";s:48:\".*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\\.php$\";s:18:\"index.php?feed=old\";s:20:\".*wp-app\\.php(/.*)?$\";s:19:\"index.php?error=403\";s:18:\".*wp-register.php$\";s:23:\"index.php?register=true\";s:32:\"feed/(feed|rdf|rss|rss2|atom)/?$\";s:27:\"index.php?&feed=$matches[1]\";s:27:\"(feed|rdf|rss|rss2|atom)/?$\";s:27:\"index.php?&feed=$matches[1]\";s:8:\"embed/?$\";s:21:\"index.php?&embed=true\";s:20:\"page/?([0-9]{1,})/?$\";s:28:\"index.php?&paged=$matches[1]\";s:27:\"comment-page-([0-9]{1,})/?$\";s:39:\"index.php?&page_id=10&cpage=$matches[1]\";s:41:\"comments/feed/(feed|rdf|rss|rss2|atom)/?$\";s:42:\"index.php?&feed=$matches[1]&withcomments=1\";s:36:\"comments/(feed|rdf|rss|rss2|atom)/?$\";s:42:\"index.php?&feed=$matches[1]&withcomments=1\";s:17:\"comments/embed/?$\";s:21:\"index.php?&embed=true\";s:44:\"search/(.+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:40:\"index.php?s=$matches[1]&feed=$matches[2]\";s:39:\"search/(.+)/(feed|rdf|rss|rss2|atom)/?$\";s:40:\"index.php?s=$matches[1]&feed=$matches[2]\";s:20:\"search/(.+)/embed/?$\";s:34:\"index.php?s=$matches[1]&embed=true\";s:32:\"search/(.+)/page/?([0-9]{1,})/?$\";s:41:\"index.php?s=$matches[1]&paged=$matches[2]\";s:14:\"search/(.+)/?$\";s:23:\"index.php?s=$matches[1]\";s:47:\"author/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:50:\"index.php?author_name=$matches[1]&feed=$matches[2]\";s:42:\"author/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:50:\"index.php?author_name=$matches[1]&feed=$matches[2]\";s:23:\"author/([^/]+)/embed/?$\";s:44:\"index.php?author_name=$matches[1]&embed=true\";s:35:\"author/([^/]+)/page/?([0-9]{1,})/?$\";s:51:\"index.php?author_name=$matches[1]&paged=$matches[2]\";s:17:\"author/([^/]+)/?$\";s:33:\"index.php?author_name=$matches[1]\";s:69:\"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/feed/(feed|rdf|rss|rss2|atom)/?$\";s:80:\"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&feed=$matches[4]\";s:64:\"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/(feed|rdf|rss|rss2|atom)/?$\";s:80:\"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&feed=$matches[4]\";s:45:\"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/embed/?$\";s:74:\"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&embed=true\";s:57:\"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/page/?([0-9]{1,})/?$\";s:81:\"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&paged=$matches[4]\";s:39:\"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$\";s:63:\"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]\";s:56:\"([0-9]{4})/([0-9]{1,2})/feed/(feed|rdf|rss|rss2|atom)/?$\";s:64:\"index.php?year=$matches[1]&monthnum=$matches[2]&feed=$matches[3]\";s:51:\"([0-9]{4})/([0-9]{1,2})/(feed|rdf|rss|rss2|atom)/?$\";s:64:\"index.php?year=$matches[1]&monthnum=$matches[2]&feed=$matches[3]\";s:32:\"([0-9]{4})/([0-9]{1,2})/embed/?$\";s:58:\"index.php?year=$matches[1]&monthnum=$matches[2]&embed=true\";s:44:\"([0-9]{4})/([0-9]{1,2})/page/?([0-9]{1,})/?$\";s:65:\"index.php?year=$matches[1]&monthnum=$matches[2]&paged=$matches[3]\";s:26:\"([0-9]{4})/([0-9]{1,2})/?$\";s:47:\"index.php?year=$matches[1]&monthnum=$matches[2]\";s:43:\"([0-9]{4})/feed/(feed|rdf|rss|rss2|atom)/?$\";s:43:\"index.php?year=$matches[1]&feed=$matches[2]\";s:38:\"([0-9]{4})/(feed|rdf|rss|rss2|atom)/?$\";s:43:\"index.php?year=$matches[1]&feed=$matches[2]\";s:19:\"([0-9]{4})/embed/?$\";s:37:\"index.php?year=$matches[1]&embed=true\";s:31:\"([0-9]{4})/page/?([0-9]{1,})/?$\";s:44:\"index.php?year=$matches[1]&paged=$matches[2]\";s:13:\"([0-9]{4})/?$\";s:26:\"index.php?year=$matches[1]\";s:27:\".?.+?/attachment/([^/]+)/?$\";s:32:\"index.php?attachment=$matches[1]\";s:37:\".?.+?/attachment/([^/]+)/trackback/?$\";s:37:\"index.php?attachment=$matches[1]&tb=1\";s:57:\".?.+?/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\".?.+?/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\".?.+?/attachment/([^/]+)/comment-page-([0-9]{1,})/?$\";s:50:\"index.php?attachment=$matches[1]&cpage=$matches[2]\";s:33:\".?.+?/attachment/([^/]+)/embed/?$\";s:43:\"index.php?attachment=$matches[1]&embed=true\";s:16:\"(.?.+?)/embed/?$\";s:41:\"index.php?pagename=$matches[1]&embed=true\";s:20:\"(.?.+?)/trackback/?$\";s:35:\"index.php?pagename=$matches[1]&tb=1\";s:40:\"(.?.+?)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:47:\"index.php?pagename=$matches[1]&feed=$matches[2]\";s:35:\"(.?.+?)/(feed|rdf|rss|rss2|atom)/?$\";s:47:\"index.php?pagename=$matches[1]&feed=$matches[2]\";s:28:\"(.?.+?)/page/?([0-9]{1,})/?$\";s:48:\"index.php?pagename=$matches[1]&paged=$matches[2]\";s:35:\"(.?.+?)/comment-page-([0-9]{1,})/?$\";s:48:\"index.php?pagename=$matches[1]&cpage=$matches[2]\";s:24:\"(.?.+?)(?:/([0-9]+))?/?$\";s:47:\"index.php?pagename=$matches[1]&page=$matches[2]\";s:27:\"[^/]+/attachment/([^/]+)/?$\";s:32:\"index.php?attachment=$matches[1]\";s:37:\"[^/]+/attachment/([^/]+)/trackback/?$\";s:37:\"index.php?attachment=$matches[1]&tb=1\";s:57:\"[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\"[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:52:\"[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$\";s:50:\"index.php?attachment=$matches[1]&cpage=$matches[2]\";s:33:\"[^/]+/attachment/([^/]+)/embed/?$\";s:43:\"index.php?attachment=$matches[1]&embed=true\";s:16:\"([^/]+)/embed/?$\";s:37:\"index.php?name=$matches[1]&embed=true\";s:20:\"([^/]+)/trackback/?$\";s:31:\"index.php?name=$matches[1]&tb=1\";s:40:\"([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:43:\"index.php?name=$matches[1]&feed=$matches[2]\";s:35:\"([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:43:\"index.php?name=$matches[1]&feed=$matches[2]\";s:28:\"([^/]+)/page/?([0-9]{1,})/?$\";s:44:\"index.php?name=$matches[1]&paged=$matches[2]\";s:35:\"([^/]+)/comment-page-([0-9]{1,})/?$\";s:44:\"index.php?name=$matches[1]&cpage=$matches[2]\";s:24:\"([^/]+)(?:/([0-9]+))?/?$\";s:43:\"index.php?name=$matches[1]&page=$matches[2]\";s:16:\"[^/]+/([^/]+)/?$\";s:32:\"index.php?attachment=$matches[1]\";s:26:\"[^/]+/([^/]+)/trackback/?$\";s:37:\"index.php?attachment=$matches[1]&tb=1\";s:46:\"[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:41:\"[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$\";s:49:\"index.php?attachment=$matches[1]&feed=$matches[2]\";s:41:\"[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$\";s:50:\"index.php?attachment=$matches[1]&cpage=$matches[2]\";s:22:\"[^/]+/([^/]+)/embed/?$\";s:43:\"index.php?attachment=$matches[1]&embed=true\";}','on'),(31,'hack_file','0','on'),(32,'blog_charset','UTF-8','on'),(33,'moderation_keys','','off'),(34,'active_plugins','a:4:{i:0;s:30:\"advanced-custom-fields/acf.php\";i:1;s:36:\"contact-form-7/wp-contact-form-7.php\";i:2;s:53:\"webp-converter-for-media/webp-converter-for-media.php\";i:3;s:24:\"wordpress-seo/wp-seo.php\";}','on'),(35,'category_base','','on'),(36,'ping_sites','https://rpc.pingomatic.com/','on'),(37,'comment_max_links','2','on'),(38,'gmt_offset','0','on'),(39,'default_email_category','1','on'),(40,'recently_edited','','off'),(41,'template','homeproz','on'),(42,'stylesheet','homeproz','on'),(43,'comment_registration','0','on'),(44,'html_type','text/html','on'),(45,'use_trackback','0','on'),(46,'default_role','subscriber','on'),(47,'db_version','60421','on'),(48,'uploads_use_yearmonth_folders','1','on'),(49,'upload_path','','on'),(50,'blog_public','1','on'),(51,'default_link_category','2','on'),(52,'show_on_front','page','on'),(53,'tag_base','','on'),(54,'show_avatars','1','on'),(55,'avatar_rating','G','on'),(56,'upload_url_path','','on'),(57,'thumbnail_size_w','150','on'),(58,'thumbnail_size_h','150','on'),(59,'thumbnail_crop','1','on'),(60,'medium_size_w','300','on'),(61,'medium_size_h','300','on'),(62,'avatar_default','mystery','on'),(63,'large_size_w','1024','on'),(64,'large_size_h','1024','on'),(65,'image_default_link_type','none','on'),(66,'image_default_size','','on'),(67,'image_default_align','','on'),(68,'close_comments_for_old_posts','0','on'),(69,'close_comments_days_old','14','on'),(70,'thread_comments','1','on'),(71,'thread_comments_depth','5','on'),(72,'page_comments','0','on'),(73,'comments_per_page','50','on'),(74,'default_comments_page','newest','on'),(75,'comment_order','asc','on'),(76,'sticky_posts','a:0:{}','on'),(77,'widget_categories','a:0:{}','on'),(78,'widget_text','a:0:{}','on'),(79,'widget_rss','a:0:{}','on'),(80,'uninstall_plugins','a:2:{s:24:\"wordpress-seo/wp-seo.php\";s:14:\"__return_false\";s:53:\"webp-converter-for-media/webp-converter-for-media.php\";a:2:{i:0;s:37:\"WebpConverter\\Plugin\\UninstallHandler\";i:1;s:22:\"load_uninstall_actions\";}}','off'),(81,'timezone_string','','on'),(82,'page_for_posts','9','on'),(83,'page_on_front','10','on'),(84,'default_post_format','0','on'),(85,'link_manager_enabled','0','on'),(86,'finished_splitting_shared_terms','1','on'),(87,'site_icon','0','on'),(88,'medium_large_size_w','768','on'),(89,'medium_large_size_h','0','on'),(90,'wp_page_for_privacy_policy','3','on'),(91,'show_comments_cookies_opt_in','1','on'),(92,'admin_email_lifespan','1779915744','on'),(93,'disallowed_keys','','off'),(94,'comment_previously_approved','1','on'),(95,'auto_plugin_theme_update_emails','a:0:{}','off'),(96,'auto_update_core_dev','enabled','on'),(97,'auto_update_core_minor','enabled','on'),(98,'auto_update_core_major','enabled','on'),(99,'wp_force_deactivated_plugins','a:0:{}','on'),(100,'wp_attachment_pages_enabled','1','on'),(101,'initial_db_version','60421','on'),(102,'wp_user_roles','a:7:{s:13:\"administrator\";a:2:{s:4:\"name\";s:13:\"Administrator\";s:12:\"capabilities\";a:62:{s:13:\"switch_themes\";b:1;s:11:\"edit_themes\";b:1;s:16:\"activate_plugins\";b:1;s:12:\"edit_plugins\";b:1;s:10:\"edit_users\";b:1;s:10:\"edit_files\";b:1;s:14:\"manage_options\";b:1;s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:6:\"import\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:8:\"level_10\";b:1;s:7:\"level_9\";b:1;s:7:\"level_8\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:12:\"delete_users\";b:1;s:12:\"create_users\";b:1;s:17:\"unfiltered_upload\";b:1;s:14:\"edit_dashboard\";b:1;s:14:\"update_plugins\";b:1;s:14:\"delete_plugins\";b:1;s:15:\"install_plugins\";b:1;s:13:\"update_themes\";b:1;s:14:\"install_themes\";b:1;s:11:\"update_core\";b:1;s:10:\"list_users\";b:1;s:12:\"remove_users\";b:1;s:13:\"promote_users\";b:1;s:18:\"edit_theme_options\";b:1;s:13:\"delete_themes\";b:1;s:6:\"export\";b:1;s:20:\"wpseo_manage_options\";b:1;}}s:6:\"editor\";a:2:{s:4:\"name\";s:6:\"Editor\";s:12:\"capabilities\";a:36:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:15:\"wpseo_bulk_edit\";b:1;s:28:\"wpseo_edit_advanced_metadata\";b:1;}}s:6:\"author\";a:2:{s:4:\"name\";s:6:\"Author\";s:12:\"capabilities\";a:10:{s:12:\"upload_files\";b:1;s:10:\"edit_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;s:22:\"delete_published_posts\";b:1;}}s:11:\"contributor\";a:2:{s:4:\"name\";s:11:\"Contributor\";s:12:\"capabilities\";a:5:{s:10:\"edit_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;}}s:10:\"subscriber\";a:2:{s:4:\"name\";s:10:\"Subscriber\";s:12:\"capabilities\";a:2:{s:4:\"read\";b:1;s:7:\"level_0\";b:1;}}s:13:\"wpseo_manager\";a:2:{s:4:\"name\";s:11:\"SEO Manager\";s:12:\"capabilities\";a:38:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:15:\"wpseo_bulk_edit\";b:1;s:28:\"wpseo_edit_advanced_metadata\";b:1;s:20:\"wpseo_manage_options\";b:1;s:23:\"view_site_health_checks\";b:1;}}s:12:\"wpseo_editor\";a:2:{s:4:\"name\";s:10:\"SEO Editor\";s:12:\"capabilities\";a:36:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:15:\"wpseo_bulk_edit\";b:1;s:28:\"wpseo_edit_advanced_metadata\";b:1;}}}','on'),(103,'fresh_site','0','off'),(104,'user_count','1','off'),(105,'widget_block','a:6:{i:2;a:1:{s:7:\"content\";s:19:\"\";}i:3;a:1:{s:7:\"content\";s:154:\"
+ + + 'search-submit')); ?> +
+ link) with the list + * of views available on this table. + * + * @since 3.1.0 + * + * @return array + */ + protected function get_views() { + return array(); + } + + /** + * Display the list of views available on this table. + * + * @since 3.1.0 + */ + public function views() { + $views = $this->get_views(); + /** + * Filters the list of available list table views. + * + * The dynamic portion of the hook name, `$this->screen->id`, refers + * to the ID of the current screen, usually a string. + * + * @since 3.5.0 + * + * @param string[] - $views An array of available list table views. + */ + $views = apply_filters("views_{$this->screen->id}", $views); + + if (empty($views)) { + return; + } + + $this->screen->render_screen_reader_content('heading_views'); + + echo "+ + + 'search-submit')); ?> +
+ link) with the list + * of views available on this table. + * + * @since 3.1.0 + * + * @return array + */ + protected function get_views() { + return array(); + } + + /** + * Display the list of views available on this table. + * + * @since 3.1.0 + */ + public function views() { + $views = $this->get_views(); + /** + * Filters the list of available list table views. + * + * The dynamic portion of the hook name, `$this->screen->id`, refers + * to the ID of the current screen, usually a string. + * + * @since 3.5.0 + * + * @param string[] $views An array of available list table views. + */ + $views = apply_filters("views_{$this->screen->id}", $views); + + if (empty($views)) { + return; + } + + $this->screen->render_screen_reader_content('heading_views'); + + echo "'; + $message .= esc_html__('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'); + $message .= '
'; + if ($return_instead_of_echo) return $message; + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML. + echo $message; + } + + /** + * Render settings successfully updated message + * + * @param bool $return_instead_of_echo - This is used for when the function needs to return the message + * + * @return string|void + */ + public static function show_msg_settings_updated_st($return_instead_of_echo = false) { + $message = ''; + $message .= esc_html__('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'); + $message .= '
'; + $message .= wp_kses_post($msg); + $message .= '
'; + $message .= wp_kses_post($msg); + $message .= '
'; + $message .= wp_kses_post($error_msg); + $message .= '
'; + $message .= wp_kses_post($error_msg); + $message .= '
' . esc_html__('Your Cloudflare Turnstile configuration is invalid.', 'all-in-one-wp-security-and-firewall').' ' . esc_html__('Please enter the correct Cloudflare Turnstile keys below to use the Turnstile feature.', 'all-in-one-wp-security-and-firewall').'
' . esc_html__('Your Google reCAPTCHA configuration is invalid.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Please enter the correct reCAPTCHA keys below to use the reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall').'
X +
+ + + + + + array( + 'name' => __('Admin username', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG, + ), + 'user-login-login-lockdown' => array( + 'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG . '&tab=login-lockout', + ), + 'filesystem-file-permissions' => array( + 'name' => __('File permission', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG, + 'feature_callback' => 'is_main_site' + ), + 'firewall-basic-rules' => array( + 'name' => __('Basic firewall', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_FIREWALL_MENU_SLUG . '&tab=htaccess-rules', + 'feature_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') + ), + 'db-security-db-prefix' => array( + 'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_DB_SEC_MENU_SLUG, + 'feature_callback' => 'is_main_site' + ), + 'filesystem-file-editing' => array( + 'name' => __('PHP file editing', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG . '&tab=file-protection', + 'feature_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin') + ), + 'bf-rename-login-page' => array( + 'name' => __('Renamed login page', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_BRUTE_FORCE_MENU_SLUG, + ), + 'wp-generator-meta-tag' => array( + 'name' => __('Hidden WP meta info', 'all-in-one-wp-security-and-firewall'), + 'url' => AIOWPSEC_SETTINGS_MENU_SLUG . '&tab=wp-version-info', + ), + ); + + $critical_features = apply_filters('aiowps_filter_critical_features_array', $critical_features); + $critical_features = array_filter($critical_features, array($this, 'should_add_feature')); + + esc_html_e('Below is the current status of the critical features that you should activate on your site to achieve a minimum level of recommended security', 'all-in-one-wp-security-and-firewall'); + echo '' . esc_html__('No data found.', 'all-in-one-wp-security-and-firewall') . '
'; + } else { + $login_summary_table_data = array(); + //$login_summary_table_data['title'] = __('Last 5 login summary:', 'all-in-one-wp-security-and-firewall'); + $login_summary_table_data['columns'] = array(__('User', 'all-in-one-wp-security-and-firewall'), __('Date', 'all-in-one-wp-security-and-firewall'), 'IP'); + foreach ($data as $entry) { + $login_summary_table_data['data'][] = array($entry['username'], gmdate('Y-m-d H:i:s', $entry['created']), $entry['ip']); + } + $login_summary_table_data = apply_filters('aios_last5_logins_summary', $login_summary_table_data, $data); + $this->dashboard_widget($login_summary_table_data); + + // View all login logs + echo '' . esc_html__('View all', 'all-in-one-wp-security-and-firewall') . '
'; + } + + echo ''; + } + + public function widget_maintenance_mode_status() { + global $aio_wp_security; + ?> ++ configs->get_value('aiowps_site_lockout')) { + echo esc_html__('Maintenance mode is currently enabled.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Remember to disable it when you are done.', 'all-in-one-wp-security-and-firewall'); + } else { + echo esc_html__('Maintenance mode is currently disabled.', 'all-in-one-wp-security-and-firewall'); + } + ?> +
+ +| : | +
+
+ configs->get_value('aiowps_site_lockout')); ?>
+
+ |
+
|---|
' . sprintf(esc_html__('The %s feature is currently active.', 'all-in-one-wp-security-and-firewall'), $brute_force_login_feature_link) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above. + echo '' . esc_html__('Your new WordPress login URL is now:', 'all-in-one-wp-security-and-firewall') . '
'; + echo '' . esc_url(AIOWPSEC_WP_URL) . '/?' . esc_html($brute_force_feature_secret_word) . '=1
'; + echo '' . sprintf(esc_html__('The %s feature is currently active.', 'all-in-one-wp-security-and-firewall'), $rename_login_feature_link) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above. + echo '' . esc_html__('Your new WordPress login URL is now:', 'all-in-one-wp-security-and-firewall') . '
'; + echo '' . esc_url($home_url) . esc_html($aio_wp_security->configs->get_value('aiowps_login_page_slug')) . '
'; + echo '' . esc_html($multiple_users_info_msg) . ' ' . esc_html($num_users) . '
'; + /* translators: %s: Users Online URL */ + $info_msg = '' . sprintf(esc_html__('Go to the %s menu to see more details', 'all-in-one-wp-security-and-firewall'), $users_online_link) . '
'; + echo $info_msg . '' . esc_html($single_user_info_msg) . '
' . esc_html__('There are no IP addresses currently locked out.', 'all-in-one-wp-security-and-firewall') . '
' . esc_html__('Number of temporarily locked out IP addresses:', 'all-in-one-wp-security-and-firewall') . ' ' . ' ' . esc_html($num_ips) . '
'; + /* translators: %s: Number of locked out IPs */ + $info_msg = '' . sprintf(esc_html__('Go to the %s menu to see more details', 'all-in-one-wp-security-and-firewall'), $locked_ips_link) . '
'; + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above. + echo $info_msg . ''.__('Error - Could not get tables or no tables found!', 'all-in-one-wp-security-and-firewall').'
'.__('Starting DB prefix change operations.....', 'all-in-one-wp-security-and-firewall').'
'; + + $info_msg_string .= ''.sprintf(__('Your WordPress system has a total of %s tables and your new DB prefix will be: %s', 'all-in-one-wp-security-and-firewall'), ''.$num_rows.'', ''.$table_new_prefix.'').'
'; + echo $info_msg_string; + + // Do a back of the config file + if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) { + echo ''.__('Failed to make a backup of the wp-config.php file.', 'all-in-one-wp-security-and-firewall') . ' ' .__('This operation will not go ahead.', 'all-in-one-wp-security-and-firewall').'
'.__('A backup copy of your wp-config.php file was created successfully!', 'all-in-one-wp-security-and-firewall').'
'; + } + + // Get multisite blog_ids if applicable + if (is_multisite()) { + $blog_ids = AIOWPSecurity_Utility::get_blog_ids(); + } + + // Rename all the table names + foreach ($result as $db_table) { + // Get table name with old prefix + $table_old_name = $db_table; + + if (strpos($table_old_name, $table_old_prefix) === 0) { + // Get table name with new prefix + $table_new_name = AIOWPSecurity_Utility::backquote($table_new_prefix . substr($table_old_name, $old_prefix_length)); + $table_old_name = AIOWPSecurity_Utility::backquote($table_old_name); + + // Write query to rename tables name + $sql = "RENAME TABLE ".$table_old_name." TO ".$table_new_name; + // $sql = "RENAME TABLE %s TO %s"; + + // Execute the query + if (false === $wpdb->query($sql)) { + $error = 1; + echo ''.sprintf(__('%s table name update failed', 'all-in-one-wp-security-and-firewall'), ''.$table_old_name.'').'
'; + $aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to change prefix of table ".$table_old_name, 4); + } else { + $table_count++; + } + } else { + continue; + } + } + if (1 == $error) { + echo ''.sprintf(__('Please change the prefix manually for the above tables to: %s', 'all-in-one-wp-security-and-firewall'), ''.$table_new_prefix.'').'
'; + } else { + echo ''.sprintf(__('%s tables had their prefix updated successfully!', 'all-in-one-wp-security-and-firewall'), ''.$table_count.'').'
'; + } + + // Let's check for mysql tables of type "view" + $this->alter_table_views($table_old_prefix, $table_new_prefix); + + // Get wp-config.php file contents and modify it with new info + $config_contents = file($config_file); + $prefix_match_string = '$table_prefix='; //this is our search string for the wp-config.php file + foreach ($config_contents as $line_num => $line) { + $no_ws_line = preg_replace('/\s+/', '', $line); //Strip white spaces + if (false !== strpos($no_ws_line, $prefix_match_string)) { + $prefix_parts = explode("=", $line); + $prefix_parts[1] = str_replace($table_old_prefix, $table_new_prefix, $prefix_parts[1]); + $config_contents[$line_num] = implode("=", $prefix_parts); + break; + } + } + // Now let's modify the wp-config.php file + if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) { + echo ''. __('wp-config.php file was updated successfully!', 'all-in-one-wp-security-and-firewall').'
'; + } else { + echo ''.sprintf(__('The "wp-config.php" file was not able to be modified.', 'all-in-one-wp-security-and-firewall').' '.__('Please modify this file manually using your favourite editor and search for variable "$table_prefix" and assign the following value to that variable: %s', 'all-in-one-wp-security-and-firewall'), ''.$table_new_prefix.'').'
'; + $aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to modify wp-config.php", 4); + } + + // Now let's update the options table + $update_option_table_query = $wpdb->prepare("UPDATE " . $table_new_prefix . "options SET option_name = '".$table_new_prefix ."user_roles' WHERE option_name = %s LIMIT 1", $table_old_prefix."user_roles"); + + if (false === $wpdb->query($update_option_table_query)) { + echo ''.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $table_new_prefix.'options', $table_old_prefix.'user_roles', $table_new_prefix.'user_roles').'
'; + $aio_wp_security->debug_logger->log_debug("DB Security Feature - Error when updating the options table", 4);//Log the highly unlikely event of DB error + } else { + echo ''. __('The options table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall') .'
'; + } + + // Now let's update the options tables for the multisite subsites if applicable + if (is_multisite()) { + if (!empty($blog_ids)) { + $main_site_id = get_main_site_id(); + foreach ($blog_ids as $blog_id) { + if ($blog_id == $main_site_id) continue; + $new_pref_and_site_id = $table_new_prefix.$blog_id.'_'; + $old_pref_and_site_id = $table_old_prefix.$blog_id.'_'; + $update_ms_option_table_query = $wpdb->prepare("UPDATE " . $new_pref_and_site_id . "options SET option_name = '".$new_pref_and_site_id."user_roles' WHERE option_name = %s LIMIT 1", $old_pref_and_site_id."user_roles"); + if (false === $wpdb->query($update_ms_option_table_query)) { + echo ''.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options', $old_pref_and_site_id.'user_roles', $new_pref_and_site_id.'user_roles').'
'; + $aio_wp_security->debug_logger->log_debug("DB change prefix feature - Error when updating the subsite options table: ".$new_pref_and_site_id.'options', 4);//Log the highly unlikely event of DB error + } else { + echo ''.sprintf(__('The %s table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options').'
'; + } + } + } + } + + //Now let's update the user meta table + $custom_sql = "SELECT user_id, meta_key FROM " . $table_new_prefix . "usermeta WHERE meta_key LIKE '" . $table_old_prefix . "%'"; + + $meta_keys = $wpdb->get_results($custom_sql); + + $error_update_usermeta = ''; + + // Update all meta_key field values which have the old table prefix in user_meta table + foreach ($meta_keys as $meta_key) { + // Create new meta key + $new_meta_key = $table_new_prefix . substr($meta_key->meta_key, $old_prefix_length); + + $update_user_meta_sql = $wpdb->prepare("UPDATE " . $table_new_prefix . "usermeta SET meta_key='" . $new_meta_key . "' WHERE meta_key=%s AND user_id=%s", $meta_key->meta_key, $meta_key->user_id); + + if (false === $wpdb->query($update_user_meta_sql)) { + $error_update_usermeta .= ''.sprintf(__('Error updating user_meta table where new meta_key = %s, old meta_key = %s and user_id = %s.', 'all-in-one-wp-security-and-firewall'), $new_meta_key, $meta_key->meta_key, $meta_key->user_id).'
'; + echo $error_update_usermeta; + $aio_wp_security->debug_logger->log_debug("DB Security Feature - Error updating user_meta table where new meta_key = ".$new_meta_key." old meta_key = ".$meta_key->meta_key." and user_id = ".$meta_key->user_id, 4);//Log the highly unlikely event of DB error + } + } + echo ''.__('The usermeta table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall').'
'; + // Display tasks finished message + $tasks_finished_msg_string = ''. __('The database prefix change tasks have been completed.', 'all-in-one-wp-security-and-firewall').'
'; + echo $tasks_finished_msg_string; + } + + /** + * This is an alternative to the deprecated "mysql_list_tables + * + * @param string $database - database name + * + * @returns array - an array of table names + */ + public function get_mysql_tables($database = '') { + global $aio_wp_security; + $tables = array(); + $list_tables_sql = "SHOW TABLES FROM `{$database}`;"; + $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); + + if ($mysqli->connect_errno) { + $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Database_Menu->get_mysql_tables() - DB connection error.", 4); + return false; + } + + $result = $mysqli->query($list_tables_sql, MYSQLI_USE_RESULT); + if ($result) { + //Alternative way to get the tables + while ($row = $result->fetch_assoc()) { + foreach ($row as $value) { + $tables[] = $value; + } + } + $result->close(); + } + $mysqli->close(); + return $tables; + } + + /** + * Will modify existing table view definitions to reflect the new DB prefix change + * + * @param string $old_db_prefix - old database prefix + * @param string $new_db_prefix - new database prefix + * + * @returns void + */ + private function alter_table_views($old_db_prefix, $new_db_prefix) { + global $wpdb, $aio_wp_security; + $db_name = $wpdb->dbname; + $info_msg_string = ''.__('Checking for MySQL tables of type "view".....', 'all-in-one-wp-security-and-firewall').'
'; + echo $info_msg_string; + + // get tables which are views + $query = "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA LIKE '".$db_name."'"; + $res = $wpdb->get_results($query); + if (empty($res)) return; + $view_count = 0; + foreach ($res as $item) { + $old_def = $item->VIEW_DEFINITION; + $new_def = AIOWPSecurity_Utility::str_replace_once($old_db_prefix, $new_db_prefix, $old_def); + $new_def = AIOWPSecurity_Utility::backquote($new_def); + + $view_name = AIOWPSecurity_Utility::backquote($item->TABLE_NAME); + $chg_view_sql = "ALTER VIEW $view_name AS $new_def"; + $view_res = $wpdb->query($chg_view_sql); + if (false === $view_res) { + echo ''.sprintf(__('Update of the following MySQL view definition failed: %s', 'all-in-one-wp-security-and-firewall'), $old_def).'
'; + $aio_wp_security->debug_logger->log_debug("Update of the following MySQL view definition failed: ".$old_def, 4);//Log the highly unlikely event of DB error + } else { + $view_count++; + } + } + if ($view_count > 0) { + echo ''.sprintf(__('%s view definitions were updated successfully.', 'all-in-one-wp-security-and-firewall'), ''.$view_count.'').'
'; + } + + return; + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filescan-menu.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filescan-menu.php new file mode 100755 index 00000000..73dc811c --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filescan-menu.php @@ -0,0 +1,75 @@ + array( + 'title' => __('File change detection', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_file_change_detect'), + ), + 'malware-scan' => array( + 'title' => __('Malware scan', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_malware_scan'), + ), + ); + + $this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab')); + } + + /** + * File change detection on your system files. + * + * @global $wpdb + * @global $aio_wp_security + * @global $aiowps_feature_mgr + */ + protected function render_file_change_detect() { + global $aio_wp_security; + + $aios_commands = new AIOWPSecurity_Commands(); + + $scanner_data = $aios_commands->get_scanner_data(); + + $aio_wp_security->include_template('wp-admin/scanner/file-change-detect.php', false, $scanner_data); + } + + /** + * Malware code scan on your system files. + * + * @return void + */ + protected function render_malware_scan() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/scanner/malware-scan.php', false, array()); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filesystem-menu.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filesystem-menu.php new file mode 100755 index 00000000..bfc86518 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-filesystem-menu.php @@ -0,0 +1,144 @@ + array( + 'title' => __('File permissions', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_file_permissions'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + 'file-protection' => array( + 'title' => __('File protection', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_file_protection'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + 'host-system-logs' => array( + 'title' => __('Host system logs', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_host_system_logs'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + 'copy-protection' => array( + 'title' => __('Copy protection', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_copy_protection'), + ), + 'frames' => array( + 'title' => __('Frames', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_frames'), + ), + ); + + $this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab')); + } + + /** + * Renders the submenu's file permissions tab + * + * @return Void + */ + protected function render_file_permissions() { + // if this is the case there is no need to display a "fix permissions" button + global $aio_wp_security, $aiowps_feature_mgr; + + $files_dirs_to_check = AIOWPSecurity_Utility_File::get_files_and_dirs_to_check(); + + + $aio_wp_security->include_template('wp-admin/filesystem-security/file-permissions.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'files_dirs_to_check' => $files_dirs_to_check, 'file_utility' => new AIOWPSecurity_Utility_File())); + } + + /** + * Renders the submenu's 'File protection' tab + * + * @return void + */ + protected function render_file_protection() { + global $aio_wp_security; + + $show_disallow_file_edit_warning = defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT && '1' != $aio_wp_security->configs->get_value('aiowps_disable_file_editing'); + + $aio_wp_security->include_template('wp-admin/filesystem-security/file-protection.php', false, array('show_disallow_file_edit_warning' => $show_disallow_file_edit_warning)); + } + + /** + * Renders the submenu's copy protection tab + * + * @return Void + */ + protected function render_copy_protection() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/filesystem-security/copy-protection.php', false, array()); + } + + /** + * Renders the submenu's render frames tab + * + * @return Void + */ + protected function render_frames() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/filesystem-security/frames.php', false, array()); + } + + /** + * Renders the submenu's host system logs tab + * + * @return Void + */ + protected function render_host_system_logs() { + global $aio_wp_security; + $sys_log_file = basename($aio_wp_security->configs->get_value('aiowps_system_log_file')); + $aio_wp_security->include_template('wp-admin/filesystem-security/host-system-logs.php', false, array('sys_log_file' => $sys_log_file)); + } + + /** + * Called via filter admin_footer, this adds the needed javascript to page + * + * @return void + */ + public function filesystem_menu_footer_code() { + ?> + + array( + 'title' => __('PHP rules', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_php_rules'), + ), + 'htaccess-rules' => array( + 'title' => __('.htaccess rules', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_htaccess_rules'), + 'display_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess'), + ), + '6g-firewall' => array( + 'title' => __('6G firewall rules', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_6g_firewall'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + '5g-firewall' => array( + 'title' => __('5G legacy rules', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_5g_firewall'), + 'display_condition_callback' => array('AIOWPSecurity_Utility', 'render_5g_legacy_tab'), + ), + 'internet-bots' => array( + 'title' => __('Internet bots', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_internet_bots'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + 'block-and-allow-lists' => array( + 'title' => __('Block & allow lists', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_block_and_allow_lists'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ), + 'advanced-settings' => array( + 'title' => __('Advanced settings', 'all-in-one-wp-security-and-firewall'), + 'render_callback' => array($this, 'render_advanced_settings'), + 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'), + ) + ); + + $this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab')); + } + + /** + * Renders the PHP Firewall settings tab + * + * @return void + */ + protected function render_php_rules() { + global $aio_wp_security; + + $aios_commands = new AIOWPSecurity_Commands(); + + $php_firewall_data = $aios_commands->get_php_firewall_data(); + + $aio_wp_security->include_template('wp-admin/firewall/php-firewall-rules.php', false, compact('php_firewall_data')); + } + + /** + * Renders the Htaccess Firewall tab + * + * @return void + */ + protected function render_htaccess_rules() { + global $aio_wp_security; + + $aios_commands = new AIOWPSecurity_Commands(); + + $htaccess_rules_data = $aios_commands->get_htaccess_rules_data(); + + $aio_wp_security->include_template('wp-admin/firewall/htaccess-firewall-rules.php', false, compact('htaccess_rules_data')); + } + + /** + * Renders the 6G Blacklist Firewall Rules tab + * + * @return void + */ + protected function render_6g_firewall() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/general/moved.php', false, array('key' => '6g')); + } + + /** + * Renders the 5G Blacklist Firewall Rules tab + * + * @return void + */ + protected function render_5g_firewall() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/firewall/5g.php'); + } + + /** + * Renders the Internet Bots tab + * + * @return void + */ + protected function render_internet_bots() { + global $aio_wp_security; + + $aio_wp_security->include_template('wp-admin/general/moved.php', false, array('key' => 'internet-bots')); + } + + + /** + * Renders the Advanced settings tab. + * + * @return void + */ + protected function render_advanced_settings() { + global $aio_wp_security; + + $aios_commands = new AIOWPSecurity_Commands(); + + $advanced_settings_data = $aios_commands->get_firewall_advanced_settings_data(); + + $aio_wp_security->include_template('wp-admin/firewall/advanced-settings.php', false, compact('advanced_settings_data')); + } + + /** + * Renders ban user tab for blacklist IPs and user agents + * + * @global $aio_wp_security + * @global $aiowps_feature_mgr + * + * @return void + */ + protected function render_block_and_allow_lists() { + global $aio_wp_security; + + $aios_commands = new AIOWPSecurity_Commands(); + + $block_allowlist_data = $aios_commands->get_block_allow_lists_data(); + + $aio_wp_security->include_template('wp-admin/firewall/block-and-allow-lists.php', false, $block_allowlist_data); + } + + /** + * Validates posted user agent list and set, save as config. + * + * @global $aio_wp_security + * @global $aiowps_firewall_config + * + * @param string $banned_user_agents + * + * @return int + */ + private function validate_user_agent_list($banned_user_agents) { + global $aio_wp_security; + $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); + $submitted_agents = AIOWPSecurity_Utility::splitby_newline_trim_filter_empty($banned_user_agents); + $agents = array_unique(array_filter(array_map('sanitize_text_field', $submitted_agents), 'strlen')); + $aio_wp_security->configs->set_value('aiowps_banned_user_agents', implode("\n", $agents)); + $aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', $agents); + $_POST['aiowps_banned_user_agents'] = ''; // Clear the post variable for the banned address list + return 1; + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-firewall-setup-notice.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-firewall-setup-notice.php new file mode 100755 index 00000000..17326037 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-firewall-setup-notice.php @@ -0,0 +1,646 @@ +bootstrap = AIOWPSecurity_Utility_Firewall::get_bootstrap_file(); + $this->wpconfig = AIOWPSecurity_Utility_Firewall::get_wpconfig_file(); + $this->muplugin = AIOWPSecurity_Utility_Firewall::get_muplugin_file(); + AIOWPSecurity_Utility_Firewall::get_firewall_rules_path(true); // Creates the needed directories for the first time. + } + + /** + * Entry point for the dashboard notice + * + * @return void + */ + public function start_firewall_setup() { + + global $aio_wp_security; + + $firewall_files = array( + 'server' => AIOWPSecurity_Utility_Firewall::get_server_file(), + 'bootstrap' => $this->bootstrap, + 'wpconfig' => $this->wpconfig, + 'muplugin' => $this->muplugin, + ); + + //Check each file and update the contents if necessary + foreach ($firewall_files as $name => $file) { + ${'is_firewall_in_'.$name} = false; + + if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP === $file) { + continue; + } + + ${'is_firewall_in_'.$name} = $file->contains_contents(); + + if (true === ${'is_firewall_in_'.$name}) { + $file->update_contents(); + } + } + + if (!$aio_wp_security->is_aiowps_admin_page()) { + return; + } + + if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) { + if (true !== $is_firewall_in_server) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- variable is set in the foreach loop + $this->render_upgrade_protection_notice(); + } + } else { + $this->render_automatic_setup_notice(); + } + + $this->render_notices(); + } + + /** + * Will execute when the user presses 'Set up now' button + * + * @return void + */ + public function do_setup() { + + $is_inserted_firewall_file = false; + + $is_inserted_bootstrap_file = $this->bootstrap->contains_contents(); + if (true !== $is_inserted_bootstrap_file) { + $is_inserted_bootstrap_file = $this->bootstrap->insert_contents(); + + if (true !== $is_inserted_bootstrap_file) { + $this->log_wp_error($is_inserted_bootstrap_file); + $this->show_notice(self::NOTICE_BOOTSTRAP); + return; + } + + } + + $firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file(); + + if ($firewall_file instanceof AIOWPSecurity_Block_Userini) { + + $directive = AIOWPSecurity_Utility_Firewall::get_already_set_directive($firewall_file); + + if (!empty($directive)) { + + if (AIOWPSecurity_Utility_Firewall::get_bootstrap_path() === $directive) { + $is_inserted_firewall_file = true; + } else { + $this->show_notice(self::NOTICE_DIRECTIVE_SET, array('directive' => $directive)); + } + + } else { + $is_inserted_firewall_file = $firewall_file->insert_contents(); + } + + } else { + + if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP !== $firewall_file) { + $is_inserted_firewall_file = $firewall_file->insert_contents(); // attempts to insert firewall into required file + } + } + + //Set up the firewall in the wp-config file + $is_inserted_wpconfig = $this->wpconfig->contains_contents(); + if (true !== $is_inserted_wpconfig) { + $is_inserted_wpconfig = $this->wpconfig->insert_contents(); + } + $this->log_wp_error($is_inserted_wpconfig); + + //Set up the firewall in the mu-plugin + $is_inserted_muplugin = $this->muplugin->contains_contents(); + if (true !== $is_inserted_muplugin) { + $is_inserted_muplugin = $this->muplugin->insert_contents(); + } + if (false === $is_inserted_muplugin) { + $this->log_wp_error(new \WP_Error( + 'file-mu-plugin-failed', + 'Unable to create the mu-plugin', + $this->muplugin + )); + } + $this->log_wp_error($is_inserted_muplugin); + + if (true === $is_inserted_firewall_file) { + $this->show_notice(self::NOTICE_INSTALLED); + } else { + $this->log_wp_error($is_inserted_firewall_file); + $this->show_notice(self::NOTICE_MANUAL); + } + + } + + /** + * Dismisses the notice. + * + * @return void + */ + private function do_dismiss() { + global $aio_wp_security; + + $aio_wp_security->configs->set_value('aios_firewall_dismiss', true, true); + } + + /** + * Checks whether the notice is dismissed + * + * @return boolean + */ + private function is_dismissed() { + global $aio_wp_security; + return (true === $aio_wp_security->configs->get_value('aios_firewall_dismiss')); + + } + + /** + * Handles the form submission for the 'Set up now' notice + * + * @return void + */ + public function handle_setup_form() { + $nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : ''; + $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-setup'); + if (!is_wp_error($result)) { + $this->do_setup(); + $this->do_redirect(); + } + } + + /** + * Handles the dismiss form + * + * @return void + */ + public function handle_dismiss_form() { + $nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : ''; + $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-setup-dismiss'); + if (!is_wp_error($result)) { + $this->do_dismiss(); + $this->do_redirect(); + } + } + + /** + * Handles the form that downgrades the firewall's protection. + * + * @return void + */ + public function handle_downgrade_protection_form() { + $nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : ''; + $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-downgrade'); + if (!is_wp_error($result)) { + AIOWPSecurity_Utility_Firewall::remove_firewall(); + $this->do_redirect(); + } + } + + /** + * Handles the redirect + * + * @return void + */ + private function do_redirect() { + + // Go back to the previous page and tab if set + if (isset($_POST['_wp_http_referer'])) { + + $matches = array(); + if (preg_match('/\?page='.AIOWPSEC_MENU_SLUG_PREFIX.'(?+ +
+ + + ++ bootstrap, PATHINFO_BASENAME)); + ?> +
+bootstrap); ?>+ +
bootstrap->get_contents()); ?>+ + render_try_again_button(); + $this->render_manual_notice_footer(); + } + + /** + * Notice is shown if auto_prepend_file directive is already set in user.ini + * + * @param string $directive_value + * @return void + */ + private function render_userini_directive_set_notice($directive_value) { + + $firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file(); + + $this->render_manual_notice_header(); + ?> +
+ +
++ +
+ ++ +
+ + + ++ +
+get_contents()); ?>+
+ +
+ render_try_again_button(); + $this->render_manual_notice_footer(); + } + + /** + * Shows when the firewall has successfully installed + * + * @return void + */ + private function render_firewall_installed_notice() { + global $aio_wp_security; + + $aio_wp_security->include_template('notices/firewall-installed-notice.php', false); + } + + /** + * Renders the 'manual setup' dashboard notice + * + * @return void + */ + private function render_manual_setup_notice() { + + $firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file(); + + if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP === $firewall_file) { + //Show users how to manually add the firewall via php.ini if we can't detect their server + $bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path(); + + $this->render_manual_notice_header(); + ?> ++ +
++ +
+ ++ +
+ render_manual_notice_footer(); + } else { + //Show users how to manually add the firewall via their own server file + $this->render_manual_notice_header(); + $firewall_file_name = pathinfo($firewall_file, PATHINFO_BASENAME); + ?> ++ +
+ +
+get_contents()); ?>+
+ +
+ render_try_again_button(); + $this->render_manual_notice_footer(); + } + } + + /** + * The header for notices that require manual intervention + * + * @return void + */ + private function render_manual_notice_header() { + ?> ++ +
++ +
++ +
+ ++ +
+'; + $error_msg .= esc_html__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'); + $error_msg .= '
'.esc_html__('You currently have no IP addresses permanently blocked due to spam.', 'all-in-one-wp-security-and-firewall').'
'.esc_html__('Spammer IPs added to permanent block list today:', 'all-in-one-wp-security-and-firewall'). ' ' . esc_html($todays_blocked_count).'
'.''.esc_html__('All time total:', 'all-in-one-wp-security-and-firewall'). ' ' .esc_html($total_count).'
'.''.esc_html__('View blocked IPs', 'all-in-one-wp-security-and-firewall').'
| '.esc_html(__('Account login name', 'all-in-one-wp-security-and-firewall')).' | ||
|---|---|---|
| '.esc_html($entry->user_login).' | '; + } else { + $account_output .= ''.esc_html($entry->user_login).' | '; + } + $user_acct_edit_link = admin_url('user-edit.php?user_id=' . $entry->ID); + $account_output .= ''.esc_html(__('Edit user', 'all-in-one-wp-security-and-firewall')).' | '; + $account_output .= '
' . __('Settings have not been saved - your secret word must consist only of alphanumeric characters i.e., letters and/or numbers only.', 'all-in-one-wp-security-and-firewall') . '
'; + $success = false; + } + + if (filter_var($redirect_url, FILTER_VALIDATE_URL)) { + $redirect_url = esc_url_raw($redirect_url); + } else { + $redirect_url = 'http://127.0.0.1'; + $info[] = __('You entered an invalid value for the redirect url.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall'); + } + + $options['aiowps_cookie_based_brute_force_redirect_url'] = $redirect_url; + + if ($success) { + $options['aiowps_enable_brute_force_attack_prevention'] = '1'; + $options['aiowps_brute_force_secret_word'] = $brute_force_feature_secret_word; + + $result = '' . __('You have successfully enabled the cookie based brute force prevention feature', 'all-in-one-wp-security-and-firewall') . '
'; + $result .= '' . __('From now on you will need to log into your WP Admin using the following URL:', 'all-in-one-wp-security-and-firewall') . '
'; + $result .= ''.AIOWPSEC_WP_URL.'/?'.esc_html($brute_force_feature_secret_word).'=1
'; + $result .= '' . __('It is important that you save this URL value somewhere in case you forget it, OR,', 'all-in-one-wp-security-and-firewall') . '
'; + $result .= '' . sprintf(__('simply remember to add a "?%s=1" to your current site URL address.', 'all-in-one-wp-security-and-firewall'), esc_html($brute_force_feature_secret_word)) . '
'; + AIOWPSecurity_Utility::set_cookie_value(AIOWPSecurity_Utility::get_brute_force_secret_cookie_name(), AIOS_Helper::get_hash($brute_force_feature_secret_word)); + } + } else { + $options['aiowps_enable_brute_force_attack_prevention'] = ''; + $message = __('You have successfully saved cookie based brute force prevention feature settings.', 'all-in-one-wp-security-and-firewall'); + $brute_force_feature_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word'); + $redirect_url = $aio_wp_security->configs->get_value('aiowps_cookie_based_brute_force_redirect_url'); + } + + $options['aiowps_brute_force_attack_prevention_pw_protected_exception'] = isset($data['aiowps_brute_force_attack_prevention_pw_protected_exception']) ? '1' : ''; + $options['aiowps_brute_force_attack_prevention_ajax_exception'] = isset($data['aiowps_brute_force_attack_prevention_ajax_exception']) ? '1' : ''; + + if ($success) { + $this->save_settings($options); + + AIOWPSecurity_Configure_Settings::set_cookie_based_bruteforce_firewall_configs(); + + $message = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'); + $values['aiowps_brute_force_secret_word'] = $brute_force_feature_secret_word; + $values['aiowps_cookie_based_brute_force_redirect_url'] = $redirect_url; + } + $content = array( + 'aios-brute-force-info-box' => $result + ); + + $badges = array("firewall-enable-brute-force-attack-prevention"); + + $args = array( + 'badges' => $badges, + 'info' => $info, + 'values' => $values, + 'content' => $content + ); + + return $this->handle_response($success, $message, $args); + } + + /** + * Handles the AJAX request for performing cookie test. + * + * @return array The response containing the status, message, and badge. + */ + public function perform_cookie_test() { + global $aio_wp_security; + + $success = true; + + $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10); + $test_cookie_name = 'aiowps_cookie_test_'.$random_suffix; + $aio_wp_security->configs->set_value('aiowps_cookie_brute_test', $test_cookie_name, true); + $set_cookie = AIOWPSecurity_Utility::set_cookie_value($test_cookie_name, '1'); + $aiowps_cookie_test_success = ''; + $args = array(); + + if ($set_cookie) { + $aiowps_cookie_test_success = '1'; + $message = __('The cookie test was successful, you can now enable this feature.', 'all-in-one-wp-security-and-firewall'); + $result = '' . __('The cookie test was successful, you can now enable this feature.', 'all-in-one-wp-security-and-firewall') . '
' . __('The cookie test failed on this server.', 'all-in-one-wp-security-and-firewall') .' '. __('Consequently, this feature cannot be used on this site.', 'all-in-one-wp-security-and-firewall') . '
'.esc_html__('You currently have no IP addresses permanently blocked due to spam.', 'all-in-one-wp-security-and-firewall').'
'; + } else { + $todays_blocked_count = $result->todays_blocked_count; + $total_count = $result->total_count; + + $block_comments_output .= ''.esc_html__('Spammer IPs added to permanent block list today:', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html($todays_blocked_count) . '
'; + $block_comments_output .= ''.esc_html__('All time total:', 'all-in-one-wp-security-and-firewall'). ' ' . $total_count.'
'; + $block_comments_output .= ''.esc_html__('View blocked IPs', 'all-in-one-wp-security-and-firewall').'
'; + } + $block_comments_output .= '' . __('You have configured your file change detection scan to occur at least once daily.', 'all-in-one-wp-security-and-firewall') . '
'; + $content['aios-file-change-info-box'] .= '' . __('For most websites we recommended that you choose a less frequent schedule such as once every few days, once a week or once a month.', 'all-in-one-wp-security-and-firewall') . '
'; + $content['aios-file-change-info-box'] .= '' . __('Choosing a less frequent schedule will also help reduce your server load.', 'all-in-one-wp-security-and-firewall') . '
'; + $content['aios-file-change-info-box'] .= '+ + + + + +
'.esc_html($ret->get_error_data()).'
', true)); + } else { + return $this->handle_response(true, AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The debug logs have been cleared.', 'all-in-one-wp-security-and-firewall'), true)); + } + } + + /** + * Renders the audit log tab content. + * + * This function handles the rendering of the audit log tab content based on the + * provided data via AJAX request. The data is used to filter the audit log or perform actions + * + * @access public + * @return void + */ + public function render_audit_log_tab() { + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. Nonce checked in previous function. + if (empty($_POST['data'])) return; + + // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later. + $data = wp_unslash($_POST['data']); + + // Needed for rendering the audit log table + include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php'); + $audit_log_list = new AIOWPSecurity_List_Audit_Log($data); + $audit_log_list->ajax_response(); + } + + /** + * Exports the audit logs as a CSV file and sends the data as an AJAX response. + * + * This function retrieves audit log data, prepares it for export, and generates a CSV string. + * The CSV data is then sent back as part of an AJAX response, along with the filename for the CSV file. + * + * @return array + */ + public function export_audit_logs() { + + // Needed for rendering the audit log table + include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php'); + $audit_log_list = new AIOWPSecurity_List_Audit_Log(); + + $audit_log_list->prepare_items(true); + $export_keys = array( + 'id' => 'ID', + 'created' => __('Date and time', 'all-in-one-wp-security-and-firewall'), + 'level' => __('Level', 'all-in-one-wp-security-and-firewall'), + 'network_id' => __('Network ID', 'all-in-one-wp-security-and-firewall'), + 'site_id' => __('Site ID', 'all-in-one-wp-security-and-firewall'), + 'username' => __('Username', 'all-in-one-wp-security-and-firewall'), + 'ip' => __('IP', 'all-in-one-wp-security-and-firewall'), + 'event_type' => __('Event', 'all-in-one-wp-security-and-firewall'), + 'details' => __('Details', 'all-in-one-wp-security-and-firewall'), + 'stacktrace' => __('Stack trace', 'all-in-one-wp-security-and-firewall') + ); + + $title = 'audit_event_logs.csv'; + ob_start(); + AIOWPSecurity_Admin_Init::aiowps_output_csv($audit_log_list->items, $export_keys, $title); + + $data = ob_get_clean(); + + return array( + 'title' => $title, + 'data' => $data + ); + } + + /** + * Initializing the WP List API, since UDC commands do not load all parts of WP. + * + * @return void + */ + private function init_wp_list() { + if (!function_exists('submit_button')) { + require_once(ABSPATH . 'wp-admin/includes/template.php'); + } + + if (!function_exists('render_screen_reader_content')) { + require_once(ABSPATH . 'wp-admin/includes/class-wp-screen.php'); + } + + if (!function_exists('get_column_headers')) { + require_once(ABSPATH . 'wp-admin/includes/screen.php'); + } + } + + /** + * Returns the data for downloading the audit log. + * + * @return array|WP_Error + */ + public function process_audit_log_export() { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + $this->init_wp_list(); + + return $this->export_audit_logs(); + } + + /** + * Returns the HTML for the audit log. + * + * @return array + */ + public function get_audit_log_contents() { + global $aio_wp_security; + + $this->init_wp_list(); + + // Needed for rendering the audit log table + include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-list-audit.php'; + $data = array(); + // phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. Processing form data without nonce verification. No nonce. + if (isset($_GET['event-filter'])) $data['event-filter'] = sanitize_text_field(wp_unslash($_GET['event-filter'])); // Failed logins and logins only to show as audit log + $audit_log_list = new AIOWPSecurity_List_Audit_Log($data); + + $tab = isset($_GET["tab"]) ? sanitize_text_field(wp_unslash($_GET["tab"])) : ''; + $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : ''; + // phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. Processing form data without nonce verification. No nonce. + + $content = $aio_wp_security->include_template('wp-admin/dashboard/audit-logs.php', true, array('audit_log_list' => $audit_log_list, 'page' => $page, 'tab' => $tab)); + + return array( + 'status' => 'success', + 'content' => $content, + ); + } + + /** + * Deletes entry from audit log. + * + * @param array $data Table config data. + * + * @return array|WP_Error + */ + public function do_delete_audit_log($data) { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + $this->init_wp_list(); + + if (!class_exists('AIOWPSecurity_Admin_Menu')) { + include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-admin-menu.php'; + } + + return $this->delete_audit_log($data); + } + + /** + * Renders audit log after actions (delete/orderby, block/unblock, etc.) + * + * @param array $data Table config data. + * + * @return array + */ + public function do_render_audit_log_tab($data) { + $this->init_wp_list(); + + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. Nonce checked in previous function. + if (empty($data)) return array(); + + // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later. + $data = wp_unslash($data); + + if (!class_exists('AIOWPSecurity_Admin_Menu')) { + include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-admin-menu.php'; + } + + // Needed for rendering the audit log table + include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php'); + $audit_log_list = new AIOWPSecurity_List_Audit_Log($data); + + return $audit_log_list->ajax_response(true); + } + + /** + * Parses raw audit log data for human-readable output. + * + * @param AIOWPSecurity_List_Audit_Log $audit_log_list Audit log object. + * @param array $data Raw audit log data. + * + * @return array + */ + private function parse_audit_log_data($audit_log_list, $data) { + $items = array(); + + foreach ($data as $db_item) { + if (empty($db_item)) { + continue; + } + + $item = array(); + + foreach ($db_item as $key => $value) { + switch ($key) { + case 'created': + $item[$key] = AIOWPSecurity_Utility::convert_timestamp($value); + break; + case 'event_type': + $item[$key] = $audit_log_list->column_event_type($db_item); + break; + case 'details': + $item[$key] = $audit_log_list->column_details($db_item); + break; + case 'stacktrace': + $item[$key] = $audit_log_list->column_stacktrace($db_item); + break; + default: + $item[$key] = $value; + break; + } + } + + $items[] = $item; + } + + return $items; + } + + /** + * Returns the data for the audit log table. + * + * @param array $data Configuration data. + * + * @return array + */ + public function get_audit_log_data($data) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later. + $data = isset($data) ? wp_unslash($data) : array(); + + $data = isset($data['data']) ? $data['data'] : $data; + + $this->init_wp_list(); + $final_column = array(); + + // Needed for rendering the audit log table + include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php'); + $audit_log_list = new AIOWPSecurity_List_Audit_Log($data); + + $audit_log_list->prepare_items(); + + list($columns, $hidden) = $audit_log_list->get_column_info(); + + foreach ($columns as $column_key => $column_display_name) { + if ('cb' !== $column_key) { + if (!in_array($column_key, $hidden, true)) { + $final_column[$column_key] = array('label' => $column_display_name); + } + } + } + + $audit_log_items = isset($audit_log_list->items) ? $audit_log_list->items : array(); + + foreach ($audit_log_items as $key => $item) { + $ip = isset($item['ip']) ? $item['ip'] : ''; + + if ('' !== $ip) { + $audit_log_items[$key]['is_ip_locked'] = AIOWPSecurity_Utility::check_locked_ip($ip, 'audit-log'); + $audit_log_items[$key]['is_ip_blacklisted'] = AIOWPSecurity_Utility::check_blacklist_ip($ip); + } + } + + $items = $this->parse_audit_log_data($audit_log_list, $audit_log_items); + + $bulk_actions = $audit_log_list->get_bulk_actions(); + + $paged = !empty($data['paged']) ? (int) $data['paged'] : 1; + + AIOWPSecurity_Audit_Events::setup_event_types(); + + return array( + 'audit_log_data' => array( + 'bulk_actions' => $bulk_actions, + 'event_types' => AIOWPSecurity_Audit_Events::$event_types, + 'log_levels' => AIOWPSecurity_Audit_Events::$log_levels, + 'columns' => $final_column, + 'items' => $items, + 'is_multisite' => is_multisite(), + 'pagination' => array('page' => $paged, 'pages' => $audit_log_list->get_pagination_arg('total_pages'), 'results' => $audit_log_list->get_pagination_arg('total_items')), + ), + ); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-settings-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-settings-commands.php new file mode 100755 index 00000000..59133c07 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-settings-commands.php @@ -0,0 +1,562 @@ +handle_response($success, $message, array('info' => $info)); + } + + /** + * Performs the action to disable all firewall rules. + * + * This method disables all firewall rules provided by the AIOWPSecurity_Settings_Tasks class. + * + * @return array An associative array containing the status and message of the operation. + * - 'status' : (string) The status of the operation, either 'success' or 'error'. + * - 'message' : (string) A message indicating the outcome of the operation. + * If the operation is successful, it contains an update message. + * If there is an error, it contains an error message. + */ + public function perform_disable_all_firewall_rules() { + $msg = AIOWPSecurity_Settings_Tasks::disable_all_firewall_rules(); + $success = true; + $message = ''; + + if (isset($msg['updated'])) { + $message = $msg['updated']; + } elseif (isset($msg['error'])) { + $message = $msg['error']; + $success = false; + } + + return $this->handle_response($success, $message); + } + + /** + * Performs the action to reset all settings. + * + * This method resets all settings provided by the AIOWPSecurity_Settings_Tasks class to their default values. + * + * @return array An associative array containing the status and message of the operation. + * - 'status' : (string) The status of the operation, either 'success' or 'error'. + * - 'message' : (string) A message indicating the outcome of the operation. + * If the operation is successful, it contains an update message. + * If there is an error, it contains an error message. + */ + public function perform_reset_all_settings() { + $msg = AIOWPSecurity_Settings_Tasks::reset_all_settings(); + + $success = true; + $message = ''; + + if (isset($msg['updated'])) { + $message = $msg['updated']; + } elseif (isset($msg['error'])) { + $message = $msg['error']; + $success = false; + } + + return $this->handle_response($success, $message); + } + + /** + * Performs the action to save debug settings. + * + * This method updates the debug settings in the AIOWPSecurity_Configs instance based on the provided data. + * + * @param array $data An associative array containing the data to update the debug settings. + * - 'aiowps_enable_debug': (bool) Indicates whether debug mode should be enabled. + * @return array An associative array containing the status and message of the operation. + * - 'status' : (string) The status of the operation, which is always 'success'. + * - 'message' : (string) A message indicating that the settings have been updated successfully. + */ + public function perform_save_debug_settings($data) { + global $aio_wp_security; + + $aio_wp_security->configs->set_value('aiowps_enable_debug', '1' === $data["aiowps_enable_debug"] ? '1' : '', true); + + return $this->handle_response(true); + } + + /** + * Performs the action to backup the .htaccess file. + * + * This method creates a backup of the .htaccess file and renames it with a random prefix. + * It also provides a message indicating the outcome of the backup operation. + * + * @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin. + * @return array An associative array containing the status and message of the backup operation. + * - 'status' : (string) The status of the operation, which can be 'success' or 'error'. + * - 'message' : (string) A message indicating the outcome of the backup operation. + */ + public function perform_backup_htaccess_file() { + global $aio_wp_security; + + $home_path = AIOWPSecurity_Utility_File::get_home_path(); + $htaccess_path = $home_path . '.htaccess'; + + $result = AIOWPSecurity_Utility_File::backup_and_rename_htaccess($htaccess_path); //Backup the htaccess file + $extra_args = array(); + + if ($result) { + $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME; + $success = true; + $message = __('Your .htaccess file was successfully backed up.', 'all-in-one-wp-security-and-firewall'); + $extra_args['data'] = file_get_contents($aiowps_backup_dir.'/'. $result .'.txt'); + $extra_args['title'] = $result; + } else { + $aio_wp_security->debug_logger->log_debug("htaccess - Backup operation failed!", 4); + $success = false; + $message = __('htaccess backup failed.', 'all-in-one-wp-security-and-firewall'); + } + + return $this->handle_response($success, $message, array('extra_args' => $extra_args)); + } + + /** + * Performs the action to restore the .htaccess file. + * + * This method restores the .htaccess file using the provided data, which includes the contents of the .htaccess file. + * It also verifies that the file chosen has valid contents relevant to the .htaccess file. + * + * @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin. + * @param array $data An associative array containing the data needed to restore the .htaccess file. + * - 'aiowps_htaccess_file' : (string) The name of the .htaccess file to restore from. + * - 'aiowps_htaccess_file_contents' : (string) The contents of the .htaccess file to restore. + * @return array An associative array containing the status and message of the restore operation. + * - 'status' : (string) The status of the operation, which can be 'success' or 'error'. + * - 'message' : (string) A message indicating the outcome of the restore operation. + */ + public function perform_restore_htaccess_file($data) { + global $aio_wp_security; + + $success = true; + + $home_path = AIOWPSecurity_Utility_File::get_home_path(); + $htaccess_path = $home_path . '.htaccess'; + + if (empty($data['aiowps_htaccess_file']) && empty($data['aiowps_htaccess_file_contents'])) { + $message = __('Please choose a valid .htaccess to restore from.', 'all-in-one-wp-security-and-firewall'); + $success = false; + } else { + $htaccess_file_contents = trim(stripslashes($data['aiowps_htaccess_file_contents'])); + //Verify that file chosen has contents which are relevant to .htaccess file + $is_htaccess = AIOWPSecurity_Utility_Htaccess::check_if_htaccess_contents($htaccess_file_contents); + if (1 == $is_htaccess) { + if (!file_put_contents($htaccess_path, $htaccess_file_contents)) { + //Failed to make a backup copy + $aio_wp_security->debug_logger->log_debug("htaccess - Restore from .htaccess operation failed.", 4); + $message = __('The restoration of the .htaccess file failed; please attempt to restore the .htaccess file manually using FTP.', 'all-in-one-wp-security-and-firewall'); + $success = false; + } else { + $message = __('Your .htaccess file has successfully been restored.', 'all-in-one-wp-security-and-firewall'); + } + } else { + $aio_wp_security->debug_logger->log_debug("htaccess restore failed - Contents of restore file appear invalid.", 4); + $success = false; + $message = __('The restoration .htaccess file has failed, please check the contents of the file you are trying to restore from.', 'all-in-one-wp-security-and-firewall'); + } + } + + return $this->handle_response($success, $message); + } + + /** + * Performs the action to restore the wp-config.php file. + * + * This method restores the wp-config.php file using the provided data, which includes the contents of the wp-config.php file. + * It also verifies that the file chosen is a valid wp-config.php file. + * + * @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin. + * @param array $data An associative array containing the data needed to restore the wp-config.php file. + * - 'aiowps_wp_config_file' : (string) The name of the wp-config.php file to restore from. + * - 'aiowps_wp_config_file_contents' : (string) The contents of the wp-config.php file to restore. + * @return array An associative array containing the status and message of the restore operation. + * - 'status' : (string) The status of the operation, which can be 'success' or 'error'. + * - 'message' : (string) A message indicating the outcome of the restore operation. + */ + public function perform_restore_wp_config_file($data) { + global $aio_wp_security; + + $success = true; + + if (empty($data['aiowps_wp_config_file']) && empty($data['aiowps_wp_config_file_contents'])) { + $message = __('Please choose a wp-config.php file to restore from.', 'all-in-one-wp-security-and-firewall'); + $success = false; + } else { + $wp_config_file_contents = trim(stripslashes($data['aiowps_wp_config_file_contents'])); + + //Verify that file chosen is a wp-config.file + $is_wp_config = AIOWPSecurity_Utility_File::check_if_wp_config_contents($wp_config_file_contents); + if ($is_wp_config) { + $active_root_wp_config = AIOWPSecurity_Utility_File::get_wp_config_file_path(); + if (!file_put_contents($active_root_wp_config, $wp_config_file_contents)) { + //Failed to make a backup copy + $aio_wp_security->debug_logger->log_debug("wp-config.php - Restore from backed up wp-config operation failed.", 4); + $message = __('The restoration of the wp-config.php file failed, please attempt to restore this file manually using FTP.', 'all-in-one-wp-security-and-firewall'); + $success = false; + } else { + $message =__('Your wp-config.php file has successfully been restored.', 'all-in-one-wp-security-and-firewall'); + } + } else { + $aio_wp_security->debug_logger->log_debug("wp-config.php restore failed - Contents of restore file appear invalid.", 4); + $message = __('The restoration of the wp-config.php file failed, please check the contents of the file you are trying to restore from.', 'all-in-one-wp-security-and-firewall'); + $success = false; + } + } + + return $this->handle_response($success, $message); + } + + /** + * Performs the action to delete plugin settings. + * + * This method deletes specific plugin settings based on the provided data. + * + * @param array $data An associative array containing the data needed to delete plugin settings. + * - 'aiowps_on_uninstall_delete_db_tables' : (string) Indicates whether to delete plugin database tables on uninstallation. + * - 'aiowps_on_uninstall_delete_configs' : (string) Indicates whether to delete plugin configuration settings on uninstallation. + * @return array An associative array containing the status and message of the delete operation. + * - 'status' : (string) The status of the operation, which can be 'success'. + * - 'message' : (string) A message indicating that the plugin settings have been successfully deleted. + */ + public function perform_delete_plugin_settings($data) { + + $options = array(); + //Save settings + $options['aiowps_on_uninstall_delete_db_tables'] = isset($data['aiowps_on_uninstall_delete_db_tables']) ? '1' : ''; + $options['aiowps_on_uninstall_delete_configs'] = isset($data['aiowps_on_uninstall_delete_configs']) ? '1' : ''; + $this->save_settings($options); + + return $this->handle_response(true); + } + + /** + * Performs the action to remove WordPress version information settings. + * + * This method sets the option to remove WordPress version information meta tags based on the provided data. + * + * @param array $data An associative array containing the data needed to configure the removal of WordPress version information. + * - 'aiowps_remove_wp_generator_meta_info' : (string) Indicates whether to remove WordPress version information meta tags. + * @return array An associative array containing the status, message, and additional badges related to the removal of WordPress version information. + * - 'status' : (string) The status of the operation, which can be 'success'. + * - 'message' : (string) A message indicating that the settings have been successfully updated. + * - 'badges' : (array) An array containing feature IDs and HTML for additional badges. + */ + public function perform_remove_wp_version_info_settings($data) { + global $aio_wp_security; + + $aio_wp_security->configs->set_value('aiowps_remove_wp_generator_meta_info', '1' === $data["aiowps_remove_wp_generator_meta_info"] ? '1' : '', true); + + return $this->handle_response(true, '', array('badges' => array('wp-generator-meta-tag'))); + } + + /** + * Performs the action to restore AIOWPS settings from an imported file. + * + * This method restores AIOWPS settings from the provided data representing an imported file. + * + * @param array $data An associative array containing the data needed to restore AIOWPS settings. + * - 'aiowps_import_settings_file' : (string) The name of the file containing the AIOWPS settings. + * - 'aiowps_import_settings_file_contents': (string) The contents of the file containing the AIOWPS settings. + * @return array An associative array containing the status and messages related to the restoration of AIOWPS settings. + * - 'status' : (string) The status of the operation, which can be 'success' or 'error'. + * - 'messages' : (array) An array of messages indicating the outcome of the restoration process. + * - 'redirect_url' : (string|null) The URL to redirect to after the restoration process, if applicable. + */ + public function perform_restore_aiowps_settings($data) { + global $aio_wp_security, $simba_two_factor_authentication; + $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); + + $success = true; + $info = array(); + $extra_args = array(); + + $msg_updated = __('Your AIOS settings were successfully imported.', 'all-in-one-wp-security-and-firewall'); + $msg_error = sprintf(__('Could not write to the %s file.', 'all-in-one-wp-security-and-firewall'), AIOWPSecurity_Utility_File::get_home_path().'.htaccess') . ' ' . __('Please check the file permissions.', 'all-in-one-wp-security-and-firewall'); + + if (empty($data['aiowps_import_settings_file']) && empty($data['aiowps_import_settings_file_contents'])) { + $success = false; + $message = __('Please choose a file to import your settings from.', 'all-in-one-wp-security-and-firewall'); + } else { + // Let's get the uploaded import file contents + $import_file_contents = trim($data['aiowps_import_settings_file_contents']); // stripslashes not required wp_unslash applied already AIOWPSecurity_Ajax::set_data + + // Verify that file chosen has valid AIOS settings contents + $aiowps_settings_file_contents = AIOWPSecurity_Utility_File::check_if_valid_aiowps_settings_content($import_file_contents); + + if ($aiowps_settings_file_contents) { + $is_enabled_cookie_bruteforce_before_import = $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention'); + // Apply the settings + $settings_array = json_decode($import_file_contents, true); + if (array_key_exists('general', $settings_array)) { + $aiowps_settings_applied = update_option('aio_wp_security_configs', $settings_array['general']); + + if (!$aiowps_settings_applied && get_option('aio_wp_security_configs') === $settings_array['general']) { + $aiowps_settings_applied = true; + } + + if (is_main_site() && is_super_admin()) { + if (array_key_exists('tfa', $settings_array) && true == $simba_two_factor_authentication->is_tfa_integrated) { + $tfa_settings_applied = $simba_two_factor_authentication->set_configs($settings_array['tfa']); + + if (!$tfa_settings_applied && $simba_two_factor_authentication->get_configs() !== $settings_array['tfa']) { + $aiowps_settings_applied = false; + } + } + + if (array_key_exists('firewall', $settings_array)) { + $aiowps_settings_applied = $aiowps_settings_applied && $aiowps_firewall_config->set_contents($settings_array['firewall']); + } + } + } else { + $aiowps_settings_applied = update_option('aio_wp_security_configs', $settings_array); + + if (!$aiowps_settings_applied && get_option('aio_wp_security_configs') === $settings_array) { + $aiowps_settings_applied = true; + } + } + + if (!$aiowps_settings_applied) { + // Failed to import settings + $aio_wp_security->debug_logger->log_debug('Import AIOS settings operation failed.', 4); + $success = false; + $message = __('Import AIOS settings operation failed.', 'all-in-one-wp-security-and-firewall'); + } else { + $aio_wp_security->configs->load_config(); // Refresh the configs global variable + + //Just in case user submits partial config settings + //Run add_option_values to make sure any missing config items are at least set to default + AIOWPSecurity_Configure_Settings::add_option_values(); + + $res = true; + + if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); + + // Now let's refresh the .htaccess file with any modified rules if applicable + + $is_enabled_cookie_bruteforce = $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention'); + + if ($is_enabled_cookie_bruteforce_before_import != $is_enabled_cookie_bruteforce && 1 == $is_enabled_cookie_bruteforce) { + $url = 'admin.php?page='.AIOWPSEC_SETTINGS_MENU_SLUG."&tab=settings-file-operations&success=import_settings"; + $url .= empty($aio_wp_security->configs->get_value('aiowps_brute_force_secret_word')) ? '' : '&'.$aio_wp_security->configs->get_value('aiowps_brute_force_secret_word').'=1'; + $url .= $res ? '' : '&error=write_htaccess'; + $extra_args['redirect_url'] = admin_url(sanitize_url($url)); + } + + $message = $msg_updated; + if (!$res) { + $info[] = $msg_error; + } + } + } else { + // Invalid settings file + $aio_wp_security->debug_logger->log_debug("The contents of your settings file are invalid.", 4); + $success = false; + $message = __('The contents of your settings file are invalid, please check the contents of the file you are trying to import settings from.', 'all-in-one-wp-security-and-firewall'); + } + } + + $args = array( + 'info' => $info, + 'extra_args' => $extra_args + ); + + return $this->handle_response($success, $message, $args); + } + + /** + * Performs the action to save IP settings. + * + * This method saves the IP settings based on the provided data. + * + * @param array $data An associative array containing the data needed to save IP settings. + * - 'aiowps_ip_retrieve_method': (string) The ID of the IP retrieval method. + * @return array An associative array containing the status and message related to saving IP settings. + * - 'status': (string) The status of the operation, which can be 'success' or 'error'. + * - 'message': (string|null) A message indicating the outcome of saving IP settings, or null if no message is provided. + */ + public function perform_save_ip_settings($data) { + global $wpdb, $aio_wp_security; + $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); + + $ip_retrieve_method_id = sanitize_text_field($data["aiowps_ip_retrieve_method"]); + + $message = false; + + if (in_array($ip_retrieve_method_id, array_keys(AIOS_Abstracted_Ids::get_ip_retrieve_methods()))) { + $aio_wp_security->configs->set_value('aiowps_ip_retrieve_method', $ip_retrieve_method_id, true); + $aiowps_firewall_config->set_value('aios_ip_retrieve_method', $ip_retrieve_method_id); + $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS; + + //Clear logged in list because it might be showing wrong addresses + if (AIOWPSecurity_Utility::is_multisite_install()) { + $current_blog_id = get_current_blog_id(); + $wpdb->query($wpdb->prepare("DELETE FROM `{$logged_in_users_table}` WHERE site_id = %d", $current_blog_id)); + } + $wpdb->query("DELETE FROM `{$logged_in_users_table}`"); + + $message = ''; + } + + return $this->handle_response(true, $message); + } + + /** + * Perform saving the wp-config.php file. + * + * This method backs up the wp-config.php file and retrieves its content. + * It returns the status of the operation, the file content, and the backup title. + * + * @return array An array containing the status, file content, and backup title. + */ + public function perform_save_wp_config() { + $wp_config_path = AIOWPSecurity_Utility_File::get_wp_config_file_path(); + AIOWPSecurity_Utility_File::backup_and_rename_wp_config($wp_config_path); // Backup the wp_config.php file + $title = "wp-config-backup.txt"; + $file_content = file_get_contents($wp_config_path); + + $extra_args = array( + 'data' => $file_content, + 'title' => $title + ); + + return $this->handle_response(true, false, array('extra_args' => $extra_args)); + } + + /** + * Perform exporting All-In-One Security settings. + * + * This method exports general settings, firewall settings, and two-factor authentication settings + * if applicable. It then returns the exported data in JSON format along with a title for the export. + * + * @return array An array containing the status, exported data in JSON format, and a title for the export. + */ + public function perform_export_aios_settings() { + global $simba_two_factor_authentication; + $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); + + $config_data = array(); + $config_data['general'] = get_option('aio_wp_security_configs'); + + if (is_main_site() && is_super_admin()) { + $config_data['firewall'] = $aiowps_firewall_config->get_contents(); + + if (true == $simba_two_factor_authentication->is_tfa_integrated) { + $config_data['tfa'] = $simba_two_factor_authentication->get_configs(); + } + } + + $output = json_encode($config_data); + + $extra_args = array( + 'data' => $output, + 'title' => 'aiowps_' . current_time('Y-m-d_H-i') . '.txt' + ); + + return $this->handle_response(true, false, array('extra_args' => $extra_args)); + } + + /** + * Render the Import/Export settings UI for legacy UDC. + * + * @return array + */ + public function get_import_export_contents() { + global $aio_wp_security; + + $content = $aio_wp_security->include_template('wp-admin/settings/settings-file-operations.php', true, array()); + + return array( + 'status' => 'success', + 'content' => $content, + ); + } + + /** + * Render the reset settings UI for legacy UDC. + * + * @return array + */ + public function get_reset_contents() { + global $aio_wp_security; + + $content = $aio_wp_security->include_template('wp-admin/settings/general-settings.php', true, array()); + + return array( + 'status' => 'success', + 'content' => $content, + ); + } + + /** + * Return ip address detection data for the advanced settings. + * + * @return array + */ + public function get_ip_address_detection_data() { + global $aio_wp_security; + + $ip_retrieve_methods_postfixes = array( + 'REMOTE_ADDR' => __('Default - if correct, then this is the best option', 'all-in-one-wp-security-and-firewall'), + 'HTTP_CF_CONNECTING_IP' => __("Only use if you're using Cloudflare.", 'all-in-one-wp-security-and-firewall'), + ); + + $ip_retrieve_methods = array(); + + foreach (AIOS_Abstracted_Ids::get_ip_retrieve_methods() as $id => $ip_method) { + $ip_retrieve_methods[$id]['ip_method'] = $ip_method; + + if (isset($_SERVER[$ip_method])) { + /* translators: %s: IP Method */ + $ip_retrieve_methods[$id]['ip_method'] .= ' ' . sprintf(__('(current value: %s)', 'all-in-one-wp-security-and-firewall'), sanitize_text_field(wp_unslash($_SERVER[$ip_method]))); + $ip_retrieve_methods[$id]['is_enabled'] = true; + } else { + $ip_retrieve_methods[$id]['ip_method'] .= ' (' . __('no value (i.e. empty) on your server', 'all-in-one-wp-security-and-firewall') . ')'; + $ip_retrieve_methods[$id]['is_enabled'] = false; + } + + if (!empty($ip_retrieve_methods_postfixes[$ip_method])) { + $ip_retrieve_methods[$id]['ip_method'] .= ' (' . $ip_retrieve_methods_postfixes[$ip_method] . ')'; + } + } + + return array( + 'is_localhost' => AIOWPSecurity_Utility::is_localhost(), + 'current_ip_retrieve_method' => $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), + 'ip_retrieve_methods' => $ip_retrieve_methods, + 'server_suitable_ip_methods' => AIOWPSecurity_Utility_IP::get_server_suitable_ip_methods() + ); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tfa-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tfa-commands.php new file mode 100755 index 00000000..5797b662 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tfa-commands.php @@ -0,0 +1,216 @@ +init_tfa(); + + $controller = $tfa->get_controller(); + + $old_algorithm = $controller->get_user_otp_algorithm($current_user->ID); + + if ($old_algorithm != $data['tfa_algorithm_type']) { + $controller->changeUserAlgorithmTo($current_user->ID, $data['tfa_algorithm_type']); + } + + return array( + 'status' => 'success', + ); + } + + /** + * Saves the TFA activation setting. + * + * @param array $data Passed arguments. + * + * @return array|WP_Error + */ + public function save_activation_setting($data) { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + global $current_user; + + $tfa = $this->init_tfa(); + + $tfa->change_tfa_enabled_status($current_user->ID, $data['tfa_enable_tfa']); + + return array( + 'status' => 'success', + ); + } + + /** + * Updates the TFA private key. + * + * @return array|WP_Error + */ + public function update_private_key() { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + global $current_user; + + $user_id = $current_user->ID; + + delete_user_meta($user_id, 'tfa_priv_key_64'); + delete_user_meta($user_id, 'simba_tfa_emergency_codes_64'); + + return array( + 'status' => 'success', + ); + } + + /** + * Updates the TFA OTP Code. + * + * @param array $data Passed arguments. + * + * @return array|WP_Error + */ + public function update_otp_code($data) { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + global $current_user; + + $tfa = $this->init_tfa(); + + if ('refreshotp' == $data['subaction']) { + $code = $tfa->get_controller()->get_current_code($current_user->ID); + + if (false === $code) { + return array( + 'status' => 'error', + 'code' => '', + ); + } + + return array( + 'status' => 'success', + 'code' => $code, + ); + } elseif ('untrust_device' == $data['subaction']) { + global $current_user; + + $trusted_devices = $tfa->user_get_trusted_devices(); + + $trusted_device = $trusted_devices[wp_unslash($data['device_id'])]; + + if (isset($trusted_device)) { + unset($trusted_device); + } + + $current_user_id = $current_user->ID; + + $tfa->user_set_trusted_devices($current_user_id, $trusted_devices); + + $trusted_list = $tfa->include_template('trusted-devices-inner-box.php', array('trusted_devices' => $tfa->user_get_trusted_devices()), true); + + return array( + 'status' => 'success', + 'trusted_list' => $trusted_list, + ); + } + + exit; + } + + /** + * Renders the TFA UI. + * + * @return array + */ + public function get_tfa_contents() { + if (!function_exists('submit_button')) { + require_once(ABSPATH . 'wp-admin/includes/template.php'); + } + + $tfa = $this->init_tfa(); + + $content = $tfa->include_template('user-settings.php', array('simba_tfa' => $tfa), true); + + return array( + 'status' => 'success', + 'content' => $content, + ); + } + + /** + * Get the TFA settings data for the new UDC theme. + * + * @return array + */ + public function get_tfa_data() { + $tfa = $this->init_tfa(); + + return array( + 'tfa_required_administrator' => $tfa->get_option('tfa_required_administrator'), + 'tfa_administrator' => $tfa->get_option('tfa_administrator'), + ); + } + + /** + * Save the TFA settings data for the new UDC theme. + * + * @param array $data The data to save. + * + * @return array|WP_Error + */ + public function perform_save_tfa($data) { + if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) { + return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall')); + } + + $success = false; + $message = ''; + + $tfa = $this->init_tfa(); + + $value = isset($data["tfa_required_administrator"]) ? '1' : ''; + + if ($tfa->update_option('tfa_required_administrator', $value)) { + $tfa->update_option('tfa_administrator', $value); + + $success = true; + } + + return $this->handle_response($success, $message); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tools-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tools-commands.php new file mode 100755 index 00000000..18196dab --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tools-commands.php @@ -0,0 +1,253 @@ +')) { + if (!(filter_var($ip_or_domain, FILTER_VALIDATE_IP) || filter_var($ip_or_domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME))) $invalid_domain = true; // phpcs:ignore PHPCompatibility.Constants.NewConstants.filter_validate_domainFound -- This code only runs on php 7.0+ so ignore the warning + } + + if ($invalid_domain) { + $result = __('Please enter a valid IP address or domain name to look up.', 'all-in-one-wp-security-and-firewall'); + $result .= __('Nothing to show.', 'all-in-one-wp-security-and-firewall'); + } else { + $result = $this->whois_lookup($ip_or_domain); + + if (is_wp_error($result)) { + $result = htmlspecialchars($result->get_error_message()); + $result .= __('Nothing to show.', 'all-in-one-wp-security-and-firewall'); + } else { + $result = htmlspecialchars($result); + } + } + + $args = array( + 'content' => array('aios-who-is-lookup-result-container' => $aio_wp_security->include_template('wp-admin/tools/partials/who-is-lookup-result.php', true, array('result' => $result, 'ip_or_domain' => $ip_or_domain))) + ); + + return $this->handle_response(true, false, $args); + } + + /** + * Store custom .htaccess settings provided by the user. + * + * @param array $data The data containing the custom .htaccess settings. + * It should include keys 'aiowps_enable_custom_rules', 'aiowps_custom_rules', + * and 'aiowps_place_custom_rules_at_top' if applicable. + * @return array An array containing the status of the operation and any relevant messages. + * The 'status' key indicates whether the operation was successful. + * The 'message' key contains any informational or error messages. + */ + public function perform_store_custom_htaccess_settings($data) { + global $aio_wp_security; + + $success = true; + $message = ''; + + $options = array(); + // Save settings + if (isset($data["aiowps_enable_custom_rules"]) && empty($data['aiowps_custom_rules'])) { + $message = __('You must enter some .htaccess directives in the text box below', 'all-in-one-wp-security-and-firewall'); + return $this->handle_response(false, $message); + } else { + if (!empty($data['aiowps_custom_rules'])) { + // Sanitize textarea shoud not be used as'; + $cap_form .= '
%1$s
'; + $antibot_hidden_fields = ''; + $key_map_arr = self::generate_antibot_keys(); + foreach ($key_map_arr[0] as $key) { + $antibot_hidden_fields .=''; + } + if (isset($key_map_arr[2])) { + $antibot_hidden_fields .=''; + } + wp_register_script('aios-front-js', AIO_WP_SECURITY_URL. '/js/wp-security-front-script.js', array('jquery'), AIO_WP_SECURITY_VERSION, true); + wp_enqueue_script('aios-front-js'); + wp_localize_script('aios-front-js', 'AIOS_FRONT', array( + 'ajaxurl' => admin_url('admin-ajax.php'), // URL to wp-admin/admin-ajax.php to process the request + 'ajax_nonce' => wp_create_nonce('wp-security-ajax-nonce'), + )); + $html_antibot_hidden_fields = sprintf($html_antibot_hidden_fields, $antibot_hidden_fields); + return $html_antibot_hidden_fields; + } + + /** + * Get antibot key-value pairs to check on post back + * + * @param boolean $update generate and save in database + * + * @return array + */ + public static function generate_antibot_keys($update = false) { + $key_map_arr = get_site_option('aios_antibot_key_map_info'); + if (!$update && is_array($key_map_arr)) { + return $key_map_arr; + } + if ($update && is_array($key_map_arr) && isset($key_map_arr[2]) && $key_map_arr[2] > time()) { + return $key_map_arr; + } + $key_map_arr = array(); + + // values for to check post back key + $max = wp_rand(2, 4); + for ($i = 1; $i <= $max; $i++) { + $string1 = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(8); + $string2 = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(12); + $key_map_arr[0][] = array($string1, $string2); + } + + // values for to check for cookie back key + $max = wp_rand(2, 4); + for ($i = 1; $i <= $max; $i++) { + $string1 = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(8); + $string2 = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(12); + $key_map_arr[1][] = array($string1, $string2); + } + // expiration time of keys + $current_time = time(); + $key_map_arr[2] = (($current_time - ($current_time % 86400)) + AIOS_UPDATE_ANTIBOT_KEYS_AFTER_DAYS * 86400); + update_site_option('aios_antibot_key_map_info', $key_map_arr); + return $key_map_arr; + } + + /** + * Update antibot key-value pairs to rotate values so it is not valid forever + * + * @return void + */ + public function update_antibot_keys() { + if ((intval(gmdate('z')) % AIOS_UPDATE_ANTIBOT_KEYS_AFTER_DAYS) == 0) self::generate_antibot_keys(true); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-config.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-config.php new file mode 100755 index 00000000..cc48759d --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-config.php @@ -0,0 +1,109 @@ +configs = get_option('aio_wp_security_configs'); + } + + public function get_value($key) { + return isset($this->configs[$key]) ? $this->configs[$key] : ''; + } + + /** + * Gets for main site config value for a given $key. + * + * @param string $key + * + * @return string|array + */ + public function get_site_value($key) { + if (is_multisite() && !is_main_site()) { + $mainsite_aio_config = get_blog_option(get_main_site_id(), 'aio_wp_security_configs'); + return isset($mainsite_aio_config[$key]) ? $mainsite_aio_config[$key] : ''; + } else { + return $this->get_value($key); + } + } + + /** + * Sets a given config $value for a given $key. + * + * @param string $key + * @param mixed $value + * @param boolean $save_config - Whether or not to also save the $configs array to the database. + * + * @return boolean + */ + public function set_value($key, $value, $save_config = false) { + $this->configs[$key] = $value; + + if ($save_config) { + return $this->save_config(); + } else { + return true; + } + } + + public function add_value($key, $value) { + if (!is_array($this->configs)) { + $this->configs = array(); + } + + if (array_key_exists($key, $this->configs)) { + //Don't update the value for this key + } else {//It is safe to update the value for this key + $this->configs[$key] = $value; + } + } + + /** + * Save configuration that are set. + * + * @return boolean True on save config, Otherwise false. + */ + public function save_config() { + return update_option('aio_wp_security_configs', $this->configs); + } + + /** + * Remove key element from config. + * + * @param String $key config key + * + * @return boolean True if removed, otherwise false. + */ + public function delete_value($key) { + if (!is_array($this->configs)) { + $this->configs = array(); + } + + if (array_key_exists($key, $this->configs)) { + unset($this->configs[$key]); + if (!isset($this->configs[$key])) { + return true; + } + } + + return false; + } + + public static function get_instance() { + if (empty(self::$_this)) { + self::$_this = new AIOWPSecurity_Config(); + self::$_this->load_config(); + return self::$_this; + } + return self::$_this; + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-configure-settings.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-configure-settings.php new file mode 100755 index 00000000..e8280513 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-configure-settings.php @@ -0,0 +1,739 @@ +configs->set_value('aiowps_enable_debug', '');//Checkbox + + //PHP backtrace + $aio_wp_security->configs->set_value('aiowps_enable_php_backtrace_in_email', '');//Checkbox + + //WP Generator Meta Tag feature + $aio_wp_security->configs->set_value('aiowps_remove_wp_generator_meta_info', '');//Checkbox + + //Prevent Image Hotlinks + $aio_wp_security->configs->set_value('aiowps_prevent_hotlinking', '');//Checkbox + //General Settings Page + + //User password feature + + //Lockout feature + $aio_wp_security->configs->set_value('aiowps_enable_login_lockdown', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_allow_unlock_requests', '1'); // Checkbox + $aio_wp_security->configs->set_value('aiowps_max_login_attempts', '3'); + $aio_wp_security->configs->set_value('aiowps_retry_time_period', '5'); + $aio_wp_security->configs->set_value('aiowps_lockout_time_length', '5'); + $aio_wp_security->configs->set_value('aiowps_max_lockout_time_length', '60'); + $aio_wp_security->configs->set_value('aiowps_set_generic_login_msg', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_enable_email_notify', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_email_address', $blog_email_address);//text field + $aio_wp_security->configs->set_value('aiowps_enable_forced_logout', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_logout_time_period', '60'); + $aio_wp_security->configs->set_value('aiowps_enable_invalid_username_lockdown', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_instantly_lockout_specific_usernames', array()); // Textarea (list of strings) + $aio_wp_security->configs->set_value('aiowps_unlock_request_secret_key', AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some unlock request processing. This will be assigned a random string generated when lockdown settings saved + $aio_wp_security->configs->set_value('aiowps_lockdown_enable_whitelisting', '');//Checkbox + $aio_wp_security->configs->set_value('aiowps_lockdown_allowed_ip_addresses', ''); + + // HTTP authentication + $aio_wp_security->configs->set_value('aiowps_http_authentication_admin', ''); // Checkbox + $aio_wp_security->configs->set_value('aiowps_http_authentication_frontend', ''); // Checkbox + $aio_wp_security->configs->set_value('aiowps_http_authentication_username', 'root'); + $aio_wp_security->configs->set_value('aiowps_http_authentication_password', 'password'); + $aio_wp_security->configs->set_value('aiowps_http_authentication_failure_message', '' . 'Site name' . ': ' . $site_name . "
"; + + $site_url = esc_url(get_bloginfo('url')); + $report .= '' . 'Site URL' . ': ' . '' . $site_url . '
'; + + $current_datetime = date_i18n(get_option('date_format') . ' ' . get_option('time_format')); + $report .= '' . 'Date and time' . ': ' . $current_datetime . "
"; + + $report .= $sections; + + $report .= self::get_debug_log(true); + + $report .= '' . esc_html('This report was generated by the All-In-One Security plugin.') . '
'; + $subject = esc_html('All-In-One Security - diagnostic report'); + + $result = $aio_wp_security->sender_obj->send_email($email, $subject, $report); + + return $result; + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-file-scan.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-file-scan.php new file mode 100755 index 00000000..cbc1ec83 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-file-scan.php @@ -0,0 +1,381 @@ +configs->get_value('aiowps_fcd_filename'); + if (empty($fcd_filename)) { + // means that we haven't done a scan before, or, + // the fcd file containing the results doesn't exist + $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10); + $fcd_filename = 'aiowps_fcd_data_' . $random_suffix; + $aio_wp_security->configs->set_value('aiowps_fcd_filename', $fcd_filename, true); + } + + $fcd_data = self::get_fcd_data(); // get previous scan data if any + + if (false === $fcd_data) { + // an error occurred so return + return false; + } + + $scanned_data = $this->do_file_change_scan(); + + if (empty($fcd_data)) { + $this->save_fcd_data($scanned_data); + $scan_result['initial_scan'] = '1'; + return $scan_result; + } else { + + $scan_result = $this->compare_scan_data($fcd_data['file_scan_data'], $scanned_data); + + $scan_result['initial_scan'] = ''; + $this->save_fcd_data($scanned_data, $scan_result); + if (!empty($scan_result['files_added']) || !empty($scan_result['files_removed']) || !empty($scan_result['files_changed'])) { + //This means there was a change detected + $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', true, true); + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - change to filesystem detected!"); + + $this->aiowps_send_file_change_alert_email($scan_result); //Send file change scan results via email if applicable + } else { + //Reset the change flag + $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false, true); + } + return $scan_result; + } + } + + /** + * Send email with notification about file changes detected by last scan. + * + * @global AIO_WP_Security $aio_wp_security + * @param array $scan_result Array with scan result returned by compare_scan_data() method. + */ + public function aiowps_send_file_change_alert_email($scan_result) { + global $aio_wp_security; + if ('1' == $aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email')) { + $subject = __('All In One WP Security - File change detected', 'all-in-one-wp-security-and-firewall') . ' ' . AIOWPSecurity_Utility::convert_timestamp(null, 'l, F jS, Y \a\\t g:i a'); + //$attachment = array(); + $message = __('A file change was detected on your system for site URL', 'all-in-one-wp-security-and-firewall') . ' ' . network_site_url() . __('. Scan was generated on', 'all-in-one-wp-security-and-firewall') . ' ' . AIOWPSecurity_Utility::convert_timestamp(null, 'l, F jS, Y \a\\t g:i a'); + $message .= "\r\n\r\n".__('A summary of the scan results is shown below:', 'all-in-one-wp-security-and-firewall'); + $message .= "\r\n\r\n"; + $message .= self::get_file_change_summary($scan_result); + $message .= "\r\n".__('Login to your site to view the scan details.', 'all-in-one-wp-security-and-firewall'); + + // Get the email address(es). + $addresses = AIOWPSecurity_Utility::get_array_from_textarea_val($aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address')); + // If no explicit email address(es) are given, send email to site admin. + $to = empty($addresses) ? array(get_site_option('admin_email')) : $addresses; + if (!wp_mail($to, $subject, $message)) { + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - File change notification email failed to send.", 4); + } + + } + } + + /** + * This function is called via the following filter 'aiowps_perform_fcd_scan_tasks' and will start the file scan + * + * @return void + */ + public function aiowps_scheduled_fcd_scan_handler() { + global $aio_wp_security; + + if ('1' != $aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan')) return; + + $aio_wp_security->debug_logger->log_debug_cron(__METHOD__ . " - Scheduled fcd_scan is enabled. Checking now to see if scan needs to be done..."); + + $current_time = time(); + + $next_fcd_scan_time = self::get_next_scheduled_scan(); + + if ($next_fcd_scan_time <= $current_time) { + // It's time to do a filescan + $result = $this->execute_file_change_detection_scan(); + if (false === $result) { + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Scheduled filescan operation failed.", 4); + } else { + $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $current_time, true); + } + } + + } + + /** + * This function will get the next scheduled scan timestamp and return it + * + * @return int|bool - the next scheduled scan timestamp, or false if the scheduled scan is not setup + */ + public static function get_next_scheduled_scan() { + global $aio_wp_security; + + if ('1' != $aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan')) return false; + + $fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency'); // Number of hours or days or months interval + $interval_setting = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval'); // Hours/Days/Months + switch ($interval_setting) { + case '0': + $interval = 'hours'; + break; + case '1': + $interval = 'days'; + break; + case '2': + $interval = 'weeks'; + break; + } + $last_fcd_scan_time = $aio_wp_security->configs->get_value('aiowps_last_fcd_scan_time'); + if (null == $last_fcd_scan_time) { + // Set the last scan time to now so it can trigger for the next scheduled period + $last_fcd_scan_time = time(); + $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $last_fcd_scan_time, true); + } elseif (is_string($last_fcd_scan_time)) { + $last_fcd_scan_time = strtotime($last_fcd_scan_time); + $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $last_fcd_scan_time, true); + } + $next_fcd_scan_time = strtotime("+".abs($fcd_scan_frequency).$interval, $last_fcd_scan_time); + + return $next_fcd_scan_time; + } + + /** + * Get the last filechange detection data which is stored in the special file. + * + * @global AIO_WP_Security $aio_wp_security + * @return bool|array - false on failure, array on success + */ + public static function get_fcd_data() { + // phpcs:disable WordPress.WP.AlternativeFunctions -- Silence wp_filesystem method suggestion. We cannot use that method. + global $aio_wp_security; + $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME; + + $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename'); + if (empty($fcd_filename)) { + // means that we haven't done a scan before, or, + // the fcd file containing the results doesn't exist + $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10); + $fcd_filename = 'aiowps_fcd_data_' . $random_suffix; + $aio_wp_security->configs->set_value('aiowps_fcd_filename', $fcd_filename, true); + } + $results_file = $aiowps_backup_dir. '/'. $fcd_filename; + + if (!is_file($results_file)) { + if (is_dir($results_file)) { + $new_dir_name = $results_file . '_backup'; + rename($results_file, $new_dir_name); //Rename the folder to create backup of the folder. This condition should not really happen, but if it does (user sets some non-sensible value), then it's better to not nuke the existing folder + } + $fp = @fopen($results_file, 'w'); //open for write - will create file if doesn't exist + return array(); + } + + if (empty(filesize($results_file))) { + return array(); // if newly created file return empty array + } + + $fp = @fopen($results_file, 'r'); //open for read and write - will create file if doesn't exist + if (false === $fp) { + // Error + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fopen returned false when opening fcd data file"); + return false; + } + + $contents = fread($fp, filesize($results_file)); + fclose($fp); + if (false === $contents) { + // Error + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fread returned false when reading fcd data file"); + return false; + } else { + + $fcd_file_contents = json_decode($contents, true); + if (isset($fcd_file_contents['file_scan_data'])) { + return $fcd_file_contents; + } else { + return array(); + } + + } + + // phpcs:enable WordPress.WP.AlternativeFunctions -- Silence wp_filesystem method suggestion. We cannot use that method. + } + + /** + * Recursively scan the entire $start_dir directory and return file size + * and last modified date of every regular file. Ignore files and file + * types specified in file scanner settings. + * + * @global AIO_WP_Security $aio_wp_security + * @param string $start_dir + * @return array + */ + public function do_file_change_scan($start_dir = ABSPATH) { + global $aio_wp_security; + $filescan_data = array(); + // Iterator key is absolute file path, iterator value is SplFileInfo object, + // iteration skips '..' and '.' records, because we're not interested in directories. + $dit = new RecursiveDirectoryIterator($start_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS); + $rit = new RecursiveIteratorIterator($dit, RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD); + + // Grab files/directories to skip + $files_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_fcd_exclude_files')); + // Grab (lowercased) file types to skip + $file_types_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty(strtolower($aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes'))); + + $start_dir_length = strlen($start_dir); + + foreach ($rit as $filename => $fileinfo) { + + if (!file_exists($filename) || is_dir($filename)) { + continue; // if file doesn't exist or is a directory move on to next iteration + } + + if ($fileinfo->getFilename() == 'wp-security-log-cron-job.txt' || $fileinfo->getFilename() == 'wp-security-log.txt') { + continue; // Skip AIOS log files + } + + // Let's omit any file types from the scan which were specified in the settings if necessary + if (!empty($file_types_to_skip)) { + //$current_file_ext = strtolower($fileinfo->getExtension()); //getExtension() only available on PHP 5.3.6 or higher + $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + if (in_array($ext, $file_types_to_skip)) { + continue; + } + } + + // Let's omit specific files or directories from the scan which were specified in the settings + if (!empty($files_to_skip)) { + + $skip_this = false; + foreach ($files_to_skip as $f_or_dir) { + // Expect files/dirs to be specified relatively to $start_dir, + // so start searching at $start_dir_length offset. + if (strpos($filename, $f_or_dir, $start_dir_length) !== false) { + $skip_this = true; + break; // ! + } + } + if ($skip_this) { + continue; + } + } + + $filescan_data[$filename] = array( + 'last_modified' => $fileinfo->getMTime(), + 'filesize' => $fileinfo->getSize(), + ); + + } + return $filescan_data; + } + + public function compare_scan_data($last_scan_data, $new_scanned_data) { + // Identify new files added: get all files which are in the new scan but not present in the old scan + $files_added = @array_diff_key($new_scanned_data, $last_scan_data); + // Identify files deleted: get all files which are in the old scan but not present in the new scan + $files_removed = @array_diff_key($last_scan_data, $new_scanned_data); + // Identify existing files: get all files which are in new scan, but were not added + $files_kept = @array_diff_key($new_scanned_data, $files_added); + + $files_changed = array(); + + // Loop through existing files and determine, if they have been changed + foreach ($files_kept as $filename => $new_scan_meta) { + $last_scan_meta = $last_scan_data[$filename]; + // Check filesize and last_modified values + if (($new_scan_meta['last_modified'] !== $last_scan_meta['last_modified']) || ($new_scan_meta['filesize'] !== $last_scan_meta['filesize'])) { + $files_changed[$filename] = $new_scan_meta; + } + } + + // Create single array of all changes + return array( + 'files_added' => $files_added, + 'files_removed' => $files_removed, + 'files_changed' => $files_changed, + ); + } + + public static function get_file_change_summary($scan_result) { + $scan_summary = ""; + if (!empty($scan_result['files_added'])) { + //Output of files added + $scan_summary .= "\r\n".__('The following files were added to your host', 'all-in-one-wp-security-and-firewall').":\r\n"; + foreach ($scan_result['files_added'] as $key => $value) { + $scan_summary .= "\r\n".$key.' ('.__('modified on:', 'all-in-one-wp-security-and-firewall'). ' ' . AIOWPSecurity_Utility::convert_timestamp($value['last_modified']).')'; + } + $scan_summary .= "\r\n======================================\r\n"; + } + if (!empty($scan_result['files_removed'])) { + //Output of files removed + $scan_summary .= "\r\n".__('The following files were removed from your host', 'all-in-one-wp-security-and-firewall').":\r\n"; + foreach ($scan_result['files_removed'] as $key => $value) { + $scan_summary .= "\r\n".$key.' ('.__('modified on:', 'all-in-one-wp-security-and-firewall'). ' ' . AIOWPSecurity_Utility::convert_timestamp($value['last_modified']).')'; + } + $scan_summary .= "\r\n======================================\r\n"; + } + + if (!empty($scan_result['files_changed'])) { + //Output of files changed + $scan_summary .= "\r\n".__('The following files were changed on your host', 'all-in-one-wp-security-and-firewall').":\r\n"; + foreach ($scan_result['files_changed'] as $key => $value) { + $scan_summary .= "\r\n".$key.' ('.__('modified on:', 'all-in-one-wp-security-and-firewall'). ' ' . AIOWPSecurity_Utility::convert_timestamp($value['last_modified']).')'; + } + $scan_summary .= "\r\n======================================\r\n"; + } + + return $scan_summary; + } + + /** + * Saves file change detection data into a special file + * + * @global AIO_WP_Security $aio_wp_security + * @param type $scanned_data + * @param type $scan_result + * @return boolean + */ + public function save_fcd_data($scanned_data, $scan_result = array()) { + global $aio_wp_security; + + $date_time = current_time('mysql'); + $data = array('date_time' => $date_time, 'file_scan_data' => $scanned_data, 'last_scan_result' => $scan_result); + + $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename'); + $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME; + + if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) { + $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Creation of DB backup directory failed!", 4); + return false; + } + + // phpcs:disable WordPress.WP.AlternativeFunctions -- Silence wp_filesystem method suggestion. We cannot use that method. + $results_file = $aiowps_backup_dir. '/'. $fcd_filename; + $fp = fopen($results_file, 'w'); + fwrite($fp, json_encode($data)); + fclose($fp); + // phpcs:enable WordPress.WP.AlternativeFunctions -- Silence wp_filesystem method suggestion. We cannot use that method. + + return true; + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource-unavailable.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource-unavailable.php new file mode 100755 index 00000000..923b1ec9 --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource-unavailable.php @@ -0,0 +1,74 @@ +resource = $resource; + do_action('aios_firewall_unavailable_resource', $this->resource); + } + + /** + * Handles call operation on an unavailable firewall resource. + * + * @param string $name + * @param array $arguments + * + * @return void + */ + public function __call($name, $arguments) { + do_action('aios_firewall_unavailable_resource_method_call', $this->resource, $name, $arguments); + } + + /** + * Handles call operation on an unavailable static firewall resource. + * + * @param string $name + * @param array $arguments + * + * @return void + */ + public static function __callStatic($name, $arguments) { + do_action('aios_firewall_unavailable_resource_static_method_call', $name, $arguments); + } + + /** + * Handles get operation on an unavailable firewall resource. + * + * @param string $name + * + * @return void + */ + public function __get($name) { + do_action('aios_firewall_unavailable_resource_get_property', $this->resource, $name); + } + + /** + * Handles set operation on an unavailable firewall resource. + * + * @param string $name + * @param mixed $value + * + * @return void + */ + public function __set($name, $value) { + do_action('aios_firewall_unavailable_resource_set_property', $this->resource, $name, $value); + } + +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource.php new file mode 100755 index 00000000..a00df11a --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-firewall-resource.php @@ -0,0 +1,53 @@ +configs->get_value('aiowps_disable_xmlrpc_pingback_methods')) { + add_filter('xmlrpc_methods', array($this, 'aiowps_disable_xmlrpc_pingback_methods')); + add_filter('wp_headers', array($this, 'aiowps_remove_x_pingback_header')); + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_disable_rss_and_atom_feeds')) { + add_action('do_feed', array($this, 'block_feed'), 1); + add_action('do_feed_rdf', array($this, 'block_feed'), 1); + add_action('do_feed_rss', array($this, 'block_feed'), 1); + add_action('do_feed_rss2', array($this, 'block_feed'), 1); + add_action('do_feed_atom', array($this, 'block_feed'), 1); + add_action('do_feed_rss2_comments', array($this, 'block_feed'), 1); + add_action('do_feed_atom_comments', array($this, 'block_feed'), 1); + + remove_action('wp_head', 'feed_links_extra', 3); + remove_action('wp_head', 'feed_links', 2); + } + + // Check permanent block list and block if applicable (ie, do PHP blocking) + if (!is_user_logged_in()) { + AIOWPSecurity_Blocking::check_visitor_ip_and_perform_blocking(); + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_spambot_detecting') && '0' == $aio_wp_security->configs->get_value('aiowps_spam_comments_should')) { + add_action('pre_comment_on_post', array($this, 'spam_detecting_and_process_comments_discard'), 10, 2); //this hook gets fired before comment is added + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_spambot_detecting') && '1' == $aio_wp_security->configs->get_value('aiowps_spam_comments_should')) { + add_filter('pre_comment_approved', array($this, 'spam_detecting_and_process_comments_mark_spam'), 10, 2); //this hook filters a comments approval status before it is set + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip')) { + add_action('comment_post', array($this, 'spam_detect_process_comment_post'), 10, 2); //this hook gets fired just after comment is saved to DB + add_action('transition_comment_status', array($this, 'process_transition_comment_status'), 10, 3); //this hook gets fired when a comment's status changes + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')) { + add_action('widgets_init', array($this, 'remove_standard_wp_meta_widget')); + add_filter('retrieve_password_message', array($this, 'decode_reset_pw_msg'), 10, 4); //Fix for non decoded html entities in password reset link + // Gravity form preview exposed renamed login page when called auth_redirect + add_filter('login_url', array($this, 'login_url_reauth_redirect'), 10, 3); + } + + if (AIOWPSecurity_Utility_Permissions::has_manage_cap() && is_admin()) { + if ('1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) { + add_action('all_admin_notices', array($this, 'google_recaptcha_notice')); + } + + if (is_main_site() && is_super_admin()) { + add_action('all_admin_notices', array($this, 'do_firewall_notice')); + add_action('admin_post_aiowps_firewall_setup', array(AIOWPSecurity_Firewall_Setup_Notice::get_instance(), 'handle_setup_form')); + add_action('admin_post_aiowps_firewall_downgrade', array(AIOWPSecurity_Firewall_Setup_Notice::get_instance(), 'handle_downgrade_protection_form')); + add_action('admin_post_aiowps_firewall_setup_dismiss', array(AIOWPSecurity_Firewall_Setup_Notice::get_instance(), 'handle_dismiss_form')); + } + } + + /** + * Send X-Frame-Options: SAMEORIGIN in HTTP header + */ + if ('1' == $aio_wp_security->configs->get_value('aiowps_prevent_site_display_inside_frame')) { + add_action('template_redirect', 'send_frame_options_header'); + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info')) { + add_filter('the_generator', array($this,'remove_wp_generator_meta_info')); + add_filter('style_loader_src', array($this,'remove_wp_css_js_meta_info')); + add_filter('script_loader_src', array($this,'remove_wp_css_js_meta_info')); + } + + // For the cookie based brute force prevention feature + // Already logged in user should not redirected to brute_force_redirect_url in any case so added condition !is_user_logged_in() + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention')) { + $bfcf_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word'); + if (isset($_GET[$bfcf_secret_word])) { + AIOWPSecurity_Utility_IP::check_login_whitelist_and_forbid(); + + // If URL contains secret word in query param then set cookie and then redirect to the login page + AIOWPSecurity_Utility::set_cookie_value(AIOWPSecurity_Utility::get_brute_force_secret_cookie_name(), AIOS_Helper::get_hash($bfcf_secret_word)); + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') && !is_user_logged_in()) { + $login_url = home_url((get_option('permalink_structure') ? '' : '?') . $aio_wp_security->configs->get_value('aiowps_login_page_slug')); + AIOWPSecurity_Utility::redirect_to_url($login_url); + } elseif (!is_user_logged_in()) { + AIOWPSecurity_Utility::redirect_to_url(AIOWPSEC_WP_URL.'/wp-admin'); + } + } + } + // Stop users enumeration feature + if (1 == $aio_wp_security->configs->get_value('aiowps_prevent_users_enumeration')) { + include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-stop-users-enumeration.php'); + add_filter('rest_request_before_callbacks', array($this, 'rest_request_before_callbacks'), 10, 1); + add_filter('oembed_response_data', array($this, 'oembed_response_data'), 10, 1); + } + + // REST API security + if ($aio_wp_security->configs->get_value('aiowps_disallow_unauthorized_rest_requests') == 1) { + add_action('rest_api_init', array($this, 'check_rest_api_requests'), 10, 1); + } + + // For user unlock request feature + if (isset($_POST['aiowps_unlock_request']) || isset($_POST['aiowps_wp_submit_unlock_request'])) { + nocache_headers(); + remove_action('wp_head', 'head_addons', 7); + include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-unlock-request.php'); + exit(); + } + + if (isset($_GET['aiowps_auth_key'])) { + //If URL contains unlock key in query param then process the request + $unlock_key = sanitize_text_field($_GET['aiowps_auth_key']); + AIOWPSecurity_User_Login::process_unlock_request($unlock_key); + } + + // For honeypot feature + if (isset($_POST['aio_special_field'])) { + $special_field_value = sanitize_text_field($_POST['aio_special_field']); + if (!empty($special_field_value)) { + //This means a robot has submitted the login form! + //Redirect back to its localhost + AIOWPSecurity_Utility::redirect_to_url('http://127.0.0.1'); + } + } + + // For 404 IP lockout feature + if ($aio_wp_security->configs->get_value('aiowps_enable_404_IP_lockout') == '1') { + if (!is_user_logged_in() || !current_user_can('administrator')) { + $this->do_404_lockout_tasks(); + } + } + + + // For login CAPTCHA feature + if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('login_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + if (AIOWPSecurity_Utility::is_memberpress_plugin_active()) { + add_action('mepr-login-form-before-submit', array($aio_wp_security->captcha_obj, 'add_captcha_script')); + add_action('mepr-login-form-before-submit', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); // for memberpress login form + } + } + } + + // For woo form CAPTCHA features + if ($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('woocommerce_login_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + } + if (isset($_POST['woocommerce-login-nonce'])) { + add_filter('woocommerce_process_login_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3); + } + } + + if ($aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('woocommerce_register_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + } + + if (isset($_POST['woocommerce-register-nonce'])) { + add_filter('woocommerce_process_registration_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3); + } + } + + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_woo_checkout_captcha') && !is_user_logged_in()) { + add_action('woocommerce_after_checkout_billing_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + add_action('woocommerce_after_checkout_validation', array($this, 'aiowps_validate_woo_checkout_captcha'), 10, 2); + } + + if ($aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('woocommerce_lostpassword_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + } + if (isset($_POST['woocommerce-lost-password-nonce'])) { + add_action('lostpassword_post', array($this, 'process_woo_lost_password_form_post')); + } + } + + // For bbPress new topic form CAPTCHA + if ($aio_wp_security->configs->get_value('aiowps_enable_bbp_new_topic_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('bbp_theme_before_topic_form_submit_wrapper', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + } + } + + // For custom login form CAPTCHA feature, ie, when wp_login_form() function is used to generate login form + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') && !is_user_logged_in()) { + add_filter('login_form_middle', array($aio_wp_security->captcha_obj, 'insert_captcha_custom_login'), 10, 2); //For cases where the WP wp_login_form() function is used + add_filter('login_form_bottom', array($aio_wp_security->captcha_obj, 'add_captcha_script'), 20); + } + + // For password protected pages CAPTCHA feature + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_password_protected_captcha')) { + add_filter('the_password_form', array($aio_wp_security->captcha_obj, 'insert_captcha_password_protected')); + add_action('login_form_postpass', array($aio_wp_security->captcha_obj, 'validate_password_protected_password_form_with_captcha')); + } + + // For honeypot feature + if ($aio_wp_security->configs->get_value('aiowps_enable_login_honeypot') == '1') { + if (!is_user_logged_in()) { + add_action('login_form', array($this, 'insert_honeypot_hidden_field')); + } + } + + // For registration honeypot feature + if ($aio_wp_security->configs->get_value('aiowps_enable_registration_honeypot') == '1') { + if (!is_user_logged_in()) { + add_action('register_form', array($this, 'insert_honeypot_hidden_field')); + } + } + + // For disable application password feature hide generate password + if ('1' == $aio_wp_security->configs->get_value('aiowps_disable_application_password')) { + add_filter('wp_is_application_passwords_available', '__return_false'); + add_action('edit_user_profile', array($this, 'show_disabled_application_password_message')); + add_action('show_user_profile', array($this, 'show_disabled_application_password_message')); + + // Override the wp_die handler for app passwords were disabled. + if (!empty($_SERVER['SCRIPT_FILENAME']) && ABSPATH . 'wp-admin/authorize-application.php' == $_SERVER['SCRIPT_FILENAME']) { + add_filter('wp_die_handler', function () { + return function ($message, $title, $args) { + if ('Application passwords are not available.' == $message) { + $message = htmlspecialchars(__('Application passwords have been disabled by All-In-One Security plugin.', 'all-in-one-wp-security-and-firewall')); + } + _default_wp_die_handler($message, $title, $args); + }; + }, 10, 1); + } + } + + // For lost password CAPTCHA feature + if ($aio_wp_security->configs->get_value('aiowps_enable_lost_password_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('lostpassword_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + add_action('lostpassword_post', array($this, 'process_lost_password_form_post')); + + if (AIOWPSecurity_Utility::is_memberpress_plugin_active()) { + add_action('mepr-forgot-password-form', array($aio_wp_security->captcha_obj, 'add_captcha_script')); + add_action('mepr-forgot-password-form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); // for memberpress forgot password form + add_filter('mepr-validate-forgot-password', array($aio_wp_security->captcha_obj, 'verify_memberpress_form')); // for memberpress forgot password form + } + } + } + + // For registration manual approval feature + if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') { + add_filter('wp_login_errors', array($this, 'modify_registration_page_messages'), 10, 2); + } + + // For registration page CAPTCHA feature + if (is_multisite()) { + $blog_id = get_current_blog_id(); + switch_to_blog($blog_id); + if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('signup_extra_fields', array($this, 'insert_captcha_question_form_multi')); + //add_action('preprocess_signup_form', array($this, 'process_signup_form_multi')); + add_filter('wpmu_validate_user_signup', array($this, 'process_signup_form_multi')); + } + } + restore_current_blog(); + } else { + if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') { + if (!is_user_logged_in()) { + add_action('register_form', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + } + } + } + + if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') { + if (AIOWPSecurity_Utility::is_memberpress_plugin_active()) { + add_action('mepr-checkout-after-password-fields', array($aio_wp_security->captcha_obj, 'add_captcha_script')); + add_action('mepr-checkout-after-password-fields', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); // for memberpress register form + add_filter('mepr-validate-signup', array($aio_wp_security->captcha_obj, 'verify_memberpress_form')); // for memberpress register form + } + } + + // For comment CAPTCHA feature or custom login form CAPTCHA + if (is_multisite()) { + $blog_id = get_current_blog_id(); + switch_to_blog($blog_id); + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') && !is_user_logged_in()) { + add_action('comment_form_after_fields', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form'), 1); + add_action('comment_form_after_fields', array($aio_wp_security->captcha_obj, 'add_captcha_script'), 10); + add_filter('preprocess_comment', array($this, 'process_comment_post')); + } + restore_current_blog(); + } else { + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') && !is_user_logged_in()) { + add_action('comment_form_after_fields', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form'), 1); + add_action('comment_form_after_fields', array($aio_wp_security->captcha_obj, 'add_captcha_script'), 10); + add_filter('preprocess_comment', array($this, 'process_comment_post')); + } + } + + // For BuddyPress registration CAPTCHA feature + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha')) { + add_action('bp_before_registration_submit_buttons', array($aio_wp_security->captcha_obj, 'insert_captcha_question_form')); + add_action('bp_before_registration_submit_buttons', array($aio_wp_security->captcha_obj, 'add_captcha_script'), 10); + add_action('bp_signup_validate', array($this, 'buddy_press_signup_validate_captcha')); + } + + // For 404 event logging + if ($aio_wp_security->configs->get_value('aiowps_enable_404_logging') == '1') { + add_action('template_redirect', array($this, 'check_404_event')); + } + + // For antibot post page set cookies. + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_spambot_detecting') && !is_user_logged_in()) { + if ('1' == $aio_wp_security->configs->get_value('aiowps_spambot_detect_usecookies')) { + add_action('template_redirect', array($this, 'post_antibot_cookie')); + } + add_filter('comment_form_submit_field', array($this, 'comment_form_submit_field'), 10, 1); + } + + // For delete readme.html and wp-config-sample.php. + if ('1' == $aio_wp_security->configs->get_value('aiowps_auto_delete_default_wp_files')) { + add_action('upgrader_process_complete', array($this, 'delete_unneeded_files_after_upgrade'), 10, 2); + } + + // filter php firewall templates array + add_filter('aiowps_modify_php_firewall_rules_template', array($this, 'filter_templates'), 10, 1); + + // For HTTP authentication. + if ('1' == $aio_wp_security->configs->get_value('aiowps_http_authentication_admin') || '1' == $aio_wp_security->configs->get_value('aiowps_http_authentication_frontend')) { + $this->http_authentication(); + } + + // for enforcing strong passwords + if ('1' == $aio_wp_security->configs->get_value('aiowps_enforce_strong_password')) { + wp_register_script('remove-weak-pw', AIO_WP_SECURITY_URL.'/js/remove-weak-pw.js', array('jquery'), AIO_WP_SECURITY_VERSION, true); + wp_enqueue_script('remove-weak-pw'); + } + + // For HIBP. + if ('1' == $aio_wp_security->configs->get_site_value('aiowps_hibp_user_profile_update')) { + add_action('user_profile_update_errors', 'AIOS_HIBP::user_profile_update_check', 1, 3); + } + + if ('1' == $aio_wp_security->configs->get_site_value('aiowps_http_password_reset')) { + add_action('validate_password_reset', 'AIOS_HIBP::password_reset_check', 1, 2); + } + + // For Upgrade unsafe HTTP calls. + if ('1' == $aio_wp_security->configs->get_site_value('aiowps_upgrade_unsafe_http_calls')) { + add_filter('http_request_reject_unsafe_urls', array($this, 'http_request_reject_unsafe_urls'), 10, 2); + } + + // Add more tasks that need to be executed at init time + + add_filter('aiowps_modify_captcha_settings_template', array($this, 'filter_captcha_settings_templates'), 10, 1); + } // end _construct() + + public function aiowps_disable_xmlrpc_pingback_methods($methods) { + unset($methods['pingback.ping']); + unset($methods['pingback.extensions.getPingbacks']); + return $methods; + } + + public function aiowps_remove_x_pingback_header($headers) { + unset($headers['X-Pingback']); + return $headers; + } + + /** + * Blocks feed by redirecting user to home url. + * + * @return Void + */ + public function block_feed() { + wp_redirect(home_url()); + } + + /** + * Spam detection and discard comment. + * + * @param int $comment_post_id + * + * @return void + */ + public function spam_detecting_and_process_comments_discard($comment_post_id) { + $is_comment_should_not_allowed = AIOWPSecurity_Comment::is_comment_spam_detected(); + if ($is_comment_should_not_allowed) { + $this->spam_discard_auto_block_ip(); + $comments = get_comments(array('number' => '1', 'post_id' => $comment_post_id)); + if ($comments) { + $loc = get_comment_link($comments[0]->comment_ID); + } else { + $loc = get_permalink($comment_post_id) . '#spam-comment-msg'; + } + wp_safe_redirect($loc); + exit; + } + } + + /** + * Block IP for spam discard after minimum comments reached. + * + * @return void + */ + public function spam_discard_auto_block_ip() { + global $aio_wp_security, $wpdb; + + if ('1' != $aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip')) return; + + AIOWPSecurity_Utility::event_logger('spam_discard'); + $comment_ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); + $spam_count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(id) FROM ".AIOWPSEC_TBL_EVENTS." WHERE ip_or_host = %s AND event_type=%s", $comment_ip, 'spam_discard')); + $min_comment_before_block = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block'); + if (!empty($min_comment_before_block) && $spam_count > $min_comment_before_block) { + AIOWPSecurity_Blocking::add_ip_to_block_list($comment_ip, 'spam_discard'); + } + } + + /** + * Spam detection and mark as spam comment. + * + * @param string $approved + * + * @return string status + */ + public function spam_detecting_and_process_comments_mark_spam($approved) { + return AIOWPSecurity_Comment::is_comment_spam_detected() ? 'spam' : $approved; + } + + public function spam_detect_process_comment_post($comment_id, $comment_approved) { + if ("spam" === $comment_approved) { + $this->block_comment_ip($comment_id); + } + + } + + public function process_transition_comment_status($new_status, $old_status, $comment) { + if ('spam' == $new_status) { + $this->block_comment_ip($comment->comment_ID); + } + + } + + /** + * Will check auto-spam blocking settings and will add IP to blocked table accordingly + * + * @param int $comment_id + */ + public function block_comment_ip($comment_id) { + global $aio_wp_security, $wpdb; + $comment_obj = get_comment($comment_id); + $comment_ip = $comment_obj->comment_author_IP; + //Get number of spam comments from this IP + $sql = $wpdb->prepare("SELECT * FROM $wpdb->comments + WHERE comment_approved = 'spam' + AND comment_author_IP = %s + ", $comment_ip); + $comment_data = $wpdb->get_results($sql, ARRAY_A); + $spam_count = count($comment_data); + $min_comment_before_block = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block'); + if (!empty($min_comment_before_block) && $spam_count >= ($min_comment_before_block - 1)) { + AIOWPSecurity_Blocking::add_ip_to_block_list($comment_ip, 'spam'); + } + } + + public function remove_standard_wp_meta_widget() { + unregister_widget('WP_Widget_Meta'); + } + + public function remove_wp_generator_meta_info() { + return ''; + } + + /** + * This function removes wp meta info from style and script src + * + * @param string|null $src - the src for the style or script + * @return string + */ + public function remove_wp_css_js_meta_info($src) { + global $wp_version; + static $wp_version_hash = null; // Cache hash value for all function calls + + if (empty($src)) return ''; + + // Replace only version number of assets with WP version + if (strpos($src, 'ver=' . $wp_version) !== false) { + if (!$wp_version_hash) { + $wp_version_hash = wp_hash($wp_version); + } + // Replace version number with computed hash + $src = add_query_arg('ver', $wp_version_hash, $src); + } + return $src; + } + + public function do_404_lockout_tasks() { + global $aio_wp_security; + $redirect_url = $aio_wp_security->configs->get_value('aiowps_404_lock_redirect_url'); //This is the redirect URL for blocked users + + $visitor_ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); + + $is_locked = AIOWPSecurity_Utility::check_locked_ip($visitor_ip, '404'); + + if ($is_locked) { + //redirect blocked user to configured URL + AIOWPSecurity_Utility::redirect_to_url($redirect_url); + } else { + //allow through + } + } + + public function insert_captcha_question_form_multi() { + global $aio_wp_security; + $default_captcha = $aio_wp_security->configs->get_value('aiowps_default_captcha'); + $aio_wp_security->captcha_obj->display_captcha_form($default_captcha); + } + + public function process_signup_form_multi($result) { + global $aio_wp_security; + // Check if CAPTCHA enabled + $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit(); + if (false === $verify_captcha) { + // wrong answer was entered + $result['errors']->add('generic', __('ERROR: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall')); + } + return $result; + } + + /** + * This function echos a honeypot hidden field into login or register form + * + * @return void + */ + public function insert_honeypot_hidden_field() { + $honey_input = ''; + echo $honey_input; + } + + /** + * Shows application password disabled message on user edit profile page. + * If logged user is admin showing the Change Setting option. + * + * @return void + */ + public function show_disabled_application_password_message() { + if (is_user_logged_in() && is_admin()) { + $disabled_message = '| '.__('Disabled', 'all-in-one-wp-security-and-firewall').' | '; + $disabled_message .= ''.htmlspecialchars(__('Application passwords have been disabled by All-In-One Security plugin.', 'all-in-one-wp-security-and-firewall'));
+ if (AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ $change_setting_url = admin_url('admin.php?page=aiowpsec_usersec&tab=additional');
+ $disabled_message .= ' '.__('Change setting', 'all-in-one-wp-security-and-firewall').' '; + } else { + $disabled_message .= ' '.__('Site admin can only change this setting.', 'all-in-one-wp-security-and-firewall'); + } + $disabled_message .= ' | ';
+ $disabled_message .= '
|---|
'; + /* translators: %s: Admin Dashboard > WP Security > Brute Force > Login CAPTCHA Tab Link */ + printf(__('Your Google reCAPTCHA configuration is invalid.', 'all-in-one-wp-security-and-firewall').' '.__('Please enter the correct reCAPTCHA keys %s to use the Google reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall'), ''.__('here', 'all-in-one-wp-security-and-firewall').''); + echo '
' . + esc_html__('The All in One Security plugin has deactivated some of the firewall settings that you had activated.', 'all-in-one-wp-security-and-firewall') . + '
'; + $firewall_upgrade_text .= '' . + esc_html__('We have upgraded the following settings so that they are now part of the PHP firewall instead of .htaccess directives:', 'all-in-one-wp-security-and-firewall') . + '
'; + $firewall_upgrade_text .= '' . esc_html__('None of the settings that have been upgraded were active.', 'all-in-one-wp-security-and-firewall').'
'; + } + + $firewall_upgrade_text .= '' . esc_html__('What would you like to do?', 'all-in-one-wp-security-and-firewall') .'
'; + + $login_whitelist_notice_text = '' . + esc_html__('The All in One Security plugin has disabled the login whitelist setting that you have enabled in the past.', 'all-in-one-wp-security-and-firewall') . + '
' . + ''; + if (AIOWPSecurity_Utility::is_apache_server()) { + $login_whitelist_notice_text .= esc_html__('Your website is running on an Apache webserver, the login whitelisting might not be functional until the recent update of AIOS (because it relied upon Apache-specific module features).', 'all-in-one-wp-security-and-firewall'); + } else { + $login_whitelist_notice_text .= esc_html__('Your website is running on a non-Apache webserver, so the login whitelisting was not functional until the recent update of AIOS (because it relied upon Apache-specific features).', 'all-in-one-wp-security-and-firewall'); + } + $login_whitelist_notice_text .= ' ' . esc_html__('It began working with AIOS version 5.0.8.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('We have disabled it so that your login page will not be blocked unexpectedly.', 'all-in-one-wp-security-and-firewall') . + '
'; + + $allowed_ip_addresses = explode("\n", $aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses')); + $allowed_ip_addresses = array_map('trim', $allowed_ip_addresses); + $login_whitelist_notice_text .= '' . + esc_html__('Whitelisted login IP address(es):', 'all-in-one-wp-security-and-firewall') . ' ' . htmlspecialchars(implode(', ', $allowed_ip_addresses)) . + '
' . + '' . + esc_html__('Would you like to re-enable login whitelisting?', 'all-in-one-wp-security-and-firewall') . + '
'; + + $child_notice_content = array( + // Upgrade AIOS backup to UDP backup in the 5.0.0 version + 'automated-database-backup' => array( + 'title' => esc_html__('Removed database backup feature from the All-In-One Security plugin', 'all-in-one-wp-security-and-firewall'), + 'text' => '' . + esc_html__('Beginning with version 5.0.0, AIOS has replaced the AIOS backup method with the superior UpdraftPlus method.', 'all-in-one-wp-security-and-firewall') . ' '. + esc_html__('It remains free and is fully supported by the UpdraftPlus team.', 'all-in-one-wp-security-and-firewall') . + '
' . + '' . + esc_html__('You are seeing this notice because you have previously set up automated database backups in AIOS.', 'all-in-one-wp-security-and-firewall') . ' ' . + esc_html__('Would you like to set up scheduled backups with UpdraftPlus?', 'all-in-one-wp-security-and-firewall') . + '
', + 'button_link' => add_query_arg(array( + 'page' => 'aiowpsec_database', + 'tab' => 'database-backup', + ), admin_url('admin.php')) . '#automated-scheduled-backups-heading', + 'button_meta' => esc_html__('Setup UpdraftPlus backup plugin', 'all-in-one-wp-security-and-firewall'), + 'dismiss_time' => 'dismiss_automated_database_backup_notice', + 'supported_positions' => array('automated-database-backup'), + 'validity_function' => 'should_show_automated_database_backup_notice', + ), + 'ip-retrieval-settings' => array( + 'title' => esc_html__('Important: set up your IP address detection settings', 'all-in-one-wp-security-and-firewall'), + 'text' => '' . + esc_html__("The All in One Security plugin couldn't be certain about the correct method to detect the IP address for your site visitors with your currently-configured IP address detection settings.", 'all-in-one-wp-security-and-firewall') . ' '. + esc_html__('It is important for your security to set the IP address detection settings properly.', 'all-in-one-wp-security-and-firewall') . + '
' . + '' . + esc_html__('Please go to the settings and set them now.', 'all-in-one-wp-security-and-firewall') . + '
', + 'button_link' => add_query_arg(array( + 'page' => 'aiowpsec_settings', + 'tab' => 'advanced-settings', + ), admin_url('admin.php')) . '#automated-scheduled-backups-heading', + 'button_meta' => esc_html__('Setup IP address detection settings', 'all-in-one-wp-security-and-firewall'), + 'dismiss_time' => 'dismiss_ip_retrieval_settings_notice', + 'supported_positions' => array('ip-retrieval-settings'), + 'validity_function' => 'should_show_ip_retrieval_settings_notice', + ), + 'load-firewall-resources-failed' => array( + 'title' => '', + 'text' => '' . + esc_html__('Failed to load the firewall resources.', 'all-in-one-wp-security-and-firewall') . ' ' . + esc_html__('The firewall won\'t operate correctly.', 'all-in-one-wp-security-and-firewall') . + '
', + 'dismiss_time' => '', + 'supported_positions' => array('load-firewall-resources-failed'), + 'validity_function' => 'should_show_load_firewall_resources_failed_notice', + ), + 'end-of-support-php-56' => array( + 'title' => esc_html__('AIOS PHP 5.6 support will end soon', 'all-in-one-wp-security-and-firewall'), + 'text' => $this->get_end_of_support_php_56_text(), + 'dismiss_time' => 'php_56_eol_dismiss_forever', + 'supported_positions' => array('end-of-support-php-56'), + 'validity_function' => 'should_show_end_of_support_php_56', + ), + 'upgrade-firewall-tab-rules' => array( + 'title' => esc_html__('Important: Disabled firewall settings', 'all-in-one-wp-security-and-firewall'), + 'text' => $firewall_upgrade_text, + 'button_link' => add_query_arg(array( + 'page' => esc_html(AIOWPSEC_FIREWALL_MENU_SLUG), + 'tab' => 'basic-firewall', + ), admin_url('admin.php')), + 'action_button_text' => esc_html__('Reactivate', 'all-in-one-wp-security-and-firewall'), + 'button_meta' => esc_html__('Configure manually', 'all-in-one-wp-security-and-firewall'), + 'dismiss_time' => 'dismiss_firewall_settings_disabled_on_upgrade_notice', + 'supported_positions' => array('upgrade-firewall-tab-rules'), + 'dismiss_text' => esc_html__('Keep deactivated', 'all-in-one-wp-security-and-firewall'), + 'validity_function' => 'should_show_upgrade_firewall_settings_notice', + ), + 'ip-blacklist-settings-on-upgrade' => array( + 'title' => esc_html__('Important: Blacklist manager disabled', 'all-in-one-wp-security-and-firewall'), + 'text' => '' . + esc_html__("The blacklist manager feature has been disabled to prevent any unexpected site lockouts.", 'all-in-one-wp-security-and-firewall') . + '
' . + '' . + esc_html__("This feature will block any IP address or range listed in its settings, please double check your own details are not included before turning it back on.", 'all-in-one-wp-security-and-firewall') . + '
' , + 'button_link' => add_query_arg(array( + 'page' => esc_html(AIOWPSEC_FIREWALL_MENU_SLUG), + 'tab' => 'blacklist' + ), admin_url('admin.php')) . '#poststuff', + 'action_button_text' => 'Turn it on', + 'button_meta' => esc_html__('Edit the settings', 'all-in-one-wp-security-and-firewall'), + 'dismiss_time' => 'dismiss_ip_blacklist_notice', + 'dismiss_text' => 'Keep it off', + 'supported_positions' => array('ip-blacklist-settings-on-upgrade'), + 'validity_function' => 'should_show_ip_blacklist_settings_on_upgrade', + ), + 'login-whitelist-disabled-on-upgrade' => array( + 'title' => esc_html__('Important: Disabled login whitelist setting', 'all-in-one-wp-security-and-firewall'), + 'text' => $login_whitelist_notice_text, + 'button_link' => add_query_arg(array( + 'page' => esc_html(AIOWPSEC_BRUTE_FORCE_MENU_SLUG), + 'tab' => 'login-whitelist', + ), admin_url('admin.php')) . '#poststuff', + 'action_button_text' => esc_html__('Turn it back on', 'all-in-one-wp-security-and-firewall'), + 'button_meta' => esc_html__('Edit the settings', 'all-in-one-wp-security-and-firewall'), + 'dismiss_time' => 'dismiss_login_whitelist_disabled_on_upgrade_notice', + 'supported_positions' => array('login-whitelist-disabled-on-upgrade'), + 'dismiss_text' => esc_html__('Keep it off', 'all-in-one-wp-security-and-firewall'), + 'validity_function' => 'should_show_login_whitelist_disabled_on_upgrade_notice', + ), + 'rate_plugin' => array( + 'text' => $this->safe_sprintf(esc_html__('We noticed AIOS has kept your site safe for a while.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('If you like us, please consider leaving a positive review.', 'all-in-one-wp-security-and-firewall'). ' ' . esc_html__('If you have any issues or questions, please contact %s.', 'all-in-one-wp-security-and-firewall'), '' . esc_html__('support', 'all-in-one-wp-security-and-firewall').'') . '' . esc_html__('AIOS will end support for PHP 5.6 on the 1st September 2025.', 'all-in-one-wp-security-and-firewall') . '
'; + + $text .= '' . esc_html__('PHP 5.6 is outdated and no longer receives security updates.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('To keep things secure and compatible with modern WordPress standards, AIOS will move to a minimum requirement of PHP 7.0.', 'all-in-one-wp-security-and-firewall') . '
'; + + $text .= '' . esc_html__('After the 1st September 2025, AIOS may not operate correctly on PHP versions below 7.0.', 'all-in-one-wp-security-and-firewall') . '
'; + + $text .= '' . esc_html__('If you require help upgrading your PHP version, please contact your hosting provider.', 'all-in-one-wp-security-and-firewall') . '
'; + + return $text; + } + + /** + * Decides whether to show the load firewall resources failed notice. + * + * @return boolean + */ + protected function should_show_load_firewall_resources_failed_notice() { + return !AIOS_Firewall_Resource::all_loaded(); + } + + /** + * Determines whether to show the notice which handles the firewall settings notice + * + * @return boolean + */ + protected function should_show_upgrade_firewall_settings_notice() { + if (!is_main_site()) { + return false; + } + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + $is_firewall_page = ('admin.php' == $GLOBALS['pagenow'] && isset($_GET['page']) && AIOWPSEC_FIREWALL_MENU_SLUG == $_GET['page']); + if ($is_firewall_page) return false; + + global $aio_wp_security; + + $active_settings = $aio_wp_security->configs->get_value('aiowps_firewall_active_upgrade'); + + if (empty($active_settings)) return false; + + $active_settings = json_decode($active_settings); + + if (empty($active_settings)) return false; + + return true; + } + + /** + * Whether the current page is the AIOS database backup admin page + * + * @return Boolean True if the current page is the AIOS database backup admin page, otherwise false. + */ + private function is_database_backup_admin_page_tab() { + return $this->is_database_security_admin_page() && $this->is_database_backup_tab(); + } + + /** + * Whether the current page is the database security admin page. + * + * @return Boolean True if the current page is the database security admin page, otherwise false. + */ + private function is_database_security_admin_page() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return ('admin.php' == $GLOBALS['pagenow'] && isset($_GET['page']) && 'aiowpsec_database' == $_GET['page']); + } + + /** + * Whether the current tab is the database backup tab. + * + * @return Boolean True if the current tab is the database backup tab, otherwise false. + */ + private function is_database_backup_tab() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return (isset($_GET['tab']) && 'database-backup' == $_GET['tab']); + } + + /** + * Decides whether to show the IP address detection settings notice. + * + * @return Boolean True if the IP address detection settings notice should be shown, otherwise false. + */ + protected function should_show_ip_retrieval_settings_notice() { + if (!is_main_site()) { + return false; + } + + if ($this->is_ip_settings_admin_page_tab()) { + return false; + } + + if (defined('AIOS_FORCE_IP_RETRIEVAL_SETTINGS_NOTICE') && AIOS_FORCE_IP_RETRIEVAL_SETTINGS_NOTICE) { + return true; + } + + global $aio_wp_security; + $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); + + // Is notice dismissed. + if ('1' == $aio_wp_security->configs->get_value('dismiss_ip_retrieval_settings_notice')) { + return false; + } + + $configured_ip_method_id = $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'); + + if (AIOWPSecurity_Utility_IP::is_server_suitable_ip_methods_give_same_ip_address()) { + if ('' === $configured_ip_method_id) { + $server_suitable_ip_methods = AIOWPSecurity_Utility_IP::get_server_suitable_ip_methods(); + $most_suitable_ip_method = reset($server_suitable_ip_methods); + if (!empty($most_suitable_ip_method)) { + $most_suitable_ip_method_id = array_search($most_suitable_ip_method, AIOS_Abstracted_Ids::get_ip_retrieve_methods()); + $aio_wp_security->configs->set_value('aiowps_ip_retrieve_method', $most_suitable_ip_method_id); + $aiowps_firewall_config->set_value('aios_ip_retrieve_method', $most_suitable_ip_method_id, true); + } + } + + return false; + } + + // If the IP retrieval method is not set. + $configured_ip_method_id = $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'); + if ('' === $configured_ip_method_id) { + return true; + } + + $server_user_ip_address = AIOS_Helper::get_server_detected_user_ip_address(); + return empty($server_user_ip_address); + } + + /** + * Whether the current page is the AIOS IP retrieval admin page + * + * @return Boolean True if the current page is the AIOS database backup admin page, otherwise false. + */ + private function is_ip_settings_admin_page_tab() { + return $this->is_settings_admin_page() && $this->is_advanced_settings_tab(); + } + + /** + * Whether the current page is the AIOS settings admin page + * + * @return Boolean True if the current page is the AIOS settings admin page, otherwise false. + */ + private function is_settings_admin_page() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return ('admin.php' == $GLOBALS['pagenow'] && isset($_GET['page']) && 'aiowpsec_settings' == $_GET['page']); + } + + /** + * Whether the current tab is the advanced settings tab. + * + * @return Boolean True if the current tab is the advanced settings tab, otherwise false. + */ + private function is_advanced_settings_tab() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return (isset($_GET['tab']) && 'advanced-settings' == $_GET['tab']); + } + + /** + * Check whether the UpdraftPlus plugin is active or not. + * + * @return bool True if the UpdraftPlus plugin is active, otherwise false. + */ + private function is_updraftplus_plugin_active() { + return class_exists('UpdraftPlus'); + } + + /** + * Check whether the database backup scheduled in the UpdraftPlus plugin. + * + * @return bool + */ + private function is_schedule_database_backup_set_in_updraftplus() { + $updraft_interval_database_option_val = get_option('updraft_interval_database', ''); + if (empty($updraft_interval_database_option_val) || 'manual' == $updraft_interval_database_option_val) { + return false; + } + + return true; + } + + /** + * Decides whether to show the IP Blacklist settings notice. + * + * @return Boolean True if the IP Blacklist settings notice should be shown, otherwise false. + */ + protected function should_show_ip_blacklist_settings_on_upgrade() { + if (!is_main_site()) { + return false; + } + + if ($this->is_blacklist_admin_page()) { + return false; + } + + global $aio_wp_security; + + if ('1' == $aio_wp_security->configs->get_value('aiowps_is_ip_blacklist_settings_notice_on_upgrade')) { + return true; + } + + return false; + } + + /** + * Whether the current page is the AIOS blacklist admin page + * + * @return Boolean True if the current page is the AIOS blacklist admin page, otherwise false. + */ + private function is_blacklist_admin_page() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return ('admin.php' == $GLOBALS['pagenow'] && isset($_GET['page']) && AIOWPSEC_FIREWALL_MENU_SLUG == $_GET['page'] && isset($_GET['tab']) && 'blacklist' == $_GET['tab']); + } + + /** + * Decides whether to show the IP address detection settings notice. + * + * @return Boolean True if the IP address detection settings notice should be shown, otherwise false. + */ + protected function should_show_login_whitelist_disabled_on_upgrade_notice() { + if (!is_main_site()) { + return false; + } + + if ($this->is_login_whitelist_admin_page_tab()) { + return false; + } + + if (defined('AIOS_FORCE_LOGIN_WHITELIST_DISABLED_ON_UPGRADE_NOTICE') && AIOS_FORCE_LOGIN_WHITELIST_DISABLED_ON_UPGRADE_NOTICE) { + return true; + } + + global $aio_wp_security; + + if ('1' == $aio_wp_security->configs->get_value('aiowps_is_login_whitelist_disabled_on_upgrade') && '1' != $aio_wp_security->configs->get_value('aiowps_enable_whitelisting')) { + return true; + } + + return false; + } + + /** + * Whether the current page is the AIOS IP retrieval admin page + * + * @return Boolean True if the current page is the AIOS database backup admin page, otherwise false. + */ + private function is_login_whitelist_admin_page_tab() { + return $this->is_brute_force_admin_page() && $this->is_login_whitelist_tab(); + } + + /** + * Whether the current page is the AIOS settings admin page + * + * @return Boolean True if the current page is the AIOS settings admin page, otherwise false. + */ + private function is_brute_force_admin_page() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return ('admin.php' == $GLOBALS['pagenow'] && isset($_GET['page']) && AIOWPSEC_BRUTE_FORCE_MENU_SLUG == $_GET['page']); + } + + /** + * Whether the current tab is the advanced settings tab. + * + * @return Boolean True if the current tab is the advanced settings tab, otherwise false. + */ + private function is_login_whitelist_tab() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check. + return (isset($_GET['tab']) && 'login-whitelist' == $_GET['tab']); + } + + /** + * Call this method to setup the notices + */ + public function notices_init() { + if ($this->initialized) return; + $this->initialized = true; + $this->notices_content = $this->populate_notices_content(); + + $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? AIO_WP_SECURITY_VERSION.'.'.time() : AIO_WP_SECURITY_VERSION; + wp_enqueue_style('aiowpsec-admin-notices-css', AIO_WP_SECURITY_URL.'/css/wp-security-notices.css', array(), $enqueue_version); + } + + /** + * Get AIOS Plugin installation timestamp. + * + * @return integer AIOS Plugin installation timestamp. + */ + public function get_aiowps_plugin_installed_timestamp() { + $installed_at = @filemtime(AIO_WP_SECURITY_PATH.'/index.html'); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore warning as we handle it below + if (false === $installed_at) { + global $aio_wp_security; + $installed_at = (int) $aio_wp_security->configs->get_value('installed-at'); + } + $installed_at = apply_filters('aiowps_plugin_installed_timestamp', $installed_at); + return $installed_at; + } + + /** + * This function will check if we should display the rate notice or not + * + * @return boolean - to indicate if we should show the notice or not + */ + protected function show_rate_notice() { + $installed_at = $this->get_aiowps_plugin_installed_timestamp(); + $time_now = $this->get_time_now(); + $installed_for = $time_now - $installed_at; + + if ($installed_at && $installed_for > 28*86400) { + return true; + } + + return false; + } + + /** + * Checks if UpdraftPlus is installed(returns false) or not(returns true). + * + * @return Boolean + */ + protected function updraftplus_not_installed() { + if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php'); + $plugins = get_plugins(); + + foreach ($plugins as $value) { + if ('updraftplus' == $value['TextDomain']) { + return false; + } + } + return true; + } + + /** + * Checks if WP-Optimize is installed(returns false) or not(returns true). + * + * @return Boolean + */ + protected function wp_optimize_not_installed() { + if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php'); + $plugins = get_plugins(); + + foreach ($plugins as $value) { + if ('wp-optimize' == $value['TextDomain']) { + return false; + } + } + return true; + } + + /** + * Determines whether to prepare a seasonal notice(returns true) or not(returns false). + * + * @param Array $notice_data - all data for the notice + * + * @return Boolean + */ + protected function skip_seasonal_notices($notice_data) { + $time_now = $this->get_time_now(); + $valid_from = strtotime($notice_data['valid_from']); + $valid_to = strtotime($notice_data['valid_to']); + $dismiss = $this->check_notice_dismissed($notice_data['dismiss_time']); + if (($time_now >= $valid_from && $time_now <= $valid_to) && !$dismiss) { + // return true so that we return this notice to be displayed + return true; + } + + return false; + } + + /** + * Get timestamp that is considered as current timestamp for notice. + * + * @return integer timestamp that should be consider as a current time. + */ + public function get_time_now() { + $time_now = defined('AIOWPSECURITY_NOTICES_FORCE_TIME') ? AIOWPSECURITY_NOTICES_FORCE_TIME : time(); + return $time_now; + } + + /** + * Checks whether a notice is dismissed(returns true) or not(returns false). + * + * @param String $dismiss_time - dismiss time id for the notice + * + * @return boolean + */ + protected function check_notice_dismissed($dismiss_time) { + $time_now = $this->get_time_now(); + + global $aio_wp_security; + $dismiss = ($time_now < (int) $aio_wp_security->configs->get_value($dismiss_time)); + + return $dismiss; + } + + /** + * Renders or returns a notice. + * + * @param Boolean|String $advert_information - all data for the notice + * @param Boolean $return_instead_of_echo - whether to return the notice(true) or render it to the page(false) + * @param String $position - notice position + * + * @return Void|String + */ + protected function render_specified_notice($advert_information, $return_instead_of_echo = false, $position = 'top') { + + if ('bottom' == $position) { + $template_file = 'bottom-notice.php'; + } elseif ('report' == $position) { + $template_file = 'report.php'; + } elseif ('report-plain' == $position) { + $template_file = 'report-plain.php'; + } elseif (in_array($position, AIOS_Abstracted_Ids::custom_admin_notice_ids())) { + $template_file = 'custom-notice.php'; + } elseif (in_array($position, AIOS_Abstracted_Ids::htaccess_to_php_feature_notice_ids())) { + $template_file = 'htaccess-to-php-feature-notice.php'; + } else { + $template_file = 'horizontal-notice.php'; + } + + global $aio_wp_security; + return $aio_wp_security->include_template('notices/'.$template_file, $return_instead_of_echo, $advert_information); + } +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-process-renamed-login-page.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-process-renamed-login-page.php new file mode 100755 index 00000000..5a28ef4e --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-process-renamed-login-page.php @@ -0,0 +1,293 @@ +aiowps_filter_wp_login_file($url); + } + + public function aiowps_wp_redirect($location) { + return $this->aiowps_filter_wp_login_file($location); + } + + /** + * Filter register link on the login page + * + * @param string $registration_url + * @return string + */ + public function register_link($registration_url) { + return $this->aiowps_filter_wp_login_file($registration_url); + } + + /** + * Filter confirm link so we hide the secret login slug in the export_personal_data email + * + * @param string $email_text + * @param string $email_data + * @return string + */ + public function aiowps_user_request_email_content($email_text, $email_data) { + global $aio_wp_security; + if (isset($email_data['request']) && isset($email_data['request']->action_name)) { + if ('export_personal_data' == $email_data['request']->action_name) { + $confirm_url = $email_data['confirm_url']; + $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug'); + if (get_option('permalink_structure')) { + $new_confirm_url = str_replace($login_slug, 'wp-login.php', $confirm_url); + } else { + $search_pattern = '?'.$login_slug.'&action'; + $new_confirm_url = str_replace($search_pattern, '/wp-login.php/?action', $confirm_url); + } + + $email_text_modified = str_replace('###CONFIRM_URL###', esc_url_raw($new_confirm_url), $email_text); + return $email_text_modified; + } + } + return $email_text; + } + + /** + * Filter all login url strings on the login page + * + * @param string $url + * @return string + */ + public function aiowps_filter_wp_login_file($url) { + if (strpos($url, 'wp-login.php') !== false) { + $args = explode('?', $url); + if (isset($args[1])) { + if (strpos($args[1], 'action=postpass') !== false) { + return $url; //Don't reveal the secret URL in the post password action url + } + parse_str($args[1], $args); + $url = esc_url(add_query_arg($args, AIOWPSecurity_Process_Renamed_Login_Page::new_login_url())); + $url = html_entity_decode($url); + } elseif (isset($_SERVER['REQUEST_URI']) && stripos(urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))), 'wp-admin/install.php')) { + return $url; + } else { + $url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url(); + } + } + return $url; + } + + /** + * Login page renamed related tasks, do not allow access if not logged with rename login page. + * + * @return void + */ + public static function renamed_login_init_tasks() { + // Bail if the host cron job is running by running the command "php wp-cron.php" + // The $_SERVER['REQUEST_URI'] is undefined when running a PHP file from the command line. + // for `wp plugin list` it will be empty so showing Not available instead plugin list. + if (empty($_SERVER['REQUEST_URI']) || defined('WP_CLI') || 'cli' == PHP_SAPI || wp_doing_cron() || wp_doing_ajax()) { + return; + } + + global $aio_wp_security; + + //The following will process the native wordpress post password protection form + //Normally this is done by wp-login.php file but we cannot use that since the login page has been renamed + + // Bots with URLs like: /index.php?action[]=aaaa will return an array here. It needs to be a string. + $action = (isset($_GET['action']) && is_string($_GET['action'])) ? sanitize_text_field(wp_unslash($_GET['action'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce available. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- No nonce available. + if (isset($_POST['post_password']) && 'postpass' == $action) { + + // Check if the captcha is enabled for the password protected pages and process validation if the login page was renamed + if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_password_protected_captcha')) { + $aio_wp_security->captcha_obj->validate_password_protected_password_form_with_captcha(); + } + + require_once ABSPATH . 'wp-includes/class-phpass.php'; + $hasher = new PasswordHash(8, true); + + /** + * Filter the life span of the post password cookie. + * + * By default, the cookie expires 10 days from creation. To turn this + * into a session cookie, return 0. + * + * @since 3.7.0 + * + * @param int $expires The expiry time, as passed to setcookie(). + */ + $expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS); + // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No nonce available, not recommended to sanitize passwords. + setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true); + + wp_safe_redirect(wp_get_referer()); + exit(); + } + + //case where someone attempting to reach wp-admin + if (is_admin() && !is_user_logged_in() && (isset($_SERVER["SCRIPT_FILENAME"]) ? basename(sanitize_text_field(wp_unslash($_SERVER["SCRIPT_FILENAME"]))) : '') !== 'admin-post.php') { + //Fix to prevent fatal error caused by some themes and Yoast SEO + do_action('aiowps_before_wp_die_renamed_login'); + wp_die(esc_html__('You do not have permission to access this page.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Please log in and try again.', 'all-in-one-wp-security-and-firewall'), 403); + } + + //case where someone attempting to reach wp-login + if (isset($_SERVER['REQUEST_URI']) && stripos(urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))), 'wp-login.php') && !is_user_logged_in()) { + + // Handle export personal data request for rename login case + if (isset($_GET['request_id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $request_id = (int) sanitize_text_field(wp_unslash($_GET['request_id'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $result = ''; + if (isset($_GET['confirm_key'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $key = sanitize_text_field(wp_unslash($_GET['confirm_key'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $result = wp_validate_user_request_key($request_id, $key); + } else { + $result = new WP_Error('invalid_key', esc_html__('Invalid key', 'all-in-one-wp-security-and-firewall')); + } + + if (is_wp_error($result)) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP error. $result is WPError object with sanitized strings. + wp_die($result); + } elseif (!empty($result)) { + _wp_privacy_account_request_confirmed($request_id); + $message = _wp_privacy_account_request_confirmed_message($request_id); + login_header(__('User action confirmed.', 'all-in-one-wp-security-and-firewall'), $message); + login_footer(); + exit; + } + } + + //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page! + if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') { + AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks(); + } else { + AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404(); + } + } + + //case where someone attempting to reach the standard register or signup pages + $request_uri = urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))); + if ('' !== $request_uri && stripos($request_uri, 'wp-register.php') || '' !== $request_uri && stripos($request_uri, 'wp-signup.php')) { + //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page! + if ('1' == $aio_wp_security->configs->get_value('aiowps_site_lockout')) { + AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks(); + } else { + AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404(); + } + } + + $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug'); + + if (self::is_renamed_login_page_requested($login_slug)) { + if (empty($action) && is_user_logged_in()) { + //if user is already logged in but tries to access the renamed login page, send them to the dashboard + // or to requested redirect-page, filtered in 'login_redirect'. + if (isset($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $redirect_to = wp_sanitize_redirect(wp_unslash($_REQUEST['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + $redirect_to = wp_validate_redirect($redirect_to, apply_filters('wp_safe_redirect_fallback', admin_url(), 302)); + $requested_redirect_to = $redirect_to; + } else { + $redirect_to = admin_url(); + $requested_redirect_to = ''; + } + $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, wp_get_current_user()); + AIOWPSecurity_Utility::redirect_to_url($redirect_to); + } else { + global $wp_version; + do_action('aiowps_rename_login_load'); + // logout action called by WooCommerce does not apply the login whitelist which shows a 403 error for the customer + if (!(isset($_GET['action']) && 'logout' == $_GET['action'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + AIOWPSecurity_Utility_IP::check_login_whitelist_and_forbid(); + } + + status_header(200); + if (version_compare($wp_version, '6.6', '>=')) { + require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature.php'); + } elseif (version_compare($wp_version, '5.7', '>=')) { + require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-6-6.php'); + } elseif (version_compare($wp_version, '5.2', '>=')) { + require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-7.php'); + } else { + require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-2.php'); + } + + die; + } + } + } + + public static function new_login_url() { + global $aio_wp_security; + $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug'); + if (get_option('permalink_structure')) { + return trailingslashit(trailingslashit(home_url()) . $login_slug); + } else { + return trailingslashit(site_url()) . '?' . $login_slug; + } + } + + public static function aiowps_set_404() { + global $wp_query; + do_action('aiowps_before_set_404'); // This hook is for themes which produce a fatal error when the rename login feature is enabled and someone visits "wp-admin" slug directly + + status_header(404); + $wp_query->set_404(); + do_action('template_redirect'); // Trigger 'template_redirect' to allow third-party plugins to intercept and inject custom logic before rendering the fallback template. + + $template = get_404_template(); + if (empty($template)) $template = get_index_template(); + $template = apply_filters('template_include', $template); + if ($template) include($template); + die; + } + + /** + * Check renamed login page is requested + * + * @param string $login_slug Renamed loginpage slug + * + * @return boolean + */ + public static function is_renamed_login_page_requested($login_slug) { + + if (empty($_SERVER['REQUEST_URI'])) return false; + + $parsed_url_path = isset($_SERVER['REQUEST_URI']) ? wp_parse_url(sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])), PHP_URL_PATH) : ''; + $home_url_with_slug = home_url($login_slug, 'relative'); + + /* + * Compatibility fix for WPML, TranslatePress plugin + */ + if (function_exists('wpml_object_id') || function_exists('trp_enable_translatepress')) { + $home_url_with_slug = home_url($login_slug); + $parsed_home_url_with_slug = wp_parse_url($home_url_with_slug); + $home_url_with_slug = $parsed_home_url_with_slug['path']; //this will return just the path minus the protocol and host + } + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available. + if (untrailingslashit($parsed_url_path) === $home_url_with_slug || (!get_option('permalink_structure') && isset($_GET[$login_slug]))) { + return true; + } + + return false; + } + +} diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-reporting.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-reporting.php new file mode 100755 index 00000000..b5bf996d --- /dev/null +++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-reporting.php @@ -0,0 +1,60 @@ + $value) { + $sanitized_key = esc_html($key); + $sanitized_value = esc_html($value); + $sanitized_section_content[$sanitized_key] = $sanitized_value; + } + + if ('text' === $output_format) { + $data .= "\n --- $section_title --- \n\n"; + $data .= self::output_section_data($sanitized_section_content); + $data .= "\n===================================\n"; + } elseif ('table' === $output_format) { + $data .= ''. + esc_html__('You have disabled login lockout by defining the AIOS_DISABLE_LOGIN_LOCKOUT constant value as true, and the login lockout setting has enabled it.', 'all-in-one-wp-security-and-firewall') . ' ' . + /* translators: 1: Locked IP Addresses admin page link */ + sprintf(esc_html__('Delete your login lockout IP from %s and define the AIOS_DISABLE_LOGIN_LOCKOUT constant value as false.', 'all-in-one-wp-security-and-firewall'), + '' . esc_html__('Locked IP addresses', 'all-in-one-wp-security-and-firewall') . '' + ). + '
+' . esc_html__('The plugin has detected that you are using a Multi-Site WordPress installation.', 'all-in-one-wp-security-and-firewall') . '
+' . esc_html__('Some features on this page can only be configured by the "superadmin".', 'all-in-one-wp-security-and-firewall') . '
'; + echo '=0&&!c||x<0&&c?o-p:o+p),{size:l,base:o,head:s,center:s+l/2}},calculateBarIndexPixels:function(t,e,n,i){var a="flex"===i.barThickness?function(t,e,n){var i,a=e.pixels,r=a[t],o=t>0?a[t-1]:null,s=t '+simba_tfasettings.error+' ';
+
+ if (form_is_ultimate_member) { html += '0&&n.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,r=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&r&&(t.save(),t.globalAlpha=a,this.drawBackground(i,e,t,n),i.y+=e.yPadding,B.rtl.overrideTextDirection(t,e.textDirection),this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),B.rtl.restoreTextDirection(t,e.textDirection),t.restore())}},handleEvent:function(t){var e,n=this,i=n._options;return n._lastActive=n._lastActive||[],"mouseout"===t.type?n._active=[]:(n._active=n._chart.getElementsAtEventForMode(t,i.mode,i),i.reverse&&n._active.reverse()),(e=!B.arrayEquals(n._active,n._lastActive))&&(n._lastActive=n._active,(i.enabled||i.custom)&&(n._eventPosition={x:t.x,y:t.y},n.update(!0),n.pivot())),e}}),Ge=ze,qe=Ue;qe.positioners=Ge;var Ze=B.valueOrDefault;function $e(){return B.merge(Object.create(null),[].slice.call(arguments),{merger:function(t,e,n,i){if("xAxes"===t||"yAxes"===t){var a,r,o,s=n[t].length;for(e[t]||(e[t]=[]),a=0;a=e[t].length&&e[t].push({}),!e[t][a].type||o.type&&o.type!==e[t][a].type?B.merge(e[t][a],[Ne.getScaleDefaults(r),o]):B.merge(e[t][a],o)}else B._merger(t,e,n,i)}})}function Xe(){return B.merge(Object.create(null),[].slice.call(arguments),{merger:function(t,e,n,i){var a=e[t]||Object.create(null),r=n[t];"scales"===t?e[t]=$e(a,r):"scale"===t?e[t]=B.merge(a,[Ne.getScaleDefaults(r.type),r]):B._merger(t,e,n,i)}})}function Ke(t){var e=t.options;B.each(t.scales,(function(e){pe.removeBox(t,e)})),e=Xe(Y.global,Y[t.config.type],e),t.options=t.config.options=e,t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.tooltip._options=e.tooltips,t.tooltip.initialize()}function Je(t,e,n){var i,a=function(t){return t.id===i};do{i=e+n++}while(B.findIndex(t,a)>=0);return i}function Qe(t){return"top"===t||"bottom"===t}function tn(t,e){return function(n,i){return n[t]===i[t]?n[e]-i[e]:n[t]-i[t]}}Y._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var en=function(t,e){return this.construct(t,e),this};B.extend(en.prototype,{construct:function(t,e){var n=this;e=function(t){var e=(t=t||Object.create(null)).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=Xe(Y.global,Y[t.type],t.options||{}),t}(e);var i=Le.acquireContext(t,e),a=i&&i.canvas,r=a&&a.height,o=a&&a.width;n.id=B.uid(),n.ctx=i,n.canvas=a,n.config=e,n.width=o,n.height=r,n.aspectRatio=r?o/r:null,n.options=e.options,n._bufferedRender=!1,n._layers=[],n.chart=n,n.controller=n,en.instances[n.id]=n,Object.defineProperty(n,"data",{get:function(){return n.config.data},set:function(t){n.config.data=t}}),i&&a?(n.initialize(),n.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return Re.notify(t,"beforeInit"),B.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.initToolTip(),Re.notify(t,"afterInit"),t},clear:function(){return B.canvas.clear(this),this},stop:function(){return Q.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,a=n.maintainAspectRatio&&e.aspectRatio||null,r=Math.max(0,Math.floor(B.getMaximumWidth(i))),o=Math.max(0,Math.floor(a?r/a:B.getMaximumHeight(i)));if((e.width!==r||e.height!==o)&&(i.width=e.width=r,i.height=e.height=o,i.style.width=r+"px",i.style.height=o+"px",B.retinaScale(e,n.devicePixelRatio),!t)){var s={width:r,height:o};Re.notify(e,"resize",[s]),n.onResize&&n.onResize(e,s),e.stop(),e.update({duration:n.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;B.each(e.xAxes,(function(t,n){t.id||(t.id=Je(e.xAxes,"x-axis-",n))})),B.each(e.yAxes,(function(t,n){t.id||(t.id=Je(e.yAxes,"y-axis-",n))})),n&&(n.id=n.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,n=t.scales||{},i=[],a=Object.keys(n).reduce((function(t,e){return t[e]=!1,t}),{});e.scales&&(i=i.concat((e.scales.xAxes||[]).map((function(t){return{options:t,dtype:"category",dposition:"bottom"}})),(e.scales.yAxes||[]).map((function(t){return{options:t,dtype:"linear",dposition:"left"}})))),e.scale&&i.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),B.each(i,(function(e){var i=e.options,r=i.id,o=Ze(i.type,e.dtype);Qe(i.position)!==Qe(e.dposition)&&(i.position=e.dposition),a[r]=!0;var s=null;if(r in n&&n[r].type===o)(s=n[r]).options=i,s.ctx=t.ctx,s.chart=t;else{var l=Ne.getScaleConstructor(o);if(!l)return;s=new l({id:r,type:o,options:i,ctx:t.ctx,chart:t}),n[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)})),B.each(a,(function(t,e){t||delete n[e]})),t.scales=n,Ne.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t,e,n=this,i=[],a=n.data.datasets;for(t=0,e=a.length;t=0;t--)e=i.getDistanceFromCenterForValue(r.ticks.reverse?i.min:i.max),n=i.getPointPosition(t,e),a.beginPath(),a.moveTo(i.xCenter,i.yCenter),a.lineTo(n.x,n.y),a.stroke();a.restore()}},_drawLabels:function(){var t=this,e=t.ctx,n=t.options.ticks;if(n.display){var i,a,r=t.getIndexAngle(0),o=B.options._parseFont(n),s=zn(n.fontColor,Y.global.defaultFontColor);e.save(),e.font=o.string,e.translate(t.xCenter,t.yCenter),e.rotate(r),e.textAlign="center",e.textBaseline="middle",B.each(t.ticks,(function(r,l){(0!==l||n.reverse)&&(i=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),n.showLabelBackdrop&&(a=e.measureText(r).width,e.fillStyle=n.backdropColor,e.fillRect(-a/2-n.backdropPaddingX,-i-o.size/2-n.backdropPaddingY,a+2*n.backdropPaddingX,o.size+2*n.backdropPaddingY)),e.fillStyle=s,e.fillText(r,0,-i))})),e.restore()}},_drawTitle:B.noop}),Xn=Hn;$n._defaults=Xn;var Kn=B._deprecated,Jn=B.options.resolve,Qn=B.valueOrDefault,ti=Number.MIN_SAFE_INTEGER||-9007199254740991,ei=Number.MAX_SAFE_INTEGER||9007199254740991,ni={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ii=Object.keys(ni);function ai(t,e){return t-e}function ri(t){return B.valueOrDefault(t.time.min,t.ticks.min)}function oi(t){return B.valueOrDefault(t.time.max,t.ticks.max)}function si(t,e,n,i){var a=function(t,e,n){for(var i,a,r,o=0,s=t.length-1;o>=0&&o<=s;){if(a=t[(i=o+s>>1)-1]||null,r=t[i],!a)return{lo:null,hi:r};if(r[e]=0;--n)(e=l[n].$filler)&&e.visible&&(a=(i=e.el)._view,r=i._children||[],o=e.mapper,s=a.backgroundColor||Y.global.defaultColor,o&&s&&r.length&&(B.canvas.clipArea(u,t.chartArea),Mi(u,r,o,a,s,i._loop),B.canvas.unclipArea(u)))}},Di=B.rtl.getRtlAdapter,Ci=B.noop,Pi=B.valueOrDefault;function Ti(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}Y._set("global",{legend:{display:!0,position:"top",align:"center",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data.datasets,n=t.options.legend||{},i=n.labels&&n.labels.usePointStyle;return t._getSortedDatasetMetas().map((function(n){var a=n.controller.getStyle(i?0:void 0);return{text:e[n.index].label,fillStyle:a.backgroundColor,hidden:!t.isDatasetVisible(n.index),lineCap:a.borderCapStyle,lineDash:a.borderDash,lineDashOffset:a.borderDashOffset,lineJoin:a.borderJoinStyle,lineWidth:a.borderWidth,strokeStyle:a.borderColor,pointStyle:a.pointStyle,rotation:a.rotation,datasetIndex:n.index}}),this)}}},legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data.datasets;for(a.setAttribute("class",t.id+"-legend"),e=0,n=r.length;e').attr('src', createCanvas(settings)[0].toDataURL('image/png'));
+ }
+
+ // Returns a `div` element representing the QR code for the given settings.
+ function createDiv(settings) {
+ var qr = createMinQRCode(settings.text, settings.ecLevel, settings.minVersion, settings.maxVersion, settings.quiet);
+ if (!qr) {
+ return null;
+ }
+
+ // some shortcuts to improve compression
+ var settings_size = settings.size;
+ var settings_bgColor = settings.background;
+ var math_floor = Math.floor;
+
+ var moduleCount = qr.moduleCount;
+ var moduleSize = math_floor(settings_size / moduleCount);
+ var offset = math_floor(0.5 * (settings_size - moduleSize * moduleCount));
+
+ var row;
+ var col;
+
+ var containerCSS = {
+ position: 'relative',
+ left: 0,
+ top: 0,
+ padding: 0,
+ margin: 0,
+ width: settings_size,
+ height: settings_size
+ };
+ var darkCSS = {
+ position: 'absolute',
+ padding: 0,
+ margin: 0,
+ width: moduleSize,
+ height: moduleSize,
+ 'background-color': settings.fill
+ };
+
+ var $div = jq('').data('qrcode', qr).css(containerCSS);
+
+ if (settings_bgColor) {
+ $div.css('background-color', settings_bgColor);
+ }
+
+ for (row = 0; row < moduleCount; row += 1) {
+ for (col = 0; col < moduleCount; col += 1) {
+ if (qr.isDark(row, col)) {
+ jq('')
+ .css(darkCSS)
+ .css({
+ left: offset + col * moduleSize,
+ top: offset + row * moduleSize
+ })
+ .appendTo($div);
+ }
+ }
+ }
+
+ return $div;
+ }
+
+ function createHTML(settings) {
+ if (hasCanvas && settings.render === 'canvas') {
+ return createCanvas(settings);
+ } else if (hasCanvas && settings.render === 'image') {
+ return createImage(settings);
+ }
+
+ return createDiv(settings);
+ }
+
+ // Plugin
+ // ======
+
+ // Default settings
+ // ----------------
+ var defaults = {
+ // render method: `'canvas'`, `'image'` or `'div'`
+ render: 'canvas',
+
+ // version range somewhere in 1 .. 40
+ minVersion: 1,
+ maxVersion: 40,
+
+ // error correction level: `'L'`, `'M'`, `'Q'` or `'H'`
+ ecLevel: 'L',
+
+ // offset in pixel if drawn onto existing canvas
+ left: 0,
+ top: 0,
+
+ // size in pixel
+ size: 200,
+
+ // code color or image element
+ fill: '#000',
+
+ // background color or image element, `null` for transparent background
+ background: null,
+
+ // content
+ text: 'no text',
+
+ // corner radius relative to module width: 0.0 .. 0.5
+ radius: 0,
+
+ // quiet zone in modules
+ quiet: 0,
+
+ // modes
+ // 0: normal
+ // 1: label strip
+ // 2: label box
+ // 3: image strip
+ // 4: image box
+ mode: 0,
+
+ mSize: 0.1,
+ mPosX: 0.5,
+ mPosY: 0.5,
+
+ label: 'no label',
+ fontname: 'sans',
+ fontcolor: '#000',
+
+ image: null
+ };
+
+ // Register the plugin
+ // -------------------
+ jq.fn.qrcode = function (options) {
+ var settings = jq.extend({}, defaults, options);
+
+ return this.each(function (idx, el) {
+ if (el.nodeName.toLowerCase() === 'canvas') {
+ drawOnCanvas(el, settings);
+ } else {
+ jq(el).append(createHTML(settings));
+ }
+ });
+ };
+}(function () {
+ // `qrcode` is the single public function defined by the `QR Code Generator`
+ //---------------------------------------------------------------------
+ //
+ // QR Code Generator for JavaScript
+ //
+ // Copyright (c) 2009 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word 'QR Code' is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ var qrcode = function() {
+
+ //---------------------------------------------------------------------
+ // qrcode
+ //---------------------------------------------------------------------
+
+ /**
+ * qrcode
+ * @param typeNumber 1 to 40
+ * @param errorCorrectLevel 'L','M','Q','H'
+ */
+ var qrcode = function(typeNumber, errorCorrectLevel) {
+
+ var PAD0 = 0xEC;
+ var PAD1 = 0x11;
+
+ var _typeNumber = typeNumber;
+ var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel];
+ var _modules = null;
+ var _moduleCount = 0;
+ var _dataCache = null;
+ var _dataList = new Array();
+
+ var _this = {};
+
+ var makeImpl = function(test, maskPattern) {
+
+ _moduleCount = _typeNumber * 4 + 17;
+ _modules = function(moduleCount) {
+ var modules = new Array(moduleCount);
+ for (var row = 0; row < moduleCount; row += 1) {
+ modules[row] = new Array(moduleCount);
+ for (var col = 0; col < moduleCount; col += 1) {
+ modules[row][col] = null;
+ }
+ }
+ return modules;
+ }(_moduleCount);
+
+ setupPositionProbePattern(0, 0);
+ setupPositionProbePattern(_moduleCount - 7, 0);
+ setupPositionProbePattern(0, _moduleCount - 7);
+ setupPositionAdjustPattern();
+ setupTimingPattern();
+ setupTypeInfo(test, maskPattern);
+
+ if (_typeNumber >= 7) {
+ setupTypeNumber(test);
+ }
+
+ if (_dataCache == null) {
+ _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
+ }
+
+ mapData(_dataCache, maskPattern);
+ };
+
+ var setupPositionProbePattern = function(row, col) {
+
+ for (var r = -1; r <= 7; r += 1) {
+
+ if (row + r <= -1 || _moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c += 1) {
+
+ if (col + c <= -1 || _moduleCount <= col + c) continue;
+
+ if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
+ || (0 <= c && c <= 6 && (r == 0 || r == 6) )
+ || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
+ _modules[row + r][col + c] = true;
+ } else {
+ _modules[row + r][col + c] = false;
+ }
+ }
+ }
+ };
+
+ var getBestMaskPattern = function() {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i += 1) {
+
+ makeImpl(true, i);
+
+ var lostPoint = QRUtil.getLostPoint(_this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ };
+
+ var setupTimingPattern = function() {
+
+ for (var r = 8; r < _moduleCount - 8; r += 1) {
+ if (_modules[r][6] != null) {
+ continue;
+ }
+ _modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < _moduleCount - 8; c += 1) {
+ if (_modules[6][c] != null) {
+ continue;
+ }
+ _modules[6][c] = (c % 2 == 0);
+ }
+ };
+
+ var setupPositionAdjustPattern = function() {
+
+ var pos = QRUtil.getPatternPosition(_typeNumber);
+
+ for (var i = 0; i < pos.length; i += 1) {
+
+ for (var j = 0; j < pos.length; j += 1) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (_modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r += 1) {
+
+ for (var c = -2; c <= 2; c += 1) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2
+ || (r == 0 && c == 0) ) {
+ _modules[row + r][col + c] = true;
+ } else {
+ _modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ };
+
+ var setupTypeNumber = function(test) {
+
+ var bits = QRUtil.getBCHTypeNumber(_typeNumber);
+
+ for (var i = 0; i < 18; i += 1) {
+ var mod = (!test && ( (bits >> i) & 1) == 1);
+ _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i += 1) {
+ var mod = (!test && ( (bits >> i) & 1) == 1);
+ _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ };
+
+ var setupTypeInfo = function(test, maskPattern) {
+
+ var data = (_errorCorrectLevel << 3) | maskPattern;
+ var bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i += 1) {
+
+ var mod = (!test && ( (bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ _modules[i][8] = mod;
+ } else if (i < 8) {
+ _modules[i + 1][8] = mod;
+ } else {
+ _modules[_moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i += 1) {
+
+ var mod = (!test && ( (bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ _modules[8][_moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ _modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ _modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ _modules[_moduleCount - 8][8] = (!test);
+ };
+
+ var mapData = function(data, maskPattern) {
+
+ var inc = -1;
+ var row = _moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+ var maskFunc = QRUtil.getMaskFunction(maskPattern);
+
+ for (var col = _moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col -= 1;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c += 1) {
+
+ if (_modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = maskFunc(row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ _modules[row][col - c] = dark;
+ bitIndex -= 1;
+
+ if (bitIndex == -1) {
+ byteIndex += 1;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || _moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+ };
+
+ var createBytes = function(buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r += 1) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i += 1) {
+ dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i += 1) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
+ }
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i += 1) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i += 1) {
+ for (var r = 0; r < rsBlocks.length; r += 1) {
+ if (i < dcdata[r].length) {
+ data[index] = dcdata[r][i];
+ index += 1;
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i += 1) {
+ for (var r = 0; r < rsBlocks.length; r += 1) {
+ if (i < ecdata[r].length) {
+ data[index] = ecdata[r][i];
+ index += 1;
+ }
+ }
+ }
+
+ return data;
+ };
+
+ var createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = qrBitBuffer();
+
+ for (var i = 0; i < dataList.length; i += 1) {
+ var data = dataList[i];
+ buffer.put(data.getMode(), 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i += 1) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error('code length overflow. ('
+ + buffer.getLengthInBits()
+ + '>'
+ + totalDataCount * 8
+ + ')');
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD1, 8);
+ }
+
+ return createBytes(buffer, rsBlocks);
+ };
+
+ _this.addData = function(data) {
+ var newData = qr8BitByte(data);
+ _dataList.push(newData);
+ _dataCache = null;
+ };
+
+ _this.isDark = function(row, col) {
+ if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
+ throw new Error(row + ',' + col);
+ }
+ return _modules[row][col];
+ };
+
+ _this.getModuleCount = function() {
+ return _moduleCount;
+ };
+
+ _this.make = function() {
+ makeImpl(false, getBestMaskPattern() );
+ };
+
+ _this.createTableTag = function(cellSize, margin) {
+
+ cellSize = cellSize || 2;
+ margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
+
+ var qrHtml = '';
+
+ qrHtml += '
';
+ qrHtml += '';
+
+ for (var r = 0; r < _this.getModuleCount(); r += 1) {
+
+ qrHtml += '
';
+
+ return qrHtml;
+ };
+
+ _this.createImgTag = function(cellSize, margin) {
+
+ cellSize = cellSize || 2;
+ margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
+
+ var size = _this.getModuleCount() * cellSize + margin * 2;
+ var min = margin;
+ var max = size - margin;
+
+ return createImgTag(size, size, function(x, y) {
+ if (min <= x && x < max && min <= y && y < max) {
+ var c = Math.floor( (x - min) / cellSize);
+ var r = Math.floor( (y - min) / cellSize);
+ return _this.isDark(r, c)? 0 : 1;
+ } else {
+ return 1;
+ }
+ } );
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // qrcode.stringToBytes
+ //---------------------------------------------------------------------
+
+ qrcode.stringToBytes = function(s) {
+ var bytes = new Array();
+ for (var i = 0; i < s.length; i += 1) {
+ var c = s.charCodeAt(i);
+ bytes.push(c & 0xff);
+ }
+ return bytes;
+ };
+
+ //---------------------------------------------------------------------
+ // qrcode.createStringToBytes
+ //---------------------------------------------------------------------
+
+ /**
+ * @param unicodeData base64 string of byte array.
+ * [16bit Unicode],[16bit Bytes], ...
+ * @param numChars
+ */
+ qrcode.createStringToBytes = function(unicodeData, numChars) {
+
+ // create conversion map.
+
+ var unicodeMap = function() {
+
+ var bin = base64DecodeInputStream(unicodeData);
+ var read = function() {
+ var b = bin.read();
+ if (b == -1) throw new Error();
+ return b;
+ };
+
+ var count = 0;
+ var unicodeMap = {};
+ while (true) {
+ var b0 = bin.read();
+ if (b0 == -1) break;
+ var b1 = read();
+ var b2 = read();
+ var b3 = read();
+ var k = String.fromCharCode( (b0 << 8) | b1);
+ var v = (b2 << 8) | b3;
+ unicodeMap[k] = v;
+ count += 1;
+ }
+ if (count != numChars) {
+ throw new Error(count + ' != ' + numChars);
+ }
+
+ return unicodeMap;
+ }();
+
+ var unknownChar = '?'.charCodeAt(0);
+
+ return function(s) {
+ var bytes = new Array();
+ for (var i = 0; i < s.length; i += 1) {
+ var c = s.charCodeAt(i);
+ if (c < 128) {
+ bytes.push(c);
+ } else {
+ var b = unicodeMap[s.charAt(i)];
+ if (typeof b == 'number') {
+ if ( (b & 0xff) == b) {
+ // 1byte
+ bytes.push(b);
+ } else {
+ // 2bytes
+ bytes.push(b >>> 8);
+ bytes.push(b & 0xff);
+ }
+ } else {
+ bytes.push(unknownChar);
+ }
+ }
+ }
+ return bytes;
+ };
+ };
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+
+ var QRMode = {
+ MODE_NUMBER : 1 << 0,
+ MODE_ALPHA_NUM : 1 << 1,
+ MODE_8BIT_BYTE : 1 << 2,
+ MODE_KANJI : 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+
+ var QRErrorCorrectLevel = {
+ L : 1,
+ M : 0,
+ Q : 3,
+ H : 2
+ };
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+
+ var QRMaskPattern = {
+ PATTERN000 : 0,
+ PATTERN001 : 1,
+ PATTERN010 : 2,
+ PATTERN011 : 3,
+ PATTERN100 : 4,
+ PATTERN101 : 5,
+ PATTERN110 : 6,
+ PATTERN111 : 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ var QRUtil = function() {
+
+ var PATTERN_POSITION_TABLE = [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ];
+ var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
+ var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
+ var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
+
+ var _this = {};
+
+ var getBCHDigit = function(data) {
+ var digit = 0;
+ while (data != 0) {
+ digit += 1;
+ data >>>= 1;
+ }
+ return digit;
+ };
+
+ _this.getBCHTypeInfo = function(data) {
+ var d = data << 10;
+ while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
+ d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
+ }
+ return ( (data << 10) | d) ^ G15_MASK;
+ };
+
+ _this.getBCHTypeNumber = function(data) {
+ var d = data << 12;
+ while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
+ d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
+ }
+ return (data << 12) | d;
+ };
+
+ _this.getPatternPosition = function(typeNumber) {
+ return PATTERN_POSITION_TABLE[typeNumber - 1];
+ };
+
+ _this.getMaskFunction = function(maskPattern) {
+
+ switch (maskPattern) {
+
+ case QRMaskPattern.PATTERN000 :
+ return function(i, j) { return (i + j) % 2 == 0; };
+ case QRMaskPattern.PATTERN001 :
+ return function(i, j) { return i % 2 == 0; };
+ case QRMaskPattern.PATTERN010 :
+ return function(i, j) { return j % 3 == 0; };
+ case QRMaskPattern.PATTERN011 :
+ return function(i, j) { return (i + j) % 3 == 0; };
+ case QRMaskPattern.PATTERN100 :
+ return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
+ case QRMaskPattern.PATTERN101 :
+ return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
+ case QRMaskPattern.PATTERN110 :
+ return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
+ case QRMaskPattern.PATTERN111 :
+ return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
+
+ default :
+ throw new Error('bad maskPattern:' + maskPattern);
+ }
+ };
+
+ _this.getErrorCorrectPolynomial = function(errorCorrectLength) {
+ var a = qrPolynomial([1], 0);
+ for (var i = 0; i < errorCorrectLength; i += 1) {
+ a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
+ }
+ return a;
+ };
+
+ _this.getLengthInBits = function(mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch(mode) {
+ case QRMode.MODE_NUMBER : return 10;
+ case QRMode.MODE_ALPHA_NUM : return 9;
+ case QRMode.MODE_8BIT_BYTE : return 8;
+ case QRMode.MODE_KANJI : return 8;
+ default :
+ throw new Error('mode:' + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch(mode) {
+ case QRMode.MODE_NUMBER : return 12;
+ case QRMode.MODE_ALPHA_NUM : return 11;
+ case QRMode.MODE_8BIT_BYTE : return 16;
+ case QRMode.MODE_KANJI : return 10;
+ default :
+ throw new Error('mode:' + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch(mode) {
+ case QRMode.MODE_NUMBER : return 14;
+ case QRMode.MODE_ALPHA_NUM : return 13;
+ case QRMode.MODE_8BIT_BYTE : return 16;
+ case QRMode.MODE_KANJI : return 12;
+ default :
+ throw new Error('mode:' + mode);
+ }
+
+ } else {
+ throw new Error('type:' + type);
+ }
+ };
+
+ _this.getLostPoint = function(qrcode) {
+
+ var moduleCount = qrcode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row += 1) {
+ for (var col = 0; col < moduleCount; col += 1) {
+
+ var sameCount = 0;
+ var dark = qrcode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r += 1) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c += 1) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrcode.isDark(row + r, col + c) ) {
+ sameCount += 1;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ };
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row += 1) {
+ for (var col = 0; col < moduleCount - 1; col += 1) {
+ var count = 0;
+ if (qrcode.isDark(row, col) ) count += 1;
+ if (qrcode.isDark(row + 1, col) ) count += 1;
+ if (qrcode.isDark(row, col + 1) ) count += 1;
+ if (qrcode.isDark(row + 1, col + 1) ) count += 1;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row += 1) {
+ for (var col = 0; col < moduleCount - 6; col += 1) {
+ if (qrcode.isDark(row, col)
+ && !qrcode.isDark(row, col + 1)
+ && qrcode.isDark(row, col + 2)
+ && qrcode.isDark(row, col + 3)
+ && qrcode.isDark(row, col + 4)
+ && !qrcode.isDark(row, col + 5)
+ && qrcode.isDark(row, col + 6) ) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col += 1) {
+ for (var row = 0; row < moduleCount - 6; row += 1) {
+ if (qrcode.isDark(row, col)
+ && !qrcode.isDark(row + 1, col)
+ && qrcode.isDark(row + 2, col)
+ && qrcode.isDark(row + 3, col)
+ && qrcode.isDark(row + 4, col)
+ && !qrcode.isDark(row + 5, col)
+ && qrcode.isDark(row + 6, col) ) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col += 1) {
+ for (var row = 0; row < moduleCount; row += 1) {
+ if (qrcode.isDark(row, col) ) {
+ darkCount += 1;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ };
+
+ return _this;
+ }();
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ var QRMath = function() {
+
+ var EXP_TABLE = new Array(256);
+ var LOG_TABLE = new Array(256);
+
+ // initialize tables
+ for (var i = 0; i < 8; i += 1) {
+ EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i += 1) {
+ EXP_TABLE[i] = EXP_TABLE[i - 4]
+ ^ EXP_TABLE[i - 5]
+ ^ EXP_TABLE[i - 6]
+ ^ EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i += 1) {
+ LOG_TABLE[EXP_TABLE[i] ] = i;
+ }
+
+ var _this = {};
+
+ _this.glog = function(n) {
+
+ if (n < 1) {
+ throw new Error('glog(' + n + ')');
+ }
+
+ return LOG_TABLE[n];
+ };
+
+ _this.gexp = function(n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return EXP_TABLE[n];
+ };
+
+ return _this;
+ }();
+
+ //---------------------------------------------------------------------
+ // qrPolynomial
+ //---------------------------------------------------------------------
+
+ function qrPolynomial(num, shift) {
+
+ if (typeof num.length == 'undefined') {
+ throw new Error(num.length + '/' + shift);
+ }
+
+ var _num = function() {
+ var offset = 0;
+ while (offset < num.length && num[offset] == 0) {
+ offset += 1;
+ }
+ var _num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i += 1) {
+ _num[i] = num[i + offset];
+ }
+ return _num;
+ }();
+
+ var _this = {};
+
+ _this.getAt = function(index) {
+ return _num[index];
+ };
+
+ _this.getLength = function() {
+ return _num.length;
+ };
+
+ _this.multiply = function(e) {
+
+ var num = new Array(_this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < _this.getLength(); i += 1) {
+ for (var j = 0; j < e.getLength(); j += 1) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
+ }
+ }
+
+ return qrPolynomial(num, 0);
+ };
+
+ _this.mod = function(e) {
+
+ if (_this.getLength() - e.getLength() < 0) {
+ return _this;
+ }
+
+ var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
+
+ var num = new Array(_this.getLength() );
+ for (var i = 0; i < _this.getLength(); i += 1) {
+ num[i] = _this.getAt(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i += 1) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
+ }
+
+ // recursive call
+ return qrPolynomial(num, 0).mod(e);
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ var QRRSBlock = function() {
+
+ var RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16],
+
+ // 11
+ [4, 101, 81],
+ [1, 80, 50, 4, 81, 51],
+ [4, 50, 22, 4, 51, 23],
+ [3, 36, 12, 8, 37, 13],
+
+ // 12
+ [2, 116, 92, 2, 117, 93],
+ [6, 58, 36, 2, 59, 37],
+ [4, 46, 20, 6, 47, 21],
+ [7, 42, 14, 4, 43, 15],
+
+ // 13
+ [4, 133, 107],
+ [8, 59, 37, 1, 60, 38],
+ [8, 44, 20, 4, 45, 21],
+ [12, 33, 11, 4, 34, 12],
+
+ // 14
+ [3, 145, 115, 1, 146, 116],
+ [4, 64, 40, 5, 65, 41],
+ [11, 36, 16, 5, 37, 17],
+ [11, 36, 12, 5, 37, 13],
+
+ // 15
+ [5, 109, 87, 1, 110, 88],
+ [5, 65, 41, 5, 66, 42],
+ [5, 54, 24, 7, 55, 25],
+ [11, 36, 12, 7, 37, 13],
+
+ // 16
+ [5, 122, 98, 1, 123, 99],
+ [7, 73, 45, 3, 74, 46],
+ [15, 43, 19, 2, 44, 20],
+ [3, 45, 15, 13, 46, 16],
+
+ // 17
+ [1, 135, 107, 5, 136, 108],
+ [10, 74, 46, 1, 75, 47],
+ [1, 50, 22, 15, 51, 23],
+ [2, 42, 14, 17, 43, 15],
+
+ // 18
+ [5, 150, 120, 1, 151, 121],
+ [9, 69, 43, 4, 70, 44],
+ [17, 50, 22, 1, 51, 23],
+ [2, 42, 14, 19, 43, 15],
+
+ // 19
+ [3, 141, 113, 4, 142, 114],
+ [3, 70, 44, 11, 71, 45],
+ [17, 47, 21, 4, 48, 22],
+ [9, 39, 13, 16, 40, 14],
+
+ // 20
+ [3, 135, 107, 5, 136, 108],
+ [3, 67, 41, 13, 68, 42],
+ [15, 54, 24, 5, 55, 25],
+ [15, 43, 15, 10, 44, 16],
+
+ // 21
+ [4, 144, 116, 4, 145, 117],
+ [17, 68, 42],
+ [17, 50, 22, 6, 51, 23],
+ [19, 46, 16, 6, 47, 17],
+
+ // 22
+ [2, 139, 111, 7, 140, 112],
+ [17, 74, 46],
+ [7, 54, 24, 16, 55, 25],
+ [34, 37, 13],
+
+ // 23
+ [4, 151, 121, 5, 152, 122],
+ [4, 75, 47, 14, 76, 48],
+ [11, 54, 24, 14, 55, 25],
+ [16, 45, 15, 14, 46, 16],
+
+ // 24
+ [6, 147, 117, 4, 148, 118],
+ [6, 73, 45, 14, 74, 46],
+ [11, 54, 24, 16, 55, 25],
+ [30, 46, 16, 2, 47, 17],
+
+ // 25
+ [8, 132, 106, 4, 133, 107],
+ [8, 75, 47, 13, 76, 48],
+ [7, 54, 24, 22, 55, 25],
+ [22, 45, 15, 13, 46, 16],
+
+ // 26
+ [10, 142, 114, 2, 143, 115],
+ [19, 74, 46, 4, 75, 47],
+ [28, 50, 22, 6, 51, 23],
+ [33, 46, 16, 4, 47, 17],
+
+ // 27
+ [8, 152, 122, 4, 153, 123],
+ [22, 73, 45, 3, 74, 46],
+ [8, 53, 23, 26, 54, 24],
+ [12, 45, 15, 28, 46, 16],
+
+ // 28
+ [3, 147, 117, 10, 148, 118],
+ [3, 73, 45, 23, 74, 46],
+ [4, 54, 24, 31, 55, 25],
+ [11, 45, 15, 31, 46, 16],
+
+ // 29
+ [7, 146, 116, 7, 147, 117],
+ [21, 73, 45, 7, 74, 46],
+ [1, 53, 23, 37, 54, 24],
+ [19, 45, 15, 26, 46, 16],
+
+ // 30
+ [5, 145, 115, 10, 146, 116],
+ [19, 75, 47, 10, 76, 48],
+ [15, 54, 24, 25, 55, 25],
+ [23, 45, 15, 25, 46, 16],
+
+ // 31
+ [13, 145, 115, 3, 146, 116],
+ [2, 74, 46, 29, 75, 47],
+ [42, 54, 24, 1, 55, 25],
+ [23, 45, 15, 28, 46, 16],
+
+ // 32
+ [17, 145, 115],
+ [10, 74, 46, 23, 75, 47],
+ [10, 54, 24, 35, 55, 25],
+ [19, 45, 15, 35, 46, 16],
+
+ // 33
+ [17, 145, 115, 1, 146, 116],
+ [14, 74, 46, 21, 75, 47],
+ [29, 54, 24, 19, 55, 25],
+ [11, 45, 15, 46, 46, 16],
+
+ // 34
+ [13, 145, 115, 6, 146, 116],
+ [14, 74, 46, 23, 75, 47],
+ [44, 54, 24, 7, 55, 25],
+ [59, 46, 16, 1, 47, 17],
+
+ // 35
+ [12, 151, 121, 7, 152, 122],
+ [12, 75, 47, 26, 76, 48],
+ [39, 54, 24, 14, 55, 25],
+ [22, 45, 15, 41, 46, 16],
+
+ // 36
+ [6, 151, 121, 14, 152, 122],
+ [6, 75, 47, 34, 76, 48],
+ [46, 54, 24, 10, 55, 25],
+ [2, 45, 15, 64, 46, 16],
+
+ // 37
+ [17, 152, 122, 4, 153, 123],
+ [29, 74, 46, 14, 75, 47],
+ [49, 54, 24, 10, 55, 25],
+ [24, 45, 15, 46, 46, 16],
+
+ // 38
+ [4, 152, 122, 18, 153, 123],
+ [13, 74, 46, 32, 75, 47],
+ [48, 54, 24, 14, 55, 25],
+ [42, 45, 15, 32, 46, 16],
+
+ // 39
+ [20, 147, 117, 4, 148, 118],
+ [40, 75, 47, 7, 76, 48],
+ [43, 54, 24, 22, 55, 25],
+ [10, 45, 15, 67, 46, 16],
+
+ // 40
+ [19, 148, 118, 6, 149, 119],
+ [18, 75, 47, 31, 76, 48],
+ [34, 54, 24, 34, 55, 25],
+ [20, 45, 15, 61, 46, 16]
+ ];
+
+ var qrRSBlock = function(totalCount, dataCount) {
+ var _this = {};
+ _this.totalCount = totalCount;
+ _this.dataCount = dataCount;
+ return _this;
+ };
+
+ var _this = {};
+
+ var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+ switch(errorCorrectLevel) {
+ case QRErrorCorrectLevel.L :
+ return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRErrorCorrectLevel.M :
+ return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRErrorCorrectLevel.Q :
+ return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRErrorCorrectLevel.H :
+ return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default :
+ return undefined;
+ }
+ };
+
+ _this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+ var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (typeof rsBlock == 'undefined') {
+ throw new Error('bad rs block @ typeNumber:' + typeNumber +
+ '/errorCorrectLevel:' + errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i += 1) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j += 1) {
+ list.push(qrRSBlock(totalCount, dataCount) );
+ }
+ }
+
+ return list;
+ };
+
+ return _this;
+ }();
+
+ //---------------------------------------------------------------------
+ // qrBitBuffer
+ //---------------------------------------------------------------------
+
+ var qrBitBuffer = function() {
+
+ var _buffer = new Array();
+ var _length = 0;
+
+ var _this = {};
+
+ _this.getBuffer = function() {
+ return _buffer;
+ };
+
+ _this.getAt = function(index) {
+ var bufIndex = Math.floor(index / 8);
+ return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
+ };
+
+ _this.put = function(num, length) {
+ for (var i = 0; i < length; i += 1) {
+ _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
+ }
+ };
+
+ _this.getLengthInBits = function() {
+ return _length;
+ };
+
+ _this.putBit = function(bit) {
+
+ var bufIndex = Math.floor(_length / 8);
+ if (_buffer.length <= bufIndex) {
+ _buffer.push(0);
+ }
+
+ if (bit) {
+ _buffer[bufIndex] |= (0x80 >>> (_length % 8) );
+ }
+
+ _length += 1;
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // qr8BitByte
+ //---------------------------------------------------------------------
+
+ var qr8BitByte = function(data) {
+
+ var _mode = QRMode.MODE_8BIT_BYTE;
+ var _data = data;
+ var _bytes = qrcode.stringToBytes(data);
+
+ var _this = {};
+
+ _this.getMode = function() {
+ return _mode;
+ };
+
+ _this.getLength = function(buffer) {
+ return _bytes.length;
+ };
+
+ _this.write = function(buffer) {
+ for (var i = 0; i < _bytes.length; i += 1) {
+ buffer.put(_bytes[i], 8);
+ }
+ };
+
+ return _this;
+ };
+
+ //=====================================================================
+ // GIF Support etc.
+ //
+
+ //---------------------------------------------------------------------
+ // byteArrayOutputStream
+ //---------------------------------------------------------------------
+
+ var byteArrayOutputStream = function() {
+
+ var _bytes = new Array();
+
+ var _this = {};
+
+ _this.writeByte = function(b) {
+ _bytes.push(b & 0xff);
+ };
+
+ _this.writeShort = function(i) {
+ _this.writeByte(i);
+ _this.writeByte(i >>> 8);
+ };
+
+ _this.writeBytes = function(b, off, len) {
+ off = off || 0;
+ len = len || b.length;
+ for (var i = 0; i < len; i += 1) {
+ _this.writeByte(b[i + off]);
+ }
+ };
+
+ _this.writeString = function(s) {
+ for (var i = 0; i < s.length; i += 1) {
+ _this.writeByte(s.charCodeAt(i) );
+ }
+ };
+
+ _this.toByteArray = function() {
+ return _bytes;
+ };
+
+ _this.toString = function() {
+ var s = '';
+ s += '[';
+ for (var i = 0; i < _bytes.length; i += 1) {
+ if (i > 0) {
+ s += ',';
+ }
+ s += _bytes[i];
+ }
+ s += ']';
+ return s;
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // base64EncodeOutputStream
+ //---------------------------------------------------------------------
+
+ var base64EncodeOutputStream = function() {
+
+ var _buffer = 0;
+ var _buflen = 0;
+ var _length = 0;
+ var _base64 = '';
+
+ var _this = {};
+
+ var writeEncoded = function(b) {
+ _base64 += String.fromCharCode(encode(b & 0x3f) );
+ };
+
+ var encode = function(n) {
+ if (n < 0) {
+ // error.
+ } else if (n < 26) {
+ return 0x41 + n;
+ } else if (n < 52) {
+ return 0x61 + (n - 26);
+ } else if (n < 62) {
+ return 0x30 + (n - 52);
+ } else if (n == 62) {
+ return 0x2b;
+ } else if (n == 63) {
+ return 0x2f;
+ }
+ throw new Error('n:' + n);
+ };
+
+ _this.writeByte = function(n) {
+
+ _buffer = (_buffer << 8) | (n & 0xff);
+ _buflen += 8;
+ _length += 1;
+
+ while (_buflen >= 6) {
+ writeEncoded(_buffer >>> (_buflen - 6) );
+ _buflen -= 6;
+ }
+ };
+
+ _this.flush = function() {
+
+ if (_buflen > 0) {
+ writeEncoded(_buffer << (6 - _buflen) );
+ _buffer = 0;
+ _buflen = 0;
+ }
+
+ if (_length % 3 != 0) {
+ // padding
+ var padlen = 3 - _length % 3;
+ for (var i = 0; i < padlen; i += 1) {
+ _base64 += '=';
+ }
+ }
+ };
+
+ _this.toString = function() {
+ return _base64;
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // base64DecodeInputStream
+ //---------------------------------------------------------------------
+
+ var base64DecodeInputStream = function(str) {
+
+ var _str = str;
+ var _pos = 0;
+ var _buffer = 0;
+ var _buflen = 0;
+
+ var _this = {};
+
+ _this.read = function() {
+
+ while (_buflen < 8) {
+
+ if (_pos >= _str.length) {
+ if (_buflen == 0) {
+ return -1;
+ }
+ throw new Error('unexpected end of file./' + _buflen);
+ }
+
+ var c = _str.charAt(_pos);
+ _pos += 1;
+
+ if (c == '=') {
+ _buflen = 0;
+ return -1;
+ } else if (c.match(/^\s$/) ) {
+ // ignore if whitespace.
+ continue;
+ }
+
+ _buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
+ _buflen += 6;
+ }
+
+ var n = (_buffer >>> (_buflen - 8) ) & 0xff;
+ _buflen -= 8;
+ return n;
+ };
+
+ var decode = function(c) {
+ if (0x41 <= c && c <= 0x5a) {
+ return c - 0x41;
+ } else if (0x61 <= c && c <= 0x7a) {
+ return c - 0x61 + 26;
+ } else if (0x30 <= c && c <= 0x39) {
+ return c - 0x30 + 52;
+ } else if (c == 0x2b) {
+ return 62;
+ } else if (c == 0x2f) {
+ return 63;
+ } else {
+ throw new Error('c:' + c);
+ }
+ };
+
+ return _this;
+ };
+
+ //---------------------------------------------------------------------
+ // gifImage (B/W)
+ //---------------------------------------------------------------------
+
+ var gifImage = function(width, height) {
+
+ var _width = width;
+ var _height = height;
+ var _data = new Array(width * height);
+
+ var _this = {};
+
+ _this.setPixel = function(x, y, pixel) {
+ _data[y * _width + x] = pixel;
+ };
+
+ _this.write = function(out) {
+
+ //---------------------------------
+ // GIF Signature
+
+ out.writeString('GIF87a');
+
+ //---------------------------------
+ // Screen Descriptor
+
+ out.writeShort(_width);
+ out.writeShort(_height);
+
+ out.writeByte(0x80); // 2bit
+ out.writeByte(0);
+ out.writeByte(0);
+
+ //---------------------------------
+ // Global Color Map
+
+ // black
+ out.writeByte(0x00);
+ out.writeByte(0x00);
+ out.writeByte(0x00);
+
+ // white
+ out.writeByte(0xff);
+ out.writeByte(0xff);
+ out.writeByte(0xff);
+
+ //---------------------------------
+ // Image Descriptor
+
+ out.writeString(',');
+ out.writeShort(0);
+ out.writeShort(0);
+ out.writeShort(_width);
+ out.writeShort(_height);
+ out.writeByte(0);
+
+ //---------------------------------
+ // Local Color Map
+
+ //---------------------------------
+ // Raster Data
+
+ var lzwMinCodeSize = 2;
+ var raster = getLZWRaster(lzwMinCodeSize);
+
+ out.writeByte(lzwMinCodeSize);
+
+ var offset = 0;
+
+ while (raster.length - offset > 255) {
+ out.writeByte(255);
+ out.writeBytes(raster, offset, 255);
+ offset += 255;
+ }
+
+ out.writeByte(raster.length - offset);
+ out.writeBytes(raster, offset, raster.length - offset);
+ out.writeByte(0x00);
+
+ //---------------------------------
+ // GIF Terminator
+ out.writeString(';');
+ };
+
+ var bitOutputStream = function(out) {
+
+ var _out = out;
+ var _bitLength = 0;
+ var _bitBuffer = 0;
+
+ var _this = {};
+
+ _this.write = function(data, length) {
+
+ if ( (data >>> length) != 0) {
+ throw new Error('length over');
+ }
+
+ while (_bitLength + length >= 8) {
+ _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
+ length -= (8 - _bitLength);
+ data >>>= (8 - _bitLength);
+ _bitBuffer = 0;
+ _bitLength = 0;
+ }
+
+ _bitBuffer = (data << _bitLength) | _bitBuffer;
+ _bitLength = _bitLength + length;
+ };
+
+ _this.flush = function() {
+ if (_bitLength > 0) {
+ _out.writeByte(_bitBuffer);
+ }
+ };
+
+ return _this;
+ };
+
+ var getLZWRaster = function(lzwMinCodeSize) {
+
+ var clearCode = 1 << lzwMinCodeSize;
+ var endCode = (1 << lzwMinCodeSize) + 1;
+ var bitLength = lzwMinCodeSize + 1;
+
+ // Setup LZWTable
+ var table = lzwTable();
+
+ for (var i = 0; i < clearCode; i += 1) {
+ table.add(String.fromCharCode(i) );
+ }
+ table.add(String.fromCharCode(clearCode) );
+ table.add(String.fromCharCode(endCode) );
+
+ var byteOut = byteArrayOutputStream();
+ var bitOut = bitOutputStream(byteOut);
+
+ // clear code
+ bitOut.write(clearCode, bitLength);
+
+ var dataIndex = 0;
+
+ var s = String.fromCharCode(_data[dataIndex]);
+ dataIndex += 1;
+
+ while (dataIndex < _data.length) {
+
+ var c = String.fromCharCode(_data[dataIndex]);
+ dataIndex += 1;
+
+ if (table.contains(s + c) ) {
+
+ s = s + c;
+
+ } else {
+
+ bitOut.write(table.indexOf(s), bitLength);
+
+ if (table.size() < 0xfff) {
+
+ if (table.size() == (1 << bitLength) ) {
+ bitLength += 1;
+ }
+
+ table.add(s + c);
+ }
+
+ s = c;
+ }
+ }
+
+ bitOut.write(table.indexOf(s), bitLength);
+
+ // end code
+ bitOut.write(endCode, bitLength);
+
+ bitOut.flush();
+
+ return byteOut.toByteArray();
+ };
+
+ var lzwTable = function() {
+
+ var _map = {};
+ var _size = 0;
+
+ var _this = {};
+
+ _this.add = function(key) {
+ if (_this.contains(key) ) {
+ throw new Error('dup key:' + key);
+ }
+ _map[key] = _size;
+ _size += 1;
+ };
+
+ _this.size = function() {
+ return _size;
+ };
+
+ _this.indexOf = function(key) {
+ return _map[key];
+ };
+
+ _this.contains = function(key) {
+ return typeof _map[key] != 'undefined';
+ };
+
+ return _this;
+ };
+
+ return _this;
+ };
+
+ var createImgTag = function(width, height, getPixel, alt) {
+
+ var gif = gifImage(width, height);
+ for (var y = 0; y < height; y += 1) {
+ for (var x = 0; x < width; x += 1) {
+ gif.setPixel(x, y, getPixel(x, y) );
+ }
+ }
+
+ var b = byteArrayOutputStream();
+ gif.write(b);
+
+ var base64 = base64EncodeOutputStream();
+ var bytes = b.toByteArray();
+ for (var i = 0; i < bytes.length; i += 1) {
+ base64.writeByte(bytes[i]);
+ }
+ base64.flush();
+
+ var img = '';
+ img += '';
+
+ for (var c = 0; c < _this.getModuleCount(); c += 1) {
+ qrHtml += ' ';
+ }
+
+ qrHtml += '';
+ qrHtml += '';
+ }
+
+ qrHtml += ' ';
+
+ return img;
+ };
+
+ //---------------------------------------------------------------------
+ // returns qrcode function.
+
+ return qrcode;
+ }();
+
+ (function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ define([], factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory();
+ }
+ }(function () {
+ return qrcode;
+ }));
+ //---------------------------------------------------------------------
+ //
+ // QR Code Generator for JavaScript UTF8 Support (optional)
+ //
+ // Copyright (c) 2011 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word 'QR Code' is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ !function(qrcode) {
+
+ //---------------------------------------------------------------------
+ // overwrite qrcode.stringToBytes
+ //---------------------------------------------------------------------
+
+ qrcode.stringToBytes = function(s) {
+ // http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
+ function toUTF8Array(str) {
+ var utf8 = [];
+ for (var i=0; i < str.length; i++) {
+ var charcode = str.charCodeAt(i);
+ if (charcode < 0x80) utf8.push(charcode);
+ else if (charcode < 0x800) {
+ utf8.push(0xc0 | (charcode >> 6),
+ 0x80 | (charcode & 0x3f));
+ }
+ else if (charcode < 0xd800 || charcode >= 0xe000) {
+ utf8.push(0xe0 | (charcode >> 12),
+ 0x80 | ((charcode>>6) & 0x3f),
+ 0x80 | (charcode & 0x3f));
+ }
+ // surrogate pair
+ else {
+ i++;
+ // UTF-16 encodes 0x10000-0x10FFFF by
+ // subtracting 0x10000 and splitting the
+ // 20 bits of 0x0-0xFFFFF into two halves
+ charcode = 0x10000 + (((charcode & 0x3ff)<<10)
+ | (str.charCodeAt(i) & 0x3ff));
+ utf8.push(0xf0 | (charcode >>18),
+ 0x80 | ((charcode>>12) & 0x3f),
+ 0x80 | ((charcode>>6) & 0x3f),
+ 0x80 | (charcode & 0x3f));
+ }
+ }
+ return utf8;
+ }
+ return toUTF8Array(s);
+ };
+
+ }(qrcode);
+
+ return qrcode; // eslint-disable-line no-undef
+}()));
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery-qrcode/jquery-qrcode.min.js b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery-qrcode/jquery-qrcode.min.js
new file mode 100755
index 00000000..f718c22b
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery-qrcode/jquery-qrcode.min.js
@@ -0,0 +1,2 @@
+/*! jquery-qrcode v0.14.0 - https://larsjung.de/jquery-qrcode/ */
+!function(r){"use strict";function t(t,e,n,o){function a(r,t){return r-=o,t-=o,0>r||r>=c||0>t||t>=c?!1:f.isDark(r,t)}function i(r,t,e,n){var o=u.isDark,a=1/l;u.isDark=function(i,u){var f=u*a,c=i*a,l=f+a,g=c+a;return o(i,u)&&(r>l||f>e||t>g||c>n)}}var u={},f=r(n,e);f.addData(t),f.make(),o=o||0;var c=f.getModuleCount(),l=f.getModuleCount()+2*o;return u.text=t,u.level=e,u.version=n,u.moduleCount=l,u.isDark=a,u.addBlank=i,u}function e(r,e,n,o,a){n=Math.max(1,n||1),o=Math.min(40,o||40);for(var i=n;o>=i;i+=1)try{return t(r,e,i,a)}catch(u){}}function n(r,t,e){var n=e.size,o="bold "+e.mSize*n+"px "+e.fontname,a=w("")[0].getContext("2d");a.font=o;var i=a.measureText(e.label).width,u=e.mSize,f=i/n,c=(1-f)*e.mPosX,l=(1-u)*e.mPosY,g=c+f,s=l+u,v=.01;1===e.mode?r.addBlank(0,l-v,n,s+v):r.addBlank(c-v,l-v,g+v,s+v),t.fillStyle=e.fontcolor,t.font=o,t.fillText(e.label,c*n,l*n+.75*e.mSize*n)}function o(r,t,e){var n=e.size,o=e.image.naturalWidth||1,a=e.image.naturalHeight||1,i=e.mSize,u=i*o/a,f=(1-u)*e.mPosX,c=(1-i)*e.mPosY,l=f+u,g=c+i,s=.01;3===e.mode?r.addBlank(0,c-s,n,g+s):r.addBlank(f-s,c-s,l+s,g+s),t.drawImage(e.image,f*n,c*n,u*n,i*n)}function a(r,t,e){w(e.background).is("img")?t.drawImage(e.background,0,0,e.size,e.size):e.background&&(t.fillStyle=e.background,t.fillRect(e.left,e.top,e.size,e.size));var a=e.mode;1===a||2===a?n(r,t,e):(3===a||4===a)&&o(r,t,e)}function i(r,t,e,n,o,a,i,u){r.isDark(i,u)&&t.rect(n,o,a,a)}function u(r,t,e,n,o,a,i,u,f,c){i?r.moveTo(t+a,e):r.moveTo(t,e),u?(r.lineTo(n-a,e),r.arcTo(n,e,n,o,a)):r.lineTo(n,e),f?(r.lineTo(n,o-a),r.arcTo(n,o,t,o,a)):r.lineTo(n,o),c?(r.lineTo(t+a,o),r.arcTo(t,o,t,e,a)):r.lineTo(t,o),i?(r.lineTo(t,e+a),r.arcTo(t,e,n,e,a)):r.lineTo(t,e)}function f(r,t,e,n,o,a,i,u,f,c){i&&(r.moveTo(t+a,e),r.lineTo(t,e),r.lineTo(t,e+a),r.arcTo(t,e,t+a,e,a)),u&&(r.moveTo(n-a,e),r.lineTo(n,e),r.lineTo(n,e+a),r.arcTo(n,e,n-a,e,a)),f&&(r.moveTo(n-a,o),r.lineTo(n,o),r.lineTo(n,o-a),r.arcTo(n,o,n-a,o,a)),c&&(r.moveTo(t+a,o),r.lineTo(t,o),r.lineTo(t,o-a),r.arcTo(t,o,t+a,o,a))}function c(r,t,e,n,o,a,i,c){var l=r.isDark,g=n+a,s=o+a,v=e.radius*a,h=i-1,d=i+1,w=c-1,m=c+1,y=l(i,c),T=l(h,w),p=l(h,c),B=l(h,m),A=l(i,m),E=l(d,m),k=l(d,c),M=l(d,w),C=l(i,w);y?u(t,n,o,g,s,v,!p&&!C,!p&&!A,!k&&!A,!k&&!C):f(t,n,o,g,s,v,p&&C&&T,p&&A&&B,k&&A&&E,k&&C&&M)}function l(r,t,e){var n,o,a=r.moduleCount,u=e.size/a,f=i;for(e.radius>0&&e.radius<=.5&&(f=c),t.beginPath(),n=0;a>n;n+=1)for(o=0;a>o;o+=1){var l=e.left+o*u,g=e.top+n*u,s=u;f(r,t,e,l,g,s,n,o)}if(w(e.fill).is("img")){t.strokeStyle="rgba(0,0,0,0.5)",t.lineWidth=2,t.stroke();var v=t.globalCompositeOperation;t.globalCompositeOperation="destination-out",t.fill(),t.globalCompositeOperation=v,t.clip(),t.drawImage(e.fill,0,0,e.size,e.size),t.restore()}else t.fillStyle=e.fill,t.fill()}function g(r,t){var n=e(t.text,t.ecLevel,t.minVersion,t.maxVersion,t.quiet);if(!n)return null;var o=w(r).data("qrcode",n),i=o[0].getContext("2d");return a(n,i,t),l(n,i,t),o}function s(r){var t=w("").attr("width",r.size).attr("height",r.size);return g(t,r)}function v(r){return w("
").attr("src",s(r)[0].toDataURL("image/png"))}function h(r){var t=e(r.text,r.ecLevel,r.minVersion,r.maxVersion,r.quiet);if(!t)return null;var n,o,a=r.size,i=r.background,u=Math.floor,f=t.moduleCount,c=u(a/f),l=u(.5*(a-c*f)),g={position:"relative",left:0,top:0,padding:0,margin:0,width:a,height:a},s={position:"absolute",padding:0,margin:0,width:c,height:c,"background-color":r.fill},v=w("").data("qrcode",t).css(g);for(i&&v.css("background-color",i),n=0;f>n;n+=1)for(o=0;f>o;o+=1)t.isDark(n,o)&&w("").css(s).css({left:l+o*c,top:l+n*c}).appendTo(v);return v}function d(r){return m&&"canvas"===r.render?s(r):m&&"image"===r.render?v(r):h(r)}var w=window.jQuery,m=function(){var r=document.createElement("canvas");return!(!r.getContext||!r.getContext("2d"))}(),y={render:"canvas",minVersion:1,maxVersion:40,ecLevel:"L",left:0,top:0,size:200,fill:"#000",background:null,text:"no text",radius:0,quiet:0,mode:0,mSize:.1,mPosX:.5,mPosY:.5,label:"no label",fontname:"sans",fontcolor:"#000",image:null};w.fn.qrcode=function(r){var t=w.extend({},y,r);return this.each(function(r,e){"canvas"===e.nodeName.toLowerCase()?g(e,t):w(e).append(d(t))})}}(function(){var r=function(){function r(t,e){if("undefined"==typeof t.length)throw new Error(t.length+"/"+e);var n=function(){for(var r=0;r
',e+="";for(var n=0;n
"},m.createImgTag=function(r,t){r=r||2,t="undefined"==typeof t?4*r:t;var e=m.getModuleCount()*r+2*t,n=t,o=e-t;return h(e,e,function(t,e){if(t>=n&&o>t&&e>=n&&o>e){var a=Math.floor((t-n)/r),i=Math.floor((e-n)/r);return m.isDark(i,a)?0:1}return 1})},m};t.stringToBytes=function(r){for(var t=new Array,e=0;e'+title+'
');
+ if (message) $m.append(''+message+'
');
+ if (timeout === undefined) timeout = 3000;
+
+ // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
+ var callBlock = function(opts) {
+ opts = opts || {};
+
+ $.blockUI({
+ message: $m,
+ fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
+ fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
+ timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
+ centerY: false,
+ showOverlay: false,
+ onUnblock: onClose,
+ css: $.blockUI.defaults.growlCSS
+ });
+ };
+
+ callBlock();
+ var nonmousedOpacity = $m.css('opacity');
+ $m.mouseover(function() {
+ callBlock({
+ fadeIn: 0,
+ timeout: 30000
+ });
+
+ var displayBlock = $('.blockMsg');
+ displayBlock.stop(); // cancel fadeout if it has started
+ displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
+ }).mouseout(function() {
+ $('.blockMsg').fadeOut(1000);
+ });
+ // End konapun additions
+ };
+
+ // plugin method for blocking element content
+ $.fn.block = function(opts) {
+ if ( this[0] === window ) {
+ $.blockUI( opts );
+ return this;
+ }
+ var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
+ this.each(function() {
+ var $el = $(this);
+ if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
+ return;
+ $el.unblock({ fadeOut: 0 });
+ });
+
+ return this.each(function() {
+ if ($.css(this,'position') == 'static') {
+ this.style.position = 'relative';
+ $(this).data('blockUI.static', true);
+ }
+ this.style.zoom = 1; // force 'hasLayout' in ie
+ install(this, opts);
+ });
+ };
+
+ // plugin method for unblocking element content
+ $.fn.unblock = function(opts) {
+ if ( this[0] === window ) {
+ $.unblockUI( opts );
+ return this;
+ }
+ return this.each(function() {
+ remove(this, opts);
+ });
+ };
+
+ $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
+
+ // override these in your code to change the default behavior and style
+ $.blockUI.defaults = {
+ // message displayed when blocking (use null for no message)
+ message: 'Please wait...
',
+
+ title: null, // title string; only used when theme == true
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
+
+ theme: false, // set to true to use with jQuery UI themes
+
+ // styles for the message when blocking; if you wish to disable
+ // these and use an external stylesheet then do this in your code:
+ // $.blockUI.defaults.css = {};
+ css: {
+ padding: 0,
+ margin: 0,
+ width: '30%',
+ top: '40%',
+ left: '35%',
+ textAlign: 'center',
+ color: '#000',
+ border: '3px solid #aaa',
+ backgroundColor:'#fff',
+ cursor: 'wait'
+ },
+
+ // minimal style set used when themes are used
+ themedCSS: {
+ width: '30%',
+ top: '40%',
+ left: '35%'
+ },
+
+ // styles for the overlay
+ overlayCSS: {
+ backgroundColor: '#000',
+ opacity: 0.6,
+ cursor: 'wait'
+ },
+
+ // style to replace wait cursor before unblocking to correct issue
+ // of lingering wait cursor
+ cursorReset: 'default',
+
+ // styles applied when using $.growlUI
+ growlCSS: {
+ width: '350px',
+ top: '10px',
+ left: '',
+ right: '10px',
+ border: 'none',
+ padding: '5px',
+ opacity: 0.6,
+ cursor: 'default',
+ color: '#fff',
+ backgroundColor: '#000',
+ '-webkit-border-radius':'10px',
+ '-moz-border-radius': '10px',
+ 'border-radius': '10px'
+ },
+
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+ // (hat tip to Jorge H. N. de Vasconcelos)
+ /*jshint scripturl:true */
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
+ forceIframe: false,
+
+ // z-index for the blocking overlay
+ baseZ: 1000,
+
+ // set these to true to have the message automatically centered
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
+ centerY: true,
+
+ // allow body element to be stetched in ie6; this makes blocking look better
+ // on "short" pages. disable if you wish to prevent changes to the body height
+ allowBodyStretch: true,
+
+ // enable if you want key and mouse events to be disabled for content that is blocked
+ bindEvents: true,
+
+ // be default blockUI will suppress tab navigation from leaving blocking content
+ // (if bindEvents is true)
+ constrainTabKey: true,
+
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
+ fadeIn: 200,
+
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+ fadeOut: 400,
+
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+ timeout: 0,
+
+ // disable if you don't want to show the overlay
+ showOverlay: true,
+
+ // if true, focus will be placed in the first available input field when
+ // page blocking
+ focusInput: true,
+
+ // elements that can receive focus
+ focusableElements: ':input:enabled:visible',
+
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+ // no longer needed in 2012
+ // applyPlatformOpacityRules: true,
+
+ // callback method invoked when fadeIn has completed and blocking message is visible
+ onBlock: null,
+
+ // callback method invoked when unblocking has completed; the callback is
+ // passed the element that has been unblocked (which is the window object for page
+ // blocks) and the options that were passed to the unblock call:
+ // onUnblock(element, options)
+ onUnblock: null,
+
+ // callback method invoked when the overlay area is clicked.
+ // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
+ onOverlayClick: null,
+
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+ quirksmodeOffsetHack: 4,
+
+ // class name of the message block
+ blockMsgClass: 'blockMsg',
+
+ // if it is already blocked, then ignore it (don't unblock and reblock)
+ ignoreIfBlocked: false
+ };
+
+ // private data and functions follow...
+
+ var pageBlock = null;
+ var pageBlockEls = [];
+
+ function install(el, opts) {
+ var css, themedCSS;
+ var full = (el == window);
+ var msg = (opts && opts.message !== undefined ? opts.message : undefined);
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+
+ if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
+ return;
+
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+ css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+ if (opts.onOverlayClick)
+ opts.overlayCSS.cursor = 'pointer';
+
+ themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+ msg = msg === undefined ? opts.message : msg;
+
+ // remove the current block (if there is one)
+ if (full && pageBlock)
+ remove(window, {fadeOut:0});
+
+ // if an existing element is being used as the blocking content then we capture
+ // its current place in the DOM (and current display style) so we can restore
+ // it when we unblock
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+ var node = msg.jquery ? msg[0] : msg;
+ var data = {};
+ $(el).data('blockUI.history', data);
+ data.el = node;
+ data.parent = node.parentNode;
+ data.display = node.style.display;
+ data.position = node.style.position;
+ if (data.parent)
+ data.parent.removeChild(node);
+ }
+
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
+ var z = opts.baseZ;
+
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+ // layer1 is the iframe layer which is used to suppress bleed through of underlying content
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+ // layer3 is the message content that is displayed while blocking
+ var lyr1, lyr2, lyr3, s;
+ if (msie || opts.forceIframe)
+ lyr1 = $('');
+ else
+ lyr1 = $('');
+
+ if (opts.theme)
+ lyr2 = $('');
+ else
+ lyr2 = $('');
+
+ if (opts.theme && full) {
+ s = '';
+ }
+ else if (opts.theme) {
+ s = '';
+ }
+ else if (full) {
+ s = '';
+ }
+ else {
+ s = '';
+ }
+ lyr3 = $(s);
+
+ // if we have a message, style it
+ if (msg) {
+ if (opts.theme) {
+ lyr3.css(themedCSS);
+ lyr3.addClass('ui-widget-content');
+ }
+ else
+ lyr3.css(css);
+ }
+
+ // style the overlay
+ if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
+ lyr2.css(opts.overlayCSS);
+ lyr2.css('position', full ? 'fixed' : 'absolute');
+
+ // make iframe layer transparent in IE
+ if (msie || opts.forceIframe)
+ lyr1.css('opacity',0.0);
+
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+ $.each(layers, function() {
+ this.appendTo($par);
+ });
+
+ if (opts.theme && opts.draggable && $.fn.draggable) {
+ lyr3.draggable({
+ handle: '.ui-dialog-titlebar',
+ cancel: 'li'
+ });
+ }
+
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+ var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
+ if (ie6 || expr) {
+ // give body 100% height
+ if (full && opts.allowBodyStretch && $.support.boxModel)
+ $('html,body').css('height','100%');
+
+ // fix ie6 issue when blocked element has a border width
+ if ((ie6 || !$.support.boxModel) && !full) {
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+ var fixT = t ? '(0 - '+t+')' : 0;
+ var fixL = l ? '(0 - '+l+')' : 0;
+ }
+
+ // simulate fixed position
+ $.each(layers, function(i,o) {
+ var s = o[0].style;
+ s.position = 'absolute';
+ if (i < 2) {
+ if (full)
+ s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
+ else
+ s.setExpression('height','this.parentNode.offsetHeight + "px"');
+ if (full)
+ s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
+ else
+ s.setExpression('width','this.parentNode.offsetWidth + "px"');
+ if (fixL) s.setExpression('left', fixL);
+ if (fixT) s.setExpression('top', fixT);
+ }
+ else if (opts.centerY) {
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+ s.marginTop = 0;
+ }
+ else if (!opts.centerY && full) {
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+ s.setExpression('top',expression);
+ }
+ });
+ }
+
+ // show the message
+ if (msg) {
+ if (opts.theme)
+ lyr3.find('.ui-widget-content').append(msg);
+ else
+ lyr3.append(msg);
+ if (msg.jquery || msg.nodeType)
+ $(msg).show();
+ }
+
+ if ((msie || opts.forceIframe) && opts.showOverlay)
+ lyr1.show(); // opacity is zero
+ if (opts.fadeIn) {
+ var cb = opts.onBlock ? opts.onBlock : noOp;
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+ var cb2 = msg ? cb : noOp;
+ if (opts.showOverlay)
+ lyr2._fadeIn(opts.fadeIn, cb1);
+ if (msg)
+ lyr3._fadeIn(opts.fadeIn, cb2);
+ }
+ else {
+ if (opts.showOverlay)
+ lyr2.show();
+ if (msg)
+ lyr3.show();
+ if (opts.onBlock)
+ opts.onBlock.bind(lyr3)();
+ }
+
+ // bind key and mouse events
+ bind(1, el, opts);
+
+ if (full) {
+ pageBlock = lyr3[0];
+ pageBlockEls = $(opts.focusableElements,pageBlock);
+ if (opts.focusInput)
+ setTimeout(focus, 20);
+ }
+ else
+ center(lyr3[0], opts.centerX, opts.centerY);
+
+ if (opts.timeout) {
+ // auto-unblock
+ var to = setTimeout(function() {
+ if (full)
+ $.unblockUI(opts);
+ else
+ $(el).unblock(opts);
+ }, opts.timeout);
+ $(el).data('blockUI.timeout', to);
+ }
+ }
+
+ // remove the block
+ function remove(el, opts) {
+ var count;
+ var full = (el == window);
+ var $el = $(el);
+ var data = $el.data('blockUI.history');
+ var to = $el.data('blockUI.timeout');
+ if (to) {
+ clearTimeout(to);
+ $el.removeData('blockUI.timeout');
+ }
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ bind(0, el, opts); // unbind events
+
+ if (opts.onUnblock === null) {
+ opts.onUnblock = $el.data('blockUI.onUnblock');
+ $el.removeData('blockUI.onUnblock');
+ }
+
+ var els;
+ if (full) // crazy selector to handle odd field errors in ie6/7
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
+ else
+ els = $el.find('>.blockUI');
+
+ // fix cursor issue
+ if ( opts.cursorReset ) {
+ if ( els.length > 1 )
+ els[1].style.cursor = opts.cursorReset;
+ if ( els.length > 2 )
+ els[2].style.cursor = opts.cursorReset;
+ }
+
+ if (full)
+ pageBlock = pageBlockEls = null;
+
+ if (opts.fadeOut) {
+ count = els.length;
+ els.stop().fadeOut(opts.fadeOut, function() {
+ if ( --count === 0)
+ reset(els,data,opts,el);
+ });
+ }
+ else
+ reset(els, data, opts, el);
+ }
+
+ // move blocking element back into the DOM where it started
+ function reset(els,data,opts,el) {
+ var $el = $(el);
+ if ( $el.data('blockUI.isBlocked') )
+ return;
+
+ els.each(function(i,o) {
+ // remove via DOM calls so we don't lose event handlers
+ if (this.parentNode)
+ this.parentNode.removeChild(this);
+ });
+
+ if (data && data.el) {
+ data.el.style.display = data.display;
+ data.el.style.position = data.position;
+ data.el.style.cursor = 'default'; // #59
+ if (data.parent)
+ data.parent.appendChild(data.el);
+ $el.removeData('blockUI.history');
+ }
+
+ if ($el.data('blockUI.static')) {
+ $el.css('position', 'static'); // #22
+ }
+
+ if (typeof opts.onUnblock == 'function')
+ opts.onUnblock(el,opts);
+
+ // fix issue in Safari 6 where block artifacts remain until reflow
+ var body = $(document.body), w = body.width(), cssW = body[0].style.width;
+ body.width(w-1).width(w);
+ body[0].style.width = cssW;
+ }
+
+ // bind/unbind the handler
+ function bind(b, el, opts) {
+ var full = el == window, $el = $(el);
+
+ // don't bother unbinding if there is nothing to unbind
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+ return;
+
+ $el.data('blockUI.isBlocked', b);
+
+ // don't bind events when overlay is not in use or if bindEvents is false
+ if (!full || !opts.bindEvents || (b && !opts.showOverlay))
+ return;
+
+ // bind anchors and inputs for mouse and key events
+ var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
+ if (b)
+ $(document).bind(events, opts, handler);
+ else
+ $(document).unbind(events, handler);
+
+ // former impl...
+ // var $e = $('a,:input');
+ // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+ }
+
+ // event handler to suppress keyboard/mouse events when blocking
+ function handler(e) {
+ // allow tab navigation (conditionally)
+ if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
+ if (pageBlock && e.data.constrainTabKey) {
+ var els = pageBlockEls;
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
+ var back = e.shiftKey && e.target === els[0];
+ if (fwd || back) {
+ setTimeout(function(){focus(back);},10);
+ return false;
+ }
+ }
+ }
+ var opts = e.data;
+ var target = $(e.target);
+ if (target.hasClass('blockOverlay') && opts.onOverlayClick)
+ opts.onOverlayClick(e);
+
+ // allow events within the message content
+ if (target.parents('div.' + opts.blockMsgClass).length > 0)
+ return true;
+
+ // allow events for content that is not being blocked
+ return target.parents().children().filter('div.blockUI').length === 0;
+ }
+
+ function focus(back) {
+ if (!pageBlockEls)
+ return;
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+ if (e)
+ e.focus();
+ }
+
+ function center(el, x, y) {
+ var p = el.parentNode, s = el.style;
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+ if (x) s.left = l > 0 ? (l+'px') : '0';
+ if (y) s.top = t > 0 ? (t+'px') : '0';
+ }
+
+ function sz(el, p) {
+ return parseInt($.css(el,p),10)||0;
+ }
+
+ }
+
+
+ /*global define:true */
+ if (typeof define === 'function' && define.amd && define.amd.jQuery) {
+ define(['jquery'], setup);
+ } else {
+ setup(jQuery);
+ }
+
+})();
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery.blockUI.min.js b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery.blockUI.min.js
new file mode 100755
index 00000000..47fb9744
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery.blockUI.min.js
@@ -0,0 +1,14 @@
+/*!
+ * jQuery blockUI plugin
+ * Version 2.70.0-2014.11.23
+ * Requires jQuery v1.7 or later
+ *
+ * Examples at: http://malsup.com/jquery/block/
+ * Copyright (c) 2007-2013 M. Alsup
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
+ */
+!function(){"use strict";function a(a){function b(b,d){var f,p,q=b==window,r=d&&void 0!==d.message?d.message:void 0;if(d=a.extend({},a.blockUI.defaults,d||{}),!d.ignoreIfBlocked||!a(b).data("blockUI.isBlocked")){if(d.overlayCSS=a.extend({},a.blockUI.defaults.overlayCSS,d.overlayCSS||{}),f=a.extend({},a.blockUI.defaults.css,d.css||{}),d.onOverlayClick&&(d.overlayCSS.cursor="pointer"),p=a.extend({},a.blockUI.defaults.themedCSS,d.themedCSS||{}),r=void 0===r?d.message:r,q&&n&&c(window,{fadeOut:0}),r&&"string"!=typeof r&&(r.parentNode||r.jquery)){var s=r.jquery?r[0]:r,t={};a(b).data("blockUI.history",t),t.el=s,t.parent=s.parentNode,t.display=s.style.display,t.position=s.style.position,t.parent&&t.parent.removeChild(s)}a(b).data("blockUI.onUnblock",d.onUnblock);var u,v,w,x,y=d.baseZ;u=a(k||d.forceIframe?'':''),v=a(d.theme?'':''),d.theme&&q?(x='"):d.theme?(x='"):x=q?'':'',w=a(x),r&&(d.theme?(w.css(p),w.addClass("ui-widget-content")):w.css(f)),d.theme||v.css(d.overlayCSS),v.css("position",q?"fixed":"absolute"),(k||d.forceIframe)&&u.css("opacity",0);var z=[u,v,w],A=a(q?"body":b);a.each(z,function(){this.appendTo(A)}),d.theme&&d.draggable&&a.fn.draggable&&w.draggable({handle:".ui-dialog-titlebar",cancel:"li"});var B=m&&(!a.support.boxModel||a("object,embed",q?null:b).length>0);if(l||B){if(q&&d.allowBodyStretch&&a.support.boxModel&&a("html,body").css("height","100%"),(l||!a.support.boxModel)&&!q)var C=i(b,"borderTopWidth"),D=i(b,"borderLeftWidth"),E=C?"(0 - "+C+")":0,F=D?"(0 - "+D+")":0;a.each(z,function(a,b){var c=b[0].style;if(c.position="absolute",2>a)q?c.setExpression("height","Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:"+d.quirksmodeOffsetHack+') + "px"'):c.setExpression("height",'this.parentNode.offsetHeight + "px"'),q?c.setExpression("width",'jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"'):c.setExpression("width",'this.parentNode.offsetWidth + "px"'),F&&c.setExpression("left",F),E&&c.setExpression("top",E);else if(d.centerY)q&&c.setExpression("top",'(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"'),c.marginTop=0;else if(!d.centerY&&q){var e=d.css&&d.css.top?parseInt(d.css.top,10):0,f="((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "+e+') + "px"';c.setExpression("top",f)}})}if(r&&(d.theme?w.find(".ui-widget-content").append(r):w.append(r),(r.jquery||r.nodeType)&&a(r).show()),(k||d.forceIframe)&&d.showOverlay&&u.show(),d.fadeIn){var G=d.onBlock?d.onBlock:j,H=d.showOverlay&&!r?G:j,I=r?G:j;d.showOverlay&&v._fadeIn(d.fadeIn,H),r&&w._fadeIn(d.fadeIn,I)}else d.showOverlay&&v.show(),r&&w.show(),d.onBlock&&d.onBlock.bind(w)();if(e(1,b,d),q?(n=w[0],o=a(d.focusableElements,n),d.focusInput&&setTimeout(g,20)):h(w[0],d.centerX,d.centerY),d.timeout){var J=setTimeout(function(){q?a.unblockUI(d):a(b).unblock(d)},d.timeout);a(b).data("blockUI.timeout",J)}}}function c(b,c){var f,g=b==window,h=a(b),i=h.data("blockUI.history"),j=h.data("blockUI.timeout");j&&(clearTimeout(j),h.removeData("blockUI.timeout")),c=a.extend({},a.blockUI.defaults,c||{}),e(0,b,c),null===c.onUnblock&&(c.onUnblock=h.data("blockUI.onUnblock"),h.removeData("blockUI.onUnblock"));var k;k=g?a("body").children().filter(".blockUI").add("body > .blockUI"):h.find(">.blockUI"),c.cursorReset&&(k.length>1&&(k[1].style.cursor=c.cursorReset),k.length>2&&(k[2].style.cursor=c.cursorReset)),g&&(n=o=null),c.fadeOut?(f=k.length,k.stop().fadeOut(c.fadeOut,function(){0===--f&&d(k,i,c,b)})):d(k,i,c,b)}function d(b,c,d,e){var f=a(e);if(!f.data("blockUI.isBlocked")){b.each(function(){this.parentNode&&this.parentNode.removeChild(this)}),c&&c.el&&(c.el.style.display=c.display,c.el.style.position=c.position,c.el.style.cursor="default",c.parent&&c.parent.appendChild(c.el),f.removeData("blockUI.history")),f.data("blockUI.static")&&f.css("position","static"),"function"==typeof d.onUnblock&&d.onUnblock(e,d);var g=a(document.body),h=g.width(),i=g[0].style.width;g.width(h-1).width(h),g[0].style.width=i}}function e(b,c,d){var e=c==window,g=a(c);if((b||(!e||n)&&(e||g.data("blockUI.isBlocked")))&&(g.data("blockUI.isBlocked",b),e&&d.bindEvents&&(!b||d.showOverlay))){var h="mousedown mouseup keydown keypress keyup touchstart touchend touchmove";b?a(document).bind(h,d,f):a(document).unbind(h,f)}}function f(b){if("keydown"===b.type&&b.keyCode&&9==b.keyCode&&n&&b.data.constrainTabKey){var c=o,d=!b.shiftKey&&b.target===c[c.length-1],e=b.shiftKey&&b.target===c[0];if(d||e)return setTimeout(function(){g(e)},10),!1}var f=b.data,h=a(b.target);return h.hasClass("blockOverlay")&&f.onOverlayClick&&f.onOverlayClick(b),h.parents("div."+f.blockMsgClass).length>0?!0:0===h.parents().children().filter("div.blockUI").length}function g(a){if(o){var b=o[a===!0?o.length-1:0];b&&b.focus()}}function h(a,b,c){var d=a.parentNode,e=a.style,f=(d.offsetWidth-a.offsetWidth)/2-i(d,"borderLeftWidth"),g=(d.offsetHeight-a.offsetHeight)/2-i(d,"borderTopWidth");b&&(e.left=f>0?f+"px":"0"),c&&(e.top=g>0?g+"px":"0")}function i(b,c){return parseInt(a.css(b,c),10)||0}a.fn._fadeIn=a.fn.fadeIn;var j=a.noop||function(){},k=/MSIE/.test(navigator.userAgent),l=/MSIE 6.0/.test(navigator.userAgent)&&!/MSIE 8.0/.test(navigator.userAgent),m=(document.documentMode||0,a.isFunction(document.createElement("div").style.setExpression));a.blockUI=function(a){b(window,a)},a.unblockUI=function(a){c(window,a)},a.growlUI=function(b,c,d,e){var f=a('');b&&f.append(""+b+"
"),c&&f.append(""+c+"
"),void 0===d&&(d=3e3);var g=function(b){b=b||{},a.blockUI({message:f,fadeIn:"undefined"!=typeof b.fadeIn?b.fadeIn:700,fadeOut:"undefined"!=typeof b.fadeOut?b.fadeOut:1e3,timeout:"undefined"!=typeof b.timeout?b.timeout:d,centerY:!1,showOverlay:!1,onUnblock:e,css:a.blockUI.defaults.growlCSS})};g();f.css("opacity");f.mouseover(function(){g({fadeIn:0,timeout:3e4});var b=a(".blockMsg");b.stop(),b.fadeTo(300,1)}).mouseout(function(){a(".blockMsg").fadeOut(1e3)})},a.fn.block=function(c){if(this[0]===window)return a.blockUI(c),this;var d=a.extend({},a.blockUI.defaults,c||{});return this.each(function(){var b=a(this);d.ignoreIfBlocked&&b.data("blockUI.isBlocked")||b.unblock({fadeOut:0})}),this.each(function(){"static"==a.css(this,"position")&&(this.style.position="relative",a(this).data("blockUI.static",!0)),this.style.zoom=1,b(this,c)})},a.fn.unblock=function(b){return this[0]===window?(a.unblockUI(b),this):this.each(function(){c(this,b)})},a.blockUI.version=2.7,a.blockUI.defaults={message:"Please wait...
",title:null,draggable:!0,theme:!1,css:{padding:0,margin:0,width:"30%",top:"40%",left:"35%",textAlign:"center",color:"#000",border:"3px solid #aaa",backgroundColor:"#fff",cursor:"wait"},themedCSS:{width:"30%",top:"40%",left:"35%"},overlayCSS:{backgroundColor:"#000",opacity:.6,cursor:"wait"},cursorReset:"default",growlCSS:{width:"350px",top:"10px",left:"",right:"10px",border:"none",padding:"5px",opacity:.6,cursor:"default",color:"#fff",backgroundColor:"#000","-webkit-border-radius":"10px","-moz-border-radius":"10px","border-radius":"10px"},iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank",forceIframe:!1,baseZ:1e3,centerX:!0,centerY:!0,allowBodyStretch:!0,bindEvents:!0,constrainTabKey:!0,fadeIn:200,fadeOut:400,timeout:0,showOverlay:!0,focusInput:!0,focusableElements:":input:enabled:visible",onBlock:null,onUnblock:null,onOverlayClick:null,quirksmodeOffsetHack:4,blockMsgClass:"blockMsg",ignoreIfBlocked:!1};var n=null,o=[]}"function"==typeof define&&define.amd&&define.amd.jQuery?define(["jquery"],a):a(jQuery)}();
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/login-form-integrations.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/login-form-integrations.php
new file mode 100755
index 00000000..931560a9
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/login-form-integrations.php
@@ -0,0 +1,146 @@
+tfa = $tfa;
+
+ $enqueue_upon_actions = array(
+ // This is needed for the login form on the dedicated payment page (e.g. /checkout/order-pay/123456/?pay_for_order=true&key=wc_order_blahblahblah)
+ 'woocommerce_login_form_start',
+ 'woocommerce_before_customer_login_form',
+ // The login form on the checkout doesn't call the woocommerce_before_customer_login_form action
+ 'woocommerce_before_checkout_form',
+ 'affwp_login_fields_before',
+ );
+
+ foreach ($enqueue_upon_actions as $action) {
+ add_action($action, array($this->tfa, 'login_enqueue_scripts'));
+ }
+
+ if (!defined('TWO_FACTOR_DISABLE') || !TWO_FACTOR_DISABLE) {
+ add_action('affwp_process_login_form', array($this, 'affwp_process_login_form'));
+ }
+
+ add_filter('tml_display', array($this, 'tml_display'));
+ add_filter('wppb_login_form_bottom', array($this, 'pb_login_form'));
+
+ // We want to run first if possible, so that we're not aborted by JavaScript exceptions in other components (our code is critical to the login process for TFA users)
+ // Unfortunately, though, people start enqueuing from init onwards (before that is buggy - https://core.trac.wordpress.org/ticket/11526), so, we try to detect the login page and go earlier there.
+ if (isset($GLOBALS['pagenow']) && 'wp-login.php' === $GLOBALS['pagenow']) {
+ add_action('init', array($this->tfa, 'login_enqueue_scripts'), -99999999999);
+ } else {
+ add_action('login_enqueue_scripts', array($this->tfa, 'login_enqueue_scripts'), -99999999999);
+ }
+
+ add_filter('do_shortcode_tag', array($this, 'do_shortcode_tag'), 10, 2);
+
+ add_filter('simba_tfa_login_enqueue_localize', array($this, 'simba_tfa_login_enqueue_localize'), 9);
+
+ }
+
+ /**
+ * Catch TML login widgets (other TML login forms already trigger)
+ *
+ * @param Mixed $whatever
+ *
+ * @return Mixed
+ */
+ public function tml_display($whatever) {
+ $this->tfa->login_enqueue_scripts();
+ return $whatever;
+ }
+
+ /**
+ * Catch Profile Builder login form
+ *
+ * @param Mixed $whatever
+ *
+ * @return Mixed
+ */
+ public function pb_login_form($whatever) {
+ $this->tfa->login_enqueue_scripts();
+ return $whatever;
+ }
+
+ /**
+ * Runs upon the WP filter simba_tfa_login_enqueue_localize.
+ *
+ * @param Array $localize
+ *
+ * @return Array
+ */
+ public function simba_tfa_login_enqueue_localize($localize) {
+ // WP login form is #loginform
+ // Ultimate Membership Pro - April 2018
+ // Theme My Login 6.x - .tml-login form[name="loginform"]
+ // Theme My Login 7.x - .tml-login form[name="login"] (July 2018)
+ // WP Members - March 2018
+ // bbPress - June 2021
+ // WooCommerce - ported over from the separate wooextend.js code, June 2021
+ // Affiliates WP - ported over from the separate wooextend.js code, June 2021
+ $localize['login_form_selectors'] .= '.tml-login form[name="loginform"], .tml-login form[name="login"], #loginform, #wpmem_login form, form#ihc_login_form, .bbp-login-form, .woocommerce form.login, #affwp-login-form, #wppb-loginform';
+ $localize['login_form_off_selectors'] .= '#ihc_login_form';
+ return $localize;
+ }
+
+ /**
+ * Runs upon the WP action affwp_process_login_form
+ */
+ public function affwp_process_login_form() {
+
+ if (!function_exists('affiliate_wp')) return;
+
+ $affiliate_wp = affiliate_wp();
+ $login = $affiliate_wp->login;
+
+ $params = array(
+ // phpcs:ignore WordPress.Security.NonceVerification -- No nonce.
+ 'log' => isset($_POST['affwp_user_login']) ? sanitize_user(wp_unslash($_POST['affwp_user_login'])): '',
+
+ $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '',
+ 'caller'=> isset($_SERVER['PHP_SELF']) ? sanitize_text_field(wp_unslash($_SERVER['PHP_SELF'])) : $request_uri,
+ // phpcs:ignore WordPress.Security.NonceVerification -- No nonce.
+ 'two_factor_code' => isset($_POST['two_factor_code']) ? sanitize_text_field(wp_unslash((string) $_POST['two_factor_code'])) : '',
+ );
+ $code_ok = $this->tfa->authorise_user_from_login($params, true);
+
+ $code_ok = apply_filters('simbatfa_affwp_process_login_form_auth_result', $code_ok, $params);
+
+ if (is_wp_error($code_ok)) {
+ $login->add_error($code_ok->get_error_code(), $code_ok->get_error_message());
+ } elseif (!$code_ok) {
+ $login->add_error('authentication_failed', __('Error:', 'all-in-one-wp-security-and-firewall').' '.apply_filters('simba_tfa_message_code_incorrect', __('The one-time password (TFA code) you entered was incorrect.', 'all-in-one-wp-security-and-firewall')));
+ }
+
+ }
+
+ /**
+ * Ultimate Membership Pro support
+ *
+ * @param String $output
+ * @param String $tag
+ *
+ * @return String
+ */
+ public function do_shortcode_tag($output, $tag) {
+ if ('ihc-login-form' == $tag) $this->tfa->login_enqueue_scripts();
+ return $output;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.css b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.css
new file mode 100755
index 00000000..750b3207
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.css
@@ -0,0 +1,481 @@
+.select2-container {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle; }
+ .select2-container .select2-selection--single {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: 28px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--single .select2-selection__rendered {
+ display: block;
+ padding-left: 8px;
+ padding-right: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-selection--single .select2-selection__clear {
+ position: relative; }
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 8px;
+ padding-left: 20px; }
+ .select2-container .select2-selection--multiple {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ min-height: 32px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
+ display: inline-block;
+ overflow: hidden;
+ padding-left: 8px;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-search--inline {
+ float: left; }
+ .select2-container .select2-search--inline .select2-search__field {
+ box-sizing: border-box;
+ border: none;
+ font-size: 100%;
+ margin-top: 5px;
+ padding: 0; }
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+.select2-dropdown {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ left: -100000px;
+ width: 100%;
+ z-index: 1051; }
+
+.select2-results {
+ display: block; }
+
+.select2-results__options {
+ list-style: none;
+ margin: 0;
+ padding: 0; }
+
+.select2-results__option {
+ padding: 6px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-results__option[aria-selected] {
+ cursor: pointer; }
+
+.select2-container--open .select2-dropdown {
+ left: 0; }
+
+.select2-container--open .select2-dropdown--above {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--open .select2-dropdown--below {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-search--dropdown {
+ display: block;
+ padding: 4px; }
+ .select2-search--dropdown .select2-search__field {
+ padding: 4px;
+ width: 100%;
+ box-sizing: border-box; }
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+ .select2-search--dropdown.select2-search--hide {
+ display: none; }
+
+.select2-close-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ display: block;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 99;
+ background-color: #fff;
+ filter: alpha(opacity=0); }
+
+.select2-hidden-accessible {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(50%) !important;
+ clip-path: inset(50%) !important;
+ height: 1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ width: 1px !important;
+ white-space: nowrap !important; }
+
+.select2-container--default .select2-selection--single {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ border-radius: 4px; }
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--default .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold; }
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto; }
+
+.select2-container--default.select2-container--disabled .select2-selection--single {
+ background-color: #eee;
+ cursor: default; }
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none; }
+
+.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--default .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none; }
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-top: 5px;
+ margin-right: 10px;
+ padding: 1px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #999;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #333; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border: solid black 1px;
+ outline: 0; }
+
+.select2-container--default.select2-container--disabled .select2-selection--multiple {
+ background-color: #eee;
+ cursor: default; }
+
+.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
+ display: none; }
+
+.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--default .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa; }
+
+.select2-container--default .select2-search--inline .select2-search__field {
+ background: transparent;
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield; }
+
+.select2-container--default .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--default .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999; }
+
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd; }
+
+.select2-container--default .select2-results__option .select2-results__option {
+ padding-left: 1em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em; }
+
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #5897fb;
+ color: white; }
+
+.select2-container--default .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic .select2-selection--single {
+ background-color: #f7f7f7;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ outline: 0;
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+ .select2-container--classic .select2-selection--single:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-right: 10px; }
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
+ background-color: #ddd;
+ border: none;
+ border-left: 1px solid #aaa;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ border: none;
+ border-right: 1px solid #aaa;
+ border-radius: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ left: 1px;
+ right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--single {
+ border: 1px solid #5897fb; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
+ background: transparent;
+ border: none; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
+
+.select2-container--classic .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text;
+ outline: 0; }
+ .select2-container--classic .select2-selection--multiple:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
+ list-style: none;
+ margin: 0;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
+ display: none; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
+ color: #888;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #555; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ float: right;
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--multiple {
+ border: 1px solid #5897fb; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--classic .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa;
+ outline: 0; }
+
+.select2-container--classic .select2-search--inline .select2-search__field {
+ outline: 0;
+ box-shadow: none; }
+
+.select2-container--classic .select2-dropdown {
+ background-color: white;
+ border: 1px solid transparent; }
+
+.select2-container--classic .select2-dropdown--above {
+ border-bottom: none; }
+
+.select2-container--classic .select2-dropdown--below {
+ border-top: none; }
+
+.select2-container--classic .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--classic .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--classic .select2-results__option[aria-disabled=true] {
+ color: grey; }
+
+.select2-container--classic .select2-results__option--highlighted[aria-selected] {
+ background-color: #3875d7;
+ color: white; }
+
+.select2-container--classic .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic.select2-container--open .select2-dropdown {
+ border-color: #5897fb; }
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.js b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.js
new file mode 100755
index 00000000..fcfb5ab4
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/select2.js
@@ -0,0 +1,6108 @@
+/*!
+ * Select2 4.0.13
+ * https://select2.github.io
+ *
+ * Released under the MIT license
+ * https://github.com/select2/select2/blob/master/LICENSE.md
+ */
+;(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node/CommonJS
+ module.exports = function (root, jQuery) {
+ if (jQuery === undefined) {
+ // require('jQuery') returns a factory that requires window to
+ // build a jQuery instance, we normalize how we use modules
+ // that require this pattern but the window provided is a noop
+ // if it's defined (how jquery works)
+ if (typeof window !== 'undefined') {
+ jQuery = require('jquery');
+ }
+ else {
+ jQuery = require('jquery')(root);
+ }
+ }
+ factory(jQuery);
+ return jQuery;
+ };
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+} (function (jQuery) {
+ // This is needed so we can catch the AMD loader configuration and use it
+ // The inner file should be wrapped (by `banner.start.js`) in a function that
+ // returns the AMD loader references.
+ var S2 =(function () {
+ // Restore the Select2 AMD loader so it can be used
+ // Needed mostly in the language files, where the loader is not inserted
+ if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
+ var S2 = jQuery.fn.select2.amd;
+ }
+var S2;(function () { if (!S2 || !S2.requirejs) {
+if (!S2) { S2 = {}; } else { require = S2; }
+/**
+ * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
+ * Released under MIT license, http://github.com/requirejs/almond/LICENSE
+ */
+//Going sloppy to avoid 'use strict' string cost, but strict practices should
+//be followed.
+/*global setTimeout: false */
+
+var requirejs, require, define;
+(function (undef) {
+ var main, req, makeMap, handlers,
+ defined = {},
+ waiting = {},
+ config = {},
+ defining = {},
+ hasOwn = Object.prototype.hasOwnProperty,
+ aps = [].slice,
+ jsSuffixRegExp = /\.js$/;
+
+ function hasProp(obj, prop) {
+ return hasOwn.call(obj, prop);
+ }
+
+ /**
+ * Given a relative module name, like ./something, normalize it to
+ * a real name that can be mapped to a path.
+ * @param {String} name the relative name
+ * @param {String} baseName a real name that the name arg is relative
+ * to.
+ * @returns {String} normalized name
+ */
+ function normalize(name, baseName) {
+ var nameParts, nameSegment, mapValue, foundMap, lastIndex,
+ foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
+ baseParts = baseName && baseName.split("/"),
+ map = config.map,
+ starMap = (map && map['*']) || {};
+
+ //Adjust any relative paths.
+ if (name) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
+
+ // If wanting node ID compatibility, strip .js from end
+ // of IDs. Have to do this here, and not in nameToUrl
+ // because node allows either .js or non .js to map
+ // to same file.
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
+
+ // Starts with a '.' so need the baseName
+ if (name[0].charAt(0) === '.' && baseParts) {
+ //Convert baseName to array, and lop off the last part,
+ //so that . matches that 'directory' and not name of the baseName's
+ //module. For instance, baseName of 'one/two/three', maps to
+ //'one/two/three.js', but we want the directory, 'one/two' for
+ //this normalization.
+ normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
+ name = normalizedBaseParts.concat(name);
+ }
+
+ //start trimDots
+ for (i = 0; i < name.length; i++) {
+ part = name[i];
+ if (part === '.') {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === '..') {
+ // If at the start, or previous value is still ..,
+ // keep them so that when converted to a path it may
+ // still work when converted to a path, even though
+ // as an ID it is less than ideal. In larger point
+ // releases, may be better to just kick out an error.
+ if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
+ continue;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
+ }
+ }
+ //end trimDots
+
+ name = name.join('/');
+ }
+
+ //Apply map config if available.
+ if ((baseParts || starMap) && map) {
+ nameParts = name.split('/');
+
+ for (i = nameParts.length; i > 0; i -= 1) {
+ nameSegment = nameParts.slice(0, i).join("/");
+
+ if (baseParts) {
+ //Find the longest baseName segment match in the config.
+ //So, do joins on the biggest to smallest lengths of baseParts.
+ for (j = baseParts.length; j > 0; j -= 1) {
+ mapValue = map[baseParts.slice(0, j).join('/')];
+
+ //baseName segment has config, find if it has one for
+ //this name.
+ if (mapValue) {
+ mapValue = mapValue[nameSegment];
+ if (mapValue) {
+ //Match, update name to the new value.
+ foundMap = mapValue;
+ foundI = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundMap) {
+ break;
+ }
+
+ //Check for a star map match, but just hold on to it,
+ //if there is a shorter segment match later in a matching
+ //config, then favor over this star map.
+ if (!foundStarMap && starMap && starMap[nameSegment]) {
+ foundStarMap = starMap[nameSegment];
+ starI = i;
+ }
+ }
+
+ if (!foundMap && foundStarMap) {
+ foundMap = foundStarMap;
+ foundI = starI;
+ }
+
+ if (foundMap) {
+ nameParts.splice(0, foundI, foundMap);
+ name = nameParts.join('/');
+ }
+ }
+
+ return name;
+ }
+
+ function makeRequire(relName, forceSync) {
+ return function () {
+ //A version of a require function that passes a moduleName
+ //value for items that may need to
+ //look up paths relative to the moduleName
+ var args = aps.call(arguments, 0);
+
+ //If first arg is not require('string'), and there is only
+ //one arg, it is the array form without a callback. Insert
+ //a null so that the following concat is correct.
+ if (typeof args[0] !== 'string' && args.length === 1) {
+ args.push(null);
+ }
+ return req.apply(undef, args.concat([relName, forceSync]));
+ };
+ }
+
+ function makeNormalize(relName) {
+ return function (name) {
+ return normalize(name, relName);
+ };
+ }
+
+ function makeLoad(depName) {
+ return function (value) {
+ defined[depName] = value;
+ };
+ }
+
+ function callDep(name) {
+ if (hasProp(waiting, name)) {
+ var args = waiting[name];
+ delete waiting[name];
+ defining[name] = true;
+ main.apply(undef, args);
+ }
+
+ if (!hasProp(defined, name) && !hasProp(defining, name)) {
+ throw new Error('No ' + name);
+ }
+ return defined[name];
+ }
+
+ //Turns a plugin!resource to [plugin, resource]
+ //with the plugin being undefined if the name
+ //did not have a plugin prefix.
+ function splitPrefix(name) {
+ var prefix,
+ index = name ? name.indexOf('!') : -1;
+ if (index > -1) {
+ prefix = name.substring(0, index);
+ name = name.substring(index + 1, name.length);
+ }
+ return [prefix, name];
+ }
+
+ //Creates a parts array for a relName where first part is plugin ID,
+ //second part is resource ID. Assumes relName has already been normalized.
+ function makeRelParts(relName) {
+ return relName ? splitPrefix(relName) : [];
+ }
+
+ /**
+ * Makes a name map, normalizing the name, and using a plugin
+ * for normalization if necessary. Grabs a ref to plugin
+ * too, as an optimization.
+ */
+ makeMap = function (name, relParts) {
+ var plugin,
+ parts = splitPrefix(name),
+ prefix = parts[0],
+ relResourceName = relParts[1];
+
+ name = parts[1];
+
+ if (prefix) {
+ prefix = normalize(prefix, relResourceName);
+ plugin = callDep(prefix);
+ }
+
+ //Normalize according
+ if (prefix) {
+ if (plugin && plugin.normalize) {
+ name = plugin.normalize(name, makeNormalize(relResourceName));
+ } else {
+ name = normalize(name, relResourceName);
+ }
+ } else {
+ name = normalize(name, relResourceName);
+ parts = splitPrefix(name);
+ prefix = parts[0];
+ name = parts[1];
+ if (prefix) {
+ plugin = callDep(prefix);
+ }
+ }
+
+ //Using ridiculous property names for space reasons
+ return {
+ f: prefix ? prefix + '!' + name : name, //fullName
+ n: name,
+ pr: prefix,
+ p: plugin
+ };
+ };
+
+ function makeConfig(name) {
+ return function () {
+ return (config && config.config && config.config[name]) || {};
+ };
+ }
+
+ handlers = {
+ require: function (name) {
+ return makeRequire(name);
+ },
+ exports: function (name) {
+ var e = defined[name];
+ if (typeof e !== 'undefined') {
+ return e;
+ } else {
+ return (defined[name] = {});
+ }
+ },
+ module: function (name) {
+ return {
+ id: name,
+ uri: '',
+ exports: defined[name],
+ config: makeConfig(name)
+ };
+ }
+ };
+
+ main = function (name, deps, callback, relName) {
+ var cjsModule, depName, ret, map, i, relParts,
+ args = [],
+ callbackType = typeof callback,
+ usingExports;
+
+ //Use name if no relName
+ relName = relName || name;
+ relParts = makeRelParts(relName);
+
+ //Call the callback to define the module, if necessary.
+ if (callbackType === 'undefined' || callbackType === 'function') {
+ //Pull out the defined dependencies and pass the ordered
+ //values to the callback.
+ //Default to [require, exports, module] if no deps
+ deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
+ for (i = 0; i < deps.length; i += 1) {
+ map = makeMap(deps[i], relParts);
+ depName = map.f;
+
+ //Fast path CommonJS standard dependencies.
+ if (depName === "require") {
+ args[i] = handlers.require(name);
+ } else if (depName === "exports") {
+ //CommonJS module spec 1.1
+ args[i] = handlers.exports(name);
+ usingExports = true;
+ } else if (depName === "module") {
+ //CommonJS module spec 1.1
+ cjsModule = args[i] = handlers.module(name);
+ } else if (hasProp(defined, depName) ||
+ hasProp(waiting, depName) ||
+ hasProp(defining, depName)) {
+ args[i] = callDep(depName);
+ } else if (map.p) {
+ map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
+ args[i] = defined[depName];
+ } else {
+ throw new Error(name + ' missing ' + depName);
+ }
+ }
+
+ ret = callback ? callback.apply(defined[name], args) : undefined;
+
+ if (name) {
+ //If setting exports via "module" is in play,
+ //favor that over return value and exports. After that,
+ //favor a non-undefined return value over exports use.
+ if (cjsModule && cjsModule.exports !== undef &&
+ cjsModule.exports !== defined[name]) {
+ defined[name] = cjsModule.exports;
+ } else if (ret !== undef || !usingExports) {
+ //Use the return value from the function.
+ defined[name] = ret;
+ }
+ }
+ } else if (name) {
+ //May just be an object definition for the module. Only
+ //worry about defining if have a module name.
+ defined[name] = callback;
+ }
+ };
+
+ requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
+ if (typeof deps === "string") {
+ if (handlers[deps]) {
+ //callback in this case is really relName
+ return handlers[deps](callback);
+ }
+ //Just return the module wanted. In this scenario, the
+ //deps arg is the module name, and second arg (if passed)
+ //is just the relName.
+ //Normalize module name, if it contains . or ..
+ return callDep(makeMap(deps, makeRelParts(callback)).f);
+ } else if (!deps.splice) {
+ //deps is a config object, not an array.
+ config = deps;
+ if (config.deps) {
+ req(config.deps, config.callback);
+ }
+ if (!callback) {
+ return;
+ }
+
+ if (callback.splice) {
+ //callback is an array, which means it is a dependency list.
+ //Adjust args if there are dependencies
+ deps = callback;
+ callback = relName;
+ relName = null;
+ } else {
+ deps = undef;
+ }
+ }
+
+ //Support require(['a'])
+ callback = callback || function () {};
+
+ //If relName is a function, it is an errback handler,
+ //so remove it.
+ if (typeof relName === 'function') {
+ relName = forceSync;
+ forceSync = alt;
+ }
+
+ //Simulate async callback;
+ if (forceSync) {
+ main(undef, deps, callback, relName);
+ } else {
+ //Using a non-zero value because of concern for what old browsers
+ //do, and latest browsers "upgrade" to 4 if lower value is used:
+ //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
+ //If want a value immediately, use require('id') instead -- something
+ //that works in almond on the global level, but not guaranteed and
+ //unlikely to work in other AMD implementations.
+ setTimeout(function () {
+ main(undef, deps, callback, relName);
+ }, 4);
+ }
+
+ return req;
+ };
+
+ /**
+ * Just drops the config on the floor, but returns req in case
+ * the config return value is used.
+ */
+ req.config = function (cfg) {
+ return req(cfg);
+ };
+
+ /**
+ * Expose module registry for debugging and tooling
+ */
+ requirejs._defined = defined;
+
+ define = function (name, deps, callback) {
+ if (typeof name !== 'string') {
+ throw new Error('See almond README: incorrect module build, no module name');
+ }
+
+ //This module may not have dependencies
+ if (!deps.splice) {
+ //deps is not an array, so probably means
+ //an object literal or factory function for
+ //the value. Adjust args.
+ callback = deps;
+ deps = [];
+ }
+
+ if (!hasProp(defined, name) && !hasProp(waiting, name)) {
+ waiting[name] = [name, deps, callback];
+ }
+ };
+
+ define.amd = {
+ jQuery: true
+ };
+}());
+
+S2.requirejs = requirejs;S2.require = require;S2.define = define;
+}
+}());
+S2.define("almond", function(){});
+
+/* global jQuery:false, $:false */
+S2.define('jquery',[],function () {
+ var _$ = jQuery || $;
+
+ if (_$ == null && console && console.error) {
+ console.error(
+ 'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
+ 'found. Make sure that you are including jQuery before Select2 on your ' +
+ 'web page.'
+ );
+ }
+
+ return _$;
+});
+
+S2.define('select2/utils',[
+ 'jquery'
+], function ($) {
+ var Utils = {};
+
+ Utils.Extend = function (ChildClass, SuperClass) {
+ var __hasProp = {}.hasOwnProperty;
+
+ function BaseConstructor () {
+ this.constructor = ChildClass;
+ }
+
+ for (var key in SuperClass) {
+ if (__hasProp.call(SuperClass, key)) {
+ ChildClass[key] = SuperClass[key];
+ }
+ }
+
+ BaseConstructor.prototype = SuperClass.prototype;
+ ChildClass.prototype = new BaseConstructor();
+ ChildClass.__super__ = SuperClass.prototype;
+
+ return ChildClass;
+ };
+
+ function getMethods (theClass) {
+ var proto = theClass.prototype;
+
+ var methods = [];
+
+ for (var methodName in proto) {
+ var m = proto[methodName];
+
+ if (typeof m !== 'function') {
+ continue;
+ }
+
+ if (methodName === 'constructor') {
+ continue;
+ }
+
+ methods.push(methodName);
+ }
+
+ return methods;
+ }
+
+ Utils.Decorate = function (SuperClass, DecoratorClass) {
+ var decoratedMethods = getMethods(DecoratorClass);
+ var superMethods = getMethods(SuperClass);
+
+ function DecoratedClass () {
+ var unshift = Array.prototype.unshift;
+
+ var argCount = DecoratorClass.prototype.constructor.length;
+
+ var calledConstructor = SuperClass.prototype.constructor;
+
+ if (argCount > 0) {
+ unshift.call(arguments, SuperClass.prototype.constructor);
+
+ calledConstructor = DecoratorClass.prototype.constructor;
+ }
+
+ calledConstructor.apply(this, arguments);
+ }
+
+ DecoratorClass.displayName = SuperClass.displayName;
+
+ function ctr () {
+ this.constructor = DecoratedClass;
+ }
+
+ DecoratedClass.prototype = new ctr();
+
+ for (var m = 0; m < superMethods.length; m++) {
+ var superMethod = superMethods[m];
+
+ DecoratedClass.prototype[superMethod] =
+ SuperClass.prototype[superMethod];
+ }
+
+ var calledMethod = function (methodName) {
+ // Stub out the original method if it's not decorating an actual method
+ var originalMethod = function () {};
+
+ if (methodName in DecoratedClass.prototype) {
+ originalMethod = DecoratedClass.prototype[methodName];
+ }
+
+ var decoratedMethod = DecoratorClass.prototype[methodName];
+
+ return function () {
+ var unshift = Array.prototype.unshift;
+
+ unshift.call(arguments, originalMethod);
+
+ return decoratedMethod.apply(this, arguments);
+ };
+ };
+
+ for (var d = 0; d < decoratedMethods.length; d++) {
+ var decoratedMethod = decoratedMethods[d];
+
+ DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
+ }
+
+ return DecoratedClass;
+ };
+
+ var Observable = function () {
+ this.listeners = {};
+ };
+
+ Observable.prototype.on = function (event, callback) {
+ this.listeners = this.listeners || {};
+
+ if (event in this.listeners) {
+ this.listeners[event].push(callback);
+ } else {
+ this.listeners[event] = [callback];
+ }
+ };
+
+ Observable.prototype.trigger = function (event) {
+ var slice = Array.prototype.slice;
+ var params = slice.call(arguments, 1);
+
+ this.listeners = this.listeners || {};
+
+ // Params should always come in as an array
+ if (params == null) {
+ params = [];
+ }
+
+ // If there are no arguments to the event, use a temporary object
+ if (params.length === 0) {
+ params.push({});
+ }
+
+ // Set the `_type` of the first object to the event
+ params[0]._type = event;
+
+ if (event in this.listeners) {
+ this.invoke(this.listeners[event], slice.call(arguments, 1));
+ }
+
+ if ('*' in this.listeners) {
+ this.invoke(this.listeners['*'], arguments);
+ }
+ };
+
+ Observable.prototype.invoke = function (listeners, params) {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].apply(this, params);
+ }
+ };
+
+ Utils.Observable = Observable;
+
+ Utils.generateChars = function (length) {
+ var chars = '';
+
+ for (var i = 0; i < length; i++) {
+ var randomChar = Math.floor(Math.random() * 36);
+ chars += randomChar.toString(36);
+ }
+
+ return chars;
+ };
+
+ Utils.bind = function (func, context) {
+ return function () {
+ func.apply(context, arguments);
+ };
+ };
+
+ Utils._convertData = function (data) {
+ for (var originalKey in data) {
+ var keys = originalKey.split('-');
+
+ var dataLevel = data;
+
+ if (keys.length === 1) {
+ continue;
+ }
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+
+ // Lowercase the first letter
+ // By default, dash-separated becomes camelCase
+ key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+ if (!(key in dataLevel)) {
+ dataLevel[key] = {};
+ }
+
+ if (k == keys.length - 1) {
+ dataLevel[key] = data[originalKey];
+ }
+
+ dataLevel = dataLevel[key];
+ }
+
+ delete data[originalKey];
+ }
+
+ return data;
+ };
+
+ Utils.hasScroll = function (index, el) {
+ // Adapted from the function created by @ShadowScripter
+ // and adapted by @BillBarry on the Stack Exchange Code Review website.
+ // The original code can be found at
+ // http://codereview.stackexchange.com/q/13338
+ // and was designed to be used with the Sizzle selector engine.
+
+ var $el = $(el);
+ var overflowX = el.style.overflowX;
+ var overflowY = el.style.overflowY;
+
+ //Check both x and y declarations
+ if (overflowX === overflowY &&
+ (overflowY === 'hidden' || overflowY === 'visible')) {
+ return false;
+ }
+
+ if (overflowX === 'scroll' || overflowY === 'scroll') {
+ return true;
+ }
+
+ return ($el.innerHeight() < el.scrollHeight ||
+ $el.innerWidth() < el.scrollWidth);
+ };
+
+ Utils.escapeMarkup = function (markup) {
+ var replaceMap = {
+ '\\': '\',
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ '\'': ''',
+ '/': '/'
+ };
+
+ // Do not try to escape the markup if it's not a string
+ if (typeof markup !== 'string') {
+ return markup;
+ }
+
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
+ return replaceMap[match];
+ });
+ };
+
+ // Append an array of jQuery nodes to a given element.
+ Utils.appendMany = function ($element, $nodes) {
+ // jQuery 1.7.x does not support $.fn.append() with an array
+ // Fall back to a jQuery object collection using $.fn.add()
+ if ($.fn.jquery.substr(0, 3) === '1.7') {
+ var $jqNodes = $();
+
+ $.map($nodes, function (node) {
+ $jqNodes = $jqNodes.add(node);
+ });
+
+ $nodes = $jqNodes;
+ }
+
+ $element.append($nodes);
+ };
+
+ // Cache objects in Utils.__cache instead of $.data (see #4346)
+ Utils.__cache = {};
+
+ var id = 0;
+ Utils.GetUniqueElementId = function (element) {
+ // Get a unique element Id. If element has no id,
+ // creates a new unique number, stores it in the id
+ // attribute and returns the new id.
+ // If an id already exists, it simply returns it.
+
+ var select2Id = element.getAttribute('data-select2-id');
+ if (select2Id == null) {
+ // If element has id, use it.
+ if (element.id) {
+ select2Id = element.id;
+ element.setAttribute('data-select2-id', select2Id);
+ } else {
+ element.setAttribute('data-select2-id', ++id);
+ select2Id = id.toString();
+ }
+ }
+ return select2Id;
+ };
+
+ Utils.StoreData = function (element, name, value) {
+ // Stores an item in the cache for a specified element.
+ // name is the cache key.
+ var id = Utils.GetUniqueElementId(element);
+ if (!Utils.__cache[id]) {
+ Utils.__cache[id] = {};
+ }
+
+ Utils.__cache[id][name] = value;
+ };
+
+ Utils.GetData = function (element, name) {
+ // Retrieves a value from the cache by its key (name)
+ // name is optional. If no name specified, return
+ // all cache items for the specified element.
+ // and for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (name) {
+ if (Utils.__cache[id]) {
+ if (Utils.__cache[id][name] != null) {
+ return Utils.__cache[id][name];
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ } else {
+ return Utils.__cache[id];
+ }
+ };
+
+ Utils.RemoveData = function (element) {
+ // Removes all cached items for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (Utils.__cache[id] != null) {
+ delete Utils.__cache[id];
+ }
+
+ element.removeAttribute('data-select2-id');
+ };
+
+ return Utils;
+});
+
+S2.define('select2/results',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Results ($element, options, dataAdapter) {
+ this.$element = $element;
+ this.data = dataAdapter;
+ this.options = options;
+
+ Results.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Results, Utils.Observable);
+
+ Results.prototype.render = function () {
+ var $results = $(
+ ''
+ );
+
+ if (this.options.get('multiple')) {
+ $results.attr('aria-multiselectable', 'true');
+ }
+
+ this.$results = $results;
+
+ return $results;
+ };
+
+ Results.prototype.clear = function () {
+ this.$results.empty();
+ };
+
+ Results.prototype.displayMessage = function (params) {
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ this.clear();
+ this.hideLoading();
+
+ var $message = $(
+ ''
+ );
+
+ var message = this.options.get('translations').get(params.message);
+
+ $message.append(
+ escapeMarkup(
+ message(params.args)
+ )
+ );
+
+ $message[0].className += ' select2-results__message';
+
+ this.$results.append($message);
+ };
+
+ Results.prototype.hideMessages = function () {
+ this.$results.find('.select2-results__message').remove();
+ };
+
+ Results.prototype.append = function (data) {
+ this.hideLoading();
+
+ var $options = [];
+
+ if (data.results == null || data.results.length === 0) {
+ if (this.$results.children().length === 0) {
+ this.trigger('results:message', {
+ message: 'noResults'
+ });
+ }
+
+ return;
+ }
+
+ data.results = this.sort(data.results);
+
+ for (var d = 0; d < data.results.length; d++) {
+ var item = data.results[d];
+
+ var $option = this.option(item);
+
+ $options.push($option);
+ }
+
+ this.$results.append($options);
+ };
+
+ Results.prototype.position = function ($results, $dropdown) {
+ var $resultsContainer = $dropdown.find('.select2-results');
+ $resultsContainer.append($results);
+ };
+
+ Results.prototype.sort = function (data) {
+ var sorter = this.options.get('sorter');
+
+ return sorter(data);
+ };
+
+ Results.prototype.highlightFirstItem = function () {
+ var $options = this.$results
+ .find('.select2-results__option[aria-selected]');
+
+ var $selected = $options.filter('[aria-selected=true]');
+
+ // Check if there are any selected options
+ if ($selected.length > 0) {
+ // If there are selected options, highlight the first
+ $selected.first().trigger('mouseenter');
+ } else {
+ // If there are no selected options, highlight the first option
+ // in the dropdown
+ $options.first().trigger('mouseenter');
+ }
+
+ this.ensureHighlightVisible();
+ };
+
+ Results.prototype.setClasses = function () {
+ var self = this;
+
+ this.data.current(function (selected) {
+ var selectedIds = $.map(selected, function (s) {
+ return s.id.toString();
+ });
+
+ var $options = self.$results
+ .find('.select2-results__option[aria-selected]');
+
+ $options.each(function () {
+ var $option = $(this);
+
+ var item = Utils.GetData(this, 'data');
+
+ // id needs to be converted to a string when comparing
+ var id = '' + item.id;
+
+ if ((item.element != null && item.element.selected) ||
+ (item.element == null && $.inArray(id, selectedIds) > -1)) {
+ $option.attr('aria-selected', 'true');
+ } else {
+ $option.attr('aria-selected', 'false');
+ }
+ });
+
+ });
+ };
+
+ Results.prototype.showLoading = function (params) {
+ this.hideLoading();
+
+ var loadingMore = this.options.get('translations').get('searching');
+
+ var loading = {
+ disabled: true,
+ loading: true,
+ text: loadingMore(params)
+ };
+ var $loading = this.option(loading);
+ $loading.className += ' loading-results';
+
+ this.$results.prepend($loading);
+ };
+
+ Results.prototype.hideLoading = function () {
+ this.$results.find('.loading-results').remove();
+ };
+
+ Results.prototype.option = function (data) {
+ var option = document.createElement('li');
+ option.className = 'select2-results__option';
+
+ var attrs = {
+ 'role': 'option',
+ 'aria-selected': 'false'
+ };
+
+ var matches = window.Element.prototype.matches ||
+ window.Element.prototype.msMatchesSelector ||
+ window.Element.prototype.webkitMatchesSelector;
+
+ if ((data.element != null && matches.call(data.element, ':disabled')) ||
+ (data.element == null && data.disabled)) {
+ delete attrs['aria-selected'];
+ attrs['aria-disabled'] = 'true';
+ }
+
+ if (data.id == null) {
+ delete attrs['aria-selected'];
+ }
+
+ if (data._resultId != null) {
+ option.id = data._resultId;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ if (data.children) {
+ attrs.role = 'group';
+ attrs['aria-label'] = data.text;
+ delete attrs['aria-selected'];
+ }
+
+ for (var attr in attrs) {
+ var val = attrs[attr];
+
+ option.setAttribute(attr, val);
+ }
+
+ if (data.children) {
+ var $option = $(option);
+
+ var label = document.createElement('strong');
+ label.className = 'select2-results__group';
+
+ var $label = $(label);
+ this.template(data, label);
+
+ var $children = [];
+
+ for (var c = 0; c < data.children.length; c++) {
+ var child = data.children[c];
+
+ var $child = this.option(child);
+
+ $children.push($child);
+ }
+
+ var $childrenContainer = $('', {
+ 'class': 'select2-results__options select2-results__options--nested'
+ });
+
+ $childrenContainer.append($children);
+
+ $option.append(label);
+ $option.append($childrenContainer);
+ } else {
+ this.template(data, option);
+ }
+
+ Utils.StoreData(option, 'data', data);
+
+ return option;
+ };
+
+ Results.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var id = container.id + '-results';
+
+ this.$results.attr('id', id);
+
+ container.on('results:all', function (params) {
+ self.clear();
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('results:append', function (params) {
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ }
+ });
+
+ container.on('query', function (params) {
+ self.hideMessages();
+ self.showLoading(params);
+ });
+
+ container.on('select', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('unselect', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expended="true"
+ self.$results.attr('aria-expanded', 'true');
+ self.$results.attr('aria-hidden', 'false');
+
+ self.setClasses();
+ self.ensureHighlightVisible();
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expended="false"
+ self.$results.attr('aria-expanded', 'false');
+ self.$results.attr('aria-hidden', 'true');
+ self.$results.removeAttr('aria-activedescendant');
+ });
+
+ container.on('results:toggle', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ $highlighted.trigger('mouseup');
+ });
+
+ container.on('results:select', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var data = Utils.GetData($highlighted[0], 'data');
+
+ if ($highlighted.attr('aria-selected') == 'true') {
+ self.trigger('close', {});
+ } else {
+ self.trigger('select', {
+ data: data
+ });
+ }
+ });
+
+ container.on('results:previous', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ // If we are already at the top, don't move further
+ // If no options, currentIndex will be -1
+ if (currentIndex <= 0) {
+ return;
+ }
+
+ var nextIndex = currentIndex - 1;
+
+ // If none are highlighted, highlight the first
+ if ($highlighted.length === 0) {
+ nextIndex = 0;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top;
+ var nextTop = $next.offset().top;
+ var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextTop - currentOffset < 0) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:next', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var nextIndex = currentIndex + 1;
+
+ // If we are at the last option, stay there
+ if (nextIndex >= $options.length) {
+ return;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top +
+ self.$results.outerHeight(false);
+ var nextBottom = $next.offset().top + $next.outerHeight(false);
+ var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextBottom > currentOffset) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ params.element.addClass('select2-results__option--highlighted');
+ });
+
+ container.on('results:message', function (params) {
+ self.displayMessage(params);
+ });
+
+ if ($.fn.mousewheel) {
+ this.$results.on('mousewheel', function (e) {
+ var top = self.$results.scrollTop();
+
+ var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
+
+ var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
+ var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
+
+ if (isAtTop) {
+ self.$results.scrollTop(0);
+
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (isAtBottom) {
+ self.$results.scrollTop(
+ self.$results.get(0).scrollHeight - self.$results.height()
+ );
+
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var $this = $(this);
+
+ var data = Utils.GetData(this, 'data');
+
+ if ($this.attr('aria-selected') === 'true') {
+ if (self.options.get('multiple')) {
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ } else {
+ self.trigger('close', {});
+ }
+
+ return;
+ }
+
+ self.trigger('select', {
+ originalEvent: evt,
+ data: data
+ });
+ });
+
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var data = Utils.GetData(this, 'data');
+
+ self.getHighlightedResults()
+ .removeClass('select2-results__option--highlighted');
+
+ self.trigger('results:focus', {
+ data: data,
+ element: $(this)
+ });
+ });
+ };
+
+ Results.prototype.getHighlightedResults = function () {
+ var $highlighted = this.$results
+ .find('.select2-results__option--highlighted');
+
+ return $highlighted;
+ };
+
+ Results.prototype.destroy = function () {
+ this.$results.remove();
+ };
+
+ Results.prototype.ensureHighlightVisible = function () {
+ var $highlighted = this.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var $options = this.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var currentOffset = this.$results.offset().top;
+ var nextTop = $highlighted.offset().top;
+ var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
+
+ var offsetDelta = nextTop - currentOffset;
+ nextOffset -= $highlighted.outerHeight(false) * 2;
+
+ if (currentIndex <= 2) {
+ this.$results.scrollTop(0);
+ } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
+ this.$results.scrollTop(nextOffset);
+ }
+ };
+
+ Results.prototype.template = function (result, container) {
+ var template = this.options.get('templateResult');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ var content = template(result, container);
+
+ if (content == null) {
+ container.style.display = 'none';
+ } else if (typeof content === 'string') {
+ container.innerHTML = escapeMarkup(content);
+ } else {
+ $(container).append(content);
+ }
+ };
+
+ return Results;
+});
+
+S2.define('select2/keys',[
+
+], function () {
+ var KEYS = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ ESC: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ DELETE: 46
+ };
+
+ return KEYS;
+});
+
+S2.define('select2/selection/base',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function BaseSelection ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ BaseSelection.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseSelection, Utils.Observable);
+
+ BaseSelection.prototype.render = function () {
+ var $selection = $(
+ '' +
+ ''
+ );
+
+ this._tabindex = 0;
+
+ if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
+ this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
+ } else if (this.$element.attr('tabindex') != null) {
+ this._tabindex = this.$element.attr('tabindex');
+ }
+
+ $selection.attr('title', this.$element.attr('title'));
+ $selection.attr('tabindex', this._tabindex);
+ $selection.attr('aria-disabled', 'false');
+
+ this.$selection = $selection;
+
+ return $selection;
+ };
+
+ BaseSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ this.container = container;
+
+ this.$selection.on('focus', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('blur', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ if (evt.which === KEYS.SPACE) {
+ evt.preventDefault();
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ self.$selection.attr('aria-activedescendant', params.data._resultId);
+ });
+
+ container.on('selection:update', function (params) {
+ self.update(params.data);
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expanded="true"
+ self.$selection.attr('aria-expanded', 'true');
+ self.$selection.attr('aria-owns', resultsId);
+
+ self._attachCloseHandler(container);
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expanded="false"
+ self.$selection.attr('aria-expanded', 'false');
+ self.$selection.removeAttr('aria-activedescendant');
+ self.$selection.removeAttr('aria-owns');
+
+ self.$selection.trigger('focus');
+
+ self._detachCloseHandler(container);
+ });
+
+ container.on('enable', function () {
+ self.$selection.attr('tabindex', self._tabindex);
+ self.$selection.attr('aria-disabled', 'false');
+ });
+
+ container.on('disable', function () {
+ self.$selection.attr('tabindex', '-1');
+ self.$selection.attr('aria-disabled', 'true');
+ });
+ };
+
+ BaseSelection.prototype._handleBlur = function (evt) {
+ var self = this;
+
+ // This needs to be delayed as the active element is the body when the tab
+ // key is pressed, possibly along with others.
+ window.setTimeout(function () {
+ // Don't trigger `blur` if the focus is still in the selection
+ if (
+ (document.activeElement == self.$selection[0]) ||
+ ($.contains(self.$selection[0], document.activeElement))
+ ) {
+ return;
+ }
+
+ self.trigger('blur', evt);
+ }, 1);
+ };
+
+ BaseSelection.prototype._attachCloseHandler = function (container) {
+
+ $(document.body).on('mousedown.select2.' + container.id, function (e) {
+ var $target = $(e.target);
+
+ var $select = $target.closest('.select2');
+
+ var $all = $('.select2.select2-container--open');
+
+ $all.each(function () {
+ if (this == $select[0]) {
+ return;
+ }
+
+ var $element = Utils.GetData(this, 'element');
+
+ $element.select2('close');
+ });
+ });
+ };
+
+ BaseSelection.prototype._detachCloseHandler = function (container) {
+ $(document.body).off('mousedown.select2.' + container.id);
+ };
+
+ BaseSelection.prototype.position = function ($selection, $container) {
+ var $selectionContainer = $container.find('.selection');
+ $selectionContainer.append($selection);
+ };
+
+ BaseSelection.prototype.destroy = function () {
+ this._detachCloseHandler(this.container);
+ };
+
+ BaseSelection.prototype.update = function (data) {
+ throw new Error('The `update` method must be defined in child classes.');
+ };
+
+ /**
+ * Helper method to abstract the "enabled" (not "disabled") state of this
+ * object.
+ *
+ * @return {true} if the instance is not disabled.
+ * @return {false} if the instance is disabled.
+ */
+ BaseSelection.prototype.isEnabled = function () {
+ return !this.isDisabled();
+ };
+
+ /**
+ * Helper method to abstract the "disabled" state of this object.
+ *
+ * @return {true} if the disabled option is true.
+ * @return {false} if the disabled option is false.
+ */
+ BaseSelection.prototype.isDisabled = function () {
+ return this.options.get('disabled');
+ };
+
+ return BaseSelection;
+});
+
+S2.define('select2/selection/single',[
+ 'jquery',
+ './base',
+ '../utils',
+ '../keys'
+], function ($, BaseSelection, Utils, KEYS) {
+ function SingleSelection () {
+ SingleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(SingleSelection, BaseSelection);
+
+ SingleSelection.prototype.render = function () {
+ var $selection = SingleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--single');
+
+ $selection.html(
+ '' +
+ '' +
+ '' +
+ ''
+ );
+
+ return $selection;
+ };
+
+ SingleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ SingleSelection.__super__.bind.apply(this, arguments);
+
+ var id = container.id + '-container';
+
+ this.$selection.find('.select2-selection__rendered')
+ .attr('id', id)
+ .attr('role', 'textbox')
+ .attr('aria-readonly', 'true');
+ this.$selection.attr('aria-labelledby', id);
+
+ this.$selection.on('mousedown', function (evt) {
+ // Only respond to left clicks
+ if (evt.which !== 1) {
+ return;
+ }
+
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on('focus', function (evt) {
+ // User focuses on the container
+ });
+
+ this.$selection.on('blur', function (evt) {
+ // User exits the container
+ });
+
+ container.on('focus', function (evt) {
+ if (!container.isOpen()) {
+ self.$selection.trigger('focus');
+ }
+ });
+ };
+
+ SingleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title'); // clear tooltip on empty
+ };
+
+ SingleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ SingleSelection.prototype.selectionContainer = function () {
+ return $('');
+ };
+
+ SingleSelection.prototype.update = function (data) {
+ if (data.length === 0) {
+ this.clear();
+ return;
+ }
+
+ var selection = data[0];
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ var formatted = this.display(selection, $rendered);
+
+ $rendered.empty().append(formatted);
+
+ var title = selection.title || selection.text;
+
+ if (title) {
+ $rendered.attr('title', title);
+ } else {
+ $rendered.removeAttr('title');
+ }
+ };
+
+ return SingleSelection;
+});
+
+S2.define('select2/selection/multiple',[
+ 'jquery',
+ './base',
+ '../utils'
+], function ($, BaseSelection, Utils) {
+ function MultipleSelection ($element, options) {
+ MultipleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(MultipleSelection, BaseSelection);
+
+ MultipleSelection.prototype.render = function () {
+ var $selection = MultipleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--multiple');
+
+ $selection.html(
+ '
'
+ );
+
+ return $selection;
+ };
+
+ MultipleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ MultipleSelection.__super__.bind.apply(this, arguments);
+
+ this.$selection.on('click', function (evt) {
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on(
+ 'click',
+ '.select2-selection__choice__remove',
+ function (evt) {
+ // Ignore the event if it is disabled
+ if (self.isDisabled()) {
+ return;
+ }
+
+ var $remove = $(this);
+ var $selection = $remove.parent();
+
+ var data = Utils.GetData($selection[0], 'data');
+
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ }
+ );
+ };
+
+ MultipleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title');
+ };
+
+ MultipleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ MultipleSelection.prototype.selectionContainer = function () {
+ var $container = $(
+ '
'),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.isDisabled()){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('
" . sprintf(__('Add the following code to the file %s', 'all-in-one-wp-security-and-firewall'), $this->get_file_path()) . "\n" . '' . nl2br(esc_html($this->get_contents())) . '
' . __('Once you have added the above code then press the button to turn on encryption again', 'all-in-one-wp-security-and-firewall'),
+ $info['dirname']
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * This function creates the contents for the mu-plugin
+ *
+ * @return string - the contents of the mu-plugin
+ */
+ public function get_contents() {
+ $encryption_key = base64_encode($this->simba_tfa->random_bytes(16));
+ $code = "0) {
+ styling = 'margin-left: 4px; position: relative; top: 4px; width: 20px; height: 20px; border:0px; box-shadow:none;';
+ }
+ $submit_button.after('');
+ }
+
+ $.ajax({
+ url: simba_tfasettings.ajaxurl,
+ type: 'POST',
+ data: {
+ action: 'simbatfa-init-otp',
+ user: username
+ },
+ dataType: 'text',
+ success: function(resp) {
+ try {
+ var json_begins = resp.search('{"jsonstarter":"justhere"');
+ if (json_begins > -1) {
+ if (json_begins > 0) {
+ console.log("Expected JSON marker found at position: "+json_begins);
+ resp = resp.substring(json_begins);
+ }
+ } else {
+ console.log("Expected JSON marker not found");
+ console.log(resp);
+ }
+
+ response = JSON.parse(resp);
+
+ if (response.hasOwnProperty('php_output')) {
+ console.log("PHP output was returned (follows)");
+ console.log(response.php_output);
+ }
+
+ if (response.hasOwnProperty('extra_output')) {
+ console.log("Extra output was returned (follows)");
+ console.log(response.extra_output);
+ }
+
+ if (only_cache_the_results) {
+ // Save the result for later processing
+ username_requires_otp[username] = response;
+ $('.simbaotp_spinner').remove();
+ } else {
+ process_user_tfa_enabled_check_results($(form), response);
+ }
+
+ } catch(err) {
+ $('#login').html(resp);
+ console.log("Simba TFA: Error when processing response");
+ console.log(err);
+ console.log(resp);
+ }
+ },
+ error: function(jq_xhr, text_status, error_thrown) {
+ console.log("Simba TFA: AJAX error: "+error_thrown+": "+text_status);
+ console.log(jq_xhr);
+ if (jq_xhr.hasOwnProperty('responseText')) {
+ console.log(jq_xhr.responseText);
+ $(form).append('
'+simba_tfasettings.is_trusted+'';
+
+ } else {
+
+ if (form_is_ultimate_member) { html += '
mother->paint_enable_tfa_radios($current_user->ID, true, $style); ?>
+ +
+http://www.ietf.org/rfc/rfc4226.txt
+http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
+
+TEST VECTOR VERIFICATION
+
+HOTP Tests:
+
+DOCBLOCK;
+
+echo "Count Method Value Pass/Fail\n";
+echo "----------------------------------------------------------------------\n";
+
+// loop over all HOTP table results, and calculate the matching value
+foreach ($table['HOTP'] as $seed => $results) {
+ $hotp = HOTP::generateByCounter($key, $seed);
+ $first = true;
+ foreach ($results as $type => $calc) {
+ if ($first) {
+ echo str_pad($seed, 4, ' ', STR_PAD_LEFT);
+ $first = false;
+ }
+ else {
+ echo ' ';
+ }
+ echo ' ';
+ echo str_pad($type, 5, ' ', STR_PAD_RIGHT);
+ echo ' ';
+ echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
+ echo ' ';
+ $method = 'to'.(ucfirst(str_replace('HMAC', 'string', $type)));
+ echo str_pad(($calc == $hotp->$method(6)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
+ echo "\n";
+ }
+}
+
+echo << $results) {
+ $totp = HOTP::generateByTime($key, 30, $seed);
+ $first = true;
+ foreach ($results as $type => $calc) {
+ if ($first) {
+ echo str_pad($seed, 10, ' ', STR_PAD_LEFT);
+ $first = false;
+ }
+ else {
+ echo ' ';
+ }
+ echo ' ';
+ echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
+ echo ' ';
+ $method = 'to'.(ucfirst(str_replace('totp', 'hotp', $type)));
+ echo str_pad(($calc == $totp->$method(8)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
+ echo "\n";
+ }
+}
+
+echo ' ';
+
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/hotp-php-master/hotp.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/hotp-php-master/hotp.php
new file mode 100755
index 00000000..090e7599
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/hotp-php-master/hotp.php
@@ -0,0 +1,174 @@
+= 0; $i--) {
+ $cur_counter[$i] = pack ('C*', $counter);
+ $counter = $counter >> 8;
+ }
+
+ $bin_counter = implode($cur_counter);
+
+ // Pad to 8 chars
+ if (strlen($bin_counter) < 8) {
+ $bin_counter = str_repeat (chr(0), 8 - strlen ($bin_counter)) . $bin_counter;
+ }
+
+ // HMAC
+ $hash = hash_hmac('sha1', $bin_counter, $key);
+
+ return new HOTPResult($hash);
+ }
+
+ /**
+ * Generate a HOTP key based on a timestamp and window size
+ * @param string $key the key to use for hashing
+ * @param int $window the size of the window a key is valid for in seconds
+ * @param int $timestamp a timestamp to calculate for, defaults to time()
+ * @return HOTPResult a HOTP Result which can be truncated or output
+ */
+ public static function generateByTime($key, $window, $timestamp = false) {
+ if (!$timestamp && $timestamp !== 0) {
+ $timestamp = HOTP::getTime();
+ }
+
+ $counter = intval($timestamp / $window);
+
+ return HOTP::generateByCounter($key, $counter);
+ }
+
+ /**
+ * Generate a HOTP key collection based on a timestamp and window size
+ * all keys that could exist between a start and end time will be included
+ * in the returned array
+ * @param string $key the key to use for hashing
+ * @param int $window the size of the window a key is valid for in seconds
+ * @param int $min the minimum window to accept before $timestamp
+ * @param int $max the maximum window to accept after $timestamp
+ * @param int $timestamp a timestamp to calculate for, defaults to time()
+ * @return array of HOTPResult
+ */
+ public static function generateByTimeWindow($key, $window, $min = -1, $max = 1, $timestamp = false) {
+ if (!$timestamp && $timestamp !== 0) {
+ $timestamp = HOTP::getTime();
+ }
+
+ $counter = intval($timestamp / $window);
+ $window = range($min, $max);
+
+ $out = array();
+ for ($i = 0; $i < count($window); $i++) {
+ $shift_counter = $window[$i];
+ $out[$shift_counter] = HOTP::generateByCounter($key, $counter + $shift_counter);
+ }
+
+ return $out;
+ }
+
+ /**
+ * Gets the current time
+ * Ensures we are operating in UTC for the entire framework
+ * Restores the timezone on exit.
+ * @return int the current time
+ */
+ public static function getTime() {
+ return time(); // PHP's time is always UTC
+ }
+}
+
+/**
+ * The HOTPResult Class converts an HOTP item to various forms
+ * Supported formats include hex, decimal, string, and HOTP
+ * @author Jakob Heuser (firstname)@felocity.com
+ */
+class HOTPResult {
+ protected $hash;
+ protected $binary;
+ protected $decimal;
+
+ /**
+ * Build an HOTP Result
+ * @param string $value the value to construct with
+ */
+ public function __construct($value) {
+ // store raw
+ $this->hash = $value;
+ }
+
+ /**
+ * Returns the string version of the HOTP
+ * @return string
+ */
+ public function toString() {
+ return $this->hash;
+ }
+
+ /**
+ * Returns the hex version of the HOTP
+ * @return string
+ */
+ public function toHex() {
+ if( !$this->hex )
+ {
+ $this->hex = dechex($this->toDec());
+ }
+ return $this->hex;
+ }
+
+ /**
+ * Returns the decimal version of the HOTP
+ * @return int
+ */
+ public function toDec() {
+ if( !$this->decimal )
+ {
+ // store calculate decimal
+ $hmac_result = array();
+
+ // Convert to decimal
+ foreach(str_split($this->hash,2) as $hex)
+ {
+ $hmac_result[] = hexdec($hex);
+ }
+
+ $offset = $hmac_result[19] & 0xf;
+
+ $this->decimal = (
+ (($hmac_result[$offset+0] & 0x7f) << 24 ) |
+ (($hmac_result[$offset+1] & 0xff) << 16 ) |
+ (($hmac_result[$offset+2] & 0xff) << 8 ) |
+ ($hmac_result[$offset+3] & 0xff)
+ );
+ }
+ return $this->decimal;
+ }
+
+ /**
+ * Returns the truncated decimal form of the HOTP
+ * @param int $length the length of the HOTP to return
+ * @return string
+ */
+ public function toHOTP($length) {
+ $str = str_pad($this->toDec(), $length, "0", STR_PAD_LEFT);
+ $str = substr($str, (-1 * $length));
+ return $str;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/loader.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/loader.php
new file mode 100755
index 00000000..b322ec6f
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/providers/totp/loader.php
@@ -0,0 +1,1034 @@
+tfa = $tfa;
+
+ $this->otp_helper = new HOTP();
+
+ add_action('plugins_loaded', array($this, 'plugins_loaded'));
+
+ add_action('admin_init', array($this, 'admin_init'));
+
+ if (!is_admin()) {
+ add_action('init', array($this, 'check_possible_reset'));
+ }
+
+ // Potentially show off-sync message for hotp
+ add_action('admin_notices', array($this, 'tfa_show_hotp_off_sync_message'));
+ }
+
+ /**
+ * Return whether or not this class detected and saved new settings
+ *
+ * @return Boolean
+ */
+ public function were_settings_saved() {
+ return $this->settings_saved;
+ }
+
+ /**
+ * Runs upon the WP action admin_init
+ */
+ public function admin_init() {
+
+ $this->check_possible_reset();
+
+ global $current_user;
+
+ if (!empty($_REQUEST['_tfa_activate_nonce']) && !empty($_POST['tfa_enable_tfa']) && wp_verify_nonce($_REQUEST['_tfa_activate_nonce'], 'tfa_activate') && !empty($_GET['settings-updated'])) {
+ $this->tfa->change_tfa_enabled_status($current_user->ID, $_POST['tfa_enable_tfa']);
+ $this->settings_saved = true;
+ }
+
+ if (!empty($_REQUEST['_tfa_algorithm_nonce']) && !empty($_POST['tfa_algorithm_type']) && !empty($_GET['settings-updated']) && wp_verify_nonce($_REQUEST['_tfa_algorithm_nonce'], 'tfa_algorithm')) {
+
+ $old_algorithm = $this->get_user_otp_algorithm($current_user->ID);
+
+ if ($old_algorithm != $_POST['tfa_algorithm_type']) {
+ $this->changeUserAlgorithmTo($current_user->ID, $_POST['tfa_algorithm_type']);
+ }
+
+ $this->settings_saved = true;
+ }
+
+ if (!empty($_GET['warning_button_clicked']) && !empty($_REQUEST['resyncnonce']) && wp_verify_nonce($_REQUEST['resyncnonce'], 'tfaresync')) {
+ delete_user_meta($current_user->ID, 'tfa_hotp_off_sync');
+ }
+
+ }
+
+ /**
+ * Enqueue adding of JavaScript for footer
+ */
+ public function add_footer() {
+
+ static $added_footer = false;
+ if ($added_footer) return;
+ $added_footer = true;
+
+ $qr_script_file = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? 'jquery-qrcode.js' : 'jquery-qrcode.min.js';
+
+ $qr_script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : filemtime($this->tfa->includes_dir()."/jquery-qrcode/$qr_script_file");
+
+ wp_register_script('jquery-qrcode', $this->tfa->includes_url()."/jquery-qrcode/$qr_script_file", array('jquery'), $qr_script_ver);
+
+ $script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : filemtime($this->tfa->includes_dir()."/totp.js");
+
+ // Adds the necessary JavaScript for rendering and updating QR codes, and handling trusted devices removal in the admin area
+ wp_enqueue_script('simba-tfa-totp', $this->tfa->includes_url()."/totp.js", array('jquery-qrcode'), $script_ver);
+
+ wp_localize_script('simba-tfa-totp', 'simbatfa_totp', $this->translation_strings());
+
+ }
+
+ /**
+ * Get textual strings used from JavaScript
+ *
+ * @return Array
+ */
+ private function translation_strings() {
+
+ // It's possible that FORCE_ADMIN_SSL will make that SSL, whilst the user is on the front-end having logged in over non-SSL - and as a result, their login cookies won't get sent, and they're not registered as logged in.
+ $ajax_url = admin_url('admin-ajax.php');
+ $also_try = '';
+ if (!is_admin() && substr(strtolower($ajax_url), 0, 6) == 'https:' && !is_ssl()) {
+ $also_try = 'http:'.substr($ajax_url, 6);
+ }
+
+ return apply_filters('simba_tfa_totp_translation_strings', array(
+ 'ajax_url' => $ajax_url,
+ 'updating' => __('Updating...', 'all-in-one-wp-security-and-firewall'),
+ 'tfa_shared_nonce' => wp_create_nonce('tfa_shared_nonce'),
+ 'also_try' => $also_try,
+ 'response' => __('Response:', 'all-in-one-wp-security-and-firewall'),
+ ));
+ }
+
+ /**
+ * Return a link to refresh the current OTP code
+ *
+ * @return String
+ */
+ public function refresh_current_otp_link() {
+ return ''.__('(update)', 'all-in-one-wp-security-and-firewall').'';
+ }
+
+ /**
+ * Echo the radio buttons for changing between TOTP/HOTP
+ *
+ * TODO: Hide this choice on new installs (TOTP only)
+ *
+ * @param Integer $user_id
+ */
+ protected function print_algorithm_choice_radios($user_id) {
+ if (!$user_id) return;
+
+ $types = array(
+ 'totp' => __('TOTP (time based - most common algorithm; used by Google Authenticator)', 'all-in-one-wp-security-and-firewall'),
+ 'hotp' => __('HOTP (event based)', 'all-in-one-wp-security-and-firewall')
+ );
+
+ $setting = $this->get_user_otp_algorithm($user_id);
+
+ foreach ($types as $id => $name) {
+ print ' + + +
+ + ++ +
++ +
+ ++ + +
+ + ++ +
++ + +
++ + +
+ ++ +
++ +
+