\";}s:12:\"_multiwidget\";i:1;}','auto'),(106,'sidebars_widgets','a:2:{s:19:\"wp_inactive_widgets\";a:5:{i:0;s:7:\"block-2\";i:1;s:7:\"block-3\";i:2;s:7:\"block-4\";i:3;s:7:\"block-5\";i:4;s:7:\"block-6\";}s:13:\"array_version\";i:3;}','auto'),(107,'widget_pages','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(108,'widget_calendar','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(109,'widget_archives','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(110,'widget_media_audio','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(111,'widget_media_image','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(112,'widget_media_gallery','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(113,'widget_media_video','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(114,'widget_meta','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(115,'widget_search','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(116,'widget_recent-posts','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(117,'widget_recent-comments','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(118,'widget_tag_cloud','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(119,'widget_nav_menu','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(120,'widget_custom_html','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(121,'_transient_wp_core_block_css_files','a:2:{s:7:\"version\";s:5:\"6.8.3\";s:5:\"files\";a:536:{i:0;s:23:\"archives/editor-rtl.css\";i:1;s:27:\"archives/editor-rtl.min.css\";i:2;s:19:\"archives/editor.css\";i:3;s:23:\"archives/editor.min.css\";i:4;s:22:\"archives/style-rtl.css\";i:5;s:26:\"archives/style-rtl.min.css\";i:6;s:18:\"archives/style.css\";i:7;s:22:\"archives/style.min.css\";i:8;s:20:\"audio/editor-rtl.css\";i:9;s:24:\"audio/editor-rtl.min.css\";i:10;s:16:\"audio/editor.css\";i:11;s:20:\"audio/editor.min.css\";i:12;s:19:\"audio/style-rtl.css\";i:13;s:23:\"audio/style-rtl.min.css\";i:14;s:15:\"audio/style.css\";i:15;s:19:\"audio/style.min.css\";i:16;s:19:\"audio/theme-rtl.css\";i:17;s:23:\"audio/theme-rtl.min.css\";i:18;s:15:\"audio/theme.css\";i:19;s:19:\"audio/theme.min.css\";i:20;s:21:\"avatar/editor-rtl.css\";i:21;s:25:\"avatar/editor-rtl.min.css\";i:22;s:17:\"avatar/editor.css\";i:23;s:21:\"avatar/editor.min.css\";i:24;s:20:\"avatar/style-rtl.css\";i:25;s:24:\"avatar/style-rtl.min.css\";i:26;s:16:\"avatar/style.css\";i:27;s:20:\"avatar/style.min.css\";i:28;s:21:\"button/editor-rtl.css\";i:29;s:25:\"button/editor-rtl.min.css\";i:30;s:17:\"button/editor.css\";i:31;s:21:\"button/editor.min.css\";i:32;s:20:\"button/style-rtl.css\";i:33;s:24:\"button/style-rtl.min.css\";i:34;s:16:\"button/style.css\";i:35;s:20:\"button/style.min.css\";i:36;s:22:\"buttons/editor-rtl.css\";i:37;s:26:\"buttons/editor-rtl.min.css\";i:38;s:18:\"buttons/editor.css\";i:39;s:22:\"buttons/editor.min.css\";i:40;s:21:\"buttons/style-rtl.css\";i:41;s:25:\"buttons/style-rtl.min.css\";i:42;s:17:\"buttons/style.css\";i:43;s:21:\"buttons/style.min.css\";i:44;s:22:\"calendar/style-rtl.css\";i:45;s:26:\"calendar/style-rtl.min.css\";i:46;s:18:\"calendar/style.css\";i:47;s:22:\"calendar/style.min.css\";i:48;s:25:\"categories/editor-rtl.css\";i:49;s:29:\"categories/editor-rtl.min.css\";i:50;s:21:\"categories/editor.css\";i:51;s:25:\"categories/editor.min.css\";i:52;s:24:\"categories/style-rtl.css\";i:53;s:28:\"categories/style-rtl.min.css\";i:54;s:20:\"categories/style.css\";i:55;s:24:\"categories/style.min.css\";i:56;s:19:\"code/editor-rtl.css\";i:57;s:23:\"code/editor-rtl.min.css\";i:58;s:15:\"code/editor.css\";i:59;s:19:\"code/editor.min.css\";i:60;s:18:\"code/style-rtl.css\";i:61;s:22:\"code/style-rtl.min.css\";i:62;s:14:\"code/style.css\";i:63;s:18:\"code/style.min.css\";i:64;s:18:\"code/theme-rtl.css\";i:65;s:22:\"code/theme-rtl.min.css\";i:66;s:14:\"code/theme.css\";i:67;s:18:\"code/theme.min.css\";i:68;s:22:\"columns/editor-rtl.css\";i:69;s:26:\"columns/editor-rtl.min.css\";i:70;s:18:\"columns/editor.css\";i:71;s:22:\"columns/editor.min.css\";i:72;s:21:\"columns/style-rtl.css\";i:73;s:25:\"columns/style-rtl.min.css\";i:74;s:17:\"columns/style.css\";i:75;s:21:\"columns/style.min.css\";i:76;s:33:\"comment-author-name/style-rtl.css\";i:77;s:37:\"comment-author-name/style-rtl.min.css\";i:78;s:29:\"comment-author-name/style.css\";i:79;s:33:\"comment-author-name/style.min.css\";i:80;s:29:\"comment-content/style-rtl.css\";i:81;s:33:\"comment-content/style-rtl.min.css\";i:82;s:25:\"comment-content/style.css\";i:83;s:29:\"comment-content/style.min.css\";i:84;s:26:\"comment-date/style-rtl.css\";i:85;s:30:\"comment-date/style-rtl.min.css\";i:86;s:22:\"comment-date/style.css\";i:87;s:26:\"comment-date/style.min.css\";i:88;s:31:\"comment-edit-link/style-rtl.css\";i:89;s:35:\"comment-edit-link/style-rtl.min.css\";i:90;s:27:\"comment-edit-link/style.css\";i:91;s:31:\"comment-edit-link/style.min.css\";i:92;s:32:\"comment-reply-link/style-rtl.css\";i:93;s:36:\"comment-reply-link/style-rtl.min.css\";i:94;s:28:\"comment-reply-link/style.css\";i:95;s:32:\"comment-reply-link/style.min.css\";i:96;s:30:\"comment-template/style-rtl.css\";i:97;s:34:\"comment-template/style-rtl.min.css\";i:98;s:26:\"comment-template/style.css\";i:99;s:30:\"comment-template/style.min.css\";i:100;s:42:\"comments-pagination-numbers/editor-rtl.css\";i:101;s:46:\"comments-pagination-numbers/editor-rtl.min.css\";i:102;s:38:\"comments-pagination-numbers/editor.css\";i:103;s:42:\"comments-pagination-numbers/editor.min.css\";i:104;s:34:\"comments-pagination/editor-rtl.css\";i:105;s:38:\"comments-pagination/editor-rtl.min.css\";i:106;s:30:\"comments-pagination/editor.css\";i:107;s:34:\"comments-pagination/editor.min.css\";i:108;s:33:\"comments-pagination/style-rtl.css\";i:109;s:37:\"comments-pagination/style-rtl.min.css\";i:110;s:29:\"comments-pagination/style.css\";i:111;s:33:\"comments-pagination/style.min.css\";i:112;s:29:\"comments-title/editor-rtl.css\";i:113;s:33:\"comments-title/editor-rtl.min.css\";i:114;s:25:\"comments-title/editor.css\";i:115;s:29:\"comments-title/editor.min.css\";i:116;s:23:\"comments/editor-rtl.css\";i:117;s:27:\"comments/editor-rtl.min.css\";i:118;s:19:\"comments/editor.css\";i:119;s:23:\"comments/editor.min.css\";i:120;s:22:\"comments/style-rtl.css\";i:121;s:26:\"comments/style-rtl.min.css\";i:122;s:18:\"comments/style.css\";i:123;s:22:\"comments/style.min.css\";i:124;s:20:\"cover/editor-rtl.css\";i:125;s:24:\"cover/editor-rtl.min.css\";i:126;s:16:\"cover/editor.css\";i:127;s:20:\"cover/editor.min.css\";i:128;s:19:\"cover/style-rtl.css\";i:129;s:23:\"cover/style-rtl.min.css\";i:130;s:15:\"cover/style.css\";i:131;s:19:\"cover/style.min.css\";i:132;s:22:\"details/editor-rtl.css\";i:133;s:26:\"details/editor-rtl.min.css\";i:134;s:18:\"details/editor.css\";i:135;s:22:\"details/editor.min.css\";i:136;s:21:\"details/style-rtl.css\";i:137;s:25:\"details/style-rtl.min.css\";i:138;s:17:\"details/style.css\";i:139;s:21:\"details/style.min.css\";i:140;s:20:\"embed/editor-rtl.css\";i:141;s:24:\"embed/editor-rtl.min.css\";i:142;s:16:\"embed/editor.css\";i:143;s:20:\"embed/editor.min.css\";i:144;s:19:\"embed/style-rtl.css\";i:145;s:23:\"embed/style-rtl.min.css\";i:146;s:15:\"embed/style.css\";i:147;s:19:\"embed/style.min.css\";i:148;s:19:\"embed/theme-rtl.css\";i:149;s:23:\"embed/theme-rtl.min.css\";i:150;s:15:\"embed/theme.css\";i:151;s:19:\"embed/theme.min.css\";i:152;s:19:\"file/editor-rtl.css\";i:153;s:23:\"file/editor-rtl.min.css\";i:154;s:15:\"file/editor.css\";i:155;s:19:\"file/editor.min.css\";i:156;s:18:\"file/style-rtl.css\";i:157;s:22:\"file/style-rtl.min.css\";i:158;s:14:\"file/style.css\";i:159;s:18:\"file/style.min.css\";i:160;s:23:\"footnotes/style-rtl.css\";i:161;s:27:\"footnotes/style-rtl.min.css\";i:162;s:19:\"footnotes/style.css\";i:163;s:23:\"footnotes/style.min.css\";i:164;s:23:\"freeform/editor-rtl.css\";i:165;s:27:\"freeform/editor-rtl.min.css\";i:166;s:19:\"freeform/editor.css\";i:167;s:23:\"freeform/editor.min.css\";i:168;s:22:\"gallery/editor-rtl.css\";i:169;s:26:\"gallery/editor-rtl.min.css\";i:170;s:18:\"gallery/editor.css\";i:171;s:22:\"gallery/editor.min.css\";i:172;s:21:\"gallery/style-rtl.css\";i:173;s:25:\"gallery/style-rtl.min.css\";i:174;s:17:\"gallery/style.css\";i:175;s:21:\"gallery/style.min.css\";i:176;s:21:\"gallery/theme-rtl.css\";i:177;s:25:\"gallery/theme-rtl.min.css\";i:178;s:17:\"gallery/theme.css\";i:179;s:21:\"gallery/theme.min.css\";i:180;s:20:\"group/editor-rtl.css\";i:181;s:24:\"group/editor-rtl.min.css\";i:182;s:16:\"group/editor.css\";i:183;s:20:\"group/editor.min.css\";i:184;s:19:\"group/style-rtl.css\";i:185;s:23:\"group/style-rtl.min.css\";i:186;s:15:\"group/style.css\";i:187;s:19:\"group/style.min.css\";i:188;s:19:\"group/theme-rtl.css\";i:189;s:23:\"group/theme-rtl.min.css\";i:190;s:15:\"group/theme.css\";i:191;s:19:\"group/theme.min.css\";i:192;s:21:\"heading/style-rtl.css\";i:193;s:25:\"heading/style-rtl.min.css\";i:194;s:17:\"heading/style.css\";i:195;s:21:\"heading/style.min.css\";i:196;s:19:\"html/editor-rtl.css\";i:197;s:23:\"html/editor-rtl.min.css\";i:198;s:15:\"html/editor.css\";i:199;s:19:\"html/editor.min.css\";i:200;s:20:\"image/editor-rtl.css\";i:201;s:24:\"image/editor-rtl.min.css\";i:202;s:16:\"image/editor.css\";i:203;s:20:\"image/editor.min.css\";i:204;s:19:\"image/style-rtl.css\";i:205;s:23:\"image/style-rtl.min.css\";i:206;s:15:\"image/style.css\";i:207;s:19:\"image/style.min.css\";i:208;s:19:\"image/theme-rtl.css\";i:209;s:23:\"image/theme-rtl.min.css\";i:210;s:15:\"image/theme.css\";i:211;s:19:\"image/theme.min.css\";i:212;s:29:\"latest-comments/style-rtl.css\";i:213;s:33:\"latest-comments/style-rtl.min.css\";i:214;s:25:\"latest-comments/style.css\";i:215;s:29:\"latest-comments/style.min.css\";i:216;s:27:\"latest-posts/editor-rtl.css\";i:217;s:31:\"latest-posts/editor-rtl.min.css\";i:218;s:23:\"latest-posts/editor.css\";i:219;s:27:\"latest-posts/editor.min.css\";i:220;s:26:\"latest-posts/style-rtl.css\";i:221;s:30:\"latest-posts/style-rtl.min.css\";i:222;s:22:\"latest-posts/style.css\";i:223;s:26:\"latest-posts/style.min.css\";i:224;s:18:\"list/style-rtl.css\";i:225;s:22:\"list/style-rtl.min.css\";i:226;s:14:\"list/style.css\";i:227;s:18:\"list/style.min.css\";i:228;s:22:\"loginout/style-rtl.css\";i:229;s:26:\"loginout/style-rtl.min.css\";i:230;s:18:\"loginout/style.css\";i:231;s:22:\"loginout/style.min.css\";i:232;s:25:\"media-text/editor-rtl.css\";i:233;s:29:\"media-text/editor-rtl.min.css\";i:234;s:21:\"media-text/editor.css\";i:235;s:25:\"media-text/editor.min.css\";i:236;s:24:\"media-text/style-rtl.css\";i:237;s:28:\"media-text/style-rtl.min.css\";i:238;s:20:\"media-text/style.css\";i:239;s:24:\"media-text/style.min.css\";i:240;s:19:\"more/editor-rtl.css\";i:241;s:23:\"more/editor-rtl.min.css\";i:242;s:15:\"more/editor.css\";i:243;s:19:\"more/editor.min.css\";i:244;s:30:\"navigation-link/editor-rtl.css\";i:245;s:34:\"navigation-link/editor-rtl.min.css\";i:246;s:26:\"navigation-link/editor.css\";i:247;s:30:\"navigation-link/editor.min.css\";i:248;s:29:\"navigation-link/style-rtl.css\";i:249;s:33:\"navigation-link/style-rtl.min.css\";i:250;s:25:\"navigation-link/style.css\";i:251;s:29:\"navigation-link/style.min.css\";i:252;s:33:\"navigation-submenu/editor-rtl.css\";i:253;s:37:\"navigation-submenu/editor-rtl.min.css\";i:254;s:29:\"navigation-submenu/editor.css\";i:255;s:33:\"navigation-submenu/editor.min.css\";i:256;s:25:\"navigation/editor-rtl.css\";i:257;s:29:\"navigation/editor-rtl.min.css\";i:258;s:21:\"navigation/editor.css\";i:259;s:25:\"navigation/editor.min.css\";i:260;s:24:\"navigation/style-rtl.css\";i:261;s:28:\"navigation/style-rtl.min.css\";i:262;s:20:\"navigation/style.css\";i:263;s:24:\"navigation/style.min.css\";i:264;s:23:\"nextpage/editor-rtl.css\";i:265;s:27:\"nextpage/editor-rtl.min.css\";i:266;s:19:\"nextpage/editor.css\";i:267;s:23:\"nextpage/editor.min.css\";i:268;s:24:\"page-list/editor-rtl.css\";i:269;s:28:\"page-list/editor-rtl.min.css\";i:270;s:20:\"page-list/editor.css\";i:271;s:24:\"page-list/editor.min.css\";i:272;s:23:\"page-list/style-rtl.css\";i:273;s:27:\"page-list/style-rtl.min.css\";i:274;s:19:\"page-list/style.css\";i:275;s:23:\"page-list/style.min.css\";i:276;s:24:\"paragraph/editor-rtl.css\";i:277;s:28:\"paragraph/editor-rtl.min.css\";i:278;s:20:\"paragraph/editor.css\";i:279;s:24:\"paragraph/editor.min.css\";i:280;s:23:\"paragraph/style-rtl.css\";i:281;s:27:\"paragraph/style-rtl.min.css\";i:282;s:19:\"paragraph/style.css\";i:283;s:23:\"paragraph/style.min.css\";i:284;s:35:\"post-author-biography/style-rtl.css\";i:285;s:39:\"post-author-biography/style-rtl.min.css\";i:286;s:31:\"post-author-biography/style.css\";i:287;s:35:\"post-author-biography/style.min.css\";i:288;s:30:\"post-author-name/style-rtl.css\";i:289;s:34:\"post-author-name/style-rtl.min.css\";i:290;s:26:\"post-author-name/style.css\";i:291;s:30:\"post-author-name/style.min.css\";i:292;s:26:\"post-author/editor-rtl.css\";i:293;s:30:\"post-author/editor-rtl.min.css\";i:294;s:22:\"post-author/editor.css\";i:295;s:26:\"post-author/editor.min.css\";i:296;s:25:\"post-author/style-rtl.css\";i:297;s:29:\"post-author/style-rtl.min.css\";i:298;s:21:\"post-author/style.css\";i:299;s:25:\"post-author/style.min.css\";i:300;s:33:\"post-comments-form/editor-rtl.css\";i:301;s:37:\"post-comments-form/editor-rtl.min.css\";i:302;s:29:\"post-comments-form/editor.css\";i:303;s:33:\"post-comments-form/editor.min.css\";i:304;s:32:\"post-comments-form/style-rtl.css\";i:305;s:36:\"post-comments-form/style-rtl.min.css\";i:306;s:28:\"post-comments-form/style.css\";i:307;s:32:\"post-comments-form/style.min.css\";i:308;s:26:\"post-content/style-rtl.css\";i:309;s:30:\"post-content/style-rtl.min.css\";i:310;s:22:\"post-content/style.css\";i:311;s:26:\"post-content/style.min.css\";i:312;s:23:\"post-date/style-rtl.css\";i:313;s:27:\"post-date/style-rtl.min.css\";i:314;s:19:\"post-date/style.css\";i:315;s:23:\"post-date/style.min.css\";i:316;s:27:\"post-excerpt/editor-rtl.css\";i:317;s:31:\"post-excerpt/editor-rtl.min.css\";i:318;s:23:\"post-excerpt/editor.css\";i:319;s:27:\"post-excerpt/editor.min.css\";i:320;s:26:\"post-excerpt/style-rtl.css\";i:321;s:30:\"post-excerpt/style-rtl.min.css\";i:322;s:22:\"post-excerpt/style.css\";i:323;s:26:\"post-excerpt/style.min.css\";i:324;s:34:\"post-featured-image/editor-rtl.css\";i:325;s:38:\"post-featured-image/editor-rtl.min.css\";i:326;s:30:\"post-featured-image/editor.css\";i:327;s:34:\"post-featured-image/editor.min.css\";i:328;s:33:\"post-featured-image/style-rtl.css\";i:329;s:37:\"post-featured-image/style-rtl.min.css\";i:330;s:29:\"post-featured-image/style.css\";i:331;s:33:\"post-featured-image/style.min.css\";i:332;s:34:\"post-navigation-link/style-rtl.css\";i:333;s:38:\"post-navigation-link/style-rtl.min.css\";i:334;s:30:\"post-navigation-link/style.css\";i:335;s:34:\"post-navigation-link/style.min.css\";i:336;s:27:\"post-template/style-rtl.css\";i:337;s:31:\"post-template/style-rtl.min.css\";i:338;s:23:\"post-template/style.css\";i:339;s:27:\"post-template/style.min.css\";i:340;s:24:\"post-terms/style-rtl.css\";i:341;s:28:\"post-terms/style-rtl.min.css\";i:342;s:20:\"post-terms/style.css\";i:343;s:24:\"post-terms/style.min.css\";i:344;s:24:\"post-title/style-rtl.css\";i:345;s:28:\"post-title/style-rtl.min.css\";i:346;s:20:\"post-title/style.css\";i:347;s:24:\"post-title/style.min.css\";i:348;s:26:\"preformatted/style-rtl.css\";i:349;s:30:\"preformatted/style-rtl.min.css\";i:350;s:22:\"preformatted/style.css\";i:351;s:26:\"preformatted/style.min.css\";i:352;s:24:\"pullquote/editor-rtl.css\";i:353;s:28:\"pullquote/editor-rtl.min.css\";i:354;s:20:\"pullquote/editor.css\";i:355;s:24:\"pullquote/editor.min.css\";i:356;s:23:\"pullquote/style-rtl.css\";i:357;s:27:\"pullquote/style-rtl.min.css\";i:358;s:19:\"pullquote/style.css\";i:359;s:23:\"pullquote/style.min.css\";i:360;s:23:\"pullquote/theme-rtl.css\";i:361;s:27:\"pullquote/theme-rtl.min.css\";i:362;s:19:\"pullquote/theme.css\";i:363;s:23:\"pullquote/theme.min.css\";i:364;s:39:\"query-pagination-numbers/editor-rtl.css\";i:365;s:43:\"query-pagination-numbers/editor-rtl.min.css\";i:366;s:35:\"query-pagination-numbers/editor.css\";i:367;s:39:\"query-pagination-numbers/editor.min.css\";i:368;s:31:\"query-pagination/editor-rtl.css\";i:369;s:35:\"query-pagination/editor-rtl.min.css\";i:370;s:27:\"query-pagination/editor.css\";i:371;s:31:\"query-pagination/editor.min.css\";i:372;s:30:\"query-pagination/style-rtl.css\";i:373;s:34:\"query-pagination/style-rtl.min.css\";i:374;s:26:\"query-pagination/style.css\";i:375;s:30:\"query-pagination/style.min.css\";i:376;s:25:\"query-title/style-rtl.css\";i:377;s:29:\"query-title/style-rtl.min.css\";i:378;s:21:\"query-title/style.css\";i:379;s:25:\"query-title/style.min.css\";i:380;s:25:\"query-total/style-rtl.css\";i:381;s:29:\"query-total/style-rtl.min.css\";i:382;s:21:\"query-total/style.css\";i:383;s:25:\"query-total/style.min.css\";i:384;s:20:\"query/editor-rtl.css\";i:385;s:24:\"query/editor-rtl.min.css\";i:386;s:16:\"query/editor.css\";i:387;s:20:\"query/editor.min.css\";i:388;s:19:\"quote/style-rtl.css\";i:389;s:23:\"quote/style-rtl.min.css\";i:390;s:15:\"quote/style.css\";i:391;s:19:\"quote/style.min.css\";i:392;s:19:\"quote/theme-rtl.css\";i:393;s:23:\"quote/theme-rtl.min.css\";i:394;s:15:\"quote/theme.css\";i:395;s:19:\"quote/theme.min.css\";i:396;s:23:\"read-more/style-rtl.css\";i:397;s:27:\"read-more/style-rtl.min.css\";i:398;s:19:\"read-more/style.css\";i:399;s:23:\"read-more/style.min.css\";i:400;s:18:\"rss/editor-rtl.css\";i:401;s:22:\"rss/editor-rtl.min.css\";i:402;s:14:\"rss/editor.css\";i:403;s:18:\"rss/editor.min.css\";i:404;s:17:\"rss/style-rtl.css\";i:405;s:21:\"rss/style-rtl.min.css\";i:406;s:13:\"rss/style.css\";i:407;s:17:\"rss/style.min.css\";i:408;s:21:\"search/editor-rtl.css\";i:409;s:25:\"search/editor-rtl.min.css\";i:410;s:17:\"search/editor.css\";i:411;s:21:\"search/editor.min.css\";i:412;s:20:\"search/style-rtl.css\";i:413;s:24:\"search/style-rtl.min.css\";i:414;s:16:\"search/style.css\";i:415;s:20:\"search/style.min.css\";i:416;s:20:\"search/theme-rtl.css\";i:417;s:24:\"search/theme-rtl.min.css\";i:418;s:16:\"search/theme.css\";i:419;s:20:\"search/theme.min.css\";i:420;s:24:\"separator/editor-rtl.css\";i:421;s:28:\"separator/editor-rtl.min.css\";i:422;s:20:\"separator/editor.css\";i:423;s:24:\"separator/editor.min.css\";i:424;s:23:\"separator/style-rtl.css\";i:425;s:27:\"separator/style-rtl.min.css\";i:426;s:19:\"separator/style.css\";i:427;s:23:\"separator/style.min.css\";i:428;s:23:\"separator/theme-rtl.css\";i:429;s:27:\"separator/theme-rtl.min.css\";i:430;s:19:\"separator/theme.css\";i:431;s:23:\"separator/theme.min.css\";i:432;s:24:\"shortcode/editor-rtl.css\";i:433;s:28:\"shortcode/editor-rtl.min.css\";i:434;s:20:\"shortcode/editor.css\";i:435;s:24:\"shortcode/editor.min.css\";i:436;s:24:\"site-logo/editor-rtl.css\";i:437;s:28:\"site-logo/editor-rtl.min.css\";i:438;s:20:\"site-logo/editor.css\";i:439;s:24:\"site-logo/editor.min.css\";i:440;s:23:\"site-logo/style-rtl.css\";i:441;s:27:\"site-logo/style-rtl.min.css\";i:442;s:19:\"site-logo/style.css\";i:443;s:23:\"site-logo/style.min.css\";i:444;s:27:\"site-tagline/editor-rtl.css\";i:445;s:31:\"site-tagline/editor-rtl.min.css\";i:446;s:23:\"site-tagline/editor.css\";i:447;s:27:\"site-tagline/editor.min.css\";i:448;s:26:\"site-tagline/style-rtl.css\";i:449;s:30:\"site-tagline/style-rtl.min.css\";i:450;s:22:\"site-tagline/style.css\";i:451;s:26:\"site-tagline/style.min.css\";i:452;s:25:\"site-title/editor-rtl.css\";i:453;s:29:\"site-title/editor-rtl.min.css\";i:454;s:21:\"site-title/editor.css\";i:455;s:25:\"site-title/editor.min.css\";i:456;s:24:\"site-title/style-rtl.css\";i:457;s:28:\"site-title/style-rtl.min.css\";i:458;s:20:\"site-title/style.css\";i:459;s:24:\"site-title/style.min.css\";i:460;s:26:\"social-link/editor-rtl.css\";i:461;s:30:\"social-link/editor-rtl.min.css\";i:462;s:22:\"social-link/editor.css\";i:463;s:26:\"social-link/editor.min.css\";i:464;s:27:\"social-links/editor-rtl.css\";i:465;s:31:\"social-links/editor-rtl.min.css\";i:466;s:23:\"social-links/editor.css\";i:467;s:27:\"social-links/editor.min.css\";i:468;s:26:\"social-links/style-rtl.css\";i:469;s:30:\"social-links/style-rtl.min.css\";i:470;s:22:\"social-links/style.css\";i:471;s:26:\"social-links/style.min.css\";i:472;s:21:\"spacer/editor-rtl.css\";i:473;s:25:\"spacer/editor-rtl.min.css\";i:474;s:17:\"spacer/editor.css\";i:475;s:21:\"spacer/editor.min.css\";i:476;s:20:\"spacer/style-rtl.css\";i:477;s:24:\"spacer/style-rtl.min.css\";i:478;s:16:\"spacer/style.css\";i:479;s:20:\"spacer/style.min.css\";i:480;s:20:\"table/editor-rtl.css\";i:481;s:24:\"table/editor-rtl.min.css\";i:482;s:16:\"table/editor.css\";i:483;s:20:\"table/editor.min.css\";i:484;s:19:\"table/style-rtl.css\";i:485;s:23:\"table/style-rtl.min.css\";i:486;s:15:\"table/style.css\";i:487;s:19:\"table/style.min.css\";i:488;s:19:\"table/theme-rtl.css\";i:489;s:23:\"table/theme-rtl.min.css\";i:490;s:15:\"table/theme.css\";i:491;s:19:\"table/theme.min.css\";i:492;s:24:\"tag-cloud/editor-rtl.css\";i:493;s:28:\"tag-cloud/editor-rtl.min.css\";i:494;s:20:\"tag-cloud/editor.css\";i:495;s:24:\"tag-cloud/editor.min.css\";i:496;s:23:\"tag-cloud/style-rtl.css\";i:497;s:27:\"tag-cloud/style-rtl.min.css\";i:498;s:19:\"tag-cloud/style.css\";i:499;s:23:\"tag-cloud/style.min.css\";i:500;s:28:\"template-part/editor-rtl.css\";i:501;s:32:\"template-part/editor-rtl.min.css\";i:502;s:24:\"template-part/editor.css\";i:503;s:28:\"template-part/editor.min.css\";i:504;s:27:\"template-part/theme-rtl.css\";i:505;s:31:\"template-part/theme-rtl.min.css\";i:506;s:23:\"template-part/theme.css\";i:507;s:27:\"template-part/theme.min.css\";i:508;s:30:\"term-description/style-rtl.css\";i:509;s:34:\"term-description/style-rtl.min.css\";i:510;s:26:\"term-description/style.css\";i:511;s:30:\"term-description/style.min.css\";i:512;s:27:\"text-columns/editor-rtl.css\";i:513;s:31:\"text-columns/editor-rtl.min.css\";i:514;s:23:\"text-columns/editor.css\";i:515;s:27:\"text-columns/editor.min.css\";i:516;s:26:\"text-columns/style-rtl.css\";i:517;s:30:\"text-columns/style-rtl.min.css\";i:518;s:22:\"text-columns/style.css\";i:519;s:26:\"text-columns/style.min.css\";i:520;s:19:\"verse/style-rtl.css\";i:521;s:23:\"verse/style-rtl.min.css\";i:522;s:15:\"verse/style.css\";i:523;s:19:\"verse/style.min.css\";i:524;s:20:\"video/editor-rtl.css\";i:525;s:24:\"video/editor-rtl.min.css\";i:526;s:16:\"video/editor.css\";i:527;s:20:\"video/editor.min.css\";i:528;s:19:\"video/style-rtl.css\";i:529;s:23:\"video/style-rtl.min.css\";i:530;s:15:\"video/style.css\";i:531;s:19:\"video/style.min.css\";i:532;s:19:\"video/theme-rtl.css\";i:533;s:23:\"video/theme-rtl.min.css\";i:534;s:15:\"video/theme.css\";i:535;s:19:\"video/theme.min.css\";}}','on'),(124,'_transient_doing_cron','1764371701.4586930274963378906250','on'),(125,'theme_mods_twentytwentyfive','a:2:{s:18:\"custom_css_post_id\";i:-1;s:16:\"sidebars_widgets\";a:2:{s:4:\"time\";i:1764367183;s:4:\"data\";a:3:{s:19:\"wp_inactive_widgets\";a:0:{}s:9:\"sidebar-1\";a:3:{i:0;s:7:\"block-2\";i:1;s:7:\"block-3\";i:2;s:7:\"block-4\";}s:9:\"sidebar-2\";a:2:{i:0;s:7:\"block-5\";i:1;s:7:\"block-6\";}}}}','off'),(126,'_transient_wp_styles_for_blocks','a:2:{s:4:\"hash\";s:32:\"64ad95698215776f80fa1e80f2eb5417\";s:6:\"blocks\";a:7:{s:11:\"core/button\";s:0:\"\";s:14:\"core/site-logo\";s:0:\"\";s:18:\"core/post-template\";s:0:\"\";s:12:\"core/columns\";s:0:\"\";s:14:\"core/pullquote\";s:121:\":root :where(.wp-block-pullquote){font-size: clamp(0.984em, 0.984rem + ((1vw - 0.2em) * 0.938), 1.5em);line-height: 1.6;}\";s:15:\"core/site-title\";s:89:\":root :where(.wp-block-site-title){font-family: var(--wp--preset--font-family--display);}\";s:15:\"core/navigation\";s:86:\":root :where(.wp-block-navigation){font-family: var(--wp--preset--font-family--body);}\";}}','on'),(129,'category_children','a:0:{}','auto'),(132,'_site_transient_update_themes','O:8:\"stdClass\":5:{s:12:\"last_checked\";i:1764371702;s:7:\"checked\";a:4:{s:8:\"homeproz\";s:5:\"1.0.0\";s:16:\"twentytwentyfive\";s:3:\"1.3\";s:16:\"twentytwentyfour\";s:3:\"1.3\";s:17:\"twentytwentythree\";s:3:\"1.6\";}s:8:\"response\";a:0:{}s:9:\"no_update\";a:3:{s:16:\"twentytwentyfive\";a:6:{s:5:\"theme\";s:16:\"twentytwentyfive\";s:11:\"new_version\";s:3:\"1.3\";s:3:\"url\";s:46:\"https://wordpress.org/themes/twentytwentyfive/\";s:7:\"package\";s:62:\"https://downloads.wordpress.org/theme/twentytwentyfive.1.3.zip\";s:8:\"requires\";s:3:\"6.7\";s:12:\"requires_php\";s:3:\"7.2\";}s:16:\"twentytwentyfour\";a:6:{s:5:\"theme\";s:16:\"twentytwentyfour\";s:11:\"new_version\";s:3:\"1.3\";s:3:\"url\";s:46:\"https://wordpress.org/themes/twentytwentyfour/\";s:7:\"package\";s:62:\"https://downloads.wordpress.org/theme/twentytwentyfour.1.3.zip\";s:8:\"requires\";s:3:\"6.4\";s:12:\"requires_php\";s:3:\"7.0\";}s:17:\"twentytwentythree\";a:6:{s:5:\"theme\";s:17:\"twentytwentythree\";s:11:\"new_version\";s:3:\"1.6\";s:3:\"url\";s:47:\"https://wordpress.org/themes/twentytwentythree/\";s:7:\"package\";s:63:\"https://downloads.wordpress.org/theme/twentytwentythree.1.6.zip\";s:8:\"requires\";s:3:\"6.1\";s:12:\"requires_php\";s:3:\"5.6\";}}s:12:\"translations\";a:0:{}}','off'),(133,'current_theme','HomeProz','auto'),(134,'theme_switched','','auto'),(135,'theme_mods_homeproz','a:2:{s:18:\"nav_menu_locations\";a:1:{s:7:\"primary\";i:15;}s:18:\"custom_css_post_id\";i:-1;}','auto'),(141,'property_type_children','a:0:{}','auto'),(144,'property_status_children','a:0:{}','auto'),(150,'property_location_children','a:0:{}','auto'),(152,'_site_transient_update_core','O:8:\"stdClass\":4:{s:7:\"updates\";a:1:{i:0;O:8:\"stdClass\":10:{s:8:\"response\";s:6:\"latest\";s:8:\"download\";s:59:\"https://downloads.wordpress.org/release/wordpress-6.8.3.zip\";s:6:\"locale\";s:5:\"en_US\";s:8:\"packages\";O:8:\"stdClass\":5:{s:4:\"full\";s:59:\"https://downloads.wordpress.org/release/wordpress-6.8.3.zip\";s:10:\"no_content\";s:70:\"https://downloads.wordpress.org/release/wordpress-6.8.3-no-content.zip\";s:11:\"new_bundled\";s:71:\"https://downloads.wordpress.org/release/wordpress-6.8.3-new-bundled.zip\";s:7:\"partial\";s:0:\"\";s:8:\"rollback\";s:0:\"\";}s:7:\"current\";s:5:\"6.8.3\";s:7:\"version\";s:5:\"6.8.3\";s:11:\"php_version\";s:6:\"7.2.24\";s:13:\"mysql_version\";s:5:\"5.5.5\";s:11:\"new_bundled\";s:3:\"6.7\";s:15:\"partial_version\";s:0:\"\";}}s:12:\"last_checked\";i:1764371702;s:15:\"version_checked\";s:5:\"6.8.3\";s:12:\"translations\";a:0:{}}','off'),(156,'acf_first_activated_version','6.6.2','on'),(157,'acf_site_health','{\"event_first_activated\":1764369116,\"last_updated\":1764369116}','off'),(158,'_site_transient_timeout_wp_theme_files_patterns-2aae27f1f26ef7a6be8ebee5c8a6a86b','1764372438','off'),(159,'_site_transient_wp_theme_files_patterns-2aae27f1f26ef7a6be8ebee5c8a6a86b','a:2:{s:7:\"version\";s:5:\"1.0.0\";s:8:\"patterns\";a:0:{}}','off'),(162,'wpcf7','a:2:{s:7:\"version\";s:5:\"6.1.3\";s:13:\"bulk_validate\";a:4:{s:9:\"timestamp\";i:1764370639;s:7:\"version\";s:5:\"6.1.3\";s:11:\"count_valid\";i:1;s:13:\"count_invalid\";i:0;}}','auto'),(165,'_site_transient_timeout_theme_roots','1764373103','off'),(166,'_site_transient_theme_roots','a:4:{s:8:\"homeproz\";s:7:\"/themes\";s:16:\"twentytwentyfive\";s:7:\"/themes\";s:16:\"twentytwentyfour\";s:7:\"/themes\";s:17:\"twentytwentythree\";s:7:\"/themes\";}','off'),(167,'yoast_migrations_free','a:1:{s:7:\"version\";s:4:\"26.4\";}','auto'),(168,'wpseo','a:120:{s:8:\"tracking\";b:0;s:16:\"toggled_tracking\";b:0;s:22:\"license_server_version\";b:0;s:15:\"ms_defaults_set\";b:0;s:40:\"ignore_search_engines_discouraged_notice\";b:0;s:19:\"indexing_first_time\";b:1;s:16:\"indexing_started\";b:0;s:15:\"indexing_reason\";s:24:\"attachments_made_enabled\";s:29:\"indexables_indexing_completed\";b:0;s:13:\"index_now_key\";s:0:\"\";s:7:\"version\";s:4:\"26.4\";s:16:\"previous_version\";s:0:\"\";s:20:\"disableadvanced_meta\";b:1;s:30:\"enable_headless_rest_endpoints\";b:1;s:17:\"ryte_indexability\";b:0;s:11:\"baiduverify\";s:0:\"\";s:12:\"googleverify\";s:0:\"\";s:8:\"msverify\";s:0:\"\";s:12:\"yandexverify\";s:0:\"\";s:12:\"ahrefsverify\";s:0:\"\";s:9:\"site_type\";s:0:\"\";s:20:\"has_multiple_authors\";s:0:\"\";s:16:\"environment_type\";s:0:\"\";s:23:\"content_analysis_active\";b:1;s:23:\"keyword_analysis_active\";b:1;s:34:\"inclusive_language_analysis_active\";b:0;s:21:\"enable_admin_bar_menu\";b:1;s:26:\"enable_cornerstone_content\";b:1;s:18:\"enable_xml_sitemap\";b:1;s:24:\"enable_text_link_counter\";b:1;s:16:\"enable_index_now\";b:1;s:19:\"enable_ai_generator\";b:1;s:22:\"ai_enabled_pre_default\";b:0;s:22:\"show_onboarding_notice\";b:1;s:18:\"first_activated_on\";i:1764371307;s:13:\"myyoast-oauth\";b:0;s:26:\"semrush_integration_active\";b:1;s:14:\"semrush_tokens\";a:0:{}s:20:\"semrush_country_code\";s:2:\"us\";s:19:\"permalink_structure\";s:0:\"\";s:8:\"home_url\";s:0:\"\";s:18:\"dynamic_permalinks\";b:0;s:17:\"category_base_url\";s:0:\"\";s:12:\"tag_base_url\";s:0:\"\";s:21:\"custom_taxonomy_slugs\";a:0:{}s:29:\"enable_enhanced_slack_sharing\";b:1;s:23:\"enable_metabox_insights\";b:1;s:23:\"enable_link_suggestions\";b:1;s:26:\"algolia_integration_active\";b:0;s:14:\"import_cursors\";a:0:{}s:13:\"workouts_data\";a:1:{s:13:\"configuration\";a:1:{s:13:\"finishedSteps\";a:0:{}}}s:28:\"configuration_finished_steps\";a:0:{}s:36:\"dismiss_configuration_workout_notice\";b:0;s:34:\"dismiss_premium_deactivated_notice\";b:0;s:19:\"importing_completed\";a:0:{}s:26:\"wincher_integration_active\";b:1;s:14:\"wincher_tokens\";a:0:{}s:36:\"wincher_automatically_add_keyphrases\";b:0;s:18:\"wincher_website_id\";s:0:\"\";s:18:\"first_time_install\";b:1;s:34:\"should_redirect_after_install_free\";b:0;s:34:\"activation_redirect_timestamp_free\";i:1764371307;s:18:\"remove_feed_global\";b:0;s:27:\"remove_feed_global_comments\";b:0;s:25:\"remove_feed_post_comments\";b:0;s:19:\"remove_feed_authors\";b:0;s:22:\"remove_feed_categories\";b:0;s:16:\"remove_feed_tags\";b:0;s:29:\"remove_feed_custom_taxonomies\";b:0;s:22:\"remove_feed_post_types\";b:0;s:18:\"remove_feed_search\";b:0;s:21:\"remove_atom_rdf_feeds\";b:0;s:17:\"remove_shortlinks\";b:0;s:21:\"remove_rest_api_links\";b:0;s:20:\"remove_rsd_wlw_links\";b:0;s:19:\"remove_oembed_links\";b:0;s:16:\"remove_generator\";b:0;s:20:\"remove_emoji_scripts\";b:0;s:24:\"remove_powered_by_header\";b:0;s:22:\"remove_pingback_header\";b:0;s:28:\"clean_campaign_tracking_urls\";b:0;s:16:\"clean_permalinks\";b:0;s:32:\"clean_permalinks_extra_variables\";s:0:\"\";s:14:\"search_cleanup\";b:0;s:20:\"search_cleanup_emoji\";b:0;s:23:\"search_cleanup_patterns\";b:0;s:22:\"search_character_limit\";i:50;s:20:\"deny_search_crawling\";b:0;s:21:\"deny_wp_json_crawling\";b:0;s:20:\"deny_adsbot_crawling\";b:0;s:19:\"deny_ccbot_crawling\";b:0;s:29:\"deny_google_extended_crawling\";b:0;s:20:\"deny_gptbot_crawling\";b:0;s:27:\"redirect_search_pretty_urls\";b:0;s:29:\"least_readability_ignore_list\";a:0:{}s:27:\"least_seo_score_ignore_list\";a:0:{}s:23:\"most_linked_ignore_list\";a:0:{}s:24:\"least_linked_ignore_list\";a:0:{}s:28:\"indexables_page_reading_list\";a:5:{i:0;b:0;i:1;b:0;i:2;b:0;i:3;b:0;i:4;b:0;}s:25:\"indexables_overview_state\";s:21:\"dashboard-not-visited\";s:28:\"last_known_public_post_types\";a:0:{}s:28:\"last_known_public_taxonomies\";a:0:{}s:23:\"last_known_no_unindexed\";a:0:{}s:14:\"new_post_types\";a:0:{}s:14:\"new_taxonomies\";a:0:{}s:34:\"show_new_content_type_notification\";b:0;s:44:\"site_kit_configuration_permanently_dismissed\";b:0;s:18:\"site_kit_connected\";b:0;s:37:\"site_kit_tracking_setup_widget_loaded\";s:2:\"no\";s:41:\"site_kit_tracking_first_interaction_stage\";s:0:\"\";s:40:\"site_kit_tracking_last_interaction_stage\";s:0:\"\";s:52:\"site_kit_tracking_setup_widget_temporarily_dismissed\";s:2:\"no\";s:52:\"site_kit_tracking_setup_widget_permanently_dismissed\";s:2:\"no\";s:31:\"google_site_kit_feature_enabled\";b:0;s:25:\"ai_free_sparks_started_on\";N;s:15:\"enable_llms_txt\";b:0;s:15:\"last_updated_on\";b:0;s:17:\"default_seo_title\";a:0:{}s:21:\"default_seo_meta_desc\";a:0:{}s:18:\"first_activated_by\";i:0;}','auto'),(169,'wpseo_titles','a:173:{s:17:\"forcerewritetitle\";b:0;s:9:\"separator\";s:7:\"sc-dash\";s:16:\"title-home-wpseo\";s:47:\"HomeProz Real Estate | Albert Lea MN Properties\";s:18:\"title-author-wpseo\";s:41:\"%%name%%, Author at %%sitename%% %%page%%\";s:19:\"title-archive-wpseo\";s:38:\"%%date%% %%page%% %%sep%% %%sitename%%\";s:18:\"title-search-wpseo\";s:63:\"You searched for %%searchphrase%% %%page%% %%sep%% %%sitename%%\";s:15:\"title-404-wpseo\";s:35:\"Page not found %%sep%% %%sitename%%\";s:25:\"social-title-author-wpseo\";s:8:\"%%name%%\";s:26:\"social-title-archive-wpseo\";s:8:\"%%date%%\";s:31:\"social-description-author-wpseo\";s:0:\"\";s:32:\"social-description-archive-wpseo\";s:0:\"\";s:29:\"social-image-url-author-wpseo\";s:0:\"\";s:30:\"social-image-url-archive-wpseo\";s:0:\"\";s:28:\"social-image-id-author-wpseo\";i:0;s:29:\"social-image-id-archive-wpseo\";i:0;s:19:\"metadesc-home-wpseo\";s:120:\"HomeProz Real Estate - Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.\";s:21:\"metadesc-author-wpseo\";s:0:\"\";s:22:\"metadesc-archive-wpseo\";s:0:\"\";s:9:\"rssbefore\";s:0:\"\";s:8:\"rssafter\";s:53:\"The post %%POSTLINK%% appeared first on %%BLOGLINK%%.\";s:20:\"noindex-author-wpseo\";b:0;s:28:\"noindex-author-noposts-wpseo\";b:0;s:21:\"noindex-archive-wpseo\";b:0;s:14:\"disable-author\";b:0;s:12:\"disable-date\";b:0;s:19:\"disable-post_format\";b:0;s:18:\"disable-attachment\";b:0;s:20:\"breadcrumbs-404crumb\";s:25:\"Error 404: Page not found\";s:29:\"breadcrumbs-display-blog-page\";b:0;s:20:\"breadcrumbs-boldlast\";b:0;s:25:\"breadcrumbs-archiveprefix\";s:12:\"Archives for\";s:18:\"breadcrumbs-enable\";b:0;s:16:\"breadcrumbs-home\";s:4:\"Home\";s:18:\"breadcrumbs-prefix\";s:0:\"\";s:24:\"breadcrumbs-searchprefix\";s:16:\"You searched for\";s:15:\"breadcrumbs-sep\";s:2:\"»\";s:12:\"website_name\";s:0:\"\";s:11:\"person_name\";s:0:\"\";s:11:\"person_logo\";s:0:\"\";s:22:\"alternate_website_name\";s:0:\"\";s:12:\"company_logo\";s:0:\"\";s:12:\"company_name\";s:0:\"\";s:22:\"company_alternate_name\";s:0:\"\";s:17:\"company_or_person\";s:7:\"company\";s:25:\"company_or_person_user_id\";b:0;s:17:\"stripcategorybase\";b:0;s:26:\"open_graph_frontpage_title\";s:12:\"%%sitename%%\";s:25:\"open_graph_frontpage_desc\";s:0:\"\";s:26:\"open_graph_frontpage_image\";s:0:\"\";s:24:\"publishing_principles_id\";i:0;s:25:\"ownership_funding_info_id\";i:0;s:29:\"actionable_feedback_policy_id\";i:0;s:21:\"corrections_policy_id\";i:0;s:16:\"ethics_policy_id\";i:0;s:19:\"diversity_policy_id\";i:0;s:28:\"diversity_staffing_report_id\";i:0;s:15:\"org-description\";s:0:\"\";s:9:\"org-email\";s:0:\"\";s:9:\"org-phone\";s:0:\"\";s:14:\"org-legal-name\";s:0:\"\";s:17:\"org-founding-date\";s:0:\"\";s:20:\"org-number-employees\";s:0:\"\";s:10:\"org-vat-id\";s:0:\"\";s:10:\"org-tax-id\";s:0:\"\";s:7:\"org-iso\";s:0:\"\";s:8:\"org-duns\";s:0:\"\";s:11:\"org-leicode\";s:0:\"\";s:9:\"org-naics\";s:0:\"\";s:10:\"title-post\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:13:\"metadesc-post\";s:0:\"\";s:12:\"noindex-post\";b:0;s:23:\"display-metabox-pt-post\";b:0;s:23:\"post_types-post-maintax\";i:0;s:21:\"schema-page-type-post\";s:7:\"WebPage\";s:24:\"schema-article-type-post\";s:7:\"Article\";s:17:\"social-title-post\";s:9:\"%%title%%\";s:23:\"social-description-post\";s:0:\"\";s:21:\"social-image-url-post\";s:0:\"\";s:20:\"social-image-id-post\";i:0;s:10:\"title-page\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:13:\"metadesc-page\";s:0:\"\";s:12:\"noindex-page\";b:0;s:23:\"display-metabox-pt-page\";b:0;s:23:\"post_types-page-maintax\";i:0;s:21:\"schema-page-type-page\";s:7:\"WebPage\";s:24:\"schema-article-type-page\";s:4:\"None\";s:17:\"social-title-page\";s:9:\"%%title%%\";s:23:\"social-description-page\";s:0:\"\";s:21:\"social-image-url-page\";s:0:\"\";s:20:\"social-image-id-page\";i:0;s:16:\"title-attachment\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:19:\"metadesc-attachment\";s:0:\"\";s:18:\"noindex-attachment\";b:0;s:29:\"display-metabox-pt-attachment\";b:0;s:29:\"post_types-attachment-maintax\";i:0;s:27:\"schema-page-type-attachment\";s:7:\"WebPage\";s:30:\"schema-article-type-attachment\";s:4:\"None\";s:18:\"title-tax-category\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:21:\"metadesc-tax-category\";s:0:\"\";s:28:\"display-metabox-tax-category\";b:0;s:20:\"noindex-tax-category\";b:0;s:25:\"social-title-tax-category\";s:23:\"%%term_title%% Archives\";s:31:\"social-description-tax-category\";s:0:\"\";s:29:\"social-image-url-tax-category\";s:0:\"\";s:28:\"social-image-id-tax-category\";i:0;s:26:\"taxonomy-category-ptparent\";i:0;s:18:\"title-tax-post_tag\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:21:\"metadesc-tax-post_tag\";s:0:\"\";s:28:\"display-metabox-tax-post_tag\";b:0;s:20:\"noindex-tax-post_tag\";b:0;s:25:\"social-title-tax-post_tag\";s:23:\"%%term_title%% Archives\";s:31:\"social-description-tax-post_tag\";s:0:\"\";s:29:\"social-image-url-tax-post_tag\";s:0:\"\";s:28:\"social-image-id-tax-post_tag\";i:0;s:26:\"taxonomy-post_tag-ptparent\";i:0;s:21:\"title-tax-post_format\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:24:\"metadesc-tax-post_format\";s:0:\"\";s:31:\"display-metabox-tax-post_format\";b:0;s:23:\"noindex-tax-post_format\";b:0;s:28:\"social-title-tax-post_format\";s:23:\"%%term_title%% Archives\";s:34:\"social-description-tax-post_format\";s:0:\"\";s:32:\"social-image-url-tax-post_format\";s:0:\"\";s:31:\"social-image-id-tax-post_format\";i:0;s:29:\"taxonomy-post_format-ptparent\";i:0;s:14:\"title-property\";s:30:\"%%title%% %%sep%% %%sitename%%\";s:17:\"metadesc-property\";s:106:\"View property details, photos, and features for %%title%%. Contact HomeProz Real Estate in Albert Lea, MN.\";s:16:\"noindex-property\";b:0;s:27:\"display-metabox-pt-property\";b:0;s:27:\"post_types-property-maintax\";i:0;s:25:\"schema-page-type-property\";s:7:\"WebPage\";s:28:\"schema-article-type-property\";s:4:\"None\";s:21:\"social-title-property\";s:9:\"%%title%%\";s:27:\"social-description-property\";s:0:\"\";s:25:\"social-image-url-property\";s:0:\"\";s:24:\"social-image-id-property\";i:0;s:24:\"title-ptarchive-property\";s:49:\"Properties For Sale %%page%% %%sep%% %%sitename%%\";s:27:\"metadesc-ptarchive-property\";s:126:\"Browse all properties for sale in Albert Lea, Minnesota and surrounding areas. Find your dream home with HomeProz Real Estate.\";s:26:\"bctitle-ptarchive-property\";s:0:\"\";s:26:\"noindex-ptarchive-property\";b:0;s:31:\"social-title-ptarchive-property\";s:21:\"%%pt_plural%% Archive\";s:37:\"social-description-ptarchive-property\";s:0:\"\";s:35:\"social-image-url-ptarchive-property\";s:0:\"\";s:34:\"social-image-id-ptarchive-property\";i:0;s:23:\"title-tax-property_type\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:26:\"metadesc-tax-property_type\";s:0:\"\";s:33:\"display-metabox-tax-property_type\";b:0;s:25:\"noindex-tax-property_type\";b:0;s:30:\"social-title-tax-property_type\";s:23:\"%%term_title%% Archives\";s:36:\"social-description-tax-property_type\";s:0:\"\";s:34:\"social-image-url-tax-property_type\";s:0:\"\";s:33:\"social-image-id-tax-property_type\";i:0;s:31:\"taxonomy-property_type-ptparent\";i:0;s:25:\"title-tax-property_status\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:28:\"metadesc-tax-property_status\";s:0:\"\";s:35:\"display-metabox-tax-property_status\";b:0;s:27:\"noindex-tax-property_status\";b:0;s:32:\"social-title-tax-property_status\";s:23:\"%%term_title%% Archives\";s:38:\"social-description-tax-property_status\";s:0:\"\";s:36:\"social-image-url-tax-property_status\";s:0:\"\";s:35:\"social-image-id-tax-property_status\";i:0;s:33:\"taxonomy-property_status-ptparent\";i:0;s:27:\"title-tax-property_location\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:30:\"metadesc-tax-property_location\";s:0:\"\";s:37:\"display-metabox-tax-property_location\";b:0;s:29:\"noindex-tax-property_location\";b:0;s:34:\"social-title-tax-property_location\";s:23:\"%%term_title%% Archives\";s:40:\"social-description-tax-property_location\";s:0:\"\";s:38:\"social-image-url-tax-property_location\";s:0:\"\";s:37:\"social-image-id-tax-property_location\";i:0;s:35:\"taxonomy-property_location-ptparent\";i:0;s:14:\"person_logo_id\";i:0;s:15:\"company_logo_id\";i:0;s:29:\"open_graph_frontpage_image_id\";i:0;}','auto'),(170,'wpseo_social','a:20:{s:13:\"facebook_site\";s:0:\"\";s:13:\"instagram_url\";s:0:\"\";s:12:\"linkedin_url\";s:0:\"\";s:11:\"myspace_url\";s:0:\"\";s:16:\"og_default_image\";s:0:\"\";s:19:\"og_default_image_id\";s:0:\"\";s:18:\"og_frontpage_title\";s:47:\"HomeProz Real Estate | Albert Lea MN Properties\";s:17:\"og_frontpage_desc\";s:97:\"Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.\";s:18:\"og_frontpage_image\";s:0:\"\";s:21:\"og_frontpage_image_id\";s:0:\"\";s:9:\"opengraph\";b:1;s:13:\"pinterest_url\";s:0:\"\";s:15:\"pinterestverify\";s:0:\"\";s:7:\"twitter\";b:1;s:12:\"twitter_site\";s:0:\"\";s:17:\"twitter_card_type\";s:19:\"summary_large_image\";s:11:\"youtube_url\";s:0:\"\";s:13:\"wikipedia_url\";s:0:\"\";s:17:\"other_social_urls\";a:0:{}s:12:\"mastodon_url\";s:0:\"\";}','auto'),(171,'wpseo_llmstxt','a:7:{s:23:\"llms_txt_selection_mode\";s:4:\"auto\";s:13:\"about_us_page\";i:0;s:12:\"contact_page\";i:0;s:10:\"terms_page\";i:0;s:19:\"privacy_policy_page\";i:0;s:9:\"shop_page\";i:0;s:20:\"other_included_pages\";a:0:{}}','auto'),(174,'webpc_is_new_installation','1','auto'),(175,'webpc_notice_thanks','1765581302','auto'),(176,'webpc_notice_pro_version','1764976502','auto'),(177,'webpc_stats_installation_date','2025-11-28 23:15:02','auto'),(178,'webpc_stats_first_version','6.3.2','auto');
+INSERT INTO `wp_options` VALUES (1,'cron','a:12:{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:1764371970;a:4:{s:26:\"aios_15_minutes_cron_event\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:21:\"aios-every-15-minutes\";s:4:\"args\";a:0:{}s:8:\"interval\";i:900;}}s:24:\"aiowps_hourly_cron_event\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"hourly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:3600;}}s:23:\"aiowps_daily_cron_event\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:5:\"daily\";s:4:\"args\";a:0:{}s:8:\"interval\";i:86400;}}s:24:\"aiowps_weekly_cron_event\";a:1:{s:32:\"40cd750bba9870f18aada2478b24840a\";a:3:{s:8:\"schedule\";s:6:\"weekly\";s:4:\"args\";a:0:{}s:8:\"interval\";i:604800;}}}i:1764371978;a:1:{s:23:\"aiowps_clean_old_events\";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:5:{i:0;s:30:\"advanced-custom-fields/acf.php\";i:1;s:51:\"all-in-one-wp-security-and-firewall/wp-security.php\";i:2;s:36:\"contact-form-7/wp-contact-form-7.php\";i:3;s:53:\"webp-converter-for-media/webp-converter-for-media.php\";i:4;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:3:{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\";}s:51:\"all-in-one-wp-security-and-firewall/wp-security.php\";a:2:{i:0;s:15:\"AIO_WP_Security\";i:1;s:17:\"uninstall_handler\";}}','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:\"
Recent Posts
\";}i:4;a:1:{s:7:\"content\";s:227:\"
Recent Comments
\";}i:5;a:1:{s:7:\"content\";s:146:\"
Archives
\";}i:6;a:1:{s:7:\"content\";s:150:\"
Categories
\";}s:12:\"_multiwidget\";i:1;}','auto'),(106,'sidebars_widgets','a:2:{s:19:\"wp_inactive_widgets\";a:5:{i:0;s:7:\"block-2\";i:1;s:7:\"block-3\";i:2;s:7:\"block-4\";i:3;s:7:\"block-5\";i:4;s:7:\"block-6\";}s:13:\"array_version\";i:3;}','auto'),(107,'widget_pages','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(108,'widget_calendar','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(109,'widget_archives','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(110,'widget_media_audio','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(111,'widget_media_image','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(112,'widget_media_gallery','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(113,'widget_media_video','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(114,'widget_meta','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(115,'widget_search','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(116,'widget_recent-posts','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(117,'widget_recent-comments','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(118,'widget_tag_cloud','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(119,'widget_nav_menu','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(120,'widget_custom_html','a:1:{s:12:\"_multiwidget\";i:1;}','auto'),(121,'_transient_wp_core_block_css_files','a:2:{s:7:\"version\";s:5:\"6.8.3\";s:5:\"files\";a:536:{i:0;s:23:\"archives/editor-rtl.css\";i:1;s:27:\"archives/editor-rtl.min.css\";i:2;s:19:\"archives/editor.css\";i:3;s:23:\"archives/editor.min.css\";i:4;s:22:\"archives/style-rtl.css\";i:5;s:26:\"archives/style-rtl.min.css\";i:6;s:18:\"archives/style.css\";i:7;s:22:\"archives/style.min.css\";i:8;s:20:\"audio/editor-rtl.css\";i:9;s:24:\"audio/editor-rtl.min.css\";i:10;s:16:\"audio/editor.css\";i:11;s:20:\"audio/editor.min.css\";i:12;s:19:\"audio/style-rtl.css\";i:13;s:23:\"audio/style-rtl.min.css\";i:14;s:15:\"audio/style.css\";i:15;s:19:\"audio/style.min.css\";i:16;s:19:\"audio/theme-rtl.css\";i:17;s:23:\"audio/theme-rtl.min.css\";i:18;s:15:\"audio/theme.css\";i:19;s:19:\"audio/theme.min.css\";i:20;s:21:\"avatar/editor-rtl.css\";i:21;s:25:\"avatar/editor-rtl.min.css\";i:22;s:17:\"avatar/editor.css\";i:23;s:21:\"avatar/editor.min.css\";i:24;s:20:\"avatar/style-rtl.css\";i:25;s:24:\"avatar/style-rtl.min.css\";i:26;s:16:\"avatar/style.css\";i:27;s:20:\"avatar/style.min.css\";i:28;s:21:\"button/editor-rtl.css\";i:29;s:25:\"button/editor-rtl.min.css\";i:30;s:17:\"button/editor.css\";i:31;s:21:\"button/editor.min.css\";i:32;s:20:\"button/style-rtl.css\";i:33;s:24:\"button/style-rtl.min.css\";i:34;s:16:\"button/style.css\";i:35;s:20:\"button/style.min.css\";i:36;s:22:\"buttons/editor-rtl.css\";i:37;s:26:\"buttons/editor-rtl.min.css\";i:38;s:18:\"buttons/editor.css\";i:39;s:22:\"buttons/editor.min.css\";i:40;s:21:\"buttons/style-rtl.css\";i:41;s:25:\"buttons/style-rtl.min.css\";i:42;s:17:\"buttons/style.css\";i:43;s:21:\"buttons/style.min.css\";i:44;s:22:\"calendar/style-rtl.css\";i:45;s:26:\"calendar/style-rtl.min.css\";i:46;s:18:\"calendar/style.css\";i:47;s:22:\"calendar/style.min.css\";i:48;s:25:\"categories/editor-rtl.css\";i:49;s:29:\"categories/editor-rtl.min.css\";i:50;s:21:\"categories/editor.css\";i:51;s:25:\"categories/editor.min.css\";i:52;s:24:\"categories/style-rtl.css\";i:53;s:28:\"categories/style-rtl.min.css\";i:54;s:20:\"categories/style.css\";i:55;s:24:\"categories/style.min.css\";i:56;s:19:\"code/editor-rtl.css\";i:57;s:23:\"code/editor-rtl.min.css\";i:58;s:15:\"code/editor.css\";i:59;s:19:\"code/editor.min.css\";i:60;s:18:\"code/style-rtl.css\";i:61;s:22:\"code/style-rtl.min.css\";i:62;s:14:\"code/style.css\";i:63;s:18:\"code/style.min.css\";i:64;s:18:\"code/theme-rtl.css\";i:65;s:22:\"code/theme-rtl.min.css\";i:66;s:14:\"code/theme.css\";i:67;s:18:\"code/theme.min.css\";i:68;s:22:\"columns/editor-rtl.css\";i:69;s:26:\"columns/editor-rtl.min.css\";i:70;s:18:\"columns/editor.css\";i:71;s:22:\"columns/editor.min.css\";i:72;s:21:\"columns/style-rtl.css\";i:73;s:25:\"columns/style-rtl.min.css\";i:74;s:17:\"columns/style.css\";i:75;s:21:\"columns/style.min.css\";i:76;s:33:\"comment-author-name/style-rtl.css\";i:77;s:37:\"comment-author-name/style-rtl.min.css\";i:78;s:29:\"comment-author-name/style.css\";i:79;s:33:\"comment-author-name/style.min.css\";i:80;s:29:\"comment-content/style-rtl.css\";i:81;s:33:\"comment-content/style-rtl.min.css\";i:82;s:25:\"comment-content/style.css\";i:83;s:29:\"comment-content/style.min.css\";i:84;s:26:\"comment-date/style-rtl.css\";i:85;s:30:\"comment-date/style-rtl.min.css\";i:86;s:22:\"comment-date/style.css\";i:87;s:26:\"comment-date/style.min.css\";i:88;s:31:\"comment-edit-link/style-rtl.css\";i:89;s:35:\"comment-edit-link/style-rtl.min.css\";i:90;s:27:\"comment-edit-link/style.css\";i:91;s:31:\"comment-edit-link/style.min.css\";i:92;s:32:\"comment-reply-link/style-rtl.css\";i:93;s:36:\"comment-reply-link/style-rtl.min.css\";i:94;s:28:\"comment-reply-link/style.css\";i:95;s:32:\"comment-reply-link/style.min.css\";i:96;s:30:\"comment-template/style-rtl.css\";i:97;s:34:\"comment-template/style-rtl.min.css\";i:98;s:26:\"comment-template/style.css\";i:99;s:30:\"comment-template/style.min.css\";i:100;s:42:\"comments-pagination-numbers/editor-rtl.css\";i:101;s:46:\"comments-pagination-numbers/editor-rtl.min.css\";i:102;s:38:\"comments-pagination-numbers/editor.css\";i:103;s:42:\"comments-pagination-numbers/editor.min.css\";i:104;s:34:\"comments-pagination/editor-rtl.css\";i:105;s:38:\"comments-pagination/editor-rtl.min.css\";i:106;s:30:\"comments-pagination/editor.css\";i:107;s:34:\"comments-pagination/editor.min.css\";i:108;s:33:\"comments-pagination/style-rtl.css\";i:109;s:37:\"comments-pagination/style-rtl.min.css\";i:110;s:29:\"comments-pagination/style.css\";i:111;s:33:\"comments-pagination/style.min.css\";i:112;s:29:\"comments-title/editor-rtl.css\";i:113;s:33:\"comments-title/editor-rtl.min.css\";i:114;s:25:\"comments-title/editor.css\";i:115;s:29:\"comments-title/editor.min.css\";i:116;s:23:\"comments/editor-rtl.css\";i:117;s:27:\"comments/editor-rtl.min.css\";i:118;s:19:\"comments/editor.css\";i:119;s:23:\"comments/editor.min.css\";i:120;s:22:\"comments/style-rtl.css\";i:121;s:26:\"comments/style-rtl.min.css\";i:122;s:18:\"comments/style.css\";i:123;s:22:\"comments/style.min.css\";i:124;s:20:\"cover/editor-rtl.css\";i:125;s:24:\"cover/editor-rtl.min.css\";i:126;s:16:\"cover/editor.css\";i:127;s:20:\"cover/editor.min.css\";i:128;s:19:\"cover/style-rtl.css\";i:129;s:23:\"cover/style-rtl.min.css\";i:130;s:15:\"cover/style.css\";i:131;s:19:\"cover/style.min.css\";i:132;s:22:\"details/editor-rtl.css\";i:133;s:26:\"details/editor-rtl.min.css\";i:134;s:18:\"details/editor.css\";i:135;s:22:\"details/editor.min.css\";i:136;s:21:\"details/style-rtl.css\";i:137;s:25:\"details/style-rtl.min.css\";i:138;s:17:\"details/style.css\";i:139;s:21:\"details/style.min.css\";i:140;s:20:\"embed/editor-rtl.css\";i:141;s:24:\"embed/editor-rtl.min.css\";i:142;s:16:\"embed/editor.css\";i:143;s:20:\"embed/editor.min.css\";i:144;s:19:\"embed/style-rtl.css\";i:145;s:23:\"embed/style-rtl.min.css\";i:146;s:15:\"embed/style.css\";i:147;s:19:\"embed/style.min.css\";i:148;s:19:\"embed/theme-rtl.css\";i:149;s:23:\"embed/theme-rtl.min.css\";i:150;s:15:\"embed/theme.css\";i:151;s:19:\"embed/theme.min.css\";i:152;s:19:\"file/editor-rtl.css\";i:153;s:23:\"file/editor-rtl.min.css\";i:154;s:15:\"file/editor.css\";i:155;s:19:\"file/editor.min.css\";i:156;s:18:\"file/style-rtl.css\";i:157;s:22:\"file/style-rtl.min.css\";i:158;s:14:\"file/style.css\";i:159;s:18:\"file/style.min.css\";i:160;s:23:\"footnotes/style-rtl.css\";i:161;s:27:\"footnotes/style-rtl.min.css\";i:162;s:19:\"footnotes/style.css\";i:163;s:23:\"footnotes/style.min.css\";i:164;s:23:\"freeform/editor-rtl.css\";i:165;s:27:\"freeform/editor-rtl.min.css\";i:166;s:19:\"freeform/editor.css\";i:167;s:23:\"freeform/editor.min.css\";i:168;s:22:\"gallery/editor-rtl.css\";i:169;s:26:\"gallery/editor-rtl.min.css\";i:170;s:18:\"gallery/editor.css\";i:171;s:22:\"gallery/editor.min.css\";i:172;s:21:\"gallery/style-rtl.css\";i:173;s:25:\"gallery/style-rtl.min.css\";i:174;s:17:\"gallery/style.css\";i:175;s:21:\"gallery/style.min.css\";i:176;s:21:\"gallery/theme-rtl.css\";i:177;s:25:\"gallery/theme-rtl.min.css\";i:178;s:17:\"gallery/theme.css\";i:179;s:21:\"gallery/theme.min.css\";i:180;s:20:\"group/editor-rtl.css\";i:181;s:24:\"group/editor-rtl.min.css\";i:182;s:16:\"group/editor.css\";i:183;s:20:\"group/editor.min.css\";i:184;s:19:\"group/style-rtl.css\";i:185;s:23:\"group/style-rtl.min.css\";i:186;s:15:\"group/style.css\";i:187;s:19:\"group/style.min.css\";i:188;s:19:\"group/theme-rtl.css\";i:189;s:23:\"group/theme-rtl.min.css\";i:190;s:15:\"group/theme.css\";i:191;s:19:\"group/theme.min.css\";i:192;s:21:\"heading/style-rtl.css\";i:193;s:25:\"heading/style-rtl.min.css\";i:194;s:17:\"heading/style.css\";i:195;s:21:\"heading/style.min.css\";i:196;s:19:\"html/editor-rtl.css\";i:197;s:23:\"html/editor-rtl.min.css\";i:198;s:15:\"html/editor.css\";i:199;s:19:\"html/editor.min.css\";i:200;s:20:\"image/editor-rtl.css\";i:201;s:24:\"image/editor-rtl.min.css\";i:202;s:16:\"image/editor.css\";i:203;s:20:\"image/editor.min.css\";i:204;s:19:\"image/style-rtl.css\";i:205;s:23:\"image/style-rtl.min.css\";i:206;s:15:\"image/style.css\";i:207;s:19:\"image/style.min.css\";i:208;s:19:\"image/theme-rtl.css\";i:209;s:23:\"image/theme-rtl.min.css\";i:210;s:15:\"image/theme.css\";i:211;s:19:\"image/theme.min.css\";i:212;s:29:\"latest-comments/style-rtl.css\";i:213;s:33:\"latest-comments/style-rtl.min.css\";i:214;s:25:\"latest-comments/style.css\";i:215;s:29:\"latest-comments/style.min.css\";i:216;s:27:\"latest-posts/editor-rtl.css\";i:217;s:31:\"latest-posts/editor-rtl.min.css\";i:218;s:23:\"latest-posts/editor.css\";i:219;s:27:\"latest-posts/editor.min.css\";i:220;s:26:\"latest-posts/style-rtl.css\";i:221;s:30:\"latest-posts/style-rtl.min.css\";i:222;s:22:\"latest-posts/style.css\";i:223;s:26:\"latest-posts/style.min.css\";i:224;s:18:\"list/style-rtl.css\";i:225;s:22:\"list/style-rtl.min.css\";i:226;s:14:\"list/style.css\";i:227;s:18:\"list/style.min.css\";i:228;s:22:\"loginout/style-rtl.css\";i:229;s:26:\"loginout/style-rtl.min.css\";i:230;s:18:\"loginout/style.css\";i:231;s:22:\"loginout/style.min.css\";i:232;s:25:\"media-text/editor-rtl.css\";i:233;s:29:\"media-text/editor-rtl.min.css\";i:234;s:21:\"media-text/editor.css\";i:235;s:25:\"media-text/editor.min.css\";i:236;s:24:\"media-text/style-rtl.css\";i:237;s:28:\"media-text/style-rtl.min.css\";i:238;s:20:\"media-text/style.css\";i:239;s:24:\"media-text/style.min.css\";i:240;s:19:\"more/editor-rtl.css\";i:241;s:23:\"more/editor-rtl.min.css\";i:242;s:15:\"more/editor.css\";i:243;s:19:\"more/editor.min.css\";i:244;s:30:\"navigation-link/editor-rtl.css\";i:245;s:34:\"navigation-link/editor-rtl.min.css\";i:246;s:26:\"navigation-link/editor.css\";i:247;s:30:\"navigation-link/editor.min.css\";i:248;s:29:\"navigation-link/style-rtl.css\";i:249;s:33:\"navigation-link/style-rtl.min.css\";i:250;s:25:\"navigation-link/style.css\";i:251;s:29:\"navigation-link/style.min.css\";i:252;s:33:\"navigation-submenu/editor-rtl.css\";i:253;s:37:\"navigation-submenu/editor-rtl.min.css\";i:254;s:29:\"navigation-submenu/editor.css\";i:255;s:33:\"navigation-submenu/editor.min.css\";i:256;s:25:\"navigation/editor-rtl.css\";i:257;s:29:\"navigation/editor-rtl.min.css\";i:258;s:21:\"navigation/editor.css\";i:259;s:25:\"navigation/editor.min.css\";i:260;s:24:\"navigation/style-rtl.css\";i:261;s:28:\"navigation/style-rtl.min.css\";i:262;s:20:\"navigation/style.css\";i:263;s:24:\"navigation/style.min.css\";i:264;s:23:\"nextpage/editor-rtl.css\";i:265;s:27:\"nextpage/editor-rtl.min.css\";i:266;s:19:\"nextpage/editor.css\";i:267;s:23:\"nextpage/editor.min.css\";i:268;s:24:\"page-list/editor-rtl.css\";i:269;s:28:\"page-list/editor-rtl.min.css\";i:270;s:20:\"page-list/editor.css\";i:271;s:24:\"page-list/editor.min.css\";i:272;s:23:\"page-list/style-rtl.css\";i:273;s:27:\"page-list/style-rtl.min.css\";i:274;s:19:\"page-list/style.css\";i:275;s:23:\"page-list/style.min.css\";i:276;s:24:\"paragraph/editor-rtl.css\";i:277;s:28:\"paragraph/editor-rtl.min.css\";i:278;s:20:\"paragraph/editor.css\";i:279;s:24:\"paragraph/editor.min.css\";i:280;s:23:\"paragraph/style-rtl.css\";i:281;s:27:\"paragraph/style-rtl.min.css\";i:282;s:19:\"paragraph/style.css\";i:283;s:23:\"paragraph/style.min.css\";i:284;s:35:\"post-author-biography/style-rtl.css\";i:285;s:39:\"post-author-biography/style-rtl.min.css\";i:286;s:31:\"post-author-biography/style.css\";i:287;s:35:\"post-author-biography/style.min.css\";i:288;s:30:\"post-author-name/style-rtl.css\";i:289;s:34:\"post-author-name/style-rtl.min.css\";i:290;s:26:\"post-author-name/style.css\";i:291;s:30:\"post-author-name/style.min.css\";i:292;s:26:\"post-author/editor-rtl.css\";i:293;s:30:\"post-author/editor-rtl.min.css\";i:294;s:22:\"post-author/editor.css\";i:295;s:26:\"post-author/editor.min.css\";i:296;s:25:\"post-author/style-rtl.css\";i:297;s:29:\"post-author/style-rtl.min.css\";i:298;s:21:\"post-author/style.css\";i:299;s:25:\"post-author/style.min.css\";i:300;s:33:\"post-comments-form/editor-rtl.css\";i:301;s:37:\"post-comments-form/editor-rtl.min.css\";i:302;s:29:\"post-comments-form/editor.css\";i:303;s:33:\"post-comments-form/editor.min.css\";i:304;s:32:\"post-comments-form/style-rtl.css\";i:305;s:36:\"post-comments-form/style-rtl.min.css\";i:306;s:28:\"post-comments-form/style.css\";i:307;s:32:\"post-comments-form/style.min.css\";i:308;s:26:\"post-content/style-rtl.css\";i:309;s:30:\"post-content/style-rtl.min.css\";i:310;s:22:\"post-content/style.css\";i:311;s:26:\"post-content/style.min.css\";i:312;s:23:\"post-date/style-rtl.css\";i:313;s:27:\"post-date/style-rtl.min.css\";i:314;s:19:\"post-date/style.css\";i:315;s:23:\"post-date/style.min.css\";i:316;s:27:\"post-excerpt/editor-rtl.css\";i:317;s:31:\"post-excerpt/editor-rtl.min.css\";i:318;s:23:\"post-excerpt/editor.css\";i:319;s:27:\"post-excerpt/editor.min.css\";i:320;s:26:\"post-excerpt/style-rtl.css\";i:321;s:30:\"post-excerpt/style-rtl.min.css\";i:322;s:22:\"post-excerpt/style.css\";i:323;s:26:\"post-excerpt/style.min.css\";i:324;s:34:\"post-featured-image/editor-rtl.css\";i:325;s:38:\"post-featured-image/editor-rtl.min.css\";i:326;s:30:\"post-featured-image/editor.css\";i:327;s:34:\"post-featured-image/editor.min.css\";i:328;s:33:\"post-featured-image/style-rtl.css\";i:329;s:37:\"post-featured-image/style-rtl.min.css\";i:330;s:29:\"post-featured-image/style.css\";i:331;s:33:\"post-featured-image/style.min.css\";i:332;s:34:\"post-navigation-link/style-rtl.css\";i:333;s:38:\"post-navigation-link/style-rtl.min.css\";i:334;s:30:\"post-navigation-link/style.css\";i:335;s:34:\"post-navigation-link/style.min.css\";i:336;s:27:\"post-template/style-rtl.css\";i:337;s:31:\"post-template/style-rtl.min.css\";i:338;s:23:\"post-template/style.css\";i:339;s:27:\"post-template/style.min.css\";i:340;s:24:\"post-terms/style-rtl.css\";i:341;s:28:\"post-terms/style-rtl.min.css\";i:342;s:20:\"post-terms/style.css\";i:343;s:24:\"post-terms/style.min.css\";i:344;s:24:\"post-title/style-rtl.css\";i:345;s:28:\"post-title/style-rtl.min.css\";i:346;s:20:\"post-title/style.css\";i:347;s:24:\"post-title/style.min.css\";i:348;s:26:\"preformatted/style-rtl.css\";i:349;s:30:\"preformatted/style-rtl.min.css\";i:350;s:22:\"preformatted/style.css\";i:351;s:26:\"preformatted/style.min.css\";i:352;s:24:\"pullquote/editor-rtl.css\";i:353;s:28:\"pullquote/editor-rtl.min.css\";i:354;s:20:\"pullquote/editor.css\";i:355;s:24:\"pullquote/editor.min.css\";i:356;s:23:\"pullquote/style-rtl.css\";i:357;s:27:\"pullquote/style-rtl.min.css\";i:358;s:19:\"pullquote/style.css\";i:359;s:23:\"pullquote/style.min.css\";i:360;s:23:\"pullquote/theme-rtl.css\";i:361;s:27:\"pullquote/theme-rtl.min.css\";i:362;s:19:\"pullquote/theme.css\";i:363;s:23:\"pullquote/theme.min.css\";i:364;s:39:\"query-pagination-numbers/editor-rtl.css\";i:365;s:43:\"query-pagination-numbers/editor-rtl.min.css\";i:366;s:35:\"query-pagination-numbers/editor.css\";i:367;s:39:\"query-pagination-numbers/editor.min.css\";i:368;s:31:\"query-pagination/editor-rtl.css\";i:369;s:35:\"query-pagination/editor-rtl.min.css\";i:370;s:27:\"query-pagination/editor.css\";i:371;s:31:\"query-pagination/editor.min.css\";i:372;s:30:\"query-pagination/style-rtl.css\";i:373;s:34:\"query-pagination/style-rtl.min.css\";i:374;s:26:\"query-pagination/style.css\";i:375;s:30:\"query-pagination/style.min.css\";i:376;s:25:\"query-title/style-rtl.css\";i:377;s:29:\"query-title/style-rtl.min.css\";i:378;s:21:\"query-title/style.css\";i:379;s:25:\"query-title/style.min.css\";i:380;s:25:\"query-total/style-rtl.css\";i:381;s:29:\"query-total/style-rtl.min.css\";i:382;s:21:\"query-total/style.css\";i:383;s:25:\"query-total/style.min.css\";i:384;s:20:\"query/editor-rtl.css\";i:385;s:24:\"query/editor-rtl.min.css\";i:386;s:16:\"query/editor.css\";i:387;s:20:\"query/editor.min.css\";i:388;s:19:\"quote/style-rtl.css\";i:389;s:23:\"quote/style-rtl.min.css\";i:390;s:15:\"quote/style.css\";i:391;s:19:\"quote/style.min.css\";i:392;s:19:\"quote/theme-rtl.css\";i:393;s:23:\"quote/theme-rtl.min.css\";i:394;s:15:\"quote/theme.css\";i:395;s:19:\"quote/theme.min.css\";i:396;s:23:\"read-more/style-rtl.css\";i:397;s:27:\"read-more/style-rtl.min.css\";i:398;s:19:\"read-more/style.css\";i:399;s:23:\"read-more/style.min.css\";i:400;s:18:\"rss/editor-rtl.css\";i:401;s:22:\"rss/editor-rtl.min.css\";i:402;s:14:\"rss/editor.css\";i:403;s:18:\"rss/editor.min.css\";i:404;s:17:\"rss/style-rtl.css\";i:405;s:21:\"rss/style-rtl.min.css\";i:406;s:13:\"rss/style.css\";i:407;s:17:\"rss/style.min.css\";i:408;s:21:\"search/editor-rtl.css\";i:409;s:25:\"search/editor-rtl.min.css\";i:410;s:17:\"search/editor.css\";i:411;s:21:\"search/editor.min.css\";i:412;s:20:\"search/style-rtl.css\";i:413;s:24:\"search/style-rtl.min.css\";i:414;s:16:\"search/style.css\";i:415;s:20:\"search/style.min.css\";i:416;s:20:\"search/theme-rtl.css\";i:417;s:24:\"search/theme-rtl.min.css\";i:418;s:16:\"search/theme.css\";i:419;s:20:\"search/theme.min.css\";i:420;s:24:\"separator/editor-rtl.css\";i:421;s:28:\"separator/editor-rtl.min.css\";i:422;s:20:\"separator/editor.css\";i:423;s:24:\"separator/editor.min.css\";i:424;s:23:\"separator/style-rtl.css\";i:425;s:27:\"separator/style-rtl.min.css\";i:426;s:19:\"separator/style.css\";i:427;s:23:\"separator/style.min.css\";i:428;s:23:\"separator/theme-rtl.css\";i:429;s:27:\"separator/theme-rtl.min.css\";i:430;s:19:\"separator/theme.css\";i:431;s:23:\"separator/theme.min.css\";i:432;s:24:\"shortcode/editor-rtl.css\";i:433;s:28:\"shortcode/editor-rtl.min.css\";i:434;s:20:\"shortcode/editor.css\";i:435;s:24:\"shortcode/editor.min.css\";i:436;s:24:\"site-logo/editor-rtl.css\";i:437;s:28:\"site-logo/editor-rtl.min.css\";i:438;s:20:\"site-logo/editor.css\";i:439;s:24:\"site-logo/editor.min.css\";i:440;s:23:\"site-logo/style-rtl.css\";i:441;s:27:\"site-logo/style-rtl.min.css\";i:442;s:19:\"site-logo/style.css\";i:443;s:23:\"site-logo/style.min.css\";i:444;s:27:\"site-tagline/editor-rtl.css\";i:445;s:31:\"site-tagline/editor-rtl.min.css\";i:446;s:23:\"site-tagline/editor.css\";i:447;s:27:\"site-tagline/editor.min.css\";i:448;s:26:\"site-tagline/style-rtl.css\";i:449;s:30:\"site-tagline/style-rtl.min.css\";i:450;s:22:\"site-tagline/style.css\";i:451;s:26:\"site-tagline/style.min.css\";i:452;s:25:\"site-title/editor-rtl.css\";i:453;s:29:\"site-title/editor-rtl.min.css\";i:454;s:21:\"site-title/editor.css\";i:455;s:25:\"site-title/editor.min.css\";i:456;s:24:\"site-title/style-rtl.css\";i:457;s:28:\"site-title/style-rtl.min.css\";i:458;s:20:\"site-title/style.css\";i:459;s:24:\"site-title/style.min.css\";i:460;s:26:\"social-link/editor-rtl.css\";i:461;s:30:\"social-link/editor-rtl.min.css\";i:462;s:22:\"social-link/editor.css\";i:463;s:26:\"social-link/editor.min.css\";i:464;s:27:\"social-links/editor-rtl.css\";i:465;s:31:\"social-links/editor-rtl.min.css\";i:466;s:23:\"social-links/editor.css\";i:467;s:27:\"social-links/editor.min.css\";i:468;s:26:\"social-links/style-rtl.css\";i:469;s:30:\"social-links/style-rtl.min.css\";i:470;s:22:\"social-links/style.css\";i:471;s:26:\"social-links/style.min.css\";i:472;s:21:\"spacer/editor-rtl.css\";i:473;s:25:\"spacer/editor-rtl.min.css\";i:474;s:17:\"spacer/editor.css\";i:475;s:21:\"spacer/editor.min.css\";i:476;s:20:\"spacer/style-rtl.css\";i:477;s:24:\"spacer/style-rtl.min.css\";i:478;s:16:\"spacer/style.css\";i:479;s:20:\"spacer/style.min.css\";i:480;s:20:\"table/editor-rtl.css\";i:481;s:24:\"table/editor-rtl.min.css\";i:482;s:16:\"table/editor.css\";i:483;s:20:\"table/editor.min.css\";i:484;s:19:\"table/style-rtl.css\";i:485;s:23:\"table/style-rtl.min.css\";i:486;s:15:\"table/style.css\";i:487;s:19:\"table/style.min.css\";i:488;s:19:\"table/theme-rtl.css\";i:489;s:23:\"table/theme-rtl.min.css\";i:490;s:15:\"table/theme.css\";i:491;s:19:\"table/theme.min.css\";i:492;s:24:\"tag-cloud/editor-rtl.css\";i:493;s:28:\"tag-cloud/editor-rtl.min.css\";i:494;s:20:\"tag-cloud/editor.css\";i:495;s:24:\"tag-cloud/editor.min.css\";i:496;s:23:\"tag-cloud/style-rtl.css\";i:497;s:27:\"tag-cloud/style-rtl.min.css\";i:498;s:19:\"tag-cloud/style.css\";i:499;s:23:\"tag-cloud/style.min.css\";i:500;s:28:\"template-part/editor-rtl.css\";i:501;s:32:\"template-part/editor-rtl.min.css\";i:502;s:24:\"template-part/editor.css\";i:503;s:28:\"template-part/editor.min.css\";i:504;s:27:\"template-part/theme-rtl.css\";i:505;s:31:\"template-part/theme-rtl.min.css\";i:506;s:23:\"template-part/theme.css\";i:507;s:27:\"template-part/theme.min.css\";i:508;s:30:\"term-description/style-rtl.css\";i:509;s:34:\"term-description/style-rtl.min.css\";i:510;s:26:\"term-description/style.css\";i:511;s:30:\"term-description/style.min.css\";i:512;s:27:\"text-columns/editor-rtl.css\";i:513;s:31:\"text-columns/editor-rtl.min.css\";i:514;s:23:\"text-columns/editor.css\";i:515;s:27:\"text-columns/editor.min.css\";i:516;s:26:\"text-columns/style-rtl.css\";i:517;s:30:\"text-columns/style-rtl.min.css\";i:518;s:22:\"text-columns/style.css\";i:519;s:26:\"text-columns/style.min.css\";i:520;s:19:\"verse/style-rtl.css\";i:521;s:23:\"verse/style-rtl.min.css\";i:522;s:15:\"verse/style.css\";i:523;s:19:\"verse/style.min.css\";i:524;s:20:\"video/editor-rtl.css\";i:525;s:24:\"video/editor-rtl.min.css\";i:526;s:16:\"video/editor.css\";i:527;s:20:\"video/editor.min.css\";i:528;s:19:\"video/style-rtl.css\";i:529;s:23:\"video/style-rtl.min.css\";i:530;s:15:\"video/style.css\";i:531;s:19:\"video/style.min.css\";i:532;s:19:\"video/theme-rtl.css\";i:533;s:23:\"video/theme-rtl.min.css\";i:534;s:15:\"video/theme.css\";i:535;s:19:\"video/theme.min.css\";}}','on'),(124,'_transient_doing_cron','1764371989.4203000068664550781250','on'),(125,'theme_mods_twentytwentyfive','a:2:{s:18:\"custom_css_post_id\";i:-1;s:16:\"sidebars_widgets\";a:2:{s:4:\"time\";i:1764367183;s:4:\"data\";a:3:{s:19:\"wp_inactive_widgets\";a:0:{}s:9:\"sidebar-1\";a:3:{i:0;s:7:\"block-2\";i:1;s:7:\"block-3\";i:2;s:7:\"block-4\";}s:9:\"sidebar-2\";a:2:{i:0;s:7:\"block-5\";i:1;s:7:\"block-6\";}}}}','off'),(126,'_transient_wp_styles_for_blocks','a:2:{s:4:\"hash\";s:32:\"64ad95698215776f80fa1e80f2eb5417\";s:6:\"blocks\";a:7:{s:11:\"core/button\";s:0:\"\";s:14:\"core/site-logo\";s:0:\"\";s:18:\"core/post-template\";s:0:\"\";s:12:\"core/columns\";s:0:\"\";s:14:\"core/pullquote\";s:121:\":root :where(.wp-block-pullquote){font-size: clamp(0.984em, 0.984rem + ((1vw - 0.2em) * 0.938), 1.5em);line-height: 1.6;}\";s:15:\"core/site-title\";s:89:\":root :where(.wp-block-site-title){font-family: var(--wp--preset--font-family--display);}\";s:15:\"core/navigation\";s:86:\":root :where(.wp-block-navigation){font-family: var(--wp--preset--font-family--body);}\";}}','on'),(129,'category_children','a:0:{}','auto'),(132,'_site_transient_update_themes','O:8:\"stdClass\":5:{s:12:\"last_checked\";i:1764371969;s:7:\"checked\";a:4:{s:8:\"homeproz\";s:5:\"1.0.0\";s:16:\"twentytwentyfive\";s:3:\"1.3\";s:16:\"twentytwentyfour\";s:3:\"1.3\";s:17:\"twentytwentythree\";s:3:\"1.6\";}s:8:\"response\";a:0:{}s:9:\"no_update\";a:3:{s:16:\"twentytwentyfive\";a:6:{s:5:\"theme\";s:16:\"twentytwentyfive\";s:11:\"new_version\";s:3:\"1.3\";s:3:\"url\";s:46:\"https://wordpress.org/themes/twentytwentyfive/\";s:7:\"package\";s:62:\"https://downloads.wordpress.org/theme/twentytwentyfive.1.3.zip\";s:8:\"requires\";s:3:\"6.7\";s:12:\"requires_php\";s:3:\"7.2\";}s:16:\"twentytwentyfour\";a:6:{s:5:\"theme\";s:16:\"twentytwentyfour\";s:11:\"new_version\";s:3:\"1.3\";s:3:\"url\";s:46:\"https://wordpress.org/themes/twentytwentyfour/\";s:7:\"package\";s:62:\"https://downloads.wordpress.org/theme/twentytwentyfour.1.3.zip\";s:8:\"requires\";s:3:\"6.4\";s:12:\"requires_php\";s:3:\"7.0\";}s:17:\"twentytwentythree\";a:6:{s:5:\"theme\";s:17:\"twentytwentythree\";s:11:\"new_version\";s:3:\"1.6\";s:3:\"url\";s:47:\"https://wordpress.org/themes/twentytwentythree/\";s:7:\"package\";s:63:\"https://downloads.wordpress.org/theme/twentytwentythree.1.6.zip\";s:8:\"requires\";s:3:\"6.1\";s:12:\"requires_php\";s:3:\"5.6\";}}s:12:\"translations\";a:0:{}}','off'),(133,'current_theme','HomeProz','auto'),(134,'theme_switched','','auto'),(135,'theme_mods_homeproz','a:2:{s:18:\"nav_menu_locations\";a:1:{s:7:\"primary\";i:15;}s:18:\"custom_css_post_id\";i:-1;}','auto'),(141,'property_type_children','a:0:{}','auto'),(144,'property_status_children','a:0:{}','auto'),(150,'property_location_children','a:0:{}','auto'),(152,'_site_transient_update_core','O:8:\"stdClass\":4:{s:7:\"updates\";a:1:{i:0;O:8:\"stdClass\":10:{s:8:\"response\";s:6:\"latest\";s:8:\"download\";s:59:\"https://downloads.wordpress.org/release/wordpress-6.8.3.zip\";s:6:\"locale\";s:5:\"en_US\";s:8:\"packages\";O:8:\"stdClass\":5:{s:4:\"full\";s:59:\"https://downloads.wordpress.org/release/wordpress-6.8.3.zip\";s:10:\"no_content\";s:70:\"https://downloads.wordpress.org/release/wordpress-6.8.3-no-content.zip\";s:11:\"new_bundled\";s:71:\"https://downloads.wordpress.org/release/wordpress-6.8.3-new-bundled.zip\";s:7:\"partial\";s:0:\"\";s:8:\"rollback\";s:0:\"\";}s:7:\"current\";s:5:\"6.8.3\";s:7:\"version\";s:5:\"6.8.3\";s:11:\"php_version\";s:6:\"7.2.24\";s:13:\"mysql_version\";s:5:\"5.5.5\";s:11:\"new_bundled\";s:3:\"6.7\";s:15:\"partial_version\";s:0:\"\";}}s:12:\"last_checked\";i:1764371969;s:15:\"version_checked\";s:5:\"6.8.3\";s:12:\"translations\";a:0:{}}','off'),(156,'acf_first_activated_version','6.6.2','on'),(157,'acf_site_health','{\"event_first_activated\":1764369116,\"last_updated\":1764369116}','off'),(158,'_site_transient_timeout_wp_theme_files_patterns-2aae27f1f26ef7a6be8ebee5c8a6a86b','1764372438','off'),(159,'_site_transient_wp_theme_files_patterns-2aae27f1f26ef7a6be8ebee5c8a6a86b','a:2:{s:7:\"version\";s:5:\"1.0.0\";s:8:\"patterns\";a:0:{}}','off'),(162,'wpcf7','a:2:{s:7:\"version\";s:5:\"6.1.3\";s:13:\"bulk_validate\";a:4:{s:9:\"timestamp\";i:1764370639;s:7:\"version\";s:5:\"6.1.3\";s:11:\"count_valid\";i:1;s:13:\"count_invalid\";i:0;}}','auto'),(165,'_site_transient_timeout_theme_roots','1764373103','off'),(166,'_site_transient_theme_roots','a:4:{s:8:\"homeproz\";s:7:\"/themes\";s:16:\"twentytwentyfive\";s:7:\"/themes\";s:16:\"twentytwentyfour\";s:7:\"/themes\";s:17:\"twentytwentythree\";s:7:\"/themes\";}','off'),(167,'yoast_migrations_free','a:1:{s:7:\"version\";s:4:\"26.4\";}','auto'),(168,'wpseo','a:120:{s:8:\"tracking\";b:0;s:16:\"toggled_tracking\";b:0;s:22:\"license_server_version\";b:0;s:15:\"ms_defaults_set\";b:0;s:40:\"ignore_search_engines_discouraged_notice\";b:0;s:19:\"indexing_first_time\";b:1;s:16:\"indexing_started\";b:0;s:15:\"indexing_reason\";s:24:\"attachments_made_enabled\";s:29:\"indexables_indexing_completed\";b:0;s:13:\"index_now_key\";s:0:\"\";s:7:\"version\";s:4:\"26.4\";s:16:\"previous_version\";s:0:\"\";s:20:\"disableadvanced_meta\";b:1;s:30:\"enable_headless_rest_endpoints\";b:1;s:17:\"ryte_indexability\";b:0;s:11:\"baiduverify\";s:0:\"\";s:12:\"googleverify\";s:0:\"\";s:8:\"msverify\";s:0:\"\";s:12:\"yandexverify\";s:0:\"\";s:12:\"ahrefsverify\";s:0:\"\";s:9:\"site_type\";s:0:\"\";s:20:\"has_multiple_authors\";s:0:\"\";s:16:\"environment_type\";s:0:\"\";s:23:\"content_analysis_active\";b:1;s:23:\"keyword_analysis_active\";b:1;s:34:\"inclusive_language_analysis_active\";b:0;s:21:\"enable_admin_bar_menu\";b:1;s:26:\"enable_cornerstone_content\";b:1;s:18:\"enable_xml_sitemap\";b:1;s:24:\"enable_text_link_counter\";b:1;s:16:\"enable_index_now\";b:1;s:19:\"enable_ai_generator\";b:1;s:22:\"ai_enabled_pre_default\";b:0;s:22:\"show_onboarding_notice\";b:1;s:18:\"first_activated_on\";i:1764371307;s:13:\"myyoast-oauth\";b:0;s:26:\"semrush_integration_active\";b:1;s:14:\"semrush_tokens\";a:0:{}s:20:\"semrush_country_code\";s:2:\"us\";s:19:\"permalink_structure\";s:0:\"\";s:8:\"home_url\";s:0:\"\";s:18:\"dynamic_permalinks\";b:0;s:17:\"category_base_url\";s:0:\"\";s:12:\"tag_base_url\";s:0:\"\";s:21:\"custom_taxonomy_slugs\";a:0:{}s:29:\"enable_enhanced_slack_sharing\";b:1;s:23:\"enable_metabox_insights\";b:1;s:23:\"enable_link_suggestions\";b:1;s:26:\"algolia_integration_active\";b:0;s:14:\"import_cursors\";a:0:{}s:13:\"workouts_data\";a:1:{s:13:\"configuration\";a:1:{s:13:\"finishedSteps\";a:0:{}}}s:28:\"configuration_finished_steps\";a:0:{}s:36:\"dismiss_configuration_workout_notice\";b:0;s:34:\"dismiss_premium_deactivated_notice\";b:0;s:19:\"importing_completed\";a:0:{}s:26:\"wincher_integration_active\";b:1;s:14:\"wincher_tokens\";a:0:{}s:36:\"wincher_automatically_add_keyphrases\";b:0;s:18:\"wincher_website_id\";s:0:\"\";s:18:\"first_time_install\";b:1;s:34:\"should_redirect_after_install_free\";b:0;s:34:\"activation_redirect_timestamp_free\";i:1764371307;s:18:\"remove_feed_global\";b:0;s:27:\"remove_feed_global_comments\";b:0;s:25:\"remove_feed_post_comments\";b:0;s:19:\"remove_feed_authors\";b:0;s:22:\"remove_feed_categories\";b:0;s:16:\"remove_feed_tags\";b:0;s:29:\"remove_feed_custom_taxonomies\";b:0;s:22:\"remove_feed_post_types\";b:0;s:18:\"remove_feed_search\";b:0;s:21:\"remove_atom_rdf_feeds\";b:0;s:17:\"remove_shortlinks\";b:0;s:21:\"remove_rest_api_links\";b:0;s:20:\"remove_rsd_wlw_links\";b:0;s:19:\"remove_oembed_links\";b:0;s:16:\"remove_generator\";b:0;s:20:\"remove_emoji_scripts\";b:0;s:24:\"remove_powered_by_header\";b:0;s:22:\"remove_pingback_header\";b:0;s:28:\"clean_campaign_tracking_urls\";b:0;s:16:\"clean_permalinks\";b:0;s:32:\"clean_permalinks_extra_variables\";s:0:\"\";s:14:\"search_cleanup\";b:0;s:20:\"search_cleanup_emoji\";b:0;s:23:\"search_cleanup_patterns\";b:0;s:22:\"search_character_limit\";i:50;s:20:\"deny_search_crawling\";b:0;s:21:\"deny_wp_json_crawling\";b:0;s:20:\"deny_adsbot_crawling\";b:0;s:19:\"deny_ccbot_crawling\";b:0;s:29:\"deny_google_extended_crawling\";b:0;s:20:\"deny_gptbot_crawling\";b:0;s:27:\"redirect_search_pretty_urls\";b:0;s:29:\"least_readability_ignore_list\";a:0:{}s:27:\"least_seo_score_ignore_list\";a:0:{}s:23:\"most_linked_ignore_list\";a:0:{}s:24:\"least_linked_ignore_list\";a:0:{}s:28:\"indexables_page_reading_list\";a:5:{i:0;b:0;i:1;b:0;i:2;b:0;i:3;b:0;i:4;b:0;}s:25:\"indexables_overview_state\";s:21:\"dashboard-not-visited\";s:28:\"last_known_public_post_types\";a:0:{}s:28:\"last_known_public_taxonomies\";a:0:{}s:23:\"last_known_no_unindexed\";a:0:{}s:14:\"new_post_types\";a:0:{}s:14:\"new_taxonomies\";a:0:{}s:34:\"show_new_content_type_notification\";b:0;s:44:\"site_kit_configuration_permanently_dismissed\";b:0;s:18:\"site_kit_connected\";b:0;s:37:\"site_kit_tracking_setup_widget_loaded\";s:2:\"no\";s:41:\"site_kit_tracking_first_interaction_stage\";s:0:\"\";s:40:\"site_kit_tracking_last_interaction_stage\";s:0:\"\";s:52:\"site_kit_tracking_setup_widget_temporarily_dismissed\";s:2:\"no\";s:52:\"site_kit_tracking_setup_widget_permanently_dismissed\";s:2:\"no\";s:31:\"google_site_kit_feature_enabled\";b:0;s:25:\"ai_free_sparks_started_on\";N;s:15:\"enable_llms_txt\";b:0;s:15:\"last_updated_on\";b:0;s:17:\"default_seo_title\";a:0:{}s:21:\"default_seo_meta_desc\";a:0:{}s:18:\"first_activated_by\";i:0;}','auto'),(169,'wpseo_titles','a:173:{s:17:\"forcerewritetitle\";b:0;s:9:\"separator\";s:7:\"sc-dash\";s:16:\"title-home-wpseo\";s:47:\"HomeProz Real Estate | Albert Lea MN Properties\";s:18:\"title-author-wpseo\";s:41:\"%%name%%, Author at %%sitename%% %%page%%\";s:19:\"title-archive-wpseo\";s:38:\"%%date%% %%page%% %%sep%% %%sitename%%\";s:18:\"title-search-wpseo\";s:63:\"You searched for %%searchphrase%% %%page%% %%sep%% %%sitename%%\";s:15:\"title-404-wpseo\";s:35:\"Page not found %%sep%% %%sitename%%\";s:25:\"social-title-author-wpseo\";s:8:\"%%name%%\";s:26:\"social-title-archive-wpseo\";s:8:\"%%date%%\";s:31:\"social-description-author-wpseo\";s:0:\"\";s:32:\"social-description-archive-wpseo\";s:0:\"\";s:29:\"social-image-url-author-wpseo\";s:0:\"\";s:30:\"social-image-url-archive-wpseo\";s:0:\"\";s:28:\"social-image-id-author-wpseo\";i:0;s:29:\"social-image-id-archive-wpseo\";i:0;s:19:\"metadesc-home-wpseo\";s:120:\"HomeProz Real Estate - Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.\";s:21:\"metadesc-author-wpseo\";s:0:\"\";s:22:\"metadesc-archive-wpseo\";s:0:\"\";s:9:\"rssbefore\";s:0:\"\";s:8:\"rssafter\";s:53:\"The post %%POSTLINK%% appeared first on %%BLOGLINK%%.\";s:20:\"noindex-author-wpseo\";b:0;s:28:\"noindex-author-noposts-wpseo\";b:0;s:21:\"noindex-archive-wpseo\";b:0;s:14:\"disable-author\";b:0;s:12:\"disable-date\";b:0;s:19:\"disable-post_format\";b:0;s:18:\"disable-attachment\";b:0;s:20:\"breadcrumbs-404crumb\";s:25:\"Error 404: Page not found\";s:29:\"breadcrumbs-display-blog-page\";b:0;s:20:\"breadcrumbs-boldlast\";b:0;s:25:\"breadcrumbs-archiveprefix\";s:12:\"Archives for\";s:18:\"breadcrumbs-enable\";b:0;s:16:\"breadcrumbs-home\";s:4:\"Home\";s:18:\"breadcrumbs-prefix\";s:0:\"\";s:24:\"breadcrumbs-searchprefix\";s:16:\"You searched for\";s:15:\"breadcrumbs-sep\";s:2:\"»\";s:12:\"website_name\";s:0:\"\";s:11:\"person_name\";s:0:\"\";s:11:\"person_logo\";s:0:\"\";s:22:\"alternate_website_name\";s:0:\"\";s:12:\"company_logo\";s:0:\"\";s:12:\"company_name\";s:0:\"\";s:22:\"company_alternate_name\";s:0:\"\";s:17:\"company_or_person\";s:7:\"company\";s:25:\"company_or_person_user_id\";b:0;s:17:\"stripcategorybase\";b:0;s:26:\"open_graph_frontpage_title\";s:12:\"%%sitename%%\";s:25:\"open_graph_frontpage_desc\";s:0:\"\";s:26:\"open_graph_frontpage_image\";s:0:\"\";s:24:\"publishing_principles_id\";i:0;s:25:\"ownership_funding_info_id\";i:0;s:29:\"actionable_feedback_policy_id\";i:0;s:21:\"corrections_policy_id\";i:0;s:16:\"ethics_policy_id\";i:0;s:19:\"diversity_policy_id\";i:0;s:28:\"diversity_staffing_report_id\";i:0;s:15:\"org-description\";s:0:\"\";s:9:\"org-email\";s:0:\"\";s:9:\"org-phone\";s:0:\"\";s:14:\"org-legal-name\";s:0:\"\";s:17:\"org-founding-date\";s:0:\"\";s:20:\"org-number-employees\";s:0:\"\";s:10:\"org-vat-id\";s:0:\"\";s:10:\"org-tax-id\";s:0:\"\";s:7:\"org-iso\";s:0:\"\";s:8:\"org-duns\";s:0:\"\";s:11:\"org-leicode\";s:0:\"\";s:9:\"org-naics\";s:0:\"\";s:10:\"title-post\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:13:\"metadesc-post\";s:0:\"\";s:12:\"noindex-post\";b:0;s:23:\"display-metabox-pt-post\";b:0;s:23:\"post_types-post-maintax\";i:0;s:21:\"schema-page-type-post\";s:7:\"WebPage\";s:24:\"schema-article-type-post\";s:7:\"Article\";s:17:\"social-title-post\";s:9:\"%%title%%\";s:23:\"social-description-post\";s:0:\"\";s:21:\"social-image-url-post\";s:0:\"\";s:20:\"social-image-id-post\";i:0;s:10:\"title-page\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:13:\"metadesc-page\";s:0:\"\";s:12:\"noindex-page\";b:0;s:23:\"display-metabox-pt-page\";b:0;s:23:\"post_types-page-maintax\";i:0;s:21:\"schema-page-type-page\";s:7:\"WebPage\";s:24:\"schema-article-type-page\";s:4:\"None\";s:17:\"social-title-page\";s:9:\"%%title%%\";s:23:\"social-description-page\";s:0:\"\";s:21:\"social-image-url-page\";s:0:\"\";s:20:\"social-image-id-page\";i:0;s:16:\"title-attachment\";s:39:\"%%title%% %%page%% %%sep%% %%sitename%%\";s:19:\"metadesc-attachment\";s:0:\"\";s:18:\"noindex-attachment\";b:0;s:29:\"display-metabox-pt-attachment\";b:0;s:29:\"post_types-attachment-maintax\";i:0;s:27:\"schema-page-type-attachment\";s:7:\"WebPage\";s:30:\"schema-article-type-attachment\";s:4:\"None\";s:18:\"title-tax-category\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:21:\"metadesc-tax-category\";s:0:\"\";s:28:\"display-metabox-tax-category\";b:0;s:20:\"noindex-tax-category\";b:0;s:25:\"social-title-tax-category\";s:23:\"%%term_title%% Archives\";s:31:\"social-description-tax-category\";s:0:\"\";s:29:\"social-image-url-tax-category\";s:0:\"\";s:28:\"social-image-id-tax-category\";i:0;s:26:\"taxonomy-category-ptparent\";i:0;s:18:\"title-tax-post_tag\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:21:\"metadesc-tax-post_tag\";s:0:\"\";s:28:\"display-metabox-tax-post_tag\";b:0;s:20:\"noindex-tax-post_tag\";b:0;s:25:\"social-title-tax-post_tag\";s:23:\"%%term_title%% Archives\";s:31:\"social-description-tax-post_tag\";s:0:\"\";s:29:\"social-image-url-tax-post_tag\";s:0:\"\";s:28:\"social-image-id-tax-post_tag\";i:0;s:26:\"taxonomy-post_tag-ptparent\";i:0;s:21:\"title-tax-post_format\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:24:\"metadesc-tax-post_format\";s:0:\"\";s:31:\"display-metabox-tax-post_format\";b:0;s:23:\"noindex-tax-post_format\";b:0;s:28:\"social-title-tax-post_format\";s:23:\"%%term_title%% Archives\";s:34:\"social-description-tax-post_format\";s:0:\"\";s:32:\"social-image-url-tax-post_format\";s:0:\"\";s:31:\"social-image-id-tax-post_format\";i:0;s:29:\"taxonomy-post_format-ptparent\";i:0;s:14:\"title-property\";s:30:\"%%title%% %%sep%% %%sitename%%\";s:17:\"metadesc-property\";s:106:\"View property details, photos, and features for %%title%%. Contact HomeProz Real Estate in Albert Lea, MN.\";s:16:\"noindex-property\";b:0;s:27:\"display-metabox-pt-property\";b:0;s:27:\"post_types-property-maintax\";i:0;s:25:\"schema-page-type-property\";s:7:\"WebPage\";s:28:\"schema-article-type-property\";s:4:\"None\";s:21:\"social-title-property\";s:9:\"%%title%%\";s:27:\"social-description-property\";s:0:\"\";s:25:\"social-image-url-property\";s:0:\"\";s:24:\"social-image-id-property\";i:0;s:24:\"title-ptarchive-property\";s:49:\"Properties For Sale %%page%% %%sep%% %%sitename%%\";s:27:\"metadesc-ptarchive-property\";s:126:\"Browse all properties for sale in Albert Lea, Minnesota and surrounding areas. Find your dream home with HomeProz Real Estate.\";s:26:\"bctitle-ptarchive-property\";s:0:\"\";s:26:\"noindex-ptarchive-property\";b:0;s:31:\"social-title-ptarchive-property\";s:21:\"%%pt_plural%% Archive\";s:37:\"social-description-ptarchive-property\";s:0:\"\";s:35:\"social-image-url-ptarchive-property\";s:0:\"\";s:34:\"social-image-id-ptarchive-property\";i:0;s:23:\"title-tax-property_type\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:26:\"metadesc-tax-property_type\";s:0:\"\";s:33:\"display-metabox-tax-property_type\";b:0;s:25:\"noindex-tax-property_type\";b:0;s:30:\"social-title-tax-property_type\";s:23:\"%%term_title%% Archives\";s:36:\"social-description-tax-property_type\";s:0:\"\";s:34:\"social-image-url-tax-property_type\";s:0:\"\";s:33:\"social-image-id-tax-property_type\";i:0;s:31:\"taxonomy-property_type-ptparent\";i:0;s:25:\"title-tax-property_status\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:28:\"metadesc-tax-property_status\";s:0:\"\";s:35:\"display-metabox-tax-property_status\";b:0;s:27:\"noindex-tax-property_status\";b:0;s:32:\"social-title-tax-property_status\";s:23:\"%%term_title%% Archives\";s:38:\"social-description-tax-property_status\";s:0:\"\";s:36:\"social-image-url-tax-property_status\";s:0:\"\";s:35:\"social-image-id-tax-property_status\";i:0;s:33:\"taxonomy-property_status-ptparent\";i:0;s:27:\"title-tax-property_location\";s:53:\"%%term_title%% Archives %%page%% %%sep%% %%sitename%%\";s:30:\"metadesc-tax-property_location\";s:0:\"\";s:37:\"display-metabox-tax-property_location\";b:0;s:29:\"noindex-tax-property_location\";b:0;s:34:\"social-title-tax-property_location\";s:23:\"%%term_title%% Archives\";s:40:\"social-description-tax-property_location\";s:0:\"\";s:38:\"social-image-url-tax-property_location\";s:0:\"\";s:37:\"social-image-id-tax-property_location\";i:0;s:35:\"taxonomy-property_location-ptparent\";i:0;s:14:\"person_logo_id\";i:0;s:15:\"company_logo_id\";i:0;s:29:\"open_graph_frontpage_image_id\";i:0;}','auto'),(170,'wpseo_social','a:20:{s:13:\"facebook_site\";s:0:\"\";s:13:\"instagram_url\";s:0:\"\";s:12:\"linkedin_url\";s:0:\"\";s:11:\"myspace_url\";s:0:\"\";s:16:\"og_default_image\";s:0:\"\";s:19:\"og_default_image_id\";s:0:\"\";s:18:\"og_frontpage_title\";s:47:\"HomeProz Real Estate | Albert Lea MN Properties\";s:17:\"og_frontpage_desc\";s:97:\"Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.\";s:18:\"og_frontpage_image\";s:0:\"\";s:21:\"og_frontpage_image_id\";s:0:\"\";s:9:\"opengraph\";b:1;s:13:\"pinterest_url\";s:0:\"\";s:15:\"pinterestverify\";s:0:\"\";s:7:\"twitter\";b:1;s:12:\"twitter_site\";s:0:\"\";s:17:\"twitter_card_type\";s:19:\"summary_large_image\";s:11:\"youtube_url\";s:0:\"\";s:13:\"wikipedia_url\";s:0:\"\";s:17:\"other_social_urls\";a:0:{}s:12:\"mastodon_url\";s:0:\"\";}','auto'),(171,'wpseo_llmstxt','a:7:{s:23:\"llms_txt_selection_mode\";s:4:\"auto\";s:13:\"about_us_page\";i:0;s:12:\"contact_page\";i:0;s:10:\"terms_page\";i:0;s:19:\"privacy_policy_page\";i:0;s:9:\"shop_page\";i:0;s:20:\"other_included_pages\";a:0:{}}','auto'),(174,'webpc_is_new_installation','1','auto'),(175,'webpc_notice_thanks','1765581302','auto'),(176,'webpc_notice_pro_version','1764976502','auto'),(177,'webpc_stats_installation_date','2025-11-28 23:15:02','auto'),(178,'webpc_stats_first_version','6.3.2','auto'),(181,'aio_wp_security_configs','a:47:{s:28:\"aiowps_enable_login_lockdown\";s:1:\"1\";s:28:\"aiowps_allow_unlock_requests\";s:1:\"1\";s:25:\"aiowps_max_login_attempts\";s:2:\"10\";s:24:\"aiowps_retry_time_period\";s:1:\"5\";s:26:\"aiowps_lockout_time_length\";s:2:\"30\";s:30:\"aiowps_max_lockout_time_length\";s:2:\"60\";s:28:\"aiowps_set_generic_login_msg\";s:1:\"1\";s:26:\"aiowps_enable_email_notify\";s:1:\"1\";s:20:\"aiowps_email_address\";s:16:\"brian@hanson.xyz\";s:39:\"aiowps_enable_invalid_username_lockdown\";s:0:\"\";s:43:\"aiowps_instantly_lockout_specific_usernames\";a:3:{i:0;s:5:\"admin\";i:1;s:13:\"administrator\";i:2;s:4:\"test\";}s:36:\"aiowps_remove_wp_generator_meta_info\";s:1:\"1\";s:27:\"aiowps_disable_file_editing\";s:1:\"1\";s:37:\"aiowps_prevent_default_wp_file_access\";s:1:\"1\";s:28:\"aiowps_enable_basic_firewall\";s:1:\"1\";s:27:\"aiowps_max_file_upload_size\";i:100;s:38:\"aiowps_disable_xmlrpc_pingback_methods\";s:1:\"1\";s:34:\"aiowps_block_debug_log_file_access\";s:1:\"1\";s:26:\"aiowps_disable_index_views\";s:1:\"1\";s:32:\"aiowps_prevent_users_enumeration\";s:1:\"1\";s:42:\"aiowps_disallow_unauthorized_rest_requests\";s:1:\"1\";s:40:\"aiowps_prevent_site_display_inside_frame\";s:1:\"1\";s:28:\"aiowps_enable_login_honeypot\";s:1:\"1\";s:35:\"aiowps_disable_application_password\";s:0:\"\";s:30:\"aiowps_enable_spambot_blocking\";s:1:\"1\";s:29:\"aiowps_enable_comment_captcha\";s:0:\"\";s:25:\"aiowps_enable_404_logging\";s:1:\"1\";s:28:\"aiowps_enable_404_IP_lockout\";s:0:\"\";s:36:\"aiowps_on_uninstall_delete_db_tables\";s:1:\"1\";s:34:\"aiowps_on_uninstall_delete_configs\";s:1:\"1\";s:31:\"aiowps_enable_rename_login_page\";s:0:\"\";s:43:\"aiowps_enable_brute_force_attack_prevention\";s:0:\"\";s:19:\"aiowps_site_lockout\";s:0:\"\";s:19:\"aiowps_enable_debug\";s:0:\"\";s:22:\"aiowps_default_captcha\";s:0:\"\";s:27:\"aiowps_enable_login_captcha\";s:0:\"\";s:35:\"aiowps_enable_registration_honeypot\";s:1:\"1\";s:26:\"aiowps_enable_blacklisting\";s:0:\"\";s:25:\"aiowps_enable_5g_firewall\";s:0:\"\";s:25:\"aiowps_enable_6g_firewall\";s:0:\"\";s:26:\"aiowps_enable_custom_rules\";s:0:\"\";s:25:\"aiowps_prevent_hotlinking\";s:0:\"\";s:22:\"aiowps_copy_protection\";s:0:\"\";s:33:\"aiowps_disable_rss_and_atom_feeds\";s:0:\"\";s:27:\"aiowps_enable_forced_logout\";s:0:\"\";s:32:\"aiowps_enable_automated_fcd_scan\";s:0:\"\";s:12:\"installed-at\";i:1764371970;}','auto'),(182,'aios_antibot_key_map_info','a:3:{i:0;a:2:{i:0;a:2:{i:0;s:8:\"dz7zzn8y\";i:1;s:12:\"ewbnnm47eqe7\";}i:1;a:2:{i:0;s:8:\"ovzo7jga\";i:1;s:12:\"zojsx526xhvu\";}}i:1;a:2:{i:0;a:2:{i:0;s:8:\"xdxz27wr\";i:1;s:12:\"xeft4p3ib2l1\";}i:1;a:2:{i:0;s:8:\"oth0fymk\";i:1;s:12:\"bjcyxlmg09pv\";}}i:2;i:1764720000;}','off'),(183,'aiowpsec_db_version','2.1.4','auto'),(184,'aiowpsec_firewall_version','1.0.8','auto');
/*!40000 ALTER TABLE `wp_options` ENABLE KEYS */;
UNLOCK TABLES;
@@ -466,7 +721,7 @@ CREATE TABLE `wp_yoast_indexable` (
KEY `subpages` (`post_parent`,`object_type`,`post_status`,`object_id`),
KEY `prominent_words` (`prominent_words_version`,`object_type`,`object_sub_type`,`post_status`),
KEY `published_sitemap_index` (`object_published_at`,`is_robots_noindex`,`object_type`,`object_sub_type`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -475,7 +730,7 @@ CREATE TABLE `wp_yoast_indexable` (
LOCK TABLES `wp_yoast_indexable` WRITE;
/*!40000 ALTER TABLE `wp_yoast_indexable` DISABLE KEYS */;
-INSERT INTO `wp_yoast_indexable` VALUES (1,NULL,NULL,NULL,'date-archive',NULL,NULL,NULL,'%%date%% %%page%% %%sep%% %%sitename%%','',NULL,NULL,1,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,1,NULL,NULL,NULL),(2,'https://homeproz.dev.hanson.xyz/properties/','43:fe19fb00353a16a1e0f990a64c3584a1',NULL,'post-type-archive','property',NULL,NULL,'Properties For Sale %%page%% %%sep%% %%sitename%%','Browse all properties for sale in Albert Lea, Minnesota and surrounding areas. Find your dream home with HomeProz Real Estate.','Properties',NULL,1,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,2,'2025-11-28 23:08:35','2025-11-28 22:33:26',NULL),(3,'https://homeproz.dev.hanson.xyz/','32:69cc765724b94f94108e52a02a04fa6f',NULL,'home-page',NULL,NULL,NULL,'HomeProz Real Estate | Albert Lea MN Properties','HomeProz Real Estate - Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.','Home',NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,'%%sitename%%','','','0',NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,2,'2025-11-28 23:08:35','2025-11-28 21:02:25',NULL);
+INSERT INTO `wp_yoast_indexable` VALUES (1,NULL,NULL,NULL,'date-archive',NULL,NULL,NULL,'%%date%% %%page%% %%sep%% %%sitename%%','',NULL,NULL,1,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,1,NULL,NULL,NULL),(2,'https://homeproz.dev.hanson.xyz/properties/','43:fe19fb00353a16a1e0f990a64c3584a1',NULL,'post-type-archive','property',NULL,NULL,'Properties For Sale %%page%% %%sep%% %%sitename%%','Browse all properties for sale in Albert Lea, Minnesota and surrounding areas. Find your dream home with HomeProz Real Estate.','Properties',NULL,1,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,2,'2025-11-28 23:08:35','2025-11-28 22:33:26',NULL),(3,'https://homeproz.dev.hanson.xyz/','32:69cc765724b94f94108e52a02a04fa6f',NULL,'home-page',NULL,NULL,NULL,'HomeProz Real Estate | Albert Lea MN Properties','HomeProz Real Estate - Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.','Home',NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,0,0,NULL,NULL,NULL,NULL,NULL,'%%sitename%%','','','0',NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:08:35','2025-11-29 05:08:35',1,NULL,NULL,NULL,NULL,0,NULL,2,'2025-11-28 23:08:35','2025-11-28 21:02:25',NULL),(4,'https://homeproz.dev.hanson.xyz/','32:69cc765724b94f94108e52a02a04fa6f',10,'post','page',0,0,NULL,NULL,'Home','publish',NULL,0,NULL,NULL,NULL,NULL,NULL,0,0,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-28 23:18:48','2025-11-29 05:18:48',1,NULL,NULL,NULL,NULL,0,NULL,2,'2025-11-28 22:57:59','2025-11-28 22:57:59',0);
/*!40000 ALTER TABLE `wp_yoast_indexable` ENABLE KEYS */;
UNLOCK TABLES;
@@ -504,6 +759,7 @@ CREATE TABLE `wp_yoast_indexable_hierarchy` (
LOCK TABLES `wp_yoast_indexable_hierarchy` WRITE;
/*!40000 ALTER TABLE `wp_yoast_indexable_hierarchy` DISABLE KEYS */;
+INSERT INTO `wp_yoast_indexable_hierarchy` VALUES (4,0,0,1);
/*!40000 ALTER TABLE `wp_yoast_indexable_hierarchy` ENABLE KEYS */;
UNLOCK TABLES;
@@ -606,4 +862,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2025-11-28 17:16:24
+-- Dump completed on 2025-11-28 17:19:54
diff --git a/wp-content/aiowps_backups/index.html b/wp-content/aiowps_backups/index.html
new file mode 100644
index 00000000..e69de29b
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/SECURITY.md b/wp-content/plugins/all-in-one-wp-security-and-firewall/SECURITY.md
new file mode 100755
index 00000000..1a912378
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/SECURITY.md
@@ -0,0 +1,19 @@
+If you believe that you have found a security issue associated with the current release of this plugin, then please report it to the email address with local part security-reports-only and the domain updraftplus.com. If receipt of the email is not acknowledged within 3 working days, then you can try again and also use the inquiry form on the plugin's website.
+
+Do not send emails on any other subject to this address. They will not be acknowledged, regardless of whether they contain pleas to do otherwise; there are inquiry forms and support forums available which are linked within the plugin and easy to find on the plugin website.
+
+Please include as much of the information listed below as you can to help us better understand and resolve the issue:
+
+* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
+* Affected version(s)
+* Impact of the issue, including how an attacker might exploit the issue
+* Step-by-step instructions to reproduce the issue
+* The location of the affected code
+* Full paths of source file(s) related to the manifestation of the issue
+* Any special configuration required to reproduce the issue
+* Any log files that are related to this issue (if possible)
+* Proof-of-concept or exploit code (if possible)
+
+This information will help us triage your report more quickly.
+
+Thank you!
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-ajax-data-table.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-ajax-data-table.php
new file mode 100755
index 00000000..efd8d1f4
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-ajax-data-table.php
@@ -0,0 +1,1486 @@
+get_column_info().
+ *
+ * @since 4.1.0
+ * @var array
+ */
+ protected $_column_headers;
+
+ /**
+ * {@internal Missing Summary}
+ *
+ * @var array
+ */
+ protected $compat_fields = array('_args', '_pagination_args', 'screen', '_actions', '_pagination');
+
+ /**
+ * {@internal Missing Summary}
+ *
+ * @var array
+ */
+ protected $compat_methods = array(
+ 'set_pagination_args',
+ 'get_views',
+ 'get_bulk_actions',
+ 'bulk_actions',
+ 'row_actions',
+ 'months_dropdown',
+ 'view_switcher',
+ 'comments_bubble',
+ 'get_items_per_page',
+ 'pagination',
+ 'get_sortable_columns',
+ 'get_column_info',
+ 'get_table_classes',
+ 'display_tablenav',
+ 'extra_tablenav',
+ 'single_row_columns',
+ );
+
+ /**
+ * Constructor.
+ *
+ * The child class should call this constructor from its own constructor to override
+ * the default $args.
+ *
+ * @since 3.1.0
+ *
+ * @param array|string $args {
+ * Array or string of arguments.
+ *
+ * @type string $plural Plural value used for labels and the objects being listed.
+ * This affects things such as CSS class-names and nonces used
+ * in the list table, e.g. 'posts'. Default empty.
+ * @type string $singular Singular label for an object being listed, e.g. 'post'.
+ * Default empty
+ * @type bool $ajax Whether the list table supports Ajax. This includes loading
+ * and sorting data, for example. If true, the class will call
+ * the js_vars() method in the footer to provide variables
+ * to any scripts handling Ajax events. Default false.
+ * @type string $screen String containing the hook name used to determine the current
+ * screen. If left null, the current screen will be automatically set.
+ * Default null.
+ * }
+ */
+ public function __construct($args = array()) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'plural' => '',
+ 'singular' => '',
+ 'ajax' => false,
+ 'screen' => null,
+ )
+ );
+
+ $this->screen = convert_to_screen($args['screen']);
+
+ add_filter("manage_{$this->screen->id}_columns", array($this, 'get_columns'), 0);
+
+ if (!$args['plural']) {
+ $args['plural'] = $this->screen->base;
+ }
+
+ $args['plural'] = sanitize_key($args['plural']);
+ $args['singular'] = sanitize_key($args['singular']);
+
+ $this->_args = $args;
+
+ if ($args['ajax']) {
+ // wp_enqueue_script('list-table');
+ add_action('admin_footer', array($this, 'js_vars'));
+ }
+
+ if (empty($this->modes)) {
+ $this->modes = array(
+ 'list' => __('List view', 'all-in-one-wp-security-and-firewall'),
+ 'excerpt' => __('Excerpt view', 'all-in-one-wp-security-and-firewall'),
+ );
+ }
+ }
+
+ /**
+ * Make private properties readable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name - Property to get.
+ * @return mixed Property.
+ */
+ public function __get($name) {
+ if (in_array($name, $this->compat_fields)) {
+ return $this->$name;
+ }
+ }
+
+ /**
+ * Make private properties settable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name - Property to check if set.
+ * @param mixed $value - Property value.
+ * @return mixed Newly-set property.
+ */
+ public function __set($name, $value) {
+ if (in_array($name, $this->compat_fields)) {
+ return $this->$name = $value;
+ }
+ }
+
+ /**
+ * Make private properties checkable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name - Property to check if set.
+ * @return bool Whether the property is set.
+ */
+ public function __isset($name) {
+ if (in_array($name, $this->compat_fields)) {
+ return isset($this->$name);
+ }
+ }
+
+ /**
+ * Make private properties un-settable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name - Property to unset.
+ */
+ public function __unset($name) {
+ if (in_array($name, $this->compat_fields)) {
+ unset($this->$name);
+ }
+ }
+
+ /**
+ * Make private/protected methods readable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name - Method to call.
+ * @param array $arguments - Arguments to pass when calling.
+ * @return mixed|bool Return value of the callback, false otherwise.
+ */
+ public function __call($name, $arguments) {
+ if (in_array($name, $this->compat_methods)) {
+ return call_user_func_array(array($this, $name), $arguments);
+ }
+ return false;
+ }
+
+ /**
+ * Checks the current user's permissions
+ *
+ * @since 3.1.0
+ * @abstract
+ */
+ public function ajax_user_can() {
+ die('function AIOWPSecurity_List_Table::ajax_user_can() must be over-ridden in a sub-class.');
+ }
+
+ /**
+ * Prepares the list of items for displaying.
+ *
+ * @uses AIOWPSecurity_List_Table::set_pagination_args()
+ *
+ * @since 3.1.0
+ * @abstract
+ */
+ public function prepare_items() {
+ die('function AIOWPSecurity_List_Table::prepare_items() must be over-ridden in a sub-class.');
+ }
+
+ /**
+ * An internal method that sets all the necessary pagination arguments
+ *
+ * @since 3.1.0
+ *
+ * @param array|string $args - Array or string of arguments with information about the pagination.
+ */
+ protected function set_pagination_args($args) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'total_items' => 0,
+ 'total_pages' => 0,
+ 'per_page' => 0,
+ )
+ );
+
+ if (!$args['total_pages'] && $args['per_page'] > 0) {
+ $args['total_pages'] = ceil($args['total_items'] / $args['per_page']);
+ }
+
+ // Redirect if page number is invalid and headers are not already sent.
+ if (!headers_sent() && !wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages']) {
+ wp_redirect(add_query_arg('paged', $args['total_pages']));
+ exit;
+ }
+
+ $this->_pagination_args = $args;
+ }
+
+ /**
+ * Access the pagination args.
+ *
+ * @since 3.1.0
+ *
+ * @param string $key - Pagination argument to retrieve. Common values include 'total_items',
+ * 'total_pages', 'per_page', or 'infinite_scroll'.
+ * @return int Number of items that correspond to the given pagination argument.
+ */
+ public function get_pagination_arg($key) {
+ if ('page' === $key) {
+ return $this->get_pagenum();
+ }
+
+ if (isset($this->_pagination_args[$key])) {
+ return $this->_pagination_args[$key];
+ }
+ }
+
+ /**
+ * Whether the table has items to display or not
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ public function has_items() {
+ return !empty($this->items);
+ }
+
+ /**
+ * Message to be displayed when there are no items
+ *
+ * @since 3.1.0
+ */
+ public function no_items() {
+ esc_html_e('No items found.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ /**
+ * Displays the search box.
+ *
+ * @since 3.1.0
+ *
+ * @param string $text - The 'submit' button label.
+ * @param string $input_id - ID attribute value for the search input field.
+ */
+ public function search_box($text, $input_id) {
+ if (empty($this->_args['data']['s']) && !$this->has_items()) {
+ return;
+ }
+
+ $input_id = $input_id . '-search-input';
+
+ if (!empty($this->_args['data']['orderby'])) {
+ echo '';
+ }
+ if (!empty($this->_args['data']['order'])) {
+ echo '';
+ }
+ if (!empty($this->_args['data']['post_mime_type'])) {
+ echo '';
+ }
+ if (!empty($this->_args['data']['detached'])) {
+ 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 "
";
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.
+ echo call_user_func(array($this, 'column_' . $column_name), $item);
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.
+ echo $this->handle_row_actions($item, $column_name, $primary);
+ echo '
';
+ } else {
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.
+ echo "
";
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.
+ echo $this->column_default($item, $column_name);
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.
+ echo $this->handle_row_actions($item, $column_name, $primary);
+ echo '
';
+ }
+ }
+ }
+
+ /**
+ * Generates and display row actions links for the list table.
+ *
+ * @since 4.3.0
+ *
+ * @param object $item - The item being acted upon.
+ * @param string $column_name - Current column name.
+ * @param string $primary - Primary column name.
+ * @return string The row actions HTML, or an empty string if the current column is the primary column.
+ */
+ protected function handle_row_actions($item, $column_name, $primary) {
+ return $column_name === $primary ? '' : '';
+ }
+
+
+ /**
+ * Handle an incoming ajax request (called from admin-ajax.php)
+ *
+ * @param bool $return_instead_of_echo - Whether to return data or die() with data.
+ *
+ * @since 3.1.0
+ */
+ public function ajax_response($return_instead_of_echo = false) {
+ $this->prepare_items(false);
+
+ ob_start();
+ if (!empty($this->_args['data']['no_placeholder'])) {
+ $this->display_rows();
+ } else {
+ $this->display_rows_or_placeholder();
+ }
+
+ $rows = ob_get_clean();
+
+ ob_start();
+ $this->print_column_headers(true);
+ $headers = ob_get_clean();
+
+ ob_start();
+ $this->pagination('top');
+ $pagination_top = ob_get_clean();
+
+ ob_start();
+ $this->pagination('bottom');
+ $pagination_bottom = ob_get_clean();
+
+ $response = array(
+ 'rows' => $rows,
+ 'pagination' => array(
+ 'top' => $pagination_top,
+ 'bottom' => $pagination_bottom,
+ ),
+ 'column_headers' => $headers,
+ );
+
+ if (isset($this->_pagination_args['total_items'])) {
+ $response['total_items_i18n'] = sprintf(
+ /* translators: %s: Total items */
+ _n('%s item', '%s items', $this->_pagination_args['total_items'], 'all-in-one-wp-security-and-firewall'),
+ number_format_i18n($this->_pagination_args['total_items'])
+ );
+ }
+ if (isset($this->_pagination_args['total_pages'])) {
+ $response['total_pages'] = $this->_pagination_args['total_pages'];
+ $response['total_pages_i18n'] = number_format_i18n($this->_pagination_args['total_pages']);
+ }
+
+ // Get the message from the helper
+ $list_message = AIOS_Helper::get_message('aios_list_message');
+ if ($list_message) {
+ $response['message'] = $list_message['message'];
+ $response['status'] = $list_message['type'];
+ }
+
+ if ($return_instead_of_echo) {
+ return $response;
+ }
+
+ die(wp_json_encode($response));
+ }
+
+ /**
+ * Send required variables to JavaScript land
+ */
+ public function js_vars() {
+ $args = array(
+ 'class' => get_class($this),
+ 'screen' => array(
+ 'id' => $this->screen->id,
+ 'base' => $this->screen->base,
+ ),
+ );
+
+ printf("\n", wp_json_encode($args));
+ }
+
+ /**
+ * Retrieves and returns current WP general settings date time format.
+ *
+ * @return String
+ */
+ protected function get_wp_date_time_format() {
+ static $wp_date_time_format;
+
+ if (!isset($wp_date_time_format)) {
+ $wp_date_time_format = get_option('date_format').' '.get_option('time_format');
+ }
+
+ return $wp_date_time_format;
+ }
+}
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-list-table.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-list-table.php
new file mode 100755
index 00000000..c3e5013c
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-list-table.php
@@ -0,0 +1,1451 @@
+get_column_info().
+ *
+ * @since 4.1.0
+ * @var array
+ */
+ protected $_column_headers;
+
+ /**
+ * {@internal Missing Summary}
+ *
+ * @var array
+ */
+ protected $compat_fields = array('_args', '_pagination_args', 'screen', '_actions', '_pagination');
+
+ /**
+ * {@internal Missing Summary}
+ *
+ * @var array
+ */
+ protected $compat_methods = array(
+ 'set_pagination_args',
+ 'get_views',
+ 'get_bulk_actions',
+ 'bulk_actions',
+ 'row_actions',
+ 'months_dropdown',
+ 'view_switcher',
+ 'comments_bubble',
+ 'get_items_per_page',
+ 'pagination',
+ 'get_sortable_columns',
+ 'get_column_info',
+ 'get_table_classes',
+ 'display_tablenav',
+ 'extra_tablenav',
+ 'single_row_columns',
+ );
+
+ /**
+ * Constructor.
+ *
+ * The child class should call this constructor from its own constructor to override
+ * the default $args.
+ *
+ * @since 3.1.0
+ *
+ * @param array|string $args {
+ *
+ * @type string $plural Plural value used for labels and the objects being listed.
+ * This affects things such as CSS class-names and nonces used
+ * in the list table, e.g. 'posts'. Default empty.
+ * @type string $singular Singular label for an object being listed, e.g. 'post'.
+ * Default empty
+ * @type bool $ajax Whether the list table supports Ajax. This includes loading
+ * and sorting data, for example. If true, the class will call
+ * the js_vars() method in the footer to provide variables
+ * to any scripts handling Ajax events. Default false.
+ * @type string $screen String containing the hook name used to determine the current
+ * screen. If left null, the current screen will be automatically set.
+ * Default null.
+ * }
+ */
+ public function __construct($args = array()) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'plural' => '',
+ 'singular' => '',
+ 'ajax' => false,
+ 'screen' => null,
+ )
+ );
+
+ $this->screen = convert_to_screen($args['screen']);
+
+ add_filter("manage_{$this->screen->id}_columns", array($this, 'get_columns'), 0);
+
+ if (!$args['plural']) {
+ $args['plural'] = $this->screen->base;
+ }
+
+ $args['plural'] = sanitize_key($args['plural']);
+ $args['singular'] = sanitize_key($args['singular']);
+
+ $this->_args = $args;
+
+ if ($args['ajax']) {
+ // wp_enqueue_script('list-table');
+ add_action('admin_footer', array($this, 'js_vars'));
+ }
+
+ if (empty($this->modes)) {
+ $this->modes = array(
+ 'list' => __('List view', 'all-in-one-wp-security-and-firewall'),
+ 'excerpt' => __('Excerpt view', 'all-in-one-wp-security-and-firewall'),
+ );
+ }
+ }
+
+ /**
+ * Make private properties readable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name Property to get.
+ * @return mixed|void Property.
+ */
+ public function __get($name) {
+ if (in_array($name, $this->compat_fields)) {
+ return $this->$name;
+ }
+ }
+
+ /**
+ * Make private properties settable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name Property to check if set.
+ * @param mixed $value Property value.
+ * @return mixed Newly-set property.
+ */
+ public function __set($name, $value) {
+ if (in_array($name, $this->compat_fields)) {
+ return $this->$name = $value;
+ }
+ }
+
+ /**
+ * Make private properties checkable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name Property to check if set.
+ * @return bool Whether the property is set.
+ */
+ public function __isset($name) {
+ if (in_array($name, $this->compat_fields)) {
+ return isset($this->$name);
+ }
+ }
+
+ /**
+ * Make private properties un-settable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name Property to unset.
+ */
+ public function __unset($name) {
+ if (in_array($name, $this->compat_fields)) {
+ unset($this->$name);
+ }
+ }
+
+ /**
+ * Make private/protected methods readable for backward compatibility.
+ *
+ * @since 4.0.0
+ *
+ * @param string $name Method to call.
+ * @param array $arguments Arguments to pass when calling.
+ * @return mixed|bool Return value of the callback, false otherwise.
+ */
+ public function __call($name, $arguments) {
+ if (in_array($name, $this->compat_methods)) {
+ return call_user_func_array(array($this, $name), $arguments);
+ }
+ return false;
+ }
+
+ /**
+ * Checks the current user's permissions
+ *
+ * @since 3.1.0
+ * @abstract
+ */
+ public function ajax_user_can() {
+ die('function AIOWPSecurity_List_Table::ajax_user_can() must be over-ridden in a sub-class.');
+ }
+
+ /**
+ * Prepares the list of items for displaying.
+ *
+ * @uses AIOWPSecurity_List_Table::set_pagination_args()
+ *
+ * @since 3.1.0
+ * @abstract
+ */
+ public function prepare_items() {
+ die('function AIOWPSecurity_List_Table::prepare_items() must be over-ridden in a sub-class.');
+ }
+
+ /**
+ * An internal method that sets all the necessary pagination arguments
+ *
+ * @since 3.1.0
+ *
+ * @param array|string $args Array or string of arguments with information about the pagination.
+ */
+ protected function set_pagination_args($args) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'total_items' => 0,
+ 'total_pages' => 0,
+ 'per_page' => 0,
+ )
+ );
+
+ if (!$args['total_pages'] && $args['per_page'] > 0) {
+ $args['total_pages'] = ceil($args['total_items'] / $args['per_page']);
+ }
+
+ // Redirect if page number is invalid and headers are not already sent.
+ if (! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages']) {
+ wp_redirect(add_query_arg('paged', $args['total_pages']));
+ exit;
+ }
+
+ $this->_pagination_args = $args;
+ }
+
+ /**
+ * Access the pagination args.
+ *
+ * @since 3.1.0
+ *
+ * @param string $key Pagination argument to retrieve. Common values include 'total_items',
+ * 'total_pages', 'per_page', or 'infinite_scroll'.
+ * @return int Number of items that correspond to the given pagination argument.
+ */
+ public function get_pagination_arg($key) {
+ if ('page' === $key) {
+ return $this->get_pagenum();
+ }
+
+ if (isset($this->_pagination_args[$key])) {
+ return $this->_pagination_args[$key];
+ }
+ }
+
+ /**
+ * Whether the table has items to display or not
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ public function has_items() {
+ return ! empty($this->items);
+ }
+
+ /**
+ * Message to be displayed when there are no items
+ *
+ * @since 3.1.0
+ */
+ public function no_items() {
+ esc_html_e('No items found.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ /**
+ * Displays the search box.
+ *
+ * @since 3.1.0
+ *
+ * @param string $text The 'submit' button label.
+ * @param string $input_id ID attribute value for the search input field.
+ */
+ public function search_box($text, $input_id) {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- No nonce.
+ if (empty($_REQUEST['s']) && !$this->has_items()) {
+ return;
+ }
+
+ $input_id = $input_id . '-search-input';
+
+ if (!empty($_REQUEST['orderby'])) {
+ echo '';
+ }
+ if (!empty($_REQUEST['order'])) {
+ echo '';
+ }
+ if (!empty($_REQUEST['post_mime_type'])) {
+ echo '';
+ }
+ if (!empty($_REQUEST['detached'])) {
+ echo '';
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended -- No nonce.
+ ?>
+
+
+
+ '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 "
+ ';
+ foreach ($this->menu_tabs as $tab_key => $tab_info) {
+ $active = $current_tab == $tab_key ? 'nav-tab-active' : '';
+ echo '' . esc_html($tab_info['title']) . '';
+ }
+ echo '';
+ }
+
+ /**
+ * Get valid current tab slug.
+ *
+ * @return string - current valid tab slug or empty string
+ */
+ protected function get_current_tab() {
+ if (is_array($this->menu_tabs) && !empty($this->menu_tabs)) {
+ $tab_keys = array_keys($this->menu_tabs);
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
+ if (empty($_GET['tab'])) {
+ return $tab_keys[0];
+ } else {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
+ $current_tab = sanitize_text_field(wp_unslash($_GET['tab']));
+ return in_array($current_tab, $tab_keys) ? $current_tab : $tab_keys[0];
+ }
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * This function checks to see if there is a display condition for the tab and if so runs it otherwise it returns true to display the tab
+ *
+ * @param array $tab_info - the tab information array contains keys like title, render_callback and display_condition_callback
+ *
+ * @return boolean - true if the tab should be displayed or false to hide it
+ */
+ protected function should_display_tab($tab_info) {
+ return AIOWPSecurity_Utility::apply_callback_filter($tab_info, 'display_condition_callback');
+ }
+
+ /**
+ * Shows postbox for settings menu
+ *
+ * @param string $id - css ID for postbox
+ * @param string $title - title of the postbox section
+ * @param string $content - the content of the postbox
+ **/
+ protected function postbox_toggle($id, $title, $content) {
+ //Always send string with translation markers in it
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
';
+ $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 .= '
';
+ if ($return_instead_of_echo) return $message;
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
+ echo $message;
+ }
+
+ /**
+ * Renders record(s) successfully deleted message at top of page.
+ *
+ * @param bool $return_instead_of_echo - This is used for when the function needs to return the message
+ * @return mixed
+ */
+ public static function show_msg_record_deleted_st($return_instead_of_echo = false) {
+ return AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall'), $return_instead_of_echo);
+ }
+
+ /**
+ * Renders record(s) unsuccessfully deleted message at top of page.
+ *
+ * @param bool $return_instead_of_echo - This is used for when the function needs to return the message
+ * @return mixed
+ */
+ public static function show_msg_record_not_deleted_st($return_instead_of_echo = false) {
+ return AIOWPSecurity_Admin_Menu::show_msg_error_st(__('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'), $return_instead_of_echo);
+ }
+
+ /**
+ * Render successfully updated message
+ *
+ * @param string $msg - This contains the message to show
+ * @param bool $return_instead_of_echo - This is used for when the function needs to return the message
+ *
+ * @return string|void
+ */
+ public function show_msg_updated($msg, $return_instead_of_echo = false) {
+ $message = '
';
+ if ($return_instead_of_echo) return $message;
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
+ echo $message;
+ }
+
+ /**
+ * Render error message
+ *
+ * @param string $error_msg - This contains the message to show
+ * @param bool $return_instead_of_echo - This is used for when the function needs to return the message
+ *
+ * @return string|void
+ */
+ public function show_msg_error($error_msg, $return_instead_of_echo = false) {
+ $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').'
';
+ }
+
+ 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');
+ }
+ ?>
+
'; //yellow box div
+ echo '';
+ } // End if statement for Rename Login box
+ }
+
+ /**
+ * This outputs the logged in users dashboard widget
+ *
+ * @return void
+ */
+ public function widget_logged_in_users() {
+ $users_online_link = ''.esc_html__('Logged in users', 'all-in-one-wp-security-and-firewall').'';
+ // default display messages
+ $multiple_users_info_msg = esc_html__('Number of users currently logged into your site (including you) is:', 'all-in-one-wp-security-and-firewall');
+ $single_user_info_msg = esc_html__('There are no other users currently logged in.', 'all-in-one-wp-security-and-firewall');
+
+ if (is_multisite()) {
+ $current_blog_id = get_current_blog_id();
+ $is_main = is_main_site($current_blog_id);
+
+ if (empty($is_main)) {
+ // Subsite - only get logged in users for this blog_id
+ $logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users(false);
+ } else {
+ // Main site - get sitewide users
+ $logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users();
+
+ // If viewing AIOS from multisite main network dashboard, then display a different message
+ $multiple_users_info_msg = __('Number of users currently logged in site-wide (including you) is:', 'all-in-one-wp-security-and-firewall');
+ $single_user_info_msg = __('There are no other site-wide users currently logged in.', 'all-in-one-wp-security-and-firewall');
+ }
+ } else {
+ $logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users();
+ }
+
+ if (empty($logged_in_users)) {
+ $num_users = 0;
+ } else {
+ $num_users = count($logged_in_users);
+ }
+ if ($num_users > 1) {
+ echo '
'.__('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').'
';
+ return;
+ } else {
+ echo '
'.__('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.'').'
'.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').'
'. __('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.'(?.*)(&tab=(?.*))?$/m', $_POST['_wp_http_referer'], $matches)) {
+ $url = 'admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX;
+
+ if (isset($matches['page'])) {
+ $url .= sanitize_text_field($matches['page']);
+
+ if (isset($matches['tab'])) {
+ $url .= '&tab='.sanitize_text_field($matches['tab']);
+ }
+ }
+
+ AIOWPSecurity_Utility::redirect_to_url(admin_url(sanitize_url($url)));
+ }
+
+ }
+
+ AIOWPSecurity_Utility::redirect_to_url(admin_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX));
+ }
+
+ /**
+ * Wrapper function to log WP_Errors to debug log
+ *
+ * @param WP_Error $wp_error - Our error which gets logged
+ * @return void
+ */
+ private function log_wp_error($wp_error) {
+
+ if (is_wp_error($wp_error)) {
+ global $aio_wp_security;
+
+ $error_message = $wp_error->get_error_message();
+ $error_message .= ' - ';
+ $error_message .= $wp_error->get_error_data();
+ $aio_wp_security->debug_logger->log_debug($error_message, 4);
+ }
+ }
+
+ /**
+ * Sets the flags to show notices
+ *
+ * @param string $type - the type of notice we want to set
+ * @param array $values - any values that need to be passed
+ * @return void
+ */
+ private function show_notice($type, $values = array()) {
+ global $aio_wp_security;
+
+ $aio_wp_security->configs->set_value('firewall_notice_'.$type, true);
+
+ if (!empty($values)) {
+ $aio_wp_security->configs->set_value('firewall_notice_values', $values);
+ }
+
+ $aio_wp_security->configs->save_config();
+ }
+
+ /**
+ * Renders any necessary notices
+ *
+ * @return void
+ */
+ public function render_notices() {
+ global $aio_wp_security;
+
+ $notices = array(
+ self::NOTICE_BOOTSTRAP,
+ self::NOTICE_MANUAL,
+ self::NOTICE_INSTALLED,
+ self::NOTICE_DIRECTIVE_SET,
+ );
+
+ foreach ($notices as $notice) {
+ if ($aio_wp_security->configs->get_value('firewall_notice_'.$notice)) {
+
+ switch ($notice) {
+ case self::NOTICE_BOOTSTRAP:
+ $this->render_bootstrap_notice();
+ break;
+ case self::NOTICE_MANUAL:
+ if (!$this->any_pending_notices(self::NOTICE_MANUAL)) {
+ $this->render_manual_setup_notice();
+ }
+ break;
+ case self::NOTICE_INSTALLED:
+ $this->render_firewall_installed_notice();
+ break;
+ case self::NOTICE_DIRECTIVE_SET:
+ $values = $aio_wp_security->configs->get_value('firewall_notice_values');
+ $this->render_userini_directive_set_notice($values['directive']);
+ $aio_wp_security->configs->delete_value('firewall_notice_values');
+ break;
+ }
+
+ $aio_wp_security->configs->delete_value('firewall_notice_'.$notice);
+ }
+ }
+
+ $aio_wp_security->configs->save_config();
+ }
+
+ /**
+ * Detects if we have any notices pending to display
+ *
+ * @param string ...$exclude - do not check the status of these notices
+ *
+ * @return boolean
+ */
+ private function any_pending_notices(...$exclude) {
+ global $aio_wp_security;
+
+ $notices = array(
+ self::NOTICE_BOOTSTRAP,
+ self::NOTICE_MANUAL,
+ self::NOTICE_INSTALLED,
+ self::NOTICE_DIRECTIVE_SET,
+ );
+ $notices = array_diff($notices, $exclude);
+
+ foreach ($notices as $notice) {
+ if (true === $aio_wp_security->configs->get_value('firewall_notice_'.$notice)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Notice is shown if we are unable to write to the bootstrap file
+ *
+ * @return void
+ */
+ private function render_bootstrap_notice() {
+ ?>
+
+
+
+
+
+
+
+
+ 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() {
+ ?>
+
+
+ is_dismissed() && !AIOWPSecurity_Utility_Firewall::is_firewall_page()) {
+ return true;
+ }
+
+ if ($this->any_pending_notices()) {
+ return true; //only display if there are no other notices waiting to be displayed
+ }
+
+ return false;
+ }
+
+ /**
+ * Renders the 'Set up now' dashboard notice
+ *
+ * @return void
+ */
+ private function render_automatic_setup_notice() {
+ global $aio_wp_security;
+
+ if ($this->should_not_show_notice()) {
+ return;
+ }
+ $aio_wp_security->include_template('notices/firewall-setup-notice.php', false, array('show_dismiss' => !AIOWPSecurity_Utility_Firewall::is_firewall_page()));
+ }
+
+ /**
+ * Ensures only one instance of the class can be created (singleton)
+ *
+ * @return AIOWPSecurity_Firewall_Setup_Notice|null
+ */
+ public static function get_instance() {
+
+ if (null === self::$instance) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-404.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-404.php
new file mode 100755
index 00000000..2780ad93
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-404.php
@@ -0,0 +1,362 @@
+ 'item', //singular name of the listed records
+ 'plural' => 'items', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+ }
+
+ /**
+ * Returns created column in datetime format as per user setting time zone.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the datetime
+ */
+ public function column_created($item) {
+ return AIOWPSecurity_Utility::convert_timestamp($item['created']);
+ }
+
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Returns id column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - html string for column rendered
+ */
+ public function column_id($item) {
+ $ip = $item['ip_or_host'];
+
+ $is_locked = AIOWPSecurity_Utility::check_locked_ip($ip, '404');
+ $blacklist_tab = 'blacklist';
+ $is_blacklist = AIOWPSecurity_Utility::check_blacklist_ip($ip);
+ $actions = array();
+ $actions['delete'] = '' . __('Delete', 'all-in-one-wp-security-and-firewall') . '';
+
+ if ($is_locked) {
+ // Build row actions for locked items
+ $actions['unblock'] = '' . __('Unblock', 'all-in-one-wp-security-and-firewall') . '';
+ } elseif ($is_blacklist) {
+ $unblock_url_nonce = wp_nonce_url(sprintf('admin.php?page=%s&tab=%s', AIOWPSEC_FIREWALL_MENU_SLUG, $blacklist_tab), "404_log_item_action", "aiowps_nonce");
+ $actions = array(
+ 'unblock' => ''.__('Unblock', 'all-in-one-wp-security-and-firewall').'',
+ );
+ } else {
+ // Build row actions for other items
+ $actions['temp_block'] = '' . __('Temporarily block', 'all-in-one-wp-security-and-firewall') . '';
+ $actions['blacklist_ip'] = '' . __('Blacklist IP', 'all-in-one-wp-security-and-firewall') . '';
+ }
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /* $1%s */ $item['id'],
+ /* $2%s */ $this->row_actions($actions)
+ );
+ }
+
+ /**
+ * Returns status column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - html string for column rendered
+ */
+ public function column_status($item) {
+ global $aio_wp_security;
+ $ip = $item['ip_or_host'];
+ //Check if this IP address is locked
+ $is_locked = AIOWPSecurity_Utility::check_locked_ip($ip, '404');
+ $blacklisted_string = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
+ $banned = strpos($blacklisted_string, $ip);
+
+ if (false !== $banned) {
+ return 'blacklisted';
+ } elseif ($is_locked) {
+ return 'temporarily blocked';
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Returns checkbox column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - html string for column rendered
+ */
+ public function column_cb($item) {
+ return sprintf('',
+ /* $1%s */ $this->_args['singular'], //Let's simply repurpose the table's singular label
+ /* $2%s */ $item['id'] //The value of the checkbox should be the record's id
+ );
+ }
+
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '', //Render a checkbox
+ 'id' => 'ID',
+ 'event_type' => __('Event type', 'all-in-one-wp-security-and-firewall'),
+ 'ip_or_host' => __('IP address', 'all-in-one-wp-security-and-firewall'),
+ 'url' => __('Attempted URL', 'all-in-one-wp-security-and-firewall'),
+ 'referer_info' => __('Referer', 'all-in-one-wp-security-and-firewall'),
+ 'created' => __('Date and time', 'all-in-one-wp-security-and-firewall'),
+ 'status' => __('Lock status', 'all-in-one-wp-security-and-firewall'),
+ );
+ $columns = apply_filters('list_404_get_columns', $columns);
+ return $columns;
+ }
+
+ public function get_sortable_columns() {
+ $sortable_columns = array(
+ 'id' => array('id', false),
+ 'event_type' => array('event_type', false),
+ 'ip_or_host' => array('ip_or_host', false),
+ 'url' => array('url', false),
+ 'referer_info' => array('referer_info', false),
+ 'created' => array('created', false),
+ );
+ $sortable_columns = apply_filters('list_404_get_sortable_columns', $sortable_columns);
+ return $sortable_columns;
+ }
+
+ /**
+ * Get bulk actions for the current WordPress screen.
+ *
+ * @return array An associative array of bulk actions where the keys are action names
+ * and the values are the corresponding action labels.
+ */
+ public function get_bulk_actions() {
+ return array(
+ //'unlock' => 'Unlock',
+ 'bulk_block_ip' => __('Temporarily block IP', 'all-in-one-wp-security-and-firewall'),
+ 'bulk_blacklist_ip' => __('Blacklist IP', 'all-in-one-wp-security-and-firewall'),
+ 'delete' => __('Delete', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ /**
+ * Process bulk actions for the current WordPress screen.
+ *
+ * This method checks for the presence of a valid nonce and user capabilities,
+ * then performs the appropriate action based on the selected bulk action.
+ *
+ * @return void
+ */
+ private function process_bulk_action() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Ignore.
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
+ if (is_wp_error($result)) return;
+
+ if ('bulk_block_ip' === $this->current_action()) {//Process delete bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
+ $this->block_ip(wp_unslash($_REQUEST['item']));
+ }
+ }
+
+ if ('bulk_blacklist_ip' === $this->current_action()) {//Process delete bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
+ $this->blacklist_ip_address(wp_unslash($_REQUEST['item']));
+ }
+ }
+ if ('delete' === $this->current_action()) {//Process delete bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
+ $this->delete_404_event_records(wp_unslash($_REQUEST['item']));
+ }
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
+ }
+
+ /**
+ * Locks an IP address by adding it to the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @param array|string $entries - ids that correspond to ip addresses in the AIOWPSEC_TBL_EVENTS table or a single ip address
+ * @param string $username - (optional)username of user being locked
+ *
+ * @return boolean|void
+ */
+ public function block_ip($entries, $username = '') {
+ global $wpdb;
+ if (is_array($entries)) {
+ //lock multiple records
+ $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
+ $id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
+ $events_table = AIOWPSEC_TBL_EVENTS;
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $results = $wpdb->get_col("SELECT ip_or_host FROM $events_table WHERE ID IN " . $id_list);
+ if (empty($results)) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Could not process the request because the IP addresses for the selected entries could not be found.', 'all-in-one-wp-security-and-firewall'));
+ return false;
+ } else {
+ foreach ($results as $entry) {
+ if (filter_var($entry, FILTER_VALIDATE_IP)) {
+ AIOWPSecurity_Utility::lock_IP($entry, '404', $username);
+ }
+ }
+ }
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses are now temporarily blocked.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Permanently blocks an IP address by adding it to the blacklist and writing rules to the htaccess file.
+ *
+ * @param array|string $entries - ids that correspond to ip addresses in the AIOWPSEC_TBL_EVENTS table or a single ip address
+ *
+ * @return boolean|void
+ */
+ public function blacklist_ip_address($entries) {
+ global $wpdb, $aio_wp_security;
+ $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
+ $bl_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'); //get the currently saved blacklisted IPs
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($bl_ip_addresses);
+
+ if (is_array($entries)) {
+ //Get the selected IP addresses
+ $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
+ $id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
+ $events_table = AIOWPSEC_TBL_EVENTS;
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $results = $wpdb->get_col("SELECT ip_or_host FROM $events_table WHERE ID IN " . $id_list);
+ if (empty($results)) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Could not process the request because the IP addresses for the selected entries could not be found.', 'all-in-one-wp-security-and-firewall'));
+ return false;
+ } else {
+ foreach ($results as $entry) {
+ $ip_list_array[] = $entry;
+ }
+ }
+ }
+
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
+ if (is_wp_error($validated_ip_list_array)) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(nl2br($validated_ip_list_array->get_error_message()));
+ } else {
+ $banned_ip_data = implode("\n", $validated_ip_list_array);
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '1'); // Force blacklist feature to be enabled.
+ $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', $banned_ip_data);
+ $aio_wp_security->configs->save_config();
+
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses have been added to the blacklist and will be permanently blocked.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Deletes one or more records from the AIOWPSEC_TBL_EVENTS table.
+ *
+ * @param array|string|integer $entries - ids or a single id
+ *
+ * @return void|string
+ */
+ public function delete_404_event_records($entries) {
+ global $wpdb, $aio_wp_security;
+ $events_table = AIOWPSEC_TBL_EVENTS;
+ if (is_array($entries)) {
+ //Delete multiple records
+ $entries = array_map('esc_sql', $entries); //escape every array element
+ $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
+ $id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query("DELETE FROM " . $events_table . " WHERE id IN " . $id_list);
+ if ($result) {
+ AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
+ } else {
+ // Error on bulk delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Events table. Database error: '.$wpdb->last_error, 4);
+ AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
+ }
+ }
+ }
+
+ /**
+ * Retrieves all items from AIOWPSEC_TBL_EVENTS according to a search term inside $_REQUEST['s'] and only '404' events if there is no search term. It then assigns to $this->items.
+ *
+ * @param Boolean $ignore_pagination - whether to not paginate
+ *
+ * @return Void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ /**
+ * First, lets decide how many records per page to show
+ */
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. Nonce checked in previous function.
+ $search_term = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : '';
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $this->process_bulk_action();
+
+ global $wpdb;
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
+
+ // Ordering parameters
+ // Parameters that are going to be used to order the result
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
+
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'id';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ if (empty($search_term)) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM $events_table_name WHERE `event_type` = '404' ORDER BY $orderby $order", ARRAY_A);
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQueryWithPlaceholder, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM $events_table_name WHERE `ip_or_host` LIKE '%%%s%%' OR `url` LIKE '%%%s%%' OR `referer_info` LIKE '%%%s%%' ORDER BY $orderby $order", $wpdb->esc_like($search_term), $wpdb->esc_like($search_term), $wpdb->esc_like($search_term)), ARRAY_A);
+ }
+
+ if (!$ignore_pagination) {
+ $current_page = $this->get_pagenum();
+ $total_items = count($data);
+ $data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
+ ));
+ }
+
+ foreach ($data as $index => $row) {
+ // Insert an empty status column - we will use later
+ $data[$index]['status'] = '';
+ }
+
+ $this->items = $data;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-audit.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-audit.php
new file mode 100755
index 00000000..4c5c1702
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-audit.php
@@ -0,0 +1,527 @@
+ 'item', // singular name of the listed records
+ 'plural' => 'items', // plural name of the listed records
+ 'ajax' => true, // does this table support ajax?
+ 'data' => $data // Request data
+ ));
+
+ }
+
+ /**
+ * Returns the default column item
+ *
+ * @param object $item - item from which column data is returned
+ * @param string $column_name - column name to be fetched from item
+ * @return string
+ */
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Returns cb column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /* $1%s */ $this->_args['singular'], // Let's simply repurpose the table's singular label
+ /* $2%s */ $item['id'] // The value of the checkbox should be the record's id
+ );
+ }
+
+ /**
+ * Returns created column html to be rendered.
+ *
+ * @param array $item Data for the columns on the current row.
+ *
+ * @return string The html to be rendered.
+ */
+ public function column_created($item) {
+ $actions = array(
+ 'delete' => '' . esc_html__('Delete', 'all-in-one-wp-security-and-firewall') . ''
+ );
+
+ return AIOWPSecurity_Utility::convert_timestamp($item['created']) . '' . $this->row_actions($actions);
+ }
+
+ /**
+ * Returns ip column html to be rendered.
+ *
+ * @param array $item Data for the columns on the current row.
+ *
+ * @return string The html to be rendered.
+ */
+ public function column_ip($item) {
+ $ip = $item['ip'];
+
+ $unblacklist_ip_warning_translation = __('Are you sure you want to unblacklist this IP address?', 'all-in-one-wp-security-and-firewall');
+ $unlock_ip_warning_translation = __('Are you sure you want to unlock this IP address?', 'all-in-one-wp-security-and-firewall');
+ $lock_ip_warning_translation = __('Are you sure you want to temporarily lock this IP address?', 'all-in-one-wp-security-and-firewall');
+ $blacklist_ip_warning_translation = __('Are you sure you want to blacklist this IP address?', 'all-in-one-wp-security-and-firewall');
+
+ // Build row actions.
+ if (AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin() && AIOWPSecurity_Utility::check_blacklist_ip($ip)) {
+ $actions = array(
+ 'unblacklist' => '' . esc_html__('Unblacklist', 'all-in-one-wp-security-and-firewall') . '',
+ );
+ } elseif (AIOWPSecurity_Utility::check_locked_ip($ip, 'audit-log')) {
+ $actions = array(
+ 'unlock' => '' . esc_html__('Unlock', 'all-in-one-wp-security-and-firewall') . '',
+ );
+ } else {
+ $actions = array(
+ 'lock_ip' => '' . esc_html__('Lock IP', 'all-in-one-wp-security-and-firewall') . '',
+ );
+
+ if (AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin()) {
+ $actions['blacklist_ip'] = '' . esc_html__('Blacklist IP', 'all-in-one-wp-security-and-firewall') . '';
+ }
+ }
+
+ return $ip . '' . $this->row_actions($actions);
+ }
+
+ /**
+ * Returns event type column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_event_type($item) {
+ if (empty($item['event_type'])) return __('No event type available.', 'all-in-one-wp-security-and-firewall');
+
+ $output = isset(AIOWPSecurity_Audit_Events::$event_types[$item['event_type']]) ? AIOWPSecurity_Audit_Events::$event_types[$item['event_type']] : $item['event_type'];
+
+ return $output;
+ }
+
+ /**
+ * Returns details column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_details($item) {
+ $details = json_decode($item['details'], true);
+
+ if (!is_array($details)) return $item['details'];
+
+ $key = array_keys($details)[0];
+
+ if (method_exists("AIOWPSecurity_Audit_Text_Handler", "{$key}_to_text")) {
+ return call_user_func("AIOWPSecurity_Audit_Text_Handler::{$key}_to_text", $details[$key]);
+ }
+
+ return $item['details'];
+ }
+
+ /**
+ * Returns stack trace column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_stacktrace($item) {
+ if (empty($item['stacktrace'])) return __('No stack trace available.', 'all-in-one-wp-security-and-firewall');
+
+ if (is_serialized($item['stacktrace'])) {
+ $stacktrace = AIOWPSecurity_Utility::unserialize($item['stacktrace']);
+ } else {
+ $stacktrace = $item['stacktrace'];
+ }
+ ob_start();
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_dump -- Part of error reporting system.
+ var_dump($stacktrace);
+ $stacktrace_output = ob_get_contents();
+ ob_end_clean();
+
+ $output = sprintf('%s', $item['id'], esc_html__('Stack trace', 'all-in-one-wp-security-and-firewall'), esc_html__('Show trace', 'all-in-one-wp-security-and-firewall'));
+ $output .= sprintf('
%s
', $item['id'], htmlspecialchars($stacktrace_output));
+
+ return $output;
+ }
+
+ /**
+ * Sets the columns for the table
+ *
+ * @return array
+ */
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '', //Render a checkbox
+ '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')
+ );
+ $columns = apply_filters('list_auditlogs_get_columns', $columns);
+ return $columns;
+ }
+
+ /**
+ * Sets which of the columns the table data can be sorted by
+ *
+ * @return array
+ */
+ public function get_sortable_columns() {
+ $sortable_columns = array(
+ 'created' => array('created', false),
+ 'network_id' => array('network_id', false),
+ 'site_id' => array('site_id', false),
+ 'level' => array('level', false),
+ 'username' => array('username', false),
+ 'ip' => array('ip', false),
+ 'event_type' => array('event_type', false),
+ 'details' => array('details', false),
+ 'stacktrace' => array('stacktrace', false)
+ );
+ $sortable_columns = apply_filters('list_auditlogs_get_sortable_columns', $sortable_columns);
+ return $sortable_columns;
+ }
+
+ /**
+ * This function will display a list of bulk actions for the list table
+ *
+ * @return array
+ */
+ public function get_bulk_actions() {
+ $actions = array(
+ 'delete_all' => __('Delete all', 'all-in-one-wp-security-and-firewall'),
+ 'delete_selected' => __('Delete selected', 'all-in-one-wp-security-and-firewall'),
+ 'delete_filtered' => __('Delete filtered', 'all-in-one-wp-security-and-firewall')
+ );
+ return $actions;
+ }
+
+ /**
+ * This function will process the bulk action request, $search_term and $filters are only used if the user is trying to bulk delete the filtered items
+ *
+ * @param string $search_term - The search term used for filtering records.
+ * @param array $filters - An array containing filters applied to the records.
+ * @param string $action - The bulk action to be performed.
+ * @param array $items - An array of record IDs on which the action will be performed. Default is an empty array.
+ *
+ * @return void
+ */
+ private function process_bulk_action($search_term, $filters, $action, $items = array()) {
+ global $wpdb;
+
+ if ('delete_selected' === $action) { // Process delete bulk actions
+ if (!isset($items)) {
+ AIOS_Helper::set_message('aios_list_message', __('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'), 'error');
+ } else {
+ $this->delete_audit_event_records($items);
+ }
+ } elseif ('delete_filtered' === $action) {
+ if (!empty($filters) || '' !== $search_term) {
+ $audit_log_tbl = AIOWPSEC_TBL_AUDIT_LOG;
+ $where_sql = $this->get_audit_list_where_sql($search_term, $filters);
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $results = $wpdb->get_results("SELECT id FROM {$audit_log_tbl} {$where_sql}", 'ARRAY_A');
+ $items = array_column($results, 'id');
+ $this->delete_audit_event_records($items);
+ } else {
+ AIOS_Helper::set_message('aios_list_message', __('Please select the level or the event type filter or filter by a search term', 'all-in-one-wp-security-and-firewall'), 'error');
+ }
+ } elseif ('delete_all' === $action) {
+ $this->delete_audit_event_records(null, true);
+ }
+ }
+
+ /**
+ * Outputs extra controls to be displayed between bulk actions and pagination
+ *
+ * @param string $which - where we are outputting content (top or bottom)
+ *
+ * @return void
+ */
+ protected function extra_tablenav($which) {
+ switch ($which) {
+ case 'top':
+ ?>
+
+
+
+
+
+ query($delete_command);
+ } elseif (is_array($entries)) {
+ // Delete multiple records
+ $entries = array_map('esc_sql', $entries); // Escape every array element
+ $entries = array_filter($entries, 'is_numeric'); // Discard non-numeric ID values
+ $chunks = array_chunk($entries, 1000);
+
+ $site_id_where_sql = (!is_super_admin()) ? ' AND site_id = ' . get_current_blog_id() : '';
+
+ // Processing each chunk
+ foreach ($chunks as $chunk) {
+ $id_list = "(" . implode(",", $chunk) . ")"; // Create comma separate list for DB operation
+ $delete_command = "DELETE FROM " . $audit_log_tbl . " WHERE id IN " . $id_list . $site_id_where_sql;
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query($delete_command);
+ if (!$result) {
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Audit log table. Database error: '.$wpdb->last_error, 4);
+ AIOS_Helper::set_message('aios_list_message', __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'), 'error');
+ return;
+ }
+ }
+ } elseif (!empty($entries)) {
+ // Delete single record
+ $site_id_where_sql = (!is_super_admin()) ? ' AND site_id = ' . get_current_blog_id() : '';
+ $delete_command = "DELETE FROM " . $audit_log_tbl . " WHERE id = '" . absint($entries) . "'" . $site_id_where_sql;
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query($delete_command);
+ }
+
+ if ($result || 0 < $result) {
+ $aios_list_message = __('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall');
+ AIOS_Helper::set_message('aios_list_message', $aios_list_message);
+ } else {
+ $aios_list_message = __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall');
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Audit log table. Database error: '.$wpdb->last_error, 4);
+ AIOS_Helper::set_message('aios_list_message', $aios_list_message, 'error');
+ }
+
+ return $aios_list_message;
+ }
+
+ /**
+ * This function will build and return the SQL WHERE statement
+ *
+ * @param string $search_term - the search term applied
+ * @param array $filters - the filters applied
+ *
+ * @return string - the SQL WHERE statement
+ */
+ private function get_audit_list_where_sql($search_term, $filters) {
+
+ $where_sql = '';
+
+ if ('' == $search_term) {
+ $where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id() : '';
+ $extra_where = '';
+
+ if (!empty($filters)) {
+ $where_sql = empty($where_sql) ? 'WHERE ' : $where_sql . ' AND ';
+ foreach ($filters as $filter => $value) {
+ if (!empty($extra_where)) $extra_where .= ' AND ';
+ $extra_where .= "`{$filter}` = '".esc_sql($value)."'";
+ }
+ }
+
+ $where_sql .= $extra_where;
+ } else {
+ $where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id().' AND ' : 'WHERE ';
+ $extra_where = '';
+
+ if (!empty($filters)) {
+ foreach ($filters as $filter => $value) {
+ if (!empty($extra_where)) $extra_where .= ' AND ';
+ $extra_where .= "`{$filter}` = '".esc_sql($value)."'";
+ }
+ $where_sql .= $extra_where . ' AND (';
+ $extra_where = '';
+ }
+
+ // We don't use FILTER_VALIDATE_IP here as we want to be able to search for partial IP's
+ if (preg_match('/^[0-9a-f:\.]+$/i', $search_term)) {
+ $extra_where .= "`ip` LIKE '".esc_sql($search_term)."%'";
+ }
+
+ if (in_array($search_term, AIOWPSecurity_Audit_Events::$log_levels) && !isset($filters['level'])) {
+ if (!empty($extra_where)) $extra_where .= ' OR ';
+ $extra_where .= "`level` = '".esc_sql($search_term)."'";
+ }
+
+ if (!empty($extra_where)) $extra_where .= ' OR ';
+ if (isset($filters['event_type'])) {
+ $extra_where .= "`username` LIKE '".esc_sql($search_term)."%'";
+ } else {
+ $extra_where .= "(`username` LIKE '".esc_sql($search_term)."%' or `event_type` LIKE '%".esc_sql($search_term)."%')";
+ }
+ if (!empty($filters)) $extra_where .= ')';
+
+ $where_sql .= $extra_where;
+ }
+
+ return $where_sql;
+ }
+
+ /**
+ * Grabs the data from database and handles the pagination
+ *
+ * @param boolean $ignore_pagination - whether to not paginate
+ *
+ * @return void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ /**
+ * First, lets decide how many records per page to show
+ */
+ $no_action = -1;
+ $per_page = defined('AIOWPSEC_AUDIT_LOG_PER_PAGE') ? absint(AIOWPSEC_AUDIT_LOG_PER_PAGE) : 100;
+ $per_page = empty($per_page) ? 100 : $per_page;
+ $current_page = $this->get_pagenum();
+ $offset = (!$ignore_pagination && $per_page > 0) ? ($current_page - 1) * $per_page : 0;
+ $columns = $this->get_columns();
+ $hidden = array('id'); // we really don't need the IDs of the log entries displayed
+ if (!is_multisite()) {
+ $hidden[] = 'network_id';
+ $hidden[] = 'site_id';
+ }
+ $sortable = $this->get_sortable_columns();
+ $filters = array();
+ if (isset($this->_args['data']['level-filter']) && $no_action != $this->_args['data']['level-filter']) $filters['level'] = sanitize_text_field($this->_args['data']['level-filter']);
+ if (isset($this->_args['data']['event-filter']) && $no_action != $this->_args['data']['event-filter']) $filters['event_type'] = sanitize_text_field($this->_args['data']['event-filter']);
+ $search_term = isset($this->_args['data']['s']) ? sanitize_text_field(stripslashes($this->_args['data']['s'])) : '';
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $items = array();
+
+ if (isset($this->_args['data']['items'])) {
+ if (is_array($this->_args['data']['items'])) {
+ foreach ($this->_args['data']['items'] as $item) {
+ $sanitized_item = sanitize_text_field($item);
+ $items[] = $sanitized_item;
+ }
+ } else {
+ $sanitized_item = sanitize_text_field($this->_args['data']['items']);
+ $items[] = $sanitized_item;
+ }
+ } else {
+ $items = null;
+ }
+
+ if (isset($this->_args['data']['action'])) $action = sanitize_text_field($this->_args['data']['action']);
+ else $action = $no_action;
+
+ if (isset($action) && $no_action !== $action) {
+ $this->process_bulk_action($search_term, $filters, $action, $items);
+ }
+
+ global $wpdb;
+
+ $audit_log_tbl = AIOWPSEC_TBL_AUDIT_LOG;
+
+ // Parameters that are going to be used to order the result
+ isset($this->_args['data']["orderby"]) ? $orderby = wp_strip_all_tags($this->_args['data']["orderby"]) : $orderby = '';
+ isset($this->_args['data']["order"]) ? $order = wp_strip_all_tags($this->_args['data']["order"]) : $order = '';
+ // By default show the most recent audit log entries.
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'created';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ $orderby = sanitize_sql_orderby($orderby);
+ $order = sanitize_sql_orderby($order);
+
+ $where_sql = $this->get_audit_list_where_sql($search_term, $filters);
+
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$audit_log_tbl} {$where_sql}");
+ if ($ignore_pagination) {
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$audit_log_tbl} {$where_sql} ORDER BY {$orderby} {$order}", 'ARRAY_A');
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$audit_log_tbl} {$where_sql} ORDER BY {$orderby} {$order} LIMIT {$per_page} OFFSET {$offset}", 'ARRAY_A');
+ }
+
+ // Filter the 'details' section
+ foreach ($data as $key => $entry) {
+ $details = json_decode($entry['details'], true);
+ $details = is_null($details) ? $entry['details'] : $details; // check if the decode worked, if not pass the json string
+ $data[$key]['details'] = wp_json_encode(apply_filters('aios_audit_filter_details', $details, $entry['event_type']));
+ }
+
+ $this->items = $data;
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, // We have to calculate the total number of items
+ 'per_page' => $per_page, // We have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) // We have to calculate the total number of pages
+ ));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-comment-spammer-ip.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-comment-spammer-ip.php
new file mode 100755
index 00000000..1c48ccc9
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-comment-spammer-ip.php
@@ -0,0 +1,221 @@
+ 'item', // singular name of the listed records
+ 'plural' => 'items', // plural name of the listed records
+ 'ajax' => false // does this table support ajax?
+ ));
+
+ }
+
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ public function column_comment_author_IP($item) {
+ //Build row actions
+ if (!is_main_site() || 'blocked' === $item['status']) {
+ //Suppress the block link if site is a multi site AND not the main site or the status is blocked
+ $actions = array(); //blank array
+ } else {
+ //Add IP to block URL
+ $ip = $item['comment_author_IP'];
+ $actions = array(
+ 'block' => ''.__('Block', 'all-in-one-wp-security-and-firewall').'',
+ );
+ }
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /*$1%s*/ $item['comment_author_IP'],
+ /*$2%s*/ $this->row_actions($actions)
+ );
+ }
+
+
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
+ /*$2%s*/ esc_attr($item['comment_author_IP']) //The value of the checkbox should be the record's id
+ );
+ }
+
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '', //Render a checkbox
+ 'comment_author_IP' => __('Spammer IP', 'all-in-one-wp-security-and-firewall'),
+ 'amount' => __('Number of spam comments from this IP', 'all-in-one-wp-security-and-firewall'),
+ 'status' => __('Status', 'all-in-one-wp-security-and-firewall'),
+ );
+ return $columns;
+ }
+
+ public function get_sortable_columns() {
+ $sortable_columns = array(
+ 'comment_author_IP' => array('comment_author_IP',false),
+ 'amount' => array('amount',false),
+ 'status' => array('status',false),
+ );
+ return $sortable_columns;
+ }
+
+ public function get_bulk_actions() {
+ if (!is_main_site()) {
+ //Suppress the block link if site is a multi site AND not the main site
+ $actions = array(); //blank array
+ } else {
+ $actions = array(
+ 'block' => __('Block', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+ return $actions;
+ }
+
+ /**
+ * This function handles bulk actions on the table
+ *
+ * @return void
+ */
+ private function process_bulk_action() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This IS the nonce check.
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput -- This IS the nonce check.
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
+ if (is_wp_error($result)) return;
+
+
+ if ('block' === $this->current_action()) {
+ //Process block bulk actions
+ if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce already checked above.
+ $error_msg = '
';
+ $error_msg .= esc_html__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall');
+ $error_msg .= '
';
+
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP error. Output already escaped.
+ echo $error_msg;
+ } else {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce already checked above.
+ $this->block_spammer_ip_records((filter_var(wp_unslash($_REQUEST['item']), FILTER_VALIDATE_IP)));
+ }
+ }
+ }
+
+
+
+ /**
+ * This function will add the selected IP addresses to the blacklist.
+ *
+ * @param int|array $entries - either an array of IDs or a single ID of ip to be blocked
+ *
+ * @return void
+ */
+ public function block_spammer_ip_records($entries) {
+ if (is_array($entries)) {
+ $entries = array_map('esc_sql', $entries); // Escape every array element
+ //Bulk selection using checkboxes were used
+ foreach ($entries as $ip_add) {
+ AIOWPSecurity_Blocking::add_ip_to_block_list($ip_add, 'spam');
+ }
+ }
+
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses are now permanently blocked.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ /**
+ * This function prepare the items rendered on the table
+ *
+ * @return void
+ */
+ public function prepare_items() {
+ //First, lets decide how many records per page to show
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $this->process_bulk_action();
+
+ global $wpdb;
+ global $aio_wp_security;
+ $minimum_comments_per_ip = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments');
+ if (empty($minimum_comments_per_ip)) {
+ $minimum_comments_per_ip = 5;
+ }
+ // Ordering parameters
+ //Parameters that are going to be used to order the result
+ isset($_GET["orderby"]) ? $orderby = wp_strip_all_tags(wp_unslash($_GET["orderby"])) : $orderby = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check.
+ isset($_GET["order"]) ? $order = wp_strip_all_tags(wp_unslash($_GET["order"])) : $order = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check.
+
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'amount';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ // status is not a key in the database so we don't want to sort the database results, but sort the array later
+ if ('status' == $orderby) {
+ $sql = $wpdb->prepare("SELECT comment_author_IP, COUNT(*) AS amount
+ FROM $wpdb->comments
+ WHERE comment_approved = 'spam'
+ GROUP BY comment_author_IP
+ HAVING amount >= %d
+ ", $minimum_comments_per_ip);
+ } else {
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby cannot be prepared.
+ $sql = $wpdb->prepare("SELECT comment_author_IP, COUNT(*) AS amount
+ FROM $wpdb->comments
+ WHERE comment_approved = 'spam'
+ GROUP BY comment_author_IP
+ HAVING amount >= %d
+ ORDER BY $orderby $order
+ ", $minimum_comments_per_ip);
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby cannot be prepared.
+ }
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- Preparing done in conditional above.
+ $data = $wpdb->get_results($sql, ARRAY_A);
+
+ // Get all permanently blocked IP addresses
+ $block_list = AIOWPSecurity_Blocking::get_list_blocked_ips();
+
+ foreach ($data as $key => $value) {
+ if (in_array($value['comment_author_IP'], $block_list)) {
+ $data[$key]['status'] = 'blocked';
+ } else {
+ $data[$key]['status'] = 'not blocked';
+ }
+ }
+
+ if ('status' == $orderby) {
+ $keys = array_column($data, 'status');
+ if ('asc' == $order) {
+ array_multisort($keys, SORT_ASC, SORT_STRING, $data);
+ } else {
+ array_multisort($keys, SORT_DESC, SORT_STRING, $data);
+ }
+ }
+
+ $current_page = $this->get_pagenum();
+ $total_items = count($data);
+ $data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
+ $this->items = $data;
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
+ ));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-debug.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-debug.php
new file mode 100755
index 00000000..4b3d221d
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-debug.php
@@ -0,0 +1,149 @@
+ 'entry', //singular name of the listed records
+ 'plural' => 'entries', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+
+ }
+
+ /**
+ * Returns logtime column in datetime format as per user setting time zone.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the datetime
+ */
+ public function column_logtime($item) {
+ return AIOWPSecurity_Utility::convert_timestamp($item['logtime']);
+ }
+
+ /**
+ * This function renders a default column item
+ *
+ * @param array $item - Item object
+ * @param string $column_name - Column name to be rendered from item object
+ *
+ * @return mixed - data to be rendered for column
+ */
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Sets the columns for the table
+ *
+ * @return array
+ */
+ public function get_columns() {
+ return array(
+ 'logtime' => __('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'),
+ 'message' => __('Message', 'all-in-one-wp-security-and-firewall'),
+ 'type' => __('Type', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ /**
+ * Sets which of the columns the table data can be sorted by
+ *
+ * @return array
+ */
+ public function get_sortable_columns() {
+ return array(
+ 'logtime' => array('logtime', false),
+ 'level' => array('level', false),
+ 'network_id' => array('network_id', false),
+ 'site_id' => array('site_id', false),
+ 'message'=>array('message', false),
+ 'type' => array('type', false)
+ );
+ }
+
+ /**
+ * Grabs the data from database and handles the pagination
+ *
+ * @param boolean $ignore_pagination - whether to not paginate
+ *
+ * @return void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ /**
+ * First, lets decide how many records per page to show
+ */
+ if (defined('AIOWPSEC_DEBUG_LOG_PER_PAGE')) {
+ $per_page = absint(AIOWPSEC_DEBUG_LOG_PER_PAGE);
+ }
+
+ $per_page = empty($per_page) ? 15 : $per_page;
+ $current_page = $this->get_pagenum();
+ $offset = ($current_page - 1) * $per_page;
+ $columns = $this->get_columns();
+ $hidden = array('id'); // we really don't need the IDs of the log entries displayed
+ if (!is_multisite()) {
+ $hidden[] = 'network_id';
+ $hidden[] = 'site_id';
+ }
+ $sortable = $this->get_sortable_columns();
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ global $wpdb;
+
+ $debug_log_tbl = AIOWPSEC_TBL_DEBUG_LOG;
+
+ /* -- Ordering parameters -- */
+
+ //Parameters that are going to be used to order the result
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ isset($_GET["orderby"]) ? $orderby = sanitize_text_field(wp_unslash($_GET["orderby"])) : $orderby = '';
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ isset($_GET["order"]) ? $order = sanitize_text_field(wp_unslash($_GET["order"])) : $order = '';
+
+ // By default show the most recent debug log entries.
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'logtime';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ $orderby = sanitize_sql_orderby($orderby);
+ $order = sanitize_sql_orderby($order);
+
+ $where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id() : '';
+
+ if ($ignore_pagination) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$debug_log_tbl}$where_sql ORDER BY $orderby $order", 'ARRAY_A');
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$debug_log_tbl} $where_sql ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
+ }
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$debug_log_tbl} $where_sql");
+ $this->items = $data;
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
+ ));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-locked-ip.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-locked-ip.php
new file mode 100755
index 00000000..a0d92106
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-locked-ip.php
@@ -0,0 +1,318 @@
+ 'item', //singular name of the listed records
+ 'plural' => 'items', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+
+ }
+
+ /**
+ * Returns created column in datetime format as per user setting time zone.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the datetime
+ */
+ public function column_created($item) {
+ return AIOWPSecurity_Utility::convert_timestamp($item['created']);
+ }
+
+ /**
+ * Returns released column in datetime format as per user setting time zone.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the datetime
+ */
+ public function column_released($item) {
+ return AIOWPSecurity_Utility::convert_timestamp($item['released']);
+ }
+
+ /**
+ * This function renders a column
+ *
+ * @param array $item - Item object
+ * @param string $column_name - Column name to be rendered from item object
+ *
+ * @return string - data to be rendered for column_name
+ */
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Function to populate the locked ip actions column in the table
+ *
+ * @param array $item - Contains the current item data
+ *
+ * @return string
+ */
+ public function column_failed_login_ip($item) {
+ $actions = array(
+ 'unlock' => ''.esc_html__('Unlock', 'all-in-one-wp-security-and-firewall').'',
+ 'delete' => ''.esc_html__('Delete', 'all-in-one-wp-security-and-firewall').'',
+ );
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /*$1%s*/ $item['failed_login_ip'],
+ /*$2%s*/ $this->row_actions($actions)
+ );
+ }
+
+
+ /**
+ * This function renders the checkbox column
+ *
+ * @param array $item - item object
+ *
+ * @return string
+ */
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
+ /*$2%s*/ $item['id'] //The value of the checkbox should be the record's id
+ );
+ }
+
+ /**
+ * Returns ip_lookup_result column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_ip_lookup_result($item) {
+ if (empty($item['ip_lookup_result'])) return __('There is no IP lookup result available.', 'all-in-one-wp-security-and-firewall');
+
+ $ip_lookup_result = json_decode($item['ip_lookup_result'], true);
+
+ // check that the json decode worked
+ if (null === $ip_lookup_result) return __('There is no IP lookup result available.', 'all-in-one-wp-security-and-firewall');
+
+ foreach ($ip_lookup_result as $key => $value) {
+ $ip_lookup_result[$key] = empty($value) ? __('Not Found', 'all-in-one-wp-security-and-firewall') : $value;
+ }
+
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- PCP warning. Part of error reporting system.
+ $ip_lookup_result = print_r($ip_lookup_result, true);
+
+ $output = sprintf('%s', esc_attr($item['id']), esc_html__('IP lookup result', 'all-in-one-wp-security-and-firewall'), esc_html__('Show result', 'all-in-one-wp-security-and-firewall'));
+ $output .= sprintf('
%s
', esc_attr($item['id']), esc_html($ip_lookup_result));
+
+ return $output;
+ }
+
+ /**
+ * Sets the columns for the table
+ *
+ * @return array
+ */
+ public function get_columns() {
+ return array(
+ 'cb' => '', //Render a checkbox
+ 'failed_login_ip' => __('Locked IP/range', 'all-in-one-wp-security-and-firewall'),
+ 'user_id' => __('User ID', 'all-in-one-wp-security-and-firewall'),
+ 'user_login' => __('Username', 'all-in-one-wp-security-and-firewall'),
+ 'lock_reason' => __('Reason', 'all-in-one-wp-security-and-firewall'),
+ 'created' => __('Date locked', 'all-in-one-wp-security-and-firewall'),
+ 'released' => __('Release date', 'all-in-one-wp-security-and-firewall'),
+ 'ip_lookup_result' => __('IP lookup result', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ /**
+ * This function returns sortable columns
+ *
+ * @return array[]
+ */
+ public function get_sortable_columns() {
+ return array(
+ 'failed_login_ip' => array('failed_login_ip',false),
+ 'user_id' => array('user_id',false),
+ 'user_login' => array('user_login',false),
+ 'lock_reason' => array('lock_reason',false),
+ 'created' => array('created',false),
+ 'released' => array('released',false)
+ );
+ }
+
+ /**
+ * This returns the bulk actions for the table
+ *
+ * @return array
+ */
+ public function get_bulk_actions() {
+ return array(
+ 'unlock' => __('Unlock', 'all-in-one-wp-security-and-firewall'),
+ 'delete' => __('Delete', 'all-in-one-wp-security-and-firewall'),
+ );
+ }
+
+ /**
+ * Process bulk actions.
+ *
+ * @return void
+ */
+ private function process_bulk_action() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. This is the nonce.
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
+ if (is_wp_error($result)) return;
+
+ if ('delete' == $this->current_action()) { // Process delete bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Sanitized later.
+ $this->delete_lockout_records(wp_unslash($_REQUEST['item']));
+ }
+ }
+
+ if ('unlock' == $this->current_action()) { //Process unlock bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Sanitized later.
+ $this->unlock_ips((wp_unslash($_REQUEST['item'])));
+ }
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
+ }
+
+ /**
+ * Unlocks multiple IP addresses by modifying the released column of records in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @param array $entries IDs that correspond to IP addresses in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @return void
+ */
+ public function unlock_ips($entries) {
+ global $wpdb;
+
+ $lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ // Unlock multiple records
+ $entries = array_filter($entries, 'is_numeric'); // Discard non-numeric ID values
+ $id_list = '(' .implode(',', $entries) .')'; // Create comma separate list for DB operation
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $result = $wpdb->query("UPDATE $lockout_table SET `released` = UNIX_TIMESTAMP() WHERE `id` IN $id_list");
+
+ if (null != $result) {
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP entries were unlocked successfully.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Deletes one or more records from the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @param array|string|integer $entries - ids or a single id
+ *
+ * @return void|string
+ */
+ public function delete_lockout_records($entries) {
+ global $wpdb, $aio_wp_security;
+ $lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ if (is_array($entries)) {
+ // Delete multiple records
+ $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
+ $id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
+ $delete_command = "DELETE FROM ".$lockout_table." WHERE id IN ".$id_list;
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query($delete_command);
+ if ($result) {
+ AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
+ } else {
+ // Error on bulk delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from login lockout table. Database error: '.$wpdb->last_error, 4);
+ AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
+ }
+ } elseif (null != $entries) {
+ // Delete single record
+ $delete_command = "DELETE FROM ".$lockout_table." WHERE id = '".absint($entries)."'";
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query($delete_command);
+ if ($result) {
+ return AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st(true);
+ } elseif (false === $result) {
+ // Error on single delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from login lockout table. Database error: '.$wpdb->last_error, 4);
+ return AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st(true);
+ }
+ }
+ }
+
+ /**
+ * Retrieves all items from AIOWPSEC_TBL_LOGIN_LOCKOUT. It may paginate and then assigns to $this->items.
+ *
+ * @param Boolean $ignore_pagination - whether to not paginate
+ *
+ * @return Void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ global $wpdb;
+
+ $lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ $this->process_bulk_action();
+
+ // How many records per page to show
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ // Parameters that are going to be used to order the result
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
+
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'created';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ $current_page = $this->get_pagenum();
+ $offset = ($current_page - 1) * $per_page;
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP()");
+
+ if ($ignore_pagination) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() ORDER BY {$orderby} {$order}", 'ARRAY_A');
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() ORDER BY {$orderby} {$order} LIMIT {$per_page} OFFSET {$offset}", 'ARRAY_A');
+ }
+
+ $this->items = $data;
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, // WE have to calculate the total number of items
+ 'per_page' => $per_page, // WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) // WE have to calculate the total number of pages
+ ));
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-logged-in-users.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-logged-in-users.php
new file mode 100755
index 00000000..284608e2
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-logged-in-users.php
@@ -0,0 +1,260 @@
+ 'item', //singular name of the listed records
+ 'plural' => 'items', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+
+ }
+
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Returns user id column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_user_id($item) {
+ //Build row actions
+ $actions = array(
+ 'logout' => ''.__('Force logout', 'all-in-one-wp-security-and-firewall').'',
+ );
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /*$1%s*/ $item['user_id'],
+ /*$2%s*/ $this->row_actions($actions)
+ );
+ }
+
+ /**
+ * Sets the columns for the table
+ *
+ * @return array
+ */
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '',
+ 'user_id' => __('User ID', 'all-in-one-wp-security-and-firewall'),
+ 'username' => __('Login name', 'all-in-one-wp-security-and-firewall'),
+ 'ip_address' => __('IP address', 'all-in-one-wp-security-and-firewall'),
+ 'site_id' => __('Site ID', 'all-in-one-wp-security-and-firewall'),
+ );
+ return $columns;
+ }
+
+ /**
+ * Returns cb column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /* $1%s */ $this->_args['singular'], // Let's simply repurpose the table's singular label
+ /* $2%s */ $item['user_id'] // The value of the checkbox should be the record's id and its ip address
+ );
+ }
+
+ /**
+ * Sets which of the columns the table data can be sorted by
+ *
+ * @return array
+ */
+ public function get_sortable_columns() {
+ return array(
+ 'user_id' => array('user_id',false),
+ 'username' => array('username',false),
+ 'ip_address' => array('ip_address',false),
+ 'site_id' => array('site_id',false),
+ );
+ }
+
+ /**
+ * Adds a bulk action user interface
+ *
+ * @return array
+ */
+ public function get_bulk_actions() {
+ return array(
+ 'force_logout_all' => __('Logout all', 'all-in-one-wp-security-and-firewall'),
+ 'force_logout_selected' => __('Logout selected', 'all-in-one-wp-security-and-firewall'),
+ );
+ }
+
+ /**
+ * Process Bulk action from menu
+ *
+ * @return void
+ */
+ private function process_bulk_action() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce used.
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
+ if (is_wp_error($result)) return;
+
+ if ('force_logout_all' === $this->current_action()) {
+ $this->force_user_logout(array(), true);
+ } elseif ('force_logout_selected' === $this->current_action()) {
+ if (isset($_REQUEST['item'])) {
+
+ if (is_array($_REQUEST['item'])) $this->force_user_logout(wp_unslash($_REQUEST['item']));
+ }
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. Nonce used.
+ }
+
+ /**
+ * This function will force selected user(s) to be logged out.
+ *
+ * @param int|array $users - id of selected user or array of user ids to be logged out
+ * @param bool $logout_all - Boolean to show if all users should be logged out
+ *
+ * @return void|string
+ */
+ public function force_user_logout($users, $logout_all = false) {
+ global $wpdb, $aio_wp_security;
+
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+
+ if ($logout_all) {
+ // get all user_id(except for the admin) in the table and make it an array for users
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $users = $wpdb->get_col("SELECT user_id FROM $logged_in_users_table");
+ }
+
+ if (is_array($users)) {
+
+ if (empty($users)) {
+ AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
+ return;
+ }
+
+ $errors = 0;
+
+ // Escape the user IDs for security
+ $users = array_map('esc_sql', $users);
+
+ foreach ($users as $user_id) {
+ if (is_numeric($user_id) && !is_super_admin($user_id) && AIOWPSecurity_Utility::is_user_member_of_blog($user_id)) {
+ if ($aio_wp_security->user_login_obj->delete_logged_in_user($user_id)) {
+ $this->logout_user($user_id);
+ continue;
+ }
+ }
+ $errors++;
+ }
+
+ if ($errors > 0) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__("Some users were not logged out due to the ID being invalid, or them being a super admin or a member of a different subsite on a multisite", 'all-in-one-wp-security-and-firewall'));
+ return;
+ }
+
+ AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
+ }
+ }
+
+
+ /**
+ * This function handles logging out a user using user_id
+ *
+ * @param int $user_id - id of user being logged out
+ *
+ * @return void
+ */
+ public function logout_user($user_id) {
+ $user_id = absint($user_id);
+ $manager = WP_Session_Tokens::get_instance($user_id);
+ $manager->destroy_all();
+ }
+
+ /**
+ * Prepares the items for the logged in users table
+ *
+ * @param bool $ignore_pagination - this is to check if data should be paginated or not
+ *
+ * @return void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ global $wpdb;
+
+ //First, lets decide how many records per page to show
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+ $current_page = $this->get_pagenum();
+ $offset = ($current_page - 1) * $per_page;
+
+ // Parameters that are going to be used to order the result
+ // phpcs:disable -- Rule won't be silenced any other way. No nonce.
+ $orderby = isset($_GET["orderby"]) ? sanitize_text_field(wp_unslash($_GET["orderby"])) : '';
+ $order = isset($_GET["order"]) ? sanitize_text_field(wp_unslash($_GET["order"])) : '';
+ // phpcs:enable -- Rule won't be silenced any other way. No nonce.
+
+ // By default show the most recent logged in user entries.
+ $orderby = empty($orderby) ? 'created' : esc_sql($orderby);
+ $order = empty($order) ? 'DESC' : esc_sql($order);
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ $orderby = sanitize_sql_orderby($orderby);
+ $order = sanitize_sql_orderby($order);
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $this->process_bulk_action(); // Process bulk actions
+
+ $where_sql = $this->get_where_sql();
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $total_items = $wpdb->get_var("SELECT COUNT(*) FROM `{$logged_in_users_table}` $where_sql");
+
+ if ($ignore_pagination) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM `{$logged_in_users_table}` $where_sql ORDER BY $orderby $order", 'ARRAY_A');
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM `{$logged_in_users_table}` $where_sql ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
+ }
+
+ $this->items = $data;
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
+ ));
+ }
+
+ /**
+ * This function will build and return the SQL WHERE statement
+ *
+ * @return string - the SQL WHERE statement
+ */
+ private function get_where_sql() {
+ if (is_main_site() && is_super_admin()) return '';
+
+ return is_multisite() ? sprintf("WHERE site_id = %d", get_current_blog_id()) : '';
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-permanent-blocked-ip.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-permanent-blocked-ip.php
new file mode 100755
index 00000000..2e5c4753
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-permanent-blocked-ip.php
@@ -0,0 +1,238 @@
+ 'item', //singular name of the listed records
+ 'plural' => 'items', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+
+ }
+
+ /**
+ * Returns created column in datetime format as per user setting time zone.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the datetime
+ */
+ public function column_created($item) {
+ return AIOWPSecurity_Utility::convert_timestamp($item['created']);
+ }
+
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Function to populate the permanent blocked ip actions column in the table
+ *
+ * @param array $item - Contains the current item data
+ *
+ * @return string
+ */
+ public function column_id($item) {
+ $actions = array(
+ 'unblock' => 'Unblock',
+ );
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /*$1%s*/
+ $item['id'],
+ /*$2%s*/
+ $this->row_actions($actions)
+ );
+ }
+
+
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /*$1%s*/
+ $this->_args['singular'], //Let's simply repurpose the table's singular label
+ /*$2%s*/
+ $item['id'] //The value of the checkbox should be the record's id
+ );
+ }
+
+ public function get_columns() {
+ return array(
+ 'cb' => '', //Render a checkbox
+ 'id' => 'ID',
+ 'blocked_ip' => __('Blocked IP', 'all-in-one-wp-security-and-firewall'),
+ 'block_reason' => __('Reason', 'all-in-one-wp-security-and-firewall'),
+ 'created' => __('Date and Time', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ public function get_sortable_columns() {
+ return array(
+ 'id' => array('id', false),
+ 'blocked_ip' => array('blocked_ip', false),
+ 'block_reason' => array('block_reason', false),
+ 'created' => array('created', false)
+ );
+ }
+
+ public function get_bulk_actions() {
+ return array(
+ 'unblock' => __('Unblock', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ private function process_bulk_action() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. It IS the nonce. Ignore.
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Ignore.
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
+ if (is_wp_error($result)) return;
+
+ if ('unblock' === $this->current_action()) { // Process unlock bulk actions
+ if (!isset($_REQUEST['item'])) {
+ AIOS_Helper::set_message('aios_list_message', __('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'), 'error');
+ } else {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitized later
+ $this->unblock_ip_address(wp_unslash($_REQUEST['item']));
+ }
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. It IS the nonce. Ignore.
+ }
+
+ /**
+ * Deletes one or more records from the AIOWPSEC_TBL_PERM_BLOCK table.
+ *
+ * @param array|string|integer $entries - ids or a single id
+ *
+ * @return void|string
+ */
+ public function unblock_ip_address($entries) {
+ global $wpdb, $aio_wp_security;
+ if (is_array($entries)) {
+ // multiple records
+
+ $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
+ $id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation
+ $delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id IN " . $id_list; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $id_list cannot be prepared.
+ $result = $wpdb->query($delete_command);
+ if ($result) {
+ AIOS_Helper::set_message('aios_list_message', __('Successfully unblocked and deleted the selected record(s).', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ // Error on bulk delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Perm Block table. Database error: '.$wpdb->last_error, 4);
+ AIOS_Helper::set_message('aios_list_message', __('Failed to unblock and delete the selected record(s).', 'all-in-one-wp-security-and-firewall'), 'error');
+ }
+ } elseif (!empty($entries)) {
+ //Delete single record
+ $delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id = %d";
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $result = $wpdb->query($wpdb->prepare($delete_command, absint($entries)));
+ if (false === $result) {
+ // Error on single delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Perm Block table. Database error: '.$wpdb->last_error, 4);
+ }
+
+ return $result;
+ }
+ }
+
+ /**
+ * This function will build and return the SQL WHERE statement
+ *
+ * @param string $search_term - the search term applied
+ *
+ * @return string - the SQL WHERE statement
+ */
+ private function get_permanent_blocked_ip_list_where_sql($search_term) {
+ $where = '';
+ if (!empty($search_term)) {
+ $where = " WHERE";
+
+ // We don't use FILTER_VALIDATE_IP here as we want to be able to search for partial IP's
+ if (preg_match('/^[0-9a-f:\.]+$/i', $search_term)) {
+ $where .= " `blocked_ip` LIKE '%".esc_sql($search_term)."%' OR";
+ }
+
+ $where .= " `block_reason` LIKE '%".esc_sql($search_term)."%'";
+ $where .= " OR `country_origin` LIKE '%".esc_sql($search_term)."%'";
+ }
+
+ return $where;
+ }
+
+ /**
+ * Grabs the data from database and handles the pagination
+ *
+ * @param boolean $ignore_pagination - whether to not paginate
+ *
+ * @return void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ /**
+ * First, lets decide how many records per page to show
+ */
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $search = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : '';
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $this->process_bulk_action();
+
+ global $wpdb;
+ $block_table_name = AIOWPSEC_TBL_PERM_BLOCK;
+
+ // Ordering parameters
+ // Parameters that are going to be used to order the result
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $orderby = isset($_GET["orderby"]) ? sanitize_text_field(wp_unslash($_GET["orderby"])) : '';
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $order = isset($_GET["order"]) ? sanitize_text_field(wp_unslash($_GET["order"])) : '';
+
+ $orderby = !empty($orderby) ? esc_sql($orderby) : 'id';
+ $order = !empty($order) ? esc_sql($order) : 'DESC';
+
+ $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
+ $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
+
+ $current_page = $this->get_pagenum();
+ $offset = ($current_page - 1) * $per_page;
+
+
+ $search_query = $this->get_permanent_blocked_ip_list_where_sql($search);
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$block_table_name}{$search_query}");
+
+ if ($ignore_pagination) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$block_table_name} {$search_query} ORDER BY $orderby$order", 'ARRAY_A');
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $data = $wpdb->get_results("SELECT * FROM {$block_table_name}{$search_query} ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
+ }
+
+ $this->items = $data;
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
+ ));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-registered-users.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-registered-users.php
new file mode 100755
index 00000000..992eda21
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-registered-users.php
@@ -0,0 +1,355 @@
+ 'item', //singular name of the listed records
+ 'plural' => 'items', //plural name of the listed records
+ 'ajax' => false //does this table support ajax?
+ ));
+
+ }
+
+ public function column_default($item, $column_name) {
+ return $item[$column_name];
+ }
+
+ /**
+ * Returns ID column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_ID($item) {
+ //Build row actions
+ $actions = array(
+ 'view' => ''.__('View', 'all-in-one-wp-security-and-firewall').'',
+ 'approve_acct' => ''. __('Approve', 'all-in-one-wp-security-and-firewall') . '',
+ 'delete_acct' => ''. __('Delete', 'all-in-one-wp-security-and-firewall') . '',
+ 'block_ip' => ''. __('Block IP', 'all-in-one-wp-security-and-firewall') . '',
+ );
+
+ //Return the user_login contents
+ return sprintf('%1$s %2$s',
+ /*$1%s*/ $item['ID'],
+ /*$2%s*/ $this->row_actions($actions)
+ );
+ }
+
+ /**
+ * Returns IP address column html to be rendered.
+ *
+ * @param array $item - data for the columns on the current row
+ *
+ * @return string - the html to be rendered
+ */
+ public function column_ip_address($item) {
+ if (AIOWPSecurity_Blocking::is_ip_blocked($item['ip_address'])) {
+ return $item['ip_address'].' '.__('blocked', 'all-in-one-wp-security-and-firewall').'';
+ } else {
+ return $item['ip_address'];
+ }
+ }
+
+ public function column_cb($item) {
+ return sprintf(
+ '',
+ /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
+ /*$2%s*/ $item['ID'] //The value of the checkbox should be the record's id
+ );
+ }
+
+
+ /**
+ * Returns array of columns to be rendered.
+ *
+ * @return array
+ */
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '', // Render a checkbox
+ 'ID' => __('User ID', 'all-in-one-wp-security-and-firewall'),
+ 'user_login' => __('Login name', 'all-in-one-wp-security-and-firewall'),
+ 'user_email' => __('Email', 'all-in-one-wp-security-and-firewall'),
+ 'user_registered' => __('Register date', 'all-in-one-wp-security-and-firewall'),
+ 'account_status' => __('Account status', 'all-in-one-wp-security-and-firewall'),
+ 'ip_address' => __('IP address', 'all-in-one-wp-security-and-firewall')
+ );
+ return $columns;
+ }
+
+ public function get_sortable_columns() {
+ $sortable_columns = array(
+ // 'ID' => array('ID',false),
+ // 'user_login' => array('user_login',false),
+ // 'user_email' => array('user_email',false),
+ // 'user_registered' => array('user_registered',false),
+ // 'account_status' => array('account_status',false),
+ );
+ return $sortable_columns;
+ }
+
+ public function get_bulk_actions() {
+ $actions = array(
+ 'approve' => __('Approve', 'all-in-one-wp-security-and-firewall'),
+ 'delete' => __('Delete', 'all-in-one-wp-security-and-firewall'),
+ 'block' => __('Block IP', 'all-in-one-wp-security-and-firewall')
+ );
+ return $actions;
+ }
+
+ /**
+ * Process bulk actions.
+ *
+ * @return void
+ */
+ private function process_bulk_action() {
+ if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ $result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap(sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])), 'bulk-items'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ if (is_wp_error($result)) return;
+
+ if ('approve' == $this->current_action()) { //Process approve bulk actions
+ if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ $this->approve_selected_accounts(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ }
+ }
+
+ if ('delete' == $this->current_action()) { //Process delete bulk actions
+ if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ $this->delete_selected_accounts(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ }
+ }
+
+ if ('block' == $this->current_action()) { //Process block bulk actions
+ if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ $this->block_selected_ips(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+ }
+ }
+
+ }
+
+ /**
+ * This function approves selected user accounts
+ *
+ * @param array|int $entries - this is an array of users or user_id to be approved
+ *
+ * @return void|string
+ */
+ public function approve_selected_accounts($entries) {
+ global $aio_wp_security;
+ $meta_key = 'aiowps_account_status';
+ $meta_value = 'approved'; // set account status
+ $failed_accts = ''; // string to store comma separated accounts which failed to update
+ $at_least_one_updated = false;
+ if (is_array($entries)) {
+ $entries = array_map('esc_sql', $entries); // Escape every array element
+ //Let's go through each entry and approve
+ foreach ($entries as $user_id) {
+ $result = update_user_meta($user_id, $meta_key, $meta_value);
+ if (false === $result) {
+ $failed_accts .= ' '.$user_id.', ';
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::approve_selected_accounts() - could not approve account ID: $user_id", 4);
+ } else {
+ $at_least_one_updated = true;
+ $user = get_user_by('id', $user_id);
+ if (false === $user) {
+ //don't send mail
+ } else {
+ $this->send_email_upon_account_activation($user);
+ }
+ }
+ }
+ if ($at_least_one_updated) {
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected accounts were approved successfully.', 'all-in-one-wp-security-and-firewall'));
+ }
+ if ('' != $failed_accts) {
+ //display any failed account updates
+ rtrim($failed_accts);
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('The following accounts failed to update successfully:', 'all-in-one-wp-security-and-firewall') . ' ' . $failed_accts);
+ }
+ }
+ }
+
+ /**
+ * This function sends an email to an approved user
+ *
+ * @param WP_User $user - the object for the approved user
+ *
+ * @return bool
+ */
+ public function send_email_upon_account_activation($user) {
+ global $aio_wp_security;
+ if (!($user instanceof WP_User)) {
+ return false;
+ }
+
+ $to_email_address = $user->user_email;
+ $email_msg = '';
+ $subject = '['.network_site_url().'] '. __('Your account is now active', 'all-in-one-wp-security-and-firewall');
+ /* translators: %s: Username */
+ $email_msg .= sprintf(__('Your account with username: %s is now active', 'all-in-one-wp-security-and-firewall'), $user->user_login) . "\n";
+ $subject = apply_filters('aiowps_register_approval_email_subject', $subject);
+ $email_msg = apply_filters('aiowps_register_approval_email_msg', $email_msg, $user); //also pass the WP_User object
+
+ $sendMail = wp_mail($to_email_address, $subject, $email_msg);
+ if (false === $sendMail) {
+ $aio_wp_security->debug_logger->log_debug("Manual account approval notification email failed to send to " . $to_email_address, 4);
+ }
+ return $sendMail;
+ }
+
+ /**
+ * This function deletes selected entries pending approval
+ *
+ * @param array|int $entries - this is an array of users or single user to be deleted
+ *
+ * @return void|string
+ */
+ public function delete_selected_accounts($entries) {
+ global $aio_wp_security;
+ if (is_array($entries)) {
+ $entries = array_map('esc_sql', $entries); // Escape every array element
+ //Let's go through each entry and delete account
+ foreach ($entries as $user_id) {
+ $result = wp_delete_user($user_id);
+ if (true !== $result) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::delete_selected_accounts() - could not delete account ID: $user_id", 4);
+ }
+ }
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected accounts were deleted successfully.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * This function blocks selected ip
+ *
+ * @param array|int $entries - this is an array of ips or ip to be blocked
+ *
+ * @return void|string
+ */
+ public function block_selected_ips($entries) {
+ global $aio_wp_security;
+ if (is_array($entries)) {
+ $entries = array_filter($entries, function ($entry) {
+ return AIOWPSecurity_Utility_IP::get_user_ip_address() != $entry;
+ });
+
+ if (empty($entries)) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Only invalid IP addresses were provided: you can not block your own IP address', 'all-in-one-wp-security-and-firewall'));
+ return;
+ }
+ $entries = array_map('esc_sql', $entries); // Escape every array element
+ //Let's go through each entry and block IP
+ $total_success = 0;
+ foreach ($entries as $id) {
+ $ip_address = get_user_meta($id, 'aiowps_registrant_ip', true);
+ $result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip_address, 'registration_spam');
+ if (false === $result) {
+ if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip_address) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip_address);
+ }
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::block_selected_ips() - could not block IP : $ip_address", 4);
+ } else {
+ $total_success++;
+ }
+ }
+ if ($total_success > 0) {
+ $msg = __('The selected IP addresses were successfully added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
+ $msg .= ' '.__('View Blocked IPs', 'all-in-one-wp-security-and-firewall').'';
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
+ }
+ }
+ }
+
+ /**
+ * Grabs the data from database and handles the pagination
+ *
+ * @param boolean $ignore_pagination - whether to not paginate
+ * @return void
+ */
+ public function prepare_items($ignore_pagination = false) {
+ //First, lets decide how many records per page to show
+ $per_page = 100;
+ $columns = $this->get_columns();
+ $current_page = $this->get_pagenum();
+ $offset = ($current_page - 1) * $per_page;
+ $hidden = array();
+ $sortable = $this->get_sortable_columns();
+ $search = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
+
+ $this->_column_headers = array($columns, $hidden, $sortable);
+
+ $this->process_bulk_action();
+
+ //Get registered users which have the special 'aiowps_account_status' meta key set to 'pending'
+ if ($ignore_pagination) {
+ $result = $this->get_registered_user_data('pending', $search);
+ } else {
+ $result = $this->get_registered_user_data('pending', $search, $per_page, $offset);
+ }
+
+ $total_items = $result['total'];
+ $this->items = $result['data'];
+
+ if ($ignore_pagination) return;
+
+ $this->set_pagination_args(array(
+ 'total_items' => $total_items, //WE have to calculate the total number of items
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
+ 'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
+ ));
+ }
+
+ /**
+ * Returns all users who have the special 'aiowps_account_status' meta key
+ *
+ * @param string $status - the status we want to search for
+ * @param string $search - the search query
+ * @param null $per_page - how many results per page
+ * @param int $offset - the page offset
+ *
+ * @return array - an array of users that match the search
+ */
+ public function get_registered_user_data($status = '', $search = '', $per_page = null, $offset = 0) {
+ $user_fields = array( 'ID', 'user_login', 'user_email', 'user_registered');
+ $user_query = new WP_User_Query(array('meta_key' => 'aiowps_account_status', 'meta_value' => $status, 'fields' => $user_fields, 'number' => $per_page, 'offset' => $offset)); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- ignore this
+ $user_results = $user_query->results;
+ $user_total = $user_query->get_total();
+
+ $final_data = array();
+ foreach ($user_results as $user) {
+ $temp_array = get_object_vars($user); //Turn the object into array
+ $temp_array['account_status'] = get_user_meta($temp_array['ID'], 'aiowps_account_status', true);
+ $ip = get_user_meta($temp_array['ID'], 'aiowps_registrant_ip', true);
+ $temp_array['ip_address'] = empty($ip) ? '' : $ip;
+ if (empty($search)) {
+ $final_data[] = $temp_array;
+ } else {
+ $input = preg_quote($search, '~'); // don't forget to quote input string!
+
+ $result = preg_grep('~' . $input . '~', $temp_array);
+ if (!empty($result)) $final_data[] = $temp_array;
+ }
+ }
+
+ return array(
+ 'data' => $final_data,
+ 'total' => $user_total,
+ );
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-reset-settings.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-reset-settings.php
new file mode 100755
index 00000000..179a49e5
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-reset-settings.php
@@ -0,0 +1,90 @@
+query('TRUNCATE ' . $wpdb->prefix . 'aiowps_login_lockdown');
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_global_meta');
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_events');
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_permanent_block');
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Ignore.
+ if (is_main_site()) {
+ $wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_LOGGED_IN_USERS);
+ $wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_MESSAGE_STORE);
+ $wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_DEBUG_LOG);
+ $wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_AUDIT_LOG);
+ }
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Ignore.
+ return true;
+ }
+ }
+
+endif;
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-settings-menu.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-settings-menu.php
new file mode 100755
index 00000000..13556c04
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-settings-menu.php
@@ -0,0 +1,157 @@
+ array(
+ 'title' => __('General settings', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_general_settings'),
+ ),
+ 'htaccess-file-operations' => array(
+ 'title' => '.htaccess '.__('file', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_htaccess_file_operations'),
+ 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
+ ),
+ 'wp-config-file-operations' => array(
+ 'title' => 'wp-config.php '.__('file', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_wp_config_file_operations'),
+ 'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
+ ),
+ 'delete-plugin-settings' => array(
+ 'title' => __('Delete plugin settings', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_delete_plugin_settings_tab')
+ ),
+ 'wp-version-info' => array(
+ 'title' => __('WP version info', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_wp_version_info'),
+ ),
+ 'settings-file-operations' => array(
+ 'title' => __('Import/Export', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_settings_file_operations'),
+ ),
+ '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'),
+ ),
+ );
+
+ $menu_tabs = apply_filters('aiowpsecurity_setting_tabs', $menu_tabs);
+ $this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
+ }
+
+ /**
+ * Renders the submenu's general settings tab.
+ *
+ * @return void
+ */
+ protected function render_general_settings() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/settings/general-settings.php', false, array());
+ }
+
+ /**
+ * Renders the submenu's htaccess file operations tab.
+ *
+ * @return void
+ */
+ protected function render_htaccess_file_operations() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/settings/htaccess-file-operations.php', false, array());
+ }
+
+ /**
+ * Renders the submenu's wp config file operations tab.
+ *
+ * @return void
+ */
+ protected function render_wp_config_file_operations() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/settings/wp-config-file-operations.php', false, array());
+ }
+
+ /**
+ * Renders the submenu's delete plugin settings tab.
+ *
+ * @return void
+ */
+ protected function render_delete_plugin_settings_tab() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/settings/delete-plugin-settings.php', false, array());
+ }
+
+ /**
+ * Renders the submenu's wp version info tab.
+ *
+ * @return void
+ */
+ protected function render_wp_version_info() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ $aio_wp_security->include_template('wp-admin/settings/wp-version-info.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
+ }
+
+ /**
+ * Renders the submenu's settings file operations tab.
+ *
+ * @return void
+ */
+ protected function render_settings_file_operations() {
+ global $aio_wp_security;
+
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
+ AIOWPSecurity_Utility::cleanup_table($events_table_name, 500);
+
+ $aio_wp_security->include_template('wp-admin/settings/settings-file-operations.php', false, array());
+ }
+
+ /**
+ * Renders advanced settings tab.
+ *
+ * @return void
+ */
+ protected function render_advanced_settings() {
+ if (!is_main_site()) {
+ return;
+ }
+
+ global $aio_wp_security;
+
+ $aios_commands = new AIOWPSecurity_Commands();
+
+ $advanced_settings_data = $aios_commands->get_ip_address_detection_data();
+
+ $aio_wp_security->include_template('wp-admin/settings/advanced-settings.php', false, $advanced_settings_data);
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-spam-menu.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-spam-menu.php
new file mode 100755
index 00000000..1c13d061
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-spam-menu.php
@@ -0,0 +1,93 @@
+ array(
+ 'title' => __('Comment spam', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_comment_spam'),
+ ),
+ 'comment-spam-ip-monitoring' => array(
+ 'title' => __('Comment spam IP monitoring', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_comment_spam_ip_monitoring'),
+ ),
+ );
+
+ $this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
+ }
+
+ /**
+ * Renders the submenu's comment spam ip monitoring tab body.
+ *
+ * @return Void
+ */
+ protected function render_comment_spam() {
+ global $aiowps_feature_mgr, $aio_wp_security;
+ $aio_wp_security->include_template('wp-admin/spam-prevention/comment-spam.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
+ }
+
+ /**
+ * Renders the submenu's comment spam ip monitoring tab body.
+ *
+ * @return Void
+ */
+ protected function render_comment_spam_ip_monitoring() {
+ global $aio_wp_security, $aiowps_feature_mgr, $wpdb;
+ include_once 'wp-security-list-comment-spammer-ip.php'; // For rendering the AIOWPSecurity_List_Table in tab2
+ $spammer_ip_list = new AIOWPSecurity_List_Comment_Spammer_IP();
+
+ $block_comments_output = '';
+
+ $min_block_comments = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
+ if (!empty($min_block_comments)) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $total_res = $wpdb->get_results($wpdb->prepare('SELECT * FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE block_reason=%s', 'spam'));
+ $block_comments_output = '
';
+ if (empty($total_res)) {
+ $block_comments_output .= '
'.esc_html__('You currently have no IP addresses permanently blocked due to spam.', 'all-in-one-wp-security-and-firewall').'
';
+ } else {
+ $total_count = count($total_res);
+ $todays_blocked_count = 0;
+ foreach ($total_res as $blocked_item) {
+ $now_date_time = new DateTime('now', new DateTimeZone('UTC'));
+ $blocked_date = new DateTime('@'.$blocked_item->created); //@ with timestamp creates correct DateTime
+ if ($blocked_date->format('Y-m-d') == $now_date_time->format('Y-m-d')) {
+ //there was an IP added to permanent block list today
+ ++$todays_blocked_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).'
'.'
'.esc_html__('All time total:', 'all-in-one-wp-security-and-firewall'). ' ' .esc_html($total_count).'
';
+ }
+ return $account_output;
+ }
+
+ /**
+ * Login Lockout configuration to set.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
+ *
+ * @return Void
+ */
+ protected function render_login_lockout() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ include_once 'wp-security-list-locked-ip.php'; // For rendering the AIOWPSecurity_List_Table in tab1
+ $locked_ip_list = new AIOWPSecurity_List_Locked_IP(); // For rendering the AIOWPSecurity_List_Table in tab1
+
+ $aiowps_lockdown_allowed_ip_addresses = $aio_wp_security->configs->get_value('aiowps_lockdown_allowed_ip_addresses');
+
+ $aio_wp_security->include_template('wp-admin/user-security/login-lockout.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'locked_ip_list' => $locked_ip_list, "aiowps_lockdown_allowed_ip_addresses" => $aiowps_lockdown_allowed_ip_addresses));
+ }
+
+ /**
+ * Force logged user to logout after x minutes.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
+ * @return void
+ */
+ protected function render_force_logout() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ $aio_wp_security->include_template('wp-admin/user-security/force-logout.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
+ }
+
+ /**
+ * Logged in users list.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @return void
+ */
+ protected function render_logged_in_users() {
+ global $aio_wp_security;
+
+ include_once 'wp-security-list-logged-in-users.php'; // For rendering the AIOWPSecurity_List_Table
+ $user_list = new AIOWPSecurity_List_Logged_In_Users();
+
+ $aio_wp_security->include_template('wp-admin/user-security/logged-in-users.php', false, array('user_list' => $user_list));
+ }
+
+ /**
+ * Renders the submenu's manual approval tab
+ *
+ * @return Void
+ */
+ protected function render_manual_approval() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ include_once 'wp-security-list-registered-users.php'; // For rendering the AIOWPSecurity_List_Table
+ $user_list = new AIOWPSecurity_List_Registered_Users();
+
+ $aio_wp_security->include_template('wp-admin/user-security/manual-approval.php', false, array('user_list' => $user_list, 'aiowps_feature_mgr' => $aiowps_feature_mgr));
+ }
+
+ /**
+ * Renders the submenu's salt tab
+ *
+ * @return Void
+ */
+ protected function render_salt_tab() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/user-security/salt.php');
+ }
+
+ /**
+ * Renders the submenu's http authentication tab.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @return void
+ */
+ protected function render_http_authentication() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ if (isset($_POST['aiowps_save_http_authentication_settings'])) {
+ $nonce_user_cap_result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_POST['_wpnonce'], 'aiowpsec-http-authentication-settings-nonce');
+
+ if (is_wp_error($nonce_user_cap_result)) {
+ $aio_wp_security->debug_logger->log_debug($nonce_user_cap_result->get_error_message(), 4);
+ die($nonce_user_cap_result->get_error_message());
+ }
+
+ $error = false;
+
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_admin', '');
+
+ if (isset($_POST['aiowps_http_authentication_admin'])) {
+ if (!is_ssl()) {
+ $this->show_msg_error(__('Failed to save \'Enable for WordPress dashboard\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Your site is currently not using https.', 'all-in-one-wp-security-and-firewall'));
+ $error = true;
+ } else {
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_admin', '1');
+ }
+ }
+
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_frontend', '');
+
+ if (isset($_POST['aiowps_http_authentication_frontend'])) {
+ if (!is_ssl()) {
+ $this->show_msg_error(__('Failed to save \'Enable for frontend\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Your site is currently not using https.', 'all-in-one-wp-security-and-firewall'));
+ $error = true;
+ } else {
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_frontend', '1');
+ }
+ }
+
+ if (empty($_POST['aiowps_http_authentication_username'])) {
+ $this->show_msg_error(__('Failed to save \'Username\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please enter a value for the HTTP authentication username.', 'all-in-one-wp-security-and-firewall'));
+ $error = true;
+ } else {
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_username', sanitize_text_field($_POST['aiowps_http_authentication_username']));
+ }
+
+ if (empty($_POST['aiowps_http_authentication_password'])) {
+ $this->show_msg_error(__('Failed to save \'Password\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please enter a value for the HTTP authentication password.', 'all-in-one-wp-security-and-firewall'));
+ $error = true;
+ } else {
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_password', sanitize_text_field($_POST['aiowps_http_authentication_password']));
+ }
+
+ $aio_wp_security->configs->set_value('aiowps_http_authentication_failure_message', htmlentities(stripslashes($_POST['aiowps_http_authentication_failure_message']), ENT_COMPAT, 'UTF-8'));
+
+ $aio_wp_security->configs->save_config();
+
+ // Recalculate points after the feature status/options have been altered.
+ $aiowps_feature_mgr->check_feature_status_and_recalculate_points();
+
+ if (!$error) {
+ $this->show_msg_settings_updated();
+ }
+ }
+
+ wp_enqueue_script('aiowpsec-pw-tool-js');
+
+ $aio_wp_security->include_template('wp-admin/user-security/http-authentication.php');
+ }
+
+ /**
+ * Renders the submenu's hibp tab.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @return void
+ */
+ protected function render_hibp() {
+ global $aio_wp_security;
+
+ $aio_wp_security->include_template('wp-admin/user-security/hibp.php');
+ }
+
+ /**
+ * Shows additional tab and field for the disable application password and saves on submit.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
+ * @return void
+ */
+ protected function render_additional() {
+ global $aio_wp_security, $aiowps_feature_mgr;
+
+ $aio_wp_security->include_template('wp-admin/user-security/additional.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/backups/index.html b/wp-content/plugins/all-in-one-wp-security-and-firewall/backups/index.html
new file mode 100755
index 00000000..e69de29b
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-brute-force-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-brute-force-commands.php
new file mode 100755
index 00000000..44783bac
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-brute-force-commands.php
@@ -0,0 +1,561 @@
+' . __('You cannot use the value "wp-admin" for your login page slug.', 'all-in-one-wp-security-and-firewall');
+ } elseif (preg_match('/[^\p{L}\p{N}_\-]/u', $aiowps_login_page_slug)) {
+ $error = ' ' . __('You must use alphanumeric characters for your login page slug.', 'all-in-one-wp-security-and-firewall');
+ }
+ }
+
+ if ($error) {
+ $success = false;
+ $message = $error;
+ } else {
+ $options['aiowps_enable_rename_login_page'] = isset($data["aiowps_enable_rename_login_page"]) ? '1' : '';
+ $options['aiowps_login_page_slug'] = $aiowps_login_page_slug;
+
+ $this->save_settings($options);
+
+ if (get_option('permalink_structure')) {
+ $home_url = trailingslashit(home_url());
+ } else {
+ $home_url = trailingslashit(home_url()) . '?';
+ }
+
+ $message = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
+ $args['badges'] = array("bf-rename-login-page");
+ $args['content'] = array('aios-rename-login-notice' => $aio_wp_security->include_template('wp-admin/brute-force/partials/rename-login-notice.php', true, array('home_url' => $home_url)));
+ }
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Handles the AJAX request to enable or configure cookie-based brute force prevention.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_cookie_based_brute_force_prevention($data) {
+ global $aio_wp_security;
+
+ $options = array();
+ $values = array();
+ $info = array();
+
+ $success = true;
+ $message = '';
+ $result = '';
+
+ if (isset($data['aiowps_enable_brute_force_attack_prevention'])) {
+ $brute_force_feature_secret_word = sanitize_text_field($data['aiowps_brute_force_secret_word']);
+ $redirect_url = sanitize_text_field($data['aiowps_cookie_based_brute_force_redirect_url']);
+ if (empty($brute_force_feature_secret_word)) {
+ $brute_force_feature_secret_word = AIOS_DEFAULT_BRUTE_FORCE_FEATURE_SECRET_WORD;
+ $info[] = __('You entered an invalid value for the secret word.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ } elseif (!ctype_alnum($brute_force_feature_secret_word)) {
+ $message = '
' . __('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') . '
' . __('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)) . '
' . __('The cookie test was successful, you can now enable this feature.', 'all-in-one-wp-security-and-firewall') . '
';
+ } else {
+ $success = false;
+ $message = __('The cookie test failed.', 'all-in-one-wp-security-and-firewall') .' '. __('Consequently, this feature cannot be used on this site.', 'all-in-one-wp-security-and-firewall');
+ $result = '
' . __('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') . '
';
+ }
+
+ $this->save_settings(array('aiowps_cookie_test_success' => $aiowps_cookie_test_success)); // save the value
+ $args['content'] = array(
+ 'aios-perform-cookie-test-div' => $this->get_perform_cookie_test_content(),
+ 'cookie-test-result-div' => $result
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Handles the AJAX request to enable or configure login whitelist settings.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_login_whitelist_settings($data) {
+ global $aio_wp_security;
+
+ $success = true;
+ $options = array();
+ $message = '';
+
+ if (!empty($data['aiowps_allowed_ip_addresses'])) {
+ $ip_addresses = sanitize_textarea_field(stripslashes($data['aiowps_allowed_ip_addresses']));
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'whitelist');
+ if (is_wp_error($validated_ip_list_array)) {
+ $result = -1;
+ $success = false;
+ $message = nl2br($validated_ip_list_array->get_error_message());
+ } else {
+ $result = 1;
+ $whitelist_ip_data = implode("\n", $validated_ip_list_array);
+ $options['aiowps_allowed_ip_addresses'] = $whitelist_ip_data;
+ }
+ } else {
+ $result = 1;
+ $options['aiowps_allowed_ip_addresses'] = ''; // Clear the IP address config value
+ }
+
+ if (1 == $result) {
+ $options['aiowps_enable_whitelisting'] = isset($data["aiowps_enable_whitelisting"]) ? '1' : '';
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_is_login_whitelist_disabled_on_upgrade')) {
+ $aio_wp_security->configs->delete_value('aiowps_is_login_whitelist_disabled_on_upgrade');
+ }
+ $this->save_settings($options);
+ }
+
+ $args = array(
+ 'badges' => array('whitelist-manager-ip-login-whitelisting')
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Handles the AJAX request to enable or configure honeypot brute force settings.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_honeypot_settings($data) {
+
+ $options = array();
+ // Save all the form values to the options
+ $options['aiowps_enable_login_honeypot'] = isset($data["aiowps_enable_login_honeypot"]) ? '1' : '';
+ $options['aiowps_enable_registration_honeypot'] = isset($data["aiowps_enable_registration_honeypot"]) ? '1' : '';
+
+ $this->save_settings($options);
+
+ $args = array(
+ 'badges' => array('login-honeypot', 'registration-honeypot')
+ );
+
+ return $this->handle_response(true, '', $args);
+ }
+
+ /**
+ * Handles the AJAX request to enable or configure captcha settings.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_captcha_settings($data) {
+ global $aio_wp_security;
+
+ $captcha_themes = $aio_wp_security->captcha_obj->get_captcha_themes();
+ $supported_captchas = $aio_wp_security->captcha_obj->get_supported_captchas();
+ $options = array();
+
+ $default_captcha = isset($data['aiowps_default_captcha']) ? sanitize_text_field($data['aiowps_default_captcha']) : '';
+
+ $default_captcha = array_key_exists($default_captcha, $supported_captchas) ? $default_captcha : 'none';
+
+ $options['aiowps_default_captcha'] = $default_captcha;
+
+ // Save all the form values to the options
+ $random_20_digit_string = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20); // Generate random 20 char string for use during CAPTCHA encode/decode
+ $options['aiowps_captcha_secret_key'] = $random_20_digit_string;
+ $options['aiowps_enable_login_captcha'] = isset($data["aiowps_enable_login_captcha"]) ? '1' : '';
+ $options['aiowps_enable_registration_page_captcha'] = isset($data["aiowps_enable_registration_page_captcha"]) ? '1' : '';
+ $options['aiowps_enable_comment_captcha'] = isset($data["aiowps_enable_comment_captcha"]) ? '1' : '';
+ $options['aiowps_enable_bp_register_captcha'] = isset($data["aiowps_enable_bp_register_captcha"]) ? '1' : '';
+ $options['aiowps_enable_bbp_new_topic_captcha'] = isset($data["aiowps_enable_bbp_new_topic_captcha"]) ? '1' : '';
+ $options['aiowps_enable_woo_login_captcha'] = isset($data["aiowps_enable_woo_login_captcha"]) ? '1' : '';
+ $options['aiowps_enable_woo_register_captcha'] = isset($data["aiowps_enable_woo_register_captcha"]) ? '1' : '';
+ $options['aiowps_enable_woo_lostpassword_captcha'] = isset($data["aiowps_enable_woo_lostpassword_captcha"]) ? '1' : '';
+ $options['aiowps_enable_woo_checkout_captcha'] = isset($data["aiowps_enable_woo_checkout_captcha"]) ? '1' : '';
+ $options['aiowps_enable_custom_login_captcha'] = isset($data["aiowps_enable_custom_login_captcha"]) ? '1' : '';
+ $options['aiowps_enable_lost_password_captcha'] = isset($data["aiowps_enable_lost_password_captcha"]) ? '1' : '';
+ $options['aiowps_enable_contact_form_7_captcha'] = isset($data["aiowps_enable_contact_form_7_captcha"]) ? '1' : '';
+ $options['aiowps_enable_password_protected_captcha'] = isset($data["aiowps_enable_password_protected_captcha"]) ? '1' : '';
+
+ $options['aiowps_turnstile_site_key'] = sanitize_text_field(stripslashes($data['aiowps_turnstile_site_key']));
+ $options['aiowps_recaptcha_site_key'] = sanitize_text_field(stripslashes($data['aiowps_recaptcha_site_key']));
+
+ $turnstile_theme = isset($data['aiowps_turnstile_theme']) ? sanitize_text_field($data['aiowps_turnstile_theme']) : '';
+ $turnstile_theme = array_key_exists($turnstile_theme, $captcha_themes) ? $turnstile_theme : 'auto';
+ $options['aiowps_turnstile_theme'] = $turnstile_theme;
+
+ // If secret key is masked then don't resave it
+ $turnstile_secret_key = sanitize_text_field($data['aiowps_turnstile_secret_key']);
+ if (strpos($turnstile_secret_key, '********') === false) {
+ $options['aiowps_turnstile_secret_key'] = $turnstile_secret_key;
+ }
+
+ // If secret key is masked then don't resave it
+ $recaptcha_secret_key = sanitize_text_field($data['aiowps_recaptcha_secret_key']);
+ if (strpos($recaptcha_secret_key, '********') === false) {
+ $options['aiowps_recaptcha_secret_key'] = $recaptcha_secret_key;
+ }
+
+ if ('google-recaptcha-v2' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && false === $aio_wp_security->captcha_obj->google_recaptcha_verify_configuration($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'), $aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key'))) {
+ $options['aios_google_recaptcha_invalid_configuration'] = '1';
+ } elseif ('1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) {
+ $aio_wp_security->configs->delete_value('aios_google_recaptcha_invalid_configuration');
+ }
+
+ $this->save_settings($options);
+
+ $success = false;
+ $message = '';
+ if ('cloudflare-turnstile' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && false === $aio_wp_security->captcha_obj->cloudflare_turnstile_verify_configuration($aio_wp_security->configs->get_value('aiowps_turnstile_site_key'), $aio_wp_security->configs->get_value('aiowps_turnstile_secret_key'))) {
+ $message = __('Your Cloudflare Turnstile configuration is invalid.', 'all-in-one-wp-security-and-firewall').' '.__('Please enter the correct Cloudflare Turnstile keys below to use the Turnstile feature.', 'all-in-one-wp-security-and-firewall');
+ } elseif ('google-recaptcha-v2' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && '1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) {
+ $message = __('Your Google reCAPTCHA configuration is invalid.', 'all-in-one-wp-security-and-firewall').' '.__('Please enter the correct reCAPTCHA keys below to use the reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $success = true;
+ }
+
+ $features = array(
+ "user-login-captcha",
+ "user-registration-captcha",
+ "lost-password-captcha",
+ "custom-login-captcha",
+ "comment-form-captcha",
+ "password_protected-captcha",
+ );
+
+ if (AIOWPSecurity_Utility::is_woocommerce_plugin_active()) {
+ $woocommerce_features = array(
+ "woo-login-captcha",
+ "woo-lostpassword-captcha",
+ "woo-register-captcha",
+ "woo-checkout-captcha",
+ );
+ $features = array_merge($features, $woocommerce_features);
+ }
+
+ if (AIOWPSecurity_Utility::is_buddypress_plugin_active()) {
+ $features[] = "bp-register-captcha";
+ }
+
+ if (AIOWPSecurity_Utility::is_bbpress_plugin_active()) {
+ $features[] = "bbp-new-topic-captcha";
+ }
+
+ if (AIOWPSecurity_Utility::is_contact_form_7_plugin_active()) {
+ $features[] = "contact-form-7-captcha";
+ }
+
+ $args = array(
+ 'badges' => $features
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Handles the AJAX request to enable or configure 404 detection and settings.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_404_settings($data) {
+
+ $options = array();
+ $info = array();
+ $values = array();
+
+ $options['aiowps_enable_404_logging'] = isset($data["aiowps_enable_404_IP_lockout"]) ? '1' : ''; //the "aiowps_enable_404_IP_lockout" checkbox currently controls both the 404 lockout and 404 logging
+ $options['aiowps_enable_404_IP_lockout'] = isset($data["aiowps_enable_404_IP_lockout"]) ? '1' : '';
+
+ $lockout_time_length = isset($data['aiowps_404_lockout_time_length']) ? sanitize_text_field($data['aiowps_404_lockout_time_length']) : '';
+ $redirect_url = isset($data['aiowps_404_lock_redirect_url']) ? sanitize_text_field(trim($data['aiowps_404_lock_redirect_url'])) : '';
+
+ if (isset($data["aiowps_enable_404_IP_lockout"])) {
+ if (!is_numeric($lockout_time_length) || $lockout_time_length < 1) {
+ $info[] = __('You entered a non numeric or negative value for the lockout time length field.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $lockout_time_length = '60'; // Set it to the default value for this field
+ }
+
+ if ('' == $redirect_url || '' == esc_url($redirect_url, array('http', 'https'))) {
+ $info[] = __('You entered an incorrect format for the "Redirect URL" field.', 'all-in-one-wp-security-and-firewall') . ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $redirect_url = 'http://127.0.0.1';
+ }
+ }
+
+ $options['aiowps_404_lockout_time_length'] = absint($lockout_time_length);
+ $options['aiowps_404_lock_redirect_url'] = $redirect_url;
+ $this->save_settings($options);
+
+ $badges = array("firewall-enable-404-blocking");
+ $values['aiowps_404_lockout_time_length'] = $lockout_time_length;
+ $values['aiowps_404_lock_redirect_url'] = $redirect_url;
+
+ $args = array(
+ 'badges' => $badges,
+ 'info' => $info,
+ 'values' => $values
+ );
+
+ return $this->handle_response(true, '', $args);
+ }
+
+ /**
+ * Handles the AJAX request to clear 404 logs.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_delete_404_event_records() {
+ global $aio_wp_security, $wpdb;
+
+ $success = true;
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
+ //Delete all 404 records from the events table
+ $where = array('event_type' => '404');
+ $result = $wpdb->delete($events_table_name, $where);
+
+ if (false === $result) {
+ $error = empty($wpdb->last_error) ? '' : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug("404 Detection Feature - Delete all 404 event logs operation failed. $error", 4);
+ $success = false;
+ $message = __('404 Detection Feature - The operation to delete all the 404 event logs failed', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $message = __('All 404 event logs were deleted from the database successfully.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ return $this->handle_response($success, $message);
+ }
+
+ /**
+ * Handles the AJAX request for 404 log item actions.
+ *
+ * @param array $data The data received from the AJAX request.
+ *
+ * @return array The response containing the status, message, and badge.
+ */
+ public function perform_404_log_item_action($data) {
+ global $wpdb, $aio_wp_security, $aiowps_firewall_config;
+
+ if (empty($data['action']) || !in_array($data['action'], array('delete', 'temp_block', 'blacklist', 'unblock'))) {
+ return $this->handle_response(false, __('Invalid action provided for 404 log item.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $action = $data['action'];
+ $message = false;
+
+ switch ($action) {
+ case 'delete':
+ if (!isset($data['id'])) {
+ return $this->handle_response(false, __('Invalid 404 event log ID provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+ $events_table = AIOWPSEC_TBL_EVENTS;
+ $id = absint($data['id']);
+ //Delete single record
+ $delete_command = "DELETE FROM " . $events_table . " WHERE id = '" . absint($id) . "'";
+ $result = $wpdb->query($delete_command);
+ if (false === $result) {
+ // Error on single delete
+ $aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Events table. Database error: '.$wpdb->last_error, 4);
+ return $this->handle_response(false, __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ $message = __('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall');
+ }
+ break;
+ case 'temp_block':
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+ $ip = sanitize_text_field($data['ip']);
+ $username = isset($data['username']) ? sanitize_user($data['username']) : '';
+
+ if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
+ return $this->handle_response(false, __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip);
+ }
+ //Block single record
+ if (filter_var($ip, FILTER_VALIDATE_IP)) {
+ AIOWPSecurity_Utility::lock_IP($ip, '404', $username);
+ $message = __('The selected IP address is now temporarily blocked.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $message = __('The selected entry is not a valid IP address.', 'all-in-one-wp-security-and-firewall');
+ return $this->handle_response(false, $message);
+ }
+ break;
+ case 'blacklist':
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $bl_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'); //get the currently saved blacklisted IPs
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($bl_ip_addresses);
+ $ip = sanitize_text_field($data['ip']);
+ $ip_list_array[] = $ip;
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
+
+ if (is_wp_error($validated_ip_list_array)) {
+ $response = nl2br($validated_ip_list_array->get_error_message());
+ return $this->handle_response(false, $response);
+ } else {
+ $banned_ip_data = implode("\n", $validated_ip_list_array);
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '1'); // Force blacklist feature to be enabled.
+ $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', $banned_ip_data);
+ $aio_wp_security->configs->save_config();
+
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
+ $message = __('The selected IP addresses have been added to the blacklist and will be permanently blocked.', 'all-in-one-wp-security-and-firewall');
+ }
+ break;
+ case 'unblock':
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('Invalid log event ID provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $ip_range = sanitize_text_field($data['ip']);
+ $lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ // get the latest data with that ip in the table that's locked and reason is 404
+ $query = $wpdb->prepare("SELECT id FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() AND `lock_reason` = %s and failed_login_ip = %s ORDER BY id ASC LIMIT 1", '404', $ip_range);
+ $id = $wpdb->get_var($query);
+
+ if (null === $id) {
+ return $this->handle_response(false, __('Invalid log event ID provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $result = $wpdb->query($wpdb->prepare("UPDATE $lockout_table SET `released` = UNIX_TIMESTAMP() WHERE `id` = %d", absint($id)));
+
+ if (null != $result) {
+ $message = __('Access from the selected IP address has been unblocked.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ return $this->handle_response(false, __('The selected IP entry could not be unlocked', 'all-in-one-wp-security-and-firewall'));
+ }
+ break;
+ }
+
+ return $this->handle_response(true, $message);
+ }
+
+ /**
+ * Get the content for performing a cookie test.
+ *
+ * This method checks if the cookie test is successful or if the brute-force attack prevention feature is already enabled.
+ * If either condition is true, it returns an empty string. Otherwise, it displays a message prompting the user to perform
+ * a cookie test before enabling the feature, along with a button to initiate the test.
+ *
+ * @return string The HTML content for the cookie test section.
+ */
+ private function get_perform_cookie_test_content() {
+ global $aio_wp_security;
+ $cookie_test_value = $aio_wp_security->configs->get_value('aiowps_cookie_test_success');
+
+ if ('1' == $cookie_test_value || '1' == $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention')) {
+ return '';
+ } else {
+ return $aio_wp_security->include_template('wp-admin/brute-force/partials/cookie-test-container.php', true);
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-comment-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-comment-commands.php
new file mode 100755
index 00000000..e2f65953
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-comment-commands.php
@@ -0,0 +1,221 @@
+ $aiowps_trash_spam_comments_after_days
+ );
+ }
+
+ $response['status'] = 'success';
+ $response['message'] = __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall');
+ $response['info'] = $info;
+
+ // Commit the config settings
+ $this->save_settings($options);
+ AIOWPSecurity_Comment::trash_spam_comments();
+ $response['badges'] = $this->get_features_id_and_html(array('detect-spambots'));
+
+ return $response;
+ }
+
+ /**
+ * Perform the saving of comment auto block spammers ip settings
+ *
+ * @param array $data - the request data contains the post data
+ *
+ * @return array
+ */
+ public function perform_auto_block_spam_ip($data) {
+ $response = array(
+ 'status' => 'success',
+ 'values' => array(),
+ 'info' => array()
+ );
+
+ $enable_auto_block_ip = isset($data["aiowps_enable_autoblock_spam_ip"]) ? '1' : '';
+
+ $spam_ip_min_comments = sanitize_text_field($data['aiowps_spam_ip_min_comments_block']);
+ if (!is_numeric($spam_ip_min_comments)) {
+ $response['info'][] = __('You entered a non-numeric value for the "minimum number of spam comments" field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $spam_ip_min_comments = '3';// Set it to the default value for this field
+ } elseif ((int) $spam_ip_min_comments <= 0 || empty($spam_ip_min_comments)) {
+ $response['info'][] = __('You must enter an integer greater than zero for the "minimum number of spam comments" field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $spam_ip_min_comments = '3';// Set it to the default value for this field
+ }
+
+ // Save all the form values to the options
+ $options = array(
+ 'aiowps_enable_autoblock_spam_ip' => $enable_auto_block_ip,
+ 'aiowps_spam_ip_min_comments_block' => absint($spam_ip_min_comments),
+ );
+
+ $this->save_settings($options);
+ $response['message'] = __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall');
+
+ $response['badges'] = $this->get_features_id_and_html(array('auto-block-spam-ips'));
+ $response['values']['aiowps_spam_ip_min_comments_block'] = absint($spam_ip_min_comments);
+
+ return $response;
+ }
+
+ /**
+ * Perform the ip spam comment search
+ *
+ * @param array $data - the request data contains the post data
+ *
+ * @return array
+ */
+ public function perform_ip_spam_search($data) {
+ $response = array(
+ 'status' => 'success',
+ 'info' => array()
+ );
+
+ $min_comments_per_ip = sanitize_text_field($data['aiowps_spam_ip_min_comments']);
+ $error = '';
+
+ if (!is_numeric($min_comments_per_ip)) {
+ $error = __('You entered a non-numeric value for the minimum spam comments per IP field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $min_comments_per_ip = '5'; // Set it to the default value for this field
+ } elseif ((int) $min_comments_per_ip <= 0 || empty($min_comments_per_ip)) {
+ $error = __('You must enter an integer greater than zero for the minimum spam comments per IP field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $min_comments_per_ip = '5'; // Set it to the default value for this field
+ }
+
+ $min_comments_per_ip = absint($min_comments_per_ip);
+
+ // Save all the form values to the options
+ $this->save_settings(array(
+ 'aiowps_spam_ip_min_comments' => $min_comments_per_ip
+ ));
+
+ if (!empty($error)) {
+ $response['message'] = $error;
+ }
+
+ $response['values']['aiowps_spam_ip_min_comments'] = $min_comments_per_ip;
+
+ return $response;
+ }
+
+ /**
+ * Perform the action of blocking a spam IP address.
+ *
+ * This function takes an IP address as input, checks if it is valid and not the user's own IP,
+ * and then attempts to add it to the block list for spam. It returns the status and message of the operation.
+ *
+ * @param array $data The data containing the IP address to block.
+ *
+ * @return array The result of the block operation, including status, message, and updated blocked comments output.
+ */
+ public function perform_block_spam_ip($data) {
+
+ if (empty($data['ip'])) {
+ return array('status' => 'error', 'message' => __('Invalid IP address provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $ip = wp_strip_all_tags($data['ip']);
+
+ if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
+ return array('status' => 'error', 'message' => __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip);
+ }
+
+ $result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip, 'spam');
+
+ if ($result) {
+ $status = 'success';
+ $message = __('The selected IP address is now permanently blocked.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $status = 'error';
+ $message = __('The selected IP address could not be blocked due to one of the following reasons:', 'all-in-one-wp-security-and-firewall');
+ $message .= ' ' . __('either it has already been blocked, or your user account lacks sufficient permissions to perform IP blocking.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ return array(
+ 'status' => $status,
+ 'message' => $message,
+ 'content' => array('aios-blocked-comments-output' => $this->get_blocked_comments_output())
+ );
+ }
+
+ /**
+ * Retrieves the output for displaying blocked comments due to spam.
+ *
+ * This function queries the database to get IP addresses that are permanently blocked due to spam.
+ * It returns HTML output that displays the count of IPs blocked today and the all-time total count.
+ *
+ * @global object $aio_wp_security The global instance of the aio_wp_security class.
+ * @global object $wpdb The global instance of the WordPress database class.
+ *
+ * @return string HTML output for the blocked comments section.
+ */
+ private function get_blocked_comments_output() {
+ global $aio_wp_security, $wpdb;
+
+ $block_comments_output = '';
+ $min_block_comments = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
+
+ if (!empty($min_block_comments)) {
+ $now_date = (new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d');
+
+ $sql = $wpdb->prepare(
+ "SELECT COUNT(*) AS total_count,
+ SUM(CASE WHEN DATE(FROM_UNIXTIME(created)) = %s THEN 1 ELSE 0 END) AS todays_blocked_count FROM ".AIOWPSEC_TBL_PERM_BLOCK." WHERE block_reason = %s",
+ $now_date,
+ 'spam'
+ );
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore
+ $result = $wpdb->get_row($sql);
+
+ $block_comments_output = '
';
+ }
+
+ return $block_comments_output;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-file-scan-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-file-scan-commands.php
new file mode 100755
index 00000000..a53bf6fb
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-file-scan-commands.php
@@ -0,0 +1,280 @@
+configs->get_value('aiowps_fcd_exclude_filetypes')) {
+ $reset_scan_data = true;
+ }
+ }
+
+ if (!empty($data['aiowps_fcd_exclude_files'])) {
+ $files = sanitize_textarea_field(trim($data['aiowps_fcd_exclude_files']));
+ // Get the currently saved config value and check if this has changed. If so do another scan to reset the scan data so it omits these files/dirs
+ if ($files != $aio_wp_security->configs->get_value('aiowps_fcd_exclude_files')) {
+ $reset_scan_data = true;
+ }
+ }
+
+ // Explode by end-of-line character, then trim and filter empty lines
+ $email_list_array = array_filter(array_map('trim', explode("\n", $data['aiowps_fcd_scan_email_address'])), 'strlen');
+ foreach ($email_list_array as $key => $value) {
+ $email_sane = sanitize_email($value);
+ if (!is_email($email_sane)) {
+ $errors[] = __('The following address was removed because it is not a valid email address:', 'all-in-one-wp-security-and-firewall') . ' ' . htmlspecialchars($value);
+ unset($email_list_array[$key]);
+ }
+ }
+ $email_address = implode("\n", $email_list_array);
+ if (!empty($errors)) {
+ $info[] = implode(' ', $errors);
+ }
+
+ // Save all the form values to the options
+ $options['aiowps_enable_automated_fcd_scan'] = isset($data["aiowps_enable_automated_fcd_scan"]) ? '1' : '';
+ $options['aiowps_fcd_scan_frequency'] = absint($fcd_scan_frequency);
+ $options['aiowps_fcd_scan_interval'] = sanitize_text_field($data["aiowps_fcd_scan_interval"]);
+ $options['aiowps_fcd_exclude_filetypes'] = $file_types;
+ $options['aiowps_fcd_exclude_files'] = $files;
+ $options['aiowps_send_fcd_scan_email'] = isset($data["aiowps_send_fcd_scan_email"]) ? '1' : '';
+ $options['aiowps_fcd_scan_email_address'] = $email_address;
+ $this->save_settings($options);
+
+ $content['aios-file-change-info-box'] = '';
+ // Let's check if backup interval was set to less than 24 hours
+ if (isset($data["aiowps_enable_automated_fcd_scan"]) && ($fcd_scan_frequency < 24) && 0 == $data["aiowps_fcd_scan_interval"]) {
+ $content['aios-file-change-info-box'] = '
';
+ $content['aios-file-change-info-box'] .= '
' . __('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'] .= '
';
+ }
+
+ if ($reset_scan_data) {
+ $aio_wp_security->scan_obj->execute_file_change_detection_scan();
+ $new_scan_alert = __('New scan completed: The plugin has detected that you have made changes to the "File Types To Ignore" or "Files To Ignore" fields.', 'all-in-one-wp-security-and-firewall').' '.__('In order to ensure that future scan results are accurate, the old scan data has been refreshed.', 'all-in-one-wp-security-and-firewall');
+ $info[] = $new_scan_alert;
+ }
+
+ $next_fcd_scan_time = AIOWPSecurity_Scan::get_next_scheduled_scan();
+
+ if (false == $next_fcd_scan_time) {
+ $next_scheduled_scan = '' . esc_html__('Nothing is currently scheduled', 'all-in-one-wp-security-and-firewall') . '';
+ } else {
+ $scan_time = AIOWPSecurity_Utility::convert_timestamp($next_fcd_scan_time, 'D, F j, Y H:i');
+ $next_scheduled_scan = '' . esc_html($scan_time) . '';
+ }
+
+ $content['aiowps-next-files-scan-inner'] = $next_scheduled_scan;
+ $values = array('aiowps_fcd_scan_frequency' => absint($fcd_scan_frequency));
+ $badges = array('scan-file-change-detection');
+
+ $args = array(
+ 'content' => $content,
+ 'values' => $values,
+ 'badges' => $badges,
+ 'info' => $info
+ );
+
+ return $this->handle_response(true, '', $args);
+ }
+
+ /**
+ * Retrieves the last file scan data and returns the data to UDC.
+ *
+ * @param array $data The request data.
+ *
+ * @return array|string[]|WP_Error
+ */
+ public function get_last_scan_data($data) {
+ global $aio_wp_security;
+
+ 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'));
+ }
+
+ if ($data['reset_change_detected']) {
+ $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false, true);
+ }
+
+ $fcd_data = AIOWPSecurity_Scan::get_fcd_data();
+
+ $data = $fcd_data['last_scan_result'];
+
+ foreach (array('files_added', 'files_removed', 'files_changed') as $key) {
+ /* Normalize missing or non-array buckets to an empty array and skip processing */
+ if (!isset($data[$key]) || !is_array($data[$key])) {
+ $data[$key] = array();
+ continue;
+ }
+
+ /* Convert last_modified for each entry */
+ foreach ($data[$key] as &$info) {
+ if (is_array($info) && array_key_exists('last_modified', $info) && is_numeric($info['last_modified'])) {
+ $info['last_modified'] = AIOWPSecurity_Utility::convert_timestamp($info['last_modified']);
+ }
+ }
+
+ unset($info);
+ }
+
+ $fcd_data['last_scan_result'] = $data;
+
+ return $this->handle_response(true, false, array('extra_args' => $fcd_data));
+ }
+
+ /**
+ * Gets the last file scan result and returns the scan result HTML template
+ *
+ * @param array $data - the request data
+ *
+ * @return array
+ */
+ public function get_last_scan_results($data) {
+ global $aio_wp_security;
+
+ if ($data['reset_change_detected']) $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false, true);
+
+ $fcd_data = AIOWPSecurity_Scan::get_fcd_data();
+
+ if (!$fcd_data || !isset($fcd_data['last_scan_result'])) {
+ // no fcd data found
+ $message = __('No previous scan data was found; either run a manual scan or schedule regular file scans', 'all-in-one-wp-security-and-firewall');
+ return $this->handle_response(false, $message);
+ }
+
+ $content = array('aiowps_previous_scan_wrapper' => $aio_wp_security->include_template('wp-admin/scanner/scan-result.php', true, array('fcd_data' => $fcd_data)));
+
+ return $this->handle_response(true, false, array('content' => $content));
+ }
+
+ /**
+ * Performs a file scan and returns the scan result
+ *
+ * @return array
+ */
+ public function perform_file_scan() {
+ global $aio_wp_security;
+
+ $content = array();
+ $extra_args = array();
+
+ $result = $aio_wp_security->scan_obj->execute_file_change_detection_scan();
+
+ if (false === $result) {
+ // error case
+ $message = __('There was an error during the file change detection scan.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please check the plugin debug logs.', 'all-in-one-wp-security-and-firewall');
+ return $this->handle_response(false, $message);
+ }
+
+ $aio_wp_security->configs->set_value('aiowps_last_scan_time', time(), true);
+
+ // If this is first scan display special message
+ if (1 == $result['initial_scan']) {
+ $extra_args['result'] = __('This is your first file change detection scan.', 'all-in-one-wp-security-and-firewall').' '.__('The details from this scan will be used for future scans.', 'all-in-one-wp-security-and-firewall'). ' ' . __('View the file scan results', 'all-in-one-wp-security-and-firewall') . '';
+ $content['aiowps-previous-files-scan-inner'] = '' . __('View last file scan results', 'all-in-one-wp-security-and-firewall') . '';
+ } elseif (!$aio_wp_security->configs->get_value('aiowps_fcds_change_detected')) {
+ $extra_args['result'] = __('The scan is complete - There were no file changes detected.', 'all-in-one-wp-security-and-firewall');
+ } elseif ($aio_wp_security->configs->get_value('aiowps_fcds_change_detected')) {
+ $extra_args['result'] = __('The scan has detected that there was a change in your website\'s files.', 'all-in-one-wp-security-and-firewall'). ' ' . __('View the file scan results', 'all-in-one-wp-security-and-firewall') . '';
+ }
+
+ $args = array(
+ 'extra_args' => $extra_args,
+ 'content' => $content
+ );
+
+ return $this->handle_response(true, false, $args);
+ }
+
+ /**
+ * Render the legacy UDC Scanner.
+ *
+ * @return array
+ */
+ public function get_scanner_contents() {
+ global $aio_wp_security;
+
+ $GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
+
+ $scanner_data = $this->get_scanner_data();
+
+ $content = $aio_wp_security->include_template('wp-admin/scanner/file-change-detect.php', true, $scanner_data);
+
+ return array(
+ 'status' => 'success',
+ 'content' => $content,
+ );
+ }
+
+ /**
+ * Return file scanner data.
+ *
+ * @return array Array of option values,
+ */
+ public function get_scanner_data() {
+ global $aio_wp_security;
+
+ $fcd_data = AIOWPSecurity_Scan::get_fcd_data();
+ $previous_scan = isset($fcd_data['last_scan_result']);
+
+ $next_fcd_scan_time = AIOWPSecurity_Scan::get_next_scheduled_scan();
+
+ $aiowps_fcds_change_detected = $aio_wp_security->configs->get_value('aiowps_fcds_change_detected');
+ $aiowps_enable_automated_fcd_scan = $aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan');
+ $aiowps_fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency');
+ $aiowps_fcd_scan_interval = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval');
+ $aiowps_fcd_exclude_filetypes = $aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes');
+ $aiowps_fcd_exclude_files = $aio_wp_security->configs->get_value('aiowps_fcd_exclude_files');
+ $aiowps_send_fcd_scan_email = $aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email');
+ $aiowps_fcd_scan_email_address = $aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address');
+ $aiowps_last_scan_time = $aio_wp_security->configs->get_value('aiowps_last_scan_time');
+
+ return array(
+ 'previous_scan' => $previous_scan,
+ 'next_fcd_scan_time' => false === $next_fcd_scan_time ? '' : AIOWPSecurity_Utility::convert_timestamp($next_fcd_scan_time, 'D, F j, Y H:i'),
+ 'aiowps_fcds_change_detected' => $aiowps_fcds_change_detected,
+ 'aiowps_enable_automated_fcd_scan' => $aiowps_enable_automated_fcd_scan,
+ 'aiowps_fcd_scan_frequency' => $aiowps_fcd_scan_frequency,
+ 'aiowps_fcd_scan_interval' => $aiowps_fcd_scan_interval,
+ 'aiowps_fcd_exclude_filetypes' => $aiowps_fcd_exclude_filetypes,
+ 'aiowps_fcd_exclude_files' => $aiowps_fcd_exclude_files,
+ 'aiowps_send_fcd_scan_email' => $aiowps_send_fcd_scan_email,
+ 'aiowps_fcd_scan_email_address' => $aiowps_fcd_scan_email_address,
+ 'aiowps_last_scan_time' => AIOWPSecurity_Utility::convert_timestamp($aiowps_last_scan_time, 'D, F j, Y H:i'),
+ );
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-files-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-files-commands.php
new file mode 100755
index 00000000..16dd18b1
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-files-commands.php
@@ -0,0 +1,224 @@
+ $aio_wp_security->include_template('wp-admin/filesystem-security/partials/file-permissions-table.php', true, array('files_dirs_to_check' => $files_dirs_to_check, 'file_utility' => new AIOWPSecurity_Utility_File())));
+ $args = array(
+ 'content' => $content,
+ 'badges' => $badges,
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * This function performs file protection settings
+ *
+ * @param array $data - the request data contains the settings
+ *
+ * @return array
+ */
+ public function perform_file_protection_settings($data) {
+ global $aio_wp_security;
+
+ $success = true;
+ $message = '';
+
+ $options = array();
+ // Update settings for delete readme.html and wp-config-sample.php.
+ $options['aiowps_auto_delete_default_wp_files'] = isset($data['aiowps_auto_delete_default_wp_files']) ? '1' : '';
+
+ // Update settings for prevent hotlinking.
+ $options['aiowps_prevent_hotlinking'] = isset($data['aiowps_prevent_hotlinking']) ? '1' : '';
+
+ // Update settings for php file editing
+ $disable_file_editing = isset($data["aiowps_disable_file_editing"]) ? '1' : '';
+ $disable_file_editing_status = $disable_file_editing ? AIOWPSecurity_Utility::disable_file_edits() : AIOWPSecurity_Utility::enable_file_edits();
+ if ($disable_file_editing_status) {
+ // Save settings if no errors
+ $options['aiowps_disable_file_editing'] = $disable_file_editing;
+ } else {
+ $message = __('Disable PHP file editing failed: unable to modify or make a backup of the wp-config.php file.', 'all-in-one-wp-security-and-firewall');
+ return $this->handle_response(false, $message);
+ }
+
+ $this->save_settings($options);
+
+
+ if (AIOWPSecurity_Utility_Htaccess::write_to_htaccess() && '' !== $options['aiowps_prevent_hotlinking']) {
+
+ // Now let's write the applicable rules to the .htaccess file
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
+
+ if ($res) {
+ $message = __('The settings have been successfully updated', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $success = false;
+ $message = __('Could not write to the .htaccess file.', 'all-in-one-wp-security-and-firewall');
+
+ // revert options affected by .htaccess write fail
+ $options['aiowps_prevent_hotlinking'] = $aio_wp_security->configs->get_value('aiowps_prevent_hotlinking');
+ $this->save_settings($options);
+ }
+ }
+
+ $features = array(
+ "auto-delete-wp-files",
+ "prevent-hotlinking",
+ "filesystem-file-editing",
+ );
+
+ return $this->handle_response($success, $message, array('badges' => $features));
+ }
+
+ /**
+ * This function performs deleting default wp files
+ *
+ * @return array
+ */
+ public function perform_delete_default_wp_files() {
+ $success = true;
+ $message = __('The files have been deleted successfully.', 'all-in-one-wp-security-and-firewall');
+
+ $result = AIOWPSecurity_Utility::delete_unneeded_default_files();
+
+ if (!empty($result['error'])) {
+ $success = false;
+ $message = sprintf(__('Failed to delete the %s file(s).', 'all-in-one-wp-security-and-firewall'), $result['error']) . ' ' . __('Please try to delete them manually.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ return $this->handle_response($success, $message, array('info' => $result['info']));
+ }
+
+ /**
+ * This function performs save copy protection settings
+ *
+ * @param array $data - the request data
+ *
+ * @return array
+ */
+ public function perform_save_copy_protection($data) {
+ $this->save_settings(array('aiowps_copy_protection' => isset($data["aiowps_copy_protection"]) ? '1' : ''));
+
+ return $this->handle_response(true, '', array('badges' => array('enable-copy-protection')));
+ }
+
+ /**
+ * This function performs save frame display prevent setting
+ *
+ * @param array $data - the request data
+ *
+ * @return array
+ */
+ public function perform_save_frame_display_prevent($data) {
+ $this->save_settings(array('aiowps_prevent_site_display_inside_frame' => isset($data["aiowps_prevent_site_display_inside_frame"]) ? '1' : ''));
+
+ return $this->handle_response(true, '', array('badges' => array('enable-frame-protection')));
+ }
+
+ /**
+ * This function performs host system logs
+ *
+ * @param array $data - the request data contains the lgos settings
+ *
+ * @return array
+ */
+ public function perform_host_system_logs($data) {
+
+ $content = array();
+ $success = true;
+ $message = false;
+
+ if (isset($data['aiowps_system_log_file'])) {
+ if ('' != $data['aiowps_system_log_file']) {
+ $sys_log_file = basename(sanitize_text_field($data['aiowps_system_log_file']));
+ } else {
+ $sys_log_file = 'error_log';
+ }
+ $this->save_settings(array('aiowps_system_log_file' => $sys_log_file));
+ }
+
+ $logResults = AIOWPSecurity_Utility_File::recursive_file_search($sys_log_file, 0, ABSPATH);
+
+ if (empty($logResults) || '' == $logResults) {
+ $success = false;
+ $message = __('No system logs were found.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $content['aios-host-system-logs-results'] = '';
+ foreach ($logResults as $file) {
+ $content['aios-host-system-logs-results'] .= $this->display_system_logs_in_table($file);
+ }
+ }
+
+ $values = array('aiowps_system_log_file' => $sys_log_file);
+
+ $args = array(
+ 'content' => $content,
+ 'values' => $values
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Displays the last 50 entries of a system log file in a table format.
+ *
+ * This function reads the contents of the specified file and returns a
+ * rendered template displaying the last 50 entries of the log file.
+ *
+ * @param string $filepath The path to the log file to be read.
+ *
+ * @return string The rendered HTML template displaying the log entries.
+ */
+ private function display_system_logs_in_table($filepath) {
+ global $aio_wp_security;
+ // Get contents of the error_log file
+ $last_50_entries = AIOWPSecurity_Utility_File::read_file_lines($filepath, -1, 50, true);
+ return $aio_wp_security->include_template('wp-admin/filesystem-security/filesystem-log-result.php', true, array('filepath' => $filepath, 'last_50_entries' => $last_50_entries));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-firewall-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-firewall-commands.php
new file mode 100755
index 00000000..152f6ff6
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-firewall-commands.php
@@ -0,0 +1,787 @@
+set_value('aiowps_enable_pingback_firewall', $enable_pingback);
+ $options['aiowps_disable_xmlrpc_pingback_methods'] = isset($data["aiowps_disable_xmlrpc_pingback_methods"]) ? '1' : ''; //this disables only pingback methods of xmlrpc but leaves other methods so that Jetpack and other apps will still work
+ $options['aiowps_disable_rss_and_atom_feeds'] = isset($data['aiowps_disable_rss_and_atom_feeds']) ? '1' : '';
+ $aiowps_firewall_config->set_value('aiowps_forbid_proxy_comments', isset($data['aiowps_forbid_proxy_comments']));
+ $aiowps_firewall_config->set_value('aiowps_deny_bad_query_strings', isset($data['aiowps_deny_bad_query_strings']));
+ $aiowps_firewall_config->set_value('aiowps_advanced_char_string_filter', isset($data['aiowps_advanced_char_string_filter']));
+
+ $block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
+ $current_request_methods_settings = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
+ $current_other_settings = array(
+ $aiowps_firewall_config->get_value('aiowps_6g_block_query'),
+ $aiowps_firewall_config->get_value('aiowps_6g_block_request'),
+ $aiowps_firewall_config->get_value('aiowps_6g_block_referrers'),
+ $aiowps_firewall_config->get_value('aiowps_6g_block_agents'),
+ );
+
+ $are_methods_set = !empty($current_request_methods_settings);
+ $are_others_set = array_reduce($current_other_settings, function($carry, $item) {
+ return $carry || $item;
+ });
+
+ if (($are_methods_set || $are_others_set) && '1' !== $aio_wp_security->configs->get_value('aiowps_enable_6g_firewall')) {
+ $options['aiowps_enable_6g_firewall'] = '1';
+ }
+
+ if (isset($data['aiowps_enable_6g_firewall'])) {
+ $aiowps_6g_block_request_methods = array_filter(AIOS_Abstracted_Ids::get_firewall_block_request_methods(), function($block_request_method) {
+ return ('PUT' != $block_request_method);
+ });
+
+ if (false === $are_methods_set && false === $are_others_set) {
+ $aiowps_firewall_config->set_value('aiowps_6g_block_request_methods', $aiowps_6g_block_request_methods);
+ $aiowps_firewall_config->set_value('aiowps_6g_block_query', true);
+ $aiowps_firewall_config->set_value('aiowps_6g_block_request', true);
+ $aiowps_firewall_config->set_value('aiowps_6g_block_referrers', true);
+ $aiowps_firewall_config->set_value('aiowps_6g_block_agents', true);
+ } else {
+ $methods = array();
+
+ foreach ($block_request_methods as $block_request_method) {
+ if (isset($data['aiowps_block_request_method_'.$block_request_method])) {
+ $methods[] = strtoupper($block_request_method);
+ }
+ }
+
+ $aiowps_firewall_config->set_value('aiowps_6g_block_request_methods', $methods);
+ $aiowps_firewall_config->set_value('aiowps_6g_block_query', isset($data['aiowps_block_query']));
+ $aiowps_firewall_config->set_value('aiowps_6g_block_request', isset($data['aiowps_block_request']));
+ $aiowps_firewall_config->set_value('aiowps_6g_block_referrers', isset($data['aiowps_block_refs']));
+ $aiowps_firewall_config->set_value('aiowps_6g_block_agents', isset($data['aiowps_block_agents']));
+ }
+
+ $options['aiowps_enable_6g_firewall'] = '1';
+
+ //shows the success notice
+ } else {
+ AIOWPSecurity_Configure_Settings::turn_off_all_6g_firewall_configs();
+ $options['aiowps_enable_6g_firewall'] = '';
+ }
+
+ $aiowps_firewall_config->set_value('aiowps_ban_post_blank_headers', isset($data['aiowps_ban_post_blank_headers']));
+
+ if (isset($data['aiowps_block_fake_googlebots'])) {
+ $validated_ip_list_array = AIOWPSecurity_Utility::get_googlebot_ip_ranges();
+
+ if (is_wp_error($validated_ip_list_array)) {
+ $info[] = __('The attempt to save the \'Block fake Googlebots\' settings failed, because it was not possible to validate the Googlebot IP addresses:', 'all-in-one-wp-security-and-firewall') . ' ' . $validated_ip_list_array->get_error_message();
+ } else {
+ $aiowps_firewall_config->set_value('aiowps_block_fake_googlebots', true);
+ $aiowps_firewall_config->set_value('aiowps_googlebot_ip_ranges', $validated_ip_list_array);
+ }
+ } else {
+ $aiowps_firewall_config->set_value('aiowps_block_fake_googlebots', false);
+ }
+ $options['aiowps_disallow_unauthorized_rest_requests'] = isset($data["aiowps_disallow_unauthorized_rest_requests"]) ? '1' : '';
+
+ $aios_whitelisted_rest_routes = array();
+ $route_namespaces = AIOWPSecurity_Utility::get_rest_namespaces();
+ foreach ($route_namespaces as $route_namespace) {
+ if (isset($data['aios_whitelisted_rest_routes_'.str_replace('-', '_', $route_namespace)])) {
+ $aios_whitelisted_rest_routes[] = $route_namespace;
+ }
+ }
+ $options['aios_whitelisted_rest_routes'] = $aios_whitelisted_rest_routes;
+
+ $aios_roles_disallowed_rest_requests = array();
+ $user_roles = AIOWPSecurity_Utility_Permissions::get_user_roles();
+ foreach ($user_roles as $id => $name) {
+ if (!isset($data['aios_allowed_roles_rest_requests_'.$id])) {
+ $aios_roles_disallowed_rest_requests[] = $id;
+ }
+ }
+ $options['aios_roles_disallowed_rest_requests'] = $aios_roles_disallowed_rest_requests;
+
+ // Commit the config settings
+ $this->save_settings($options);
+
+ $block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
+ $methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
+ if (empty($methods)) {
+ $methods = array();
+ }
+
+ $blocked_query = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
+ $blocked_request = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
+ $blocked_referrers = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
+ $blocked_agents = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
+ $content = array('aios-6g-firewall-settings-container .aios-advanced-options-panel' => $aio_wp_security->include_template('wp-admin/firewall/partials/advanced-settings-6g.php', true, compact('methods', 'blocked_query', 'blocked_request', 'blocked_referrers', 'blocked_agents', 'block_request_methods')));
+
+ $features = array(
+ 'firewall-pingback-rules',
+ 'firewall-disable-rss-and-atom',
+ 'firewall-forbid-proxy-comments',
+ 'firewall-deny-bad-queries',
+ 'firewall-advanced-character-string-filter',
+ 'firewall-enable-6g',
+ 'firewall-block-fake-googlebots',
+ 'firewall-ban-post-blank-headers',
+ 'disallow-unauthorised-requests',
+ );
+
+ $args = array(
+ 'badges' => $features,
+ 'content' => $content,
+ 'info' => $info,
+ 'extra_args' => array('xmlprc_warning' => $enable_pingback ? $aio_wp_security->include_template('wp-admin/firewall/partials/xmlrpc-warning-notice.php', true) : '')
+ );
+
+ return $this->handle_response(true, '', $args);
+ }
+
+ /**
+ * Perform saving .htaccess firewall settings
+ *
+ * @param array $data - the request data contains the firewall settings
+ *
+ * @return array - containing a status and message
+ */
+ public function perform_htaccess_firewall_settings($data) {
+ global $aio_wp_security;
+
+
+ $options = array();
+ $info = array();
+ $message = '';
+ $success = true;
+
+ // Max file upload size in basic rules
+ $upload_size = absint($data['aiowps_max_file_upload_size']);
+
+ $max_allowed = apply_filters('aiowps_max_allowed_upload_config', 250); // Set a filterable limit of 250MB
+ $max_allowed = absint($max_allowed);
+
+ if ($upload_size > $max_allowed) {
+ $upload_size = $max_allowed;
+ } elseif (empty($upload_size) || 0 > $upload_size) {
+ $upload_size = AIOS_FIREWALL_MAX_FILE_UPLOAD_LIMIT_MB;
+ $info[] = __('Max file upload limit was set to default value, because you entered a negative or zero value');
+ }
+
+ // Store the current value in case the .htaccess write operation fails and we need to revert it
+ $original_options = array(
+ 'aiowps_enable_basic_firewall' => $aio_wp_security->configs->get_value("aiowps_enable_basic_firewall"),
+ 'aiowps_max_file_upload_size' => $aio_wp_security->configs->get_value('aiowps_max_file_upload_size'),
+ 'aiowps_block_debug_log_file_access' => $aio_wp_security->configs->get_value("aiowps_block_debug_log_file_access"),
+ 'aiowps_disable_index_views' => $aio_wp_security->configs->get_value('aiowps_disable_index_views'),
+ );
+
+
+ // Save settings
+ $options['aiowps_enable_basic_firewall'] = isset($data["aiowps_enable_basic_firewall"]) ? '1' : '';
+ $options['aiowps_max_file_upload_size'] = $upload_size;
+ $options['aiowps_block_debug_log_file_access'] = isset($data["aiowps_block_debug_log_file_access"]) ? '1' : '';
+ $options['aiowps_disable_index_views'] = isset($data['aiowps_disable_index_views']) ? '1' : '';
+
+ // Commit the config settings
+ $this->save_settings($options);
+
+ //Now let's write the applicable rules to the .htaccess file
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
+
+ if (!$res) {
+ $success = false;
+ $message = __('Could not write to the .htaccess file', 'all-in-one-wp-security-and-firewall');
+
+ $this->save_settings($original_options);
+ }
+
+ $features = array(
+ 'firewall-basic-rules',
+ 'firewall-block-debug-file-access',
+ 'firewall-disable-index-views',
+ );
+
+ $values = array('aiowps_max_file_upload_size' => $upload_size);
+
+ $args = array(
+ 'badges' => $features,
+ 'info' => $info,
+ 'values' => $values
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Save and update the 5G firewall settings, and conditionally update the .htaccess file if needed.
+ *
+ * This function handles the saving of the 5G firewall settings based on user input. It checks if
+ * the 5G firewall setting has been modified and writes the applicable rules to the .htaccess file
+ * if necessary. In case of failure to write to the .htaccess file, it returns an error message.
+ *
+ * @param array $data The data array containing the 5G firewall setting.
+ *
+ * @global object $aio_wp_security The global instance of the All-In-One WP Security & Firewall plugin.
+ *
+ * @return array An array containing the status ('success' or 'error') and a message indicating
+ * the result of the operation.
+ */
+ public function perform_save_5g_settings($data) {
+ global $aio_wp_security;
+
+ $response = array(
+ 'status' => 'success',
+ 'message' => __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall')
+ );
+
+ $options = array();
+
+ // If the user has changed the 5G firewall checkbox settings, then there is a need to write htaccess rules again.
+ $is_5G_firewall_option_changed = ((isset($data['aiowps_enable_5g_firewall']) && '1' != $aio_wp_security->configs->get_value('aiowps_enable_5g_firewall')) || (!isset($data['aiowps_enable_5g_firewall']) && '1' == $aio_wp_security->configs->get_value('aiowps_enable_5g_firewall')));
+
+ // Save settings
+ $options['aiowps_enable_5g_firewall'] = isset($data['aiowps_enable_5g_firewall']) ? '1' : '';
+ $this->save_settings($options);
+
+ $res = true;
+
+ if ($is_5G_firewall_option_changed) {
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); // let's write the applicable rules to the .htaccess file
+ }
+
+ if (!$res) {
+ $response['status'] = 'error';
+ $response['message'] = __('Could not write to the .htaccess file for the 5G firewall settings, please check the file permissions.', 'all-in-one-wp-security-and-firewall');
+ // revert settings
+ $options['aiowps_enable_5g_firewall'] = '';
+ $this->save_settings($options);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Perform saving blacklist settings
+ *
+ * @param array $data - the request data contains blacklist settings
+ *
+ * @return array - containing a status, message and feature badge html
+ */
+ public function perform_save_blacklist_settings($data) {
+ global $aio_wp_security;
+ $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
+
+ $options = array();
+ $message = '';
+ $success = true;
+
+ $result = 1;
+ $aiowps_enable_blacklisting = isset($data["aiowps_enable_blacklisting"]) ? '1' : '';
+
+ if (!empty($data['aiowps_banned_ip_addresses'])) {
+ $ip_addresses = sanitize_textarea_field(stripslashes($data['aiowps_banned_ip_addresses']));
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
+ if (is_wp_error($validated_ip_list_array)) {
+ $result = -1;
+ $success = false;
+ $message = nl2br($validated_ip_list_array->get_error_message());
+ } else {
+ $banned_ip_addresses_list = preg_split('/\R/', $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses')); // Historical settings where the separator may have depended on PHP_EOL.
+ if ($banned_ip_addresses_list !== $validated_ip_list_array) {
+ $banned_ip_data = implode("\n", $validated_ip_list_array);
+ $options['aiowps_banned_ip_addresses'] = $banned_ip_data;
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
+ }
+ $data['aiowps_banned_ip_addresses'] = ''; // Clear the post variable for the banned address list.
+ }
+ } else {
+ $options['aiowps_banned_ip_addresses'] = ''; // Clear the IP address config value
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', array());
+ }
+
+ if (!empty($data['aiowps_banned_user_agents'])) {
+ $this->validate_user_agent_list(stripslashes($data['aiowps_banned_user_agents']));
+ } else {
+ // Clear the user agent list
+ $options['aiowps_banned_user_agents'] = '';
+ $aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', array());
+ }
+
+ if (1 == $result) {
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', $aiowps_enable_blacklisting, true);
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_is_ip_blacklist_settings_notice_on_upgrade')) {
+ $aio_wp_security->configs->delete_value('aiowps_is_ip_blacklist_settings_notice_on_upgrade');
+ }
+ }
+
+ $this->save_settings($options);
+
+ $args = array(
+ 'badges' => array("blacklist-manager-ip-user-agent-blacklisting")
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * The AJAX function for storing ips in firewall allowlist
+ *
+ * @param array $data - the request data contains data to updated
+ *
+ * @return array - containing a status and message
+ */
+ public function perform_firewall_allowlist($data) {
+ $aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
+
+ $message = '';
+ $success = true;
+ $allowlist = $data['aios_firewall_allowlist'];
+
+ if (empty($allowlist)) {
+ $aiowps_firewall_allow_list::add_ips('');
+ return $this->handle_response(true, '');
+ }
+
+ $ips = sanitize_textarea_field(wp_unslash($allowlist));
+ $ips = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ips);
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ips, 'firewall_allowlist');
+
+ if (is_wp_error($validated_ip_list_array)) {
+ $success = false;
+ $message = nl2br($validated_ip_list_array->get_error_message());
+ } else {
+ $aiowps_firewall_allow_list::add_ips($validated_ip_list_array);
+ }
+
+ return $this->handle_response($success, $message);
+ }
+
+ /**
+ * The AJAX function for saving PHP firewall and block and allowlists in UDC.
+ *
+ * @param array $data The data send from UDC.
+ *
+ * @return array|WP_Error
+ */
+ public function perform_save_firewall($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'));
+ }
+
+ $response = $this->perform_firewall_allowlist($data);
+ if ('error' === $response['status']) {
+ return $response;
+ }
+
+ $response = $this->perform_save_blacklist_settings($data);
+ if ('error' === $response['status']) {
+ return $response;
+ }
+
+ return $this->perform_php_firewall_settings($data);
+ }
+
+ /**
+ * Perform the setup process for the firewall.
+ *
+ * This function handles the setup form for the firewall and renders notices accordingly.
+ *
+ * @return array An array containing the content and message for the response.
+ */
+ public function perform_setup_firewall() {
+ global $aio_wp_security;
+
+ $firewall_setup = AIOWPSecurity_Firewall_Setup_Notice::get_instance();
+ $content = array('aiowps-firewall-status-container' => $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-set-up-button.php', true));
+
+ $firewall_setup->do_setup();
+ ob_start();
+ $firewall_setup->render_notices();
+ $result = ob_get_clean();
+
+
+ $args = array(
+ 'content' => $content,
+ 'extra_args' => array('info_box' => $result)
+ );
+
+ $message = false;
+
+ if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) {
+ $content['aiowps-firewall-status-container'] = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-downgrade-button.php', true);
+ $message = __('Firewall has been setup successfully.', 'all-in-one-wp-security-and-firewall');
+ $args['content'] = $content;
+ }
+
+ return $this->handle_response(AIOWPSecurity_Utility_Firewall::is_firewall_setup(), $message, $args);
+ }
+
+ /**
+ * Perform the downgrade process for the firewall.
+ *
+ * This function removes the firewall and returns a response indicating success.
+ *
+ * @return array An array containing the status, content, and message for the response.
+ */
+ public function perform_downgrade_firewall() {
+ global $aio_wp_security;
+
+ AIOWPSecurity_Utility_Firewall::remove_firewall();
+
+ $message = AIOWPSecurity_Utility_Firewall::is_firewall_setup() ? __('Something went wrong please try again later.', 'all-in-one-wp-security-and-firewall') : __('Firewall has been downgraded successfully.', 'all-in-one-wp-security-and-firewall');
+ $success = true;
+ $downgrade_button = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-set-up-button.php', true);
+ $extra_args = array();
+
+ if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) {
+ $success = false;
+ $downgrade_button = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-downgrade-button.php', true);
+ } else {
+ $extra_args['info_box'] = $aio_wp_security->include_template('notices/firewall-setup-notice.php', true, array('show_dismiss' => false));
+ }
+
+ $args = array(
+ 'content' => array('aiowps-firewall-status-container' => $downgrade_button),
+ 'extra_args' => $extra_args
+ );
+
+ return $this->handle_response($success, $message, $args);
+ }
+
+ /**
+ * Validates posted user agent list and set, save as config.
+ *
+ * @param string $banned_user_agents - List of banned user agents
+ *
+ * @return void
+ */
+ private function validate_user_agent_list($banned_user_agents) {
+ $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'
+ )
+ );
+ $aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', $agents);
+ $this->save_settings(array(
+ 'aiowps_banned_user_agents' => implode("\n", $agents)
+ ));
+ }
+
+ /**
+ * This function performs save upgrade unsafe http calls settings.
+ *
+ * @param array $data - The request data.
+ *
+ * @return array
+ */
+ public function perform_save_upgrade_unsafe_http_calls_settings($data) {
+ $upgrade_unsafe_http_calls_url_exceptions = sanitize_textarea_field(wp_unslash($data['aiowps_upgrade_unsafe_http_calls_url_exceptions']));
+
+ $errors = '';
+
+ if (!empty($upgrade_unsafe_http_calls_url_exceptions)) {
+ foreach (preg_split('/\R/', $upgrade_unsafe_http_calls_url_exceptions) as $url) {
+ $url = sanitize_url($url);
+
+ if (empty($url)) {
+ continue;
+ }
+
+ if (0 === strpos($url, '#')) {
+ continue;
+ }
+
+ $parsed_url = parse_url($url); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- Using the same function as WordPress in order to not preclude URLs that would be allowed by WordPress.
+
+ if (empty($parsed_url['scheme'])) { // The same weak sanity check used by the WordPress wp_remote_* functions.
+ /* translators: %s URL entered by user. */
+ $errors .= "\n" . sprintf(__('%s is not a valid url.', 'all-in-one-wp-security-and-firewall'), $url);
+ continue;
+ }
+ }
+ }
+
+ if (!empty($errors)) {
+ return $this->handle_response(false, nl2br(trim($errors)), array('badges' => array('upgrade-unsafe-http-calls')));
+ }
+
+ $this->save_settings(array(
+ 'aiowps_upgrade_unsafe_http_calls' => isset($data['aiowps_upgrade_unsafe_http_calls']) ? '1' : '',
+ 'aiowps_upgrade_unsafe_http_calls_url_exceptions' => $upgrade_unsafe_http_calls_url_exceptions
+ ));
+
+ return $this->handle_response(true, '', array('badges' => array('upgrade-unsafe-http-calls')));
+ }
+
+ /**
+ * Render the PHP firewall rules for the legacy UDC theme.
+ *
+ * @return array
+ */
+ public function get_php_firewall_contents() {
+ global $aio_wp_security;
+
+ $GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
+ $php_firewall_data = $this->get_php_firewall_data();
+
+ $content = $aio_wp_security->include_template('/wp-admin/firewall/php-firewall-rules.php', true, compact('php_firewall_data'));
+
+ return array(
+ 'status' => 'success',
+ 'content' => $php_firewall_data['no_firewall'] . $content,
+ );
+ }
+
+ /**
+ * Render the .htaccess firewall rules for the legacy UDC theme.
+ *
+ * @return array
+ */
+ public function get_htaccess_contents() {
+ global $aio_wp_security;
+
+ $GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
+
+ $htaccess_rules_data = $this->get_htaccess_rules_data();
+
+ $content = $aio_wp_security->include_template('/wp-admin/firewall/htaccess-firewall-rules.php', true, compact('htaccess_rules_data'));
+
+ return array(
+ 'status' => 'success',
+ 'content' => $content,
+ );
+ }
+
+ /**
+ * Render the Block & Allow Lists for the legacy UDC theme.
+ *
+ * @return array
+ */
+ public function get_block_allow_lists_contents() {
+ global $aio_wp_security;
+
+ /* Needed for submit_button() */
+ require_once(ABSPATH . 'wp-admin/includes/template.php');
+
+ $GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
+
+ $block_allowlist_data = $this->get_block_allow_lists_data();
+
+ $content = $aio_wp_security->include_template('wp-admin/firewall/block-and-allow-lists.php', true, $block_allowlist_data);
+
+ return array(
+ 'status' => 'success',
+ 'content' => $content,
+ );
+ }
+
+ /**
+ * Render the Advanced Settings for the legacy UDC theme.
+ *
+ * @return array
+ */
+ public function get_advanced_settings_contents() {
+ global $aio_wp_security;
+
+ $GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
+
+ $advanced_settings_data = $this->get_firewall_advanced_settings_data();
+
+ $content = $aio_wp_security->include_template('wp-admin/firewall/advanced-settings.php', true, compact('advanced_settings_data'));
+
+ return array(
+ 'status' => 'success',
+ 'content' => $content,
+ );
+ }
+
+ /**
+ * Return data for the advanced firewall.
+ *
+ * @return array
+ */
+ public function get_firewall_advanced_settings_data() {
+ global $aio_wp_security;
+
+ $aiowps_upgrade_unsafe_http_calls = $aio_wp_security->configs->get_value('aiowps_upgrade_unsafe_http_calls');
+ $aiowps_upgrade_unsafe_http_calls_url_exceptions = $aio_wp_security->configs->get_value('aiowps_upgrade_unsafe_http_calls_url_exceptions');
+
+ return array(
+ 'aiowps_upgrade_unsafe_http_calls' => $aiowps_upgrade_unsafe_http_calls,
+ 'aiowps_upgrade_unsafe_http_calls_url_exceptions' => $aiowps_upgrade_unsafe_http_calls_url_exceptions,
+ );
+ }
+
+
+ /**
+ * Return data for the allow & block lists.
+ *
+ * @return array
+ */
+ public function get_block_allow_lists_data() {
+ global $aio_wp_security;
+
+ $aiowps_enable_blacklisting = $aio_wp_security->configs->get_value('aiowps_enable_blacklisting');
+ $aiowps_banned_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
+ $aiowps_banned_user_agents = $aio_wp_security->configs->get_value('aiowps_banned_user_agents');
+
+ $aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
+ $allowlist = $aiowps_firewall_allow_list::get_ips();
+
+ return array(
+ 'aiowps_enable_blacklisting' => $aiowps_enable_blacklisting,
+ 'aiowps_banned_ip_addresses' => $aiowps_banned_ip_addresses,
+ 'aiowps_banned_user_agents' => $aiowps_banned_user_agents,
+ 'allowlist' => $allowlist,
+ );
+ }
+
+ /**
+ * Return data for the .htaccess rules.
+ *
+ * @return array
+ */
+ public function get_htaccess_rules_data() {
+ global $aio_wp_security;
+
+ $aiowps_enable_basic_firewall = $aio_wp_security->configs->get_value('aiowps_enable_basic_firewall');
+ $aiowps_max_file_upload_size = $aio_wp_security->configs->get_value('aiowps_max_file_upload_size');
+ $aiowps_block_debug_log_file_access = $aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access');
+ $aiowps_disable_index_views = $aio_wp_security->configs->get_value('aiowps_disable_index_views');
+
+ return array(
+ 'aiowps_enable_basic_firewall' => $aiowps_enable_basic_firewall,
+ 'aiowps_max_file_upload_size' => $aiowps_max_file_upload_size,
+ 'aiowps_block_debug_log_file_access' => $aiowps_block_debug_log_file_access,
+ 'aiowps_disable_index_views' => $aiowps_disable_index_views,
+ );
+ }
+
+ /**
+ * Return data for the PHP firewall.
+ *
+ * @return array
+ */
+ public function get_php_firewall_data() {
+ global $aio_wp_security, $aiowps_firewall_config, $aiowps_feature_mgr;
+
+ $is_udc_request = AIOS_Helper::is_updraft_central_request();
+
+ $block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
+
+ $no_firewall_notice = '';
+ $user_roles = array();
+
+ // Load required data from config
+ if (!empty($aiowps_firewall_config)) {
+ // firewall config is available
+ $methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
+ if (empty($methods)) {
+ $methods = array();
+ }
+
+ $blocked_query = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
+ $blocked_request = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
+ $blocked_referrers = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
+ $blocked_agents = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
+
+ if (empty($methods) && (!$blocked_query && !$blocked_request && !$blocked_referrers && !$blocked_agents) && '1' == $aio_wp_security->configs->get_value('aiowps_enable_6g_firewall')) {
+ $aio_wp_security->configs->set_value('aiowps_enable_6g_firewall', '');
+ $aio_wp_security->configs->save_config();
+ $aiowps_feature_mgr->check_feature_status_and_recalculate_points();
+ }
+
+ } else {
+ if ($is_udc_request) {
+ ob_start();
+ }
+
+ ?>
+
+
+
+
+
+
+
+
+ configs->get_value('aiowps_enable_6g_firewall');
+ $advanced_options_disabled = '1' != $aiowps_enable_6g_firewall;
+
+ $settings = array_merge(array('methods' => $methods), compact('aiowps_enable_6g_firewall', 'blocked_query', 'blocked_request', 'blocked_referrers', 'blocked_agents', 'block_request_methods', 'aiowps_firewall_config', 'advanced_options_disabled'));
+
+ $aiowps_enable_pingback_firewall = $aiowps_firewall_config->get_value('aiowps_enable_pingback_firewall');
+ $aiowps_disable_xmlrpc_pingback_methods = $aio_wp_security->configs->get_value('aiowps_disable_xmlrpc_pingback_methods');
+ $aiowps_disable_rss_and_atom_feeds = $aio_wp_security->configs->get_value('aiowps_disable_rss_and_atom_feeds');
+ $aiowps_forbid_proxy_comments = $aiowps_firewall_config->get_value('aiowps_forbid_proxy_comments');
+ $aiowps_deny_bad_query_strings = $aiowps_firewall_config->get_value('aiowps_deny_bad_query_strings');
+ $aiowps_advanced_char_string_filter = $aiowps_firewall_config->get_value('aiowps_advanced_char_string_filter');
+
+ $aiowps_disallow_unauthorized_rest_requests = $aio_wp_security->configs->get_value('aiowps_disallow_unauthorized_rest_requests');
+ $aios_roles_disallowed_rest_requests = $aio_wp_security->configs->get_value('aios_roles_disallowed_rest_requests');
+ $aios_whitelisted_rest_routes = $aio_wp_security->configs->get_value('aios_whitelisted_rest_routes');
+ $aiowps_block_fake_googlebots = $aiowps_firewall_config->get_value('aiowps_block_fake_googlebots');
+ $aiowps_ban_post_blank_headers = $aiowps_firewall_config->get_value('aiowps_ban_post_blank_headers');
+
+ $wp_user_roles = AIOWPSecurity_Utility_Permissions::get_user_roles();
+ foreach ($wp_user_roles as $role => $role_name) {
+ $user_roles[] = $role;
+ }
+
+
+ return array(
+ 'aiowps_enable_pingback_firewall' => $aiowps_enable_pingback_firewall,
+ 'aiowps_disable_xmlrpc_pingback_methods' => $aiowps_disable_xmlrpc_pingback_methods,
+ 'aiowps_disable_rss_and_atom_feeds' => $aiowps_disable_rss_and_atom_feeds,
+ 'aiowps_forbid_proxy_comments' => $aiowps_forbid_proxy_comments,
+ 'aiowps_deny_bad_query_strings' => $aiowps_deny_bad_query_strings,
+ 'aiowps_advanced_char_string_filter' => $aiowps_advanced_char_string_filter,
+ 'aiowps_disallow_unauthorized_rest_requests' => $aiowps_disallow_unauthorized_rest_requests,
+ 'aios_roles_disallowed_rest_requests' => $aios_roles_disallowed_rest_requests,
+ 'aios_whitelisted_rest_routes' => $aios_whitelisted_rest_routes,
+ 'user_roles' => $user_roles,
+ 'aiowps_block_fake_googlebots' => $aiowps_block_fake_googlebots,
+ 'aiowps_ban_post_blank_headers' => $aiowps_ban_post_blank_headers,
+ 'ng_settings' => $settings,
+ 'no_firewall' => $no_firewall_notice,
+ );
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-ip-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-ip-commands.php
new file mode 100755
index 00000000..5cfc124f
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-ip-commands.php
@@ -0,0 +1,133 @@
+handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!AIOWPSecurity_Utility::unlock_ip($data['ip'])) {
+ return $this->handle_response(false, __('Failed to unlock the selected IP address.', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ return $this->handle_response(true, __('The selected IP address was unlocked successfully.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Unblacklists an IP.
+ *
+ * @param array $data Contains the IP address to be unblacklisted.
+ *
+ * @return array
+ */
+ public function unblacklist_ip($data) {
+
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!AIOWPSecurity_Utility::unblacklist_ip($data['ip'])) {
+ return $this->handle_response(false, __('Failed to unblacklist the selected IP address.', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ return $this->handle_response(true, __('The selected IP address was unblacklisted successfully.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Unblocks an IP by permanent block record ID.
+ *
+ * @param array $data Contains the ID of the entry in the AIOWPSEC_TBL_PERM_BLOCK table.
+ *
+ * @return array
+ */
+ public function blocked_ip_list_unblock_ip($data) {
+
+ if (!isset($data['id'])) {
+ return $this->handle_response(false, __('Invalid blocked IP ID provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-list-permanent-blocked-ip.php'; // For rendering the AIOWPSecurity_List_Table
+ $blocked_ip_list = new AIOWPSecurity_List_Blocked_IP(); // For rendering the AIOWPSecurity_List_Table
+ $result = $blocked_ip_list->unblock_ip_address($data['id']);
+
+ if (false === $result) {
+ $message = __('Failed to unblock and delete the selected record(s).', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $message = __('Successfully unblocked and deleted the selected record(s).', 'all-in-one-wp-security-and-firewall');
+ }
+ return $this->handle_response(true, $message);
+ }
+
+ /**
+ * Locks an IP.
+ *
+ * @param array $data Contains the IP address to be locked.
+ *
+ * @return array
+ */
+ public function lock_ip($data) {
+
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!isset($data['lock_reason'])) {
+ return $this->handle_response(false, __('No lockout reason provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ AIOWPSecurity_Utility::lock_ip($data['ip'], $data['lock_reason']);
+
+ return $this->handle_response(true, __('The selected IP address is now temporarily locked.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ /**
+ * Blacklists an IP.
+ *
+ * @param array $data Contains the IP address to be blacklisted.
+ *
+ * @return array
+ */
+ public function blacklist_ip($data) {
+
+ if (!isset($data['ip'])) {
+ return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
+ return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ $result = AIOWPSecurity_Utility::blacklist_ip($data['ip']);
+
+ if (is_wp_error($result)) {
+ return $this->handle_response(false, nl2br($result->get_error_message()));
+ } else {
+ return $this->handle_response(true, __('The selected IP address has been added to the blacklist.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-log-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-log-commands.php
new file mode 100755
index 00000000..f527439d
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-log-commands.php
@@ -0,0 +1,345 @@
+handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(__('No audit log ID provided.', 'all-in-one-wp-security-and-firewall'), true));
+ }
+
+ include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php';
+ $audit_log_list = new AIOWPSecurity_List_Audit_Log();
+
+ return $this->handle_response(true, $audit_log_list->delete_audit_event_records($data['id']));
+ }
+
+ /**
+ * Deletes an IP lockout record.
+ *
+ * @param array $data Contains the ID of the entry in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @return array
+ */
+ public function delete_locked_ip_record($data) {
+
+ if (!isset($data['id'])) {
+ return $this->handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(__('No locked IP record ID provided.', 'all-in-one-wp-security-and-firewall'), true));
+ }
+
+ include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-list-locked-ip.php';
+
+ $locked_ip_list = new AIOWPSecurity_List_Locked_IP();
+ $result = $locked_ip_list->delete_lockout_records($data['id']);
+ return $this->handle_response(true, $result);
+ }
+
+ /**
+ * Clear debug logs
+ *
+ * @return array
+ */
+ public function clear_debug_logs() {
+ global $aio_wp_security;
+
+ $ret = $aio_wp_security->debug_logger->clear_logs();
+
+ if (is_wp_error($ret)) {
+ return $this->handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(esc_html($ret->get_error_message()).'
'.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 etc rules gets removed.
+ // Escape textarea should not be used the & becomes &.
+ // Here stripslashes as old version 5.3.0 not required, AIOWPSecurity_Ajax::set_data applies wp_unslash for ajax data.
+ // So the .htacces rule having index\.php backslashes removed if used stripslashes below.
+ $options['aiowps_custom_rules'] = $data['aiowps_custom_rules'];
+ } else {
+ $options['aiowps_custom_rules'] = ''; //Clear the custom rules config value
+ }
+
+ $aiowps_custom_rules = $aio_wp_security->configs->get_value('aiowps_custom_rules');
+ $aiowps_place_custom_rules_at_top = $aio_wp_security->configs->get_value('aiowps_place_custom_rules_at_top');
+
+ $options['aiowps_enable_custom_rules'] = isset($data["aiowps_enable_custom_rules"]) ? '1' : '';
+ $options['aiowps_place_custom_rules_at_top'] = isset($data["aiowps_place_custom_rules_at_top"]) ? '1' : '';
+ $this->save_settings($options); // Save the configuration
+
+ $write_result = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); //now let's write to the .htaccess file
+ if (!$write_result) {
+ $options['aiowps_enable_custom_rules'] = $aiowps_custom_rules;
+ $options['aiowps_place_custom_rules_at_top'] = $aiowps_place_custom_rules_at_top;
+
+ $this->save_settings($options);
+
+ $success = false;
+ $message = __('The plugin was unable to write to the .htaccess file, please edit file manually.', 'all-in-one-wp-security-and-firewall');
+ $aio_wp_security->debug_logger->log_debug("Custom Rules feature - The plugin was unable to write to the .htaccess file.");
+ }
+ }
+
+ return $this->handle_response($success, $message);
+ }
+
+ /**
+ * Perform the general visitor lockout settings operation.
+ *
+ * @param array $data The data containing the general visitor lockout settings.
+ * It should include keys 'aiowps_site_lockout' and 'aiowps_site_lockout_msg'.
+ * @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 an informational message about the outcome of the operation.
+ */
+ public function perform_general_visitor_lockout($data) {
+ $options = array();
+
+ // Save settings
+ $options['aiowps_site_lockout'] = isset($data["aiowps_site_lockout"]) ? '1' : '';
+ $maint_msg = wp_kses_post(wp_unslash($data['aiowps_site_lockout_msg']));
+ $options['aiowps_site_lockout_msg'] = $maint_msg; // Text area/msg box
+ $this->save_settings($options);
+
+ do_action('aiowps_site_lockout_settings_saved');
+
+ return array(
+ 'status' => 'success',
+ 'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ /**
+ * Perform the general visitor lockout setting operation for the dashboard widget.
+ *
+ * @param array $data The data containing the general visitor lockout setting.
+ * It should include the 'aiowps_site_lockout' key.
+ * @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 an informational message about the outcome of the operation.
+ */
+ public function perform_general_visitor_lockout_dashboard_widget($data) {
+ $options = array();
+
+ // Save settings
+ $options['aiowps_site_lockout'] = isset($data["aiowps_site_lockout"]) ? '1' : '';
+ $this->save_settings($options);
+
+ do_action('aiowps_site_lockout_settings_saved');
+
+ return $this->handle_response(true);
+ }
+
+ /**
+ * Checks a password against the HIBP database.
+ *
+ * @param array $data Contains the password to be checked.
+ *
+ * @return array
+ */
+ public function hibp_check_password($data) {
+ return array(
+ 'status' => 'success',
+ 'pwned' => AIOS_HIBP::password_is_pwned($data['password']),
+ );
+ }
+
+ /**
+ * Does a WHOIS lookup on an IP address or domain name and then returns the result.
+ *
+ * @param String $search - IP address or domain name to do a WHOIS lookup on
+ * @param Integer $timeout - connection timeout for fsockopen
+ *
+ * @return String|WP_Error - returns preformatted WHOIS lookup result or WP_Error
+ */
+ private function whois_lookup($search, $timeout = 10) {
+ $fp = @fsockopen('whois.iana.org', 43, $errno, $errstr, $timeout);
+
+ if (!$fp) {
+ return new WP_Error('whois_lookup_failed', 'whois.iana.org: Socket Error '.$errno.' - '.$errstr);
+ }
+
+ $queries = sprintf(__('Querying %s: %s', 'all-in-one-wp-security-and-firewall'), 'whois.iana.org', $search)."\n";
+
+ fputs($fp, $search."\r\n");
+ $out = '';
+ while (!feof($fp)) {
+ $line = fgets($fp);
+ if (preg_match('/refer: +(\S+)/', $line, $matches)) {
+ $referral_server = $matches[1];
+ $queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
+ break;
+ }
+ $out .= $line;
+ }
+ fclose($fp);
+
+ if (!isset($referral_server) && filter_var($search, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && preg_match('/whois: +(\S+)/', $out, $matches)) {
+ $referral_server = $matches[1];
+ $queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
+ }
+
+ $referrals = array();
+
+ while (isset($referral_server)) {
+ $referrals[] = $referral_server;
+
+ $fp = @fsockopen($referral_server, 43, $errno, $errstr, $timeout);
+
+ if (!$fp) {
+ return new WP_Error('whois_lookup_failed', $referral_server.': Socket Error '.$errno.' - '.$errstr);
+ }
+
+ if ('whois.arin.net' == $referral_server) {
+ $formatted_search = 'n + '.$search;
+ } elseif ('whois.denic.de' == $referral_server) {
+ $formatted_search = '-T dn,ace '.$search;
+ } elseif ('whois.dk-hostmaster.dk' == $referral_server) {
+ $formatted_search = '--charset=utf-8 --show-handles '.$search;
+ } elseif ('whois.nic.ad.jp' == $referral_server || 'whois.jprs.jp' == $referral_server) {
+ $formatted_search = $search.'/e';
+ } else {
+ $formatted_search = $search;
+ }
+
+ $queries .= sprintf(__('Querying %s: %s', 'all-in-one-wp-security-and-firewall'), $referral_server, $formatted_search)."\n";
+
+ $referral_server = null;
+
+ fputs($fp, $formatted_search."\r\n");
+ $out = '';
+ while (!feof($fp)) {
+ $line = fgets($fp);
+ if (preg_match('/Registrar WHOIS Server: +(\S+)/', $line, $matches)
+ || preg_match('/% referto: +whois -h (\S+)/', $line, $matches)
+ || preg_match('/% referto: +(\S+)/', $line, $matches)
+ || preg_match('/ReferralServer: +rwhois:\/\/(\S+)/', $line, $matches)
+ || preg_match('/ReferralServer: +whois:\/\/(\S+)/', $line, $matches)
+ ) {
+ if (!in_array($matches[1], $referrals)) {
+ $referral_server = $matches[1];
+ $queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
+ break;
+ }
+ }
+ $out .= $line;
+ }
+ fclose($fp);
+ }
+
+ return $queries."\n".$out;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-user-security-commands.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-user-security-commands.php
new file mode 100755
index 00000000..33c5c700
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-user-security-commands.php
@@ -0,0 +1,716 @@
+configs->set_value('aiowps_prevent_users_enumeration', isset($data["aiowps_prevent_users_enumeration"]) ? '1' : '', true);
+ $aio_wp_security->configs->set_value('aiowps_enforce_strong_password', isset($data['aiowps_enforce_strong_password']) ? '1' : '', true);
+
+ $badges = array('enforce-strong-password', 'disable-users-enumeration');
+
+ return $this->handle_response(true, '', array('badges' => $badges));
+ }
+
+ /**
+ * Performs the action to change the admin username.
+ *
+ * @param array $data An array containing the data for changing the admin username.
+ * The array may contain the following keys:
+ * - 'aiowps_new_user_name': The new username to be set for the admin.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * and a message indicating the result of the operation.
+ * If the operation is successful, it also includes a badge representing the updated feature details.
+ */
+ public function perform_change_admin_username($data) {
+ global $wpdb, $aio_wp_security;
+
+ $response = array(
+ 'status' => 'success',
+ 'content' => array()
+ );
+
+ $error = '';
+ if (!empty($data['aiowps_new_user_name'])) {
+ $new_username = sanitize_text_field($data['aiowps_new_user_name']);
+ if (validate_username($new_username)) {
+ if (AIOWPSecurity_Utility::check_user_exists($new_username)) {
+ $response['status'] = 'error';
+ $error = sprintf(__('Username: %s already exists, please enter another value.', 'all-in-one-wp-security-and-firewall'), $new_username);
+ } else {
+ // let's check if currently logged in username is 'admin'
+ $user = wp_get_current_user();
+ $user_login = $user->user_login;
+ if ('admin' == strtolower($user_login)) {
+ $username_is_admin = true;
+ } else {
+ $username_is_admin = false;
+ }
+ // Now let's change the username
+ $sql = $wpdb->prepare("UPDATE `" . $wpdb->users . "` SET user_login = '" . esc_sql($new_username) . "' WHERE user_login=%s", "admin");
+ $result = $wpdb->query($sql);
+ if (false === $result) {
+ // There was an error updating the users table
+ $user_update_error = __('The database update operation of the user account failed.', 'all-in-one-wp-security-and-firewall');
+ $response['status'] = 'error';
+ $response['message'] = $user_update_error;
+ $aio_wp_security->debug_logger->log_debug($user_update_error . ' ' . $wpdb->last_error, 4);
+ return $response;
+ }
+
+ // multisite considerations
+ if (is_multisite()) { // process sitemeta if we're in a multi-site situation
+ $oldAdmins = $wpdb->get_var("SELECT meta_value FROM `" . $wpdb->sitemeta . "` WHERE meta_key = 'site_admins'");
+ $newAdmins = str_replace('5:"admin"', strlen($new_username) . ':"' . esc_sql($new_username) . '"', $oldAdmins);
+ $wpdb->query("UPDATE `" . $wpdb->sitemeta . "` SET meta_value = '" . esc_sql($newAdmins) . "' WHERE meta_key = 'site_admins'");
+ }
+
+ // If user is logged in with username "admin" then log user out and send to login page so they can login again
+ if ($username_is_admin) {
+ // Lets logout the user
+ $aio_wp_security->debug_logger->log_debug("Logging user out with login ".$user_login. " because they changed their username.");
+ $after_logout_url = AIOWPSecurity_Utility::get_current_page_url();
+ $after_logout_payload = array('redirect_to' => $after_logout_url, 'msg' => $aio_wp_security->user_login_obj->key_login_msg.'=admin_user_changed');
+ //Save some of the logout redirect data to a transient
+ is_multisite() ? set_site_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60) : set_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60);
+
+ $logout_url = AIOWPSEC_WP_URL.'?aiowpsec_do_log_out=1';
+ $logout_url = AIOWPSecurity_Utility::add_query_data_to_url($logout_url, 'al_additional_data', '1');
+
+ $response['logout_user'] = true;
+ $response['logout_url'] = $logout_url;
+ }
+ }
+ } else { // An invalid username was entered
+ $error = __('You entered an invalid username, please enter another value.', 'all-in-one-wp-security-and-firewall');
+ }
+ } else { // No username value was entered
+ $response['status'] = 'error';
+ $error = __('Please enter a value for your username.', 'all-in-one-wp-security-and-firewall');
+ }
+
+ if (!empty($error)) { // We have some validation or other error
+ $response['message'] = $error;
+ } else {
+ $response['message'] = __('The username has been successfully changed.', 'all-in-one-wp-security-and-firewall');
+ $response['badges'] = $this->get_features_id_and_html(array('user-accounts-change-admin-user'));
+ $response['content']['change-admin-username-content'] = $aio_wp_security->include_template('wp-admin/user-security/partials/wp-username-content.php', true);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Performs the action to save the login lockout settings.
+ *
+ * @param array $data An array containing the data to be saved.
+ *
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_save_login_lockout_settings($data) {
+
+ $response = array(
+ 'status' => 'success',
+ 'values' => array(),
+ 'info' => array()
+ );
+
+ $invalid_fields = array();
+
+ $max_login_attempt_val = sanitize_text_field($data['aiowps_max_login_attempts']);
+ if (!is_numeric($max_login_attempt_val) || 1 > $max_login_attempt_val) {
+ $invalid_fields[] = 'max login attempts';
+ $max_login_attempt_val = '3'; // Set it to the default value for this field
+ }
+
+ $login_retry_time_period = sanitize_text_field($data['aiowps_retry_time_period']);
+ if (!is_numeric($login_retry_time_period) || 1 > $login_retry_time_period) {
+ $invalid_fields[] = 'login retry time period';
+ $login_retry_time_period = '5'; // Set it to the default value for this field
+ }
+
+ $lockout_time_length = sanitize_text_field($data['aiowps_lockout_time_length']);
+ if (!is_numeric($lockout_time_length) || 1 > $lockout_time_length) {
+ $invalid_fields[] = 'minimum lockout time length';
+ $lockout_time_length = '5'; // Set it to the default value for this field
+ }
+
+ $max_lockout_time_length = sanitize_text_field($data['aiowps_max_lockout_time_length']);
+ if (!is_numeric($max_lockout_time_length) || 1 > $max_lockout_time_length) {
+ $invalid_fields[] = 'maximum lockout time length';
+ $max_lockout_time_length = '60'; // Set it to the default value for this field
+ }
+
+ if ($lockout_time_length >= $max_lockout_time_length) {
+ $invalid_fields[] = 'minimum lockout time length';
+ $lockout_time_length = '5'; // Set it to the default value for this field
+ $max_lockout_time_length = '60'; // Set it to the default value for this field
+ }
+
+ $email_addresses = isset($data['aiowps_email_address']) ? stripslashes($data['aiowps_email_address']) : get_bloginfo('admin_email');
+ $email_addresses_trimmed = AIOWPSecurity_Utility::explode_trim_filter_empty($email_addresses, "\n");
+ // Read into array, sanitize, filter empty and keep only unique usernames.
+ $email_address_list = array_unique(
+ array_filter(
+ array_map(
+ 'sanitize_email',
+ $email_addresses_trimmed
+ ),
+ 'is_email'
+ )
+ );
+
+ if (isset($data['aiowps_enable_email_notify']) && 1 == $data['aiowps_enable_email_notify'] && 0 == count($email_addresses_trimmed)) {
+ $invalid_fields[] = 'email addresses';
+ } elseif (isset($data['aiowps_enable_email_notify']) && 1 == $data['aiowps_enable_email_notify'] && (0 == count($email_address_list) || count($email_address_list) != count($email_addresses_trimmed))) {
+ $invalid_fields[] = 'email addresses';
+ }
+ if (isset($data['aiowps_enable_email_notify']) && 0 == count($email_address_list)) {
+ $email_address_list[] = get_bloginfo('admin_email');
+ }
+
+ // Instantly lockout specific usernames
+ $instantly_lockout_specific_usernames = isset($data['aiowps_instantly_lockout_specific_usernames']) ? $data['aiowps_instantly_lockout_specific_usernames'] : '';
+ // Read into array, sanitize, filter empty and keep only unique usernames.
+ $instantly_lockout_specific_usernames = array_unique(
+ array_filter(
+ array_map(
+ 'sanitize_user',
+ AIOWPSecurity_Utility::explode_trim_filter_empty($instantly_lockout_specific_usernames)
+ ),
+ 'strlen'
+ )
+ );
+
+ $response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
+
+ if (!empty($invalid_fields)) {
+ $invalid_fields = array_unique($invalid_fields);
+ $invalid_fields = implode(", ", $invalid_fields);
+ $response['info'][] = sprintf(__('The following options had invalid values and have been set to the defaults: %s', 'all-in-one-wp-security-and-firewall'), $invalid_fields);
+ }
+
+ $options = array();
+
+ // Save all the form values to the options
+ $random_20_digit_string = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20); // Generate random 20 char string for use during CAPTCHA encode/decode
+ $options['aiowps_unlock_request_secret_key'] = $random_20_digit_string;
+
+ $options['aiowps_enable_login_lockdown'] = isset($data["aiowps_enable_login_lockdown"]) ? '1' : '';
+ $options['aiowps_allow_unlock_requests'] = isset($data["aiowps_allow_unlock_requests"]) ? '1' : '';
+ $options['aiowps_max_login_attempts'] = absint($max_login_attempt_val);
+ $options['aiowps_retry_time_period'] = absint($login_retry_time_period);
+ $options['aiowps_lockout_time_length'] = absint($lockout_time_length);
+ $options['aiowps_max_lockout_time_length'] = absint($max_lockout_time_length);
+ $options['aiowps_set_generic_login_msg'] = isset($data["aiowps_set_generic_login_msg"]) ? '1' : '';
+ $options['aiowps_enable_invalid_username_lockdown']= isset($data["aiowps_enable_invalid_username_lockdown"]) ? '1' : '';
+ $options['aiowps_instantly_lockout_specific_usernames'] = $instantly_lockout_specific_usernames;
+ $options['aiowps_enable_email_notify'] = isset($data["aiowps_enable_email_notify"]) ? '1' : '';
+ $options['aiowps_enable_php_backtrace_in_email'] = isset($data['aiowps_enable_php_backtrace_in_email']) ? '1' : '';
+ $options['aiowps_email_address'] = $email_address_list;
+ $this->save_settings($options);
+
+ $response['values']['aiowps_max_login_attempts'] = absint($max_login_attempt_val);
+ $response['values']['aiowps_retry_time_period'] = absint($login_retry_time_period);
+ $response['values']['aiowps_lockout_time_length'] = absint($lockout_time_length);
+ $response['values']['aiowps_max_lockout_time_length'] = absint($max_lockout_time_length);
+ $response['values']['aiowps_email_address'] = implode("\n", $email_address_list);
+
+ $response['badges'] = $this->get_features_id_and_html(array('user-login-login-lockdown'));
+
+ return $response;
+ }
+
+ /**
+ * Performs the action to save the login lockout whitelist settings.
+ *
+ * @param array $data An array containing the data to be saved.
+ * The array may contain the following keys:
+ * - 'aiowps_lockdown_enable_whitelisting': A boolean indicating whether whitelisting is enabled.
+ * - 'aiowps_lockdown_allowed_ip_addresses': The allowed IP addresses for whitelisting.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_save_login_lockout_whitelist_settings($data) {
+ global $aio_wp_security;
+
+ $response = array(
+ 'status' => 'success'
+ );
+
+ $options = array();
+ $result = 1;
+
+ if (!empty($data['aiowps_lockdown_allowed_ip_addresses'])) {
+ $ip_addresses = sanitize_textarea_field(wp_unslash($data['aiowps_lockdown_allowed_ip_addresses']));
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'whitelist');
+ if (is_wp_error($validated_ip_list_array)) {
+ $result = -1;
+ $response['status'] = 'error';
+ $response['message'] = AIOWPSecurity_Admin_Menu::show_msg_error_st(nl2br($validated_ip_list_array->get_error_message()), true);
+ } else {
+ $allowed_ip_data = implode("\n", $validated_ip_list_array);
+ $options['aiowps_lockdown_allowed_ip_addresses'] = $allowed_ip_data;
+ }
+ } else {
+ $options['aiowps_lockdown_allowed_ip_addresses'] = ''; //Clear the IP address config value
+ }
+
+ if (1 == $result) {
+ $aio_wp_security->configs->set_value('aiowps_lockdown_enable_whitelisting', isset($data["aiowps_lockdown_enable_whitelisting"]) ? '1' : '', true);
+ $response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
+ $response['badges'] = $this->get_features_id_and_html(array('user-login-lockout-ip-whitelisting'));
+ }
+
+ $this->save_settings($options);
+
+ return $response;
+ }
+
+ /**
+ * Performs the action to force logout users.
+ *
+ * @param array $data An array containing the data to be saved.
+ * The array may contain the following keys:
+ * - 'aiowps_logout_time_period': The time period (in minutes) for logout.
+ * - 'aiowps_enable_forced_logout': A boolean indicating whether forced logout is enabled.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * an array of messages indicating the result of the operation,
+ * the content representing the logout time period,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_force_logout($data) {
+ global $aio_wp_security;
+ $response = array(
+ 'status' => 'success',
+ 'info' => array(),
+ 'values' => array()
+ );
+
+ $options = array();
+
+
+ $logout_time_period = sanitize_text_field($data['aiowps_logout_time_period']);
+ if (isset($data["aiowps_enable_forced_logout"]) && (!is_numeric($logout_time_period) || $logout_time_period < 1)) {
+ $response['info'][] = __('You entered a non numeric or negative value for the logout time period field, it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
+ $logout_time_period = '60'; // Set it to the default value for this field
+ }
+
+ // Save all the form values to the options
+ $options['aiowps_logout_time_period'] = absint($logout_time_period);
+ $options['aiowps_enable_forced_logout'] = isset($data["aiowps_enable_forced_logout"]) ? '1' : '';
+ $this->save_settings($options);
+
+ $response['values']['aiowps_logout_time_period'] = absint($logout_time_period);
+ $response['badges'] = $this->get_features_id_and_html(array('user-login-force-logout'));
+ $response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
+
+ if ('1' === $options['aiowps_enable_forced_logout']) {
+ $response['logout_user'] = $this->check_logout_user();
+ $response['logout_url'] = $aio_wp_security->user_login_obj->aiowps_force_logout_action_handler(true);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Performs the action to save the HIBP settings.
+ *
+ * @param array $data An array containing the data to be saved.
+ *
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_save_hibp_settings($data) {
+ global $aio_wp_security;
+
+ $aio_wp_security->configs->set_value('aiowps_hibp_user_profile_update', isset($data['aiowps_hibp_user_profile_update']) ? '1' : '', true);
+ $aio_wp_security->configs->set_value('aiowps_http_password_reset', isset($data['aiowps_http_password_reset']) ? '1' : '', true);
+ $aio_wp_security->configs->save_config();
+
+ return $this->handle_response(true, false, array('badges' => array('hibp')));
+ }
+
+ /**
+ * Performs the action to disable application password.
+ *
+ * @param array $data An array containing the data to be saved.
+ * The array may contain the following key:
+ * - 'aiowps_disable_application_password': A boolean indicating whether application password is disabled.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_disable_application_password($data) {
+ global $aio_wp_security;
+
+ // Save all the form values to the options
+ $aio_wp_security->configs->set_value('aiowps_disable_application_password', isset($data['aiowps_disable_application_password']) ? '1' : '', true);
+
+ return array(
+ 'status' => 'success',
+ 'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'),
+ 'badges' => $this->get_features_id_and_html(array('disable-application-password'))
+ );
+ }
+
+ /**
+ * Performs the action to add salt postfix.
+ *
+ * @param array $data An array containing the data to be saved.
+ * The array may contain the following key:
+ * - 'aiowps_enable_salt_postfix': A boolean indicating whether salt postfix is enabled.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_add_salt_postfix($data) {
+ global $aio_wp_security;
+
+ $response = array(
+ 'status' => 'success'
+ );
+
+ // Save settings
+ $aiowps_enable_salt_postfix = isset($data['aiowps_enable_salt_postfix']) ? '1' : '';
+ if ($aiowps_enable_salt_postfix == $aio_wp_security->configs->get_value('aiowps_enable_salt_postfix')) {
+ $is_setting_changed = true;
+ } else {
+ $is_setting_changed = false;
+ }
+
+ $aio_wp_security->configs->set_value('aiowps_enable_salt_postfix', $aiowps_enable_salt_postfix, true);
+ $ret_schedule = $this->schedule_change_auth_keys_and_salt();
+
+ if (is_wp_error($ret_schedule)) {
+ $aio_wp_security->debug_logger->log_debug($ret_schedule->get_error_message(), 4);
+ }
+
+ if ('1' == $aiowps_enable_salt_postfix && $is_setting_changed) {
+ AIOWPSecurity_Utility::change_salt_postfixes();
+ }
+
+ $response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
+ $response['badges'] = $this->get_features_id_and_html(array('enable-salt-postfix'));
+
+ return $response;
+ }
+
+ /**
+ * Performs actions on logged-in users.
+ *
+ * @param array $data An array containing the data for the action to be performed.
+ * The array may contain the following keys:
+ * - 'action': The action to be performed on logged-in users (e.g., 'force_user_logout').
+ * - 'logged_in_id': The ID of the logged-in user on which the action will be performed.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * and a message indicating the result of the operation.
+ */
+ public function perform_logged_in_user_action($data) {
+ global $aio_wp_security;
+ include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-logged-in-users.php'; // For rendering the AIOWPSecurity_List_Table
+ $user_list = new AIOWPSecurity_List_Logged_In_Users();
+ $response = array(
+ 'status' => 'success'
+ );
+
+ if (empty($data['action']) || !in_array($data['action'], array('force_user_logout'))) { // more actions can be added
+ return array(
+ 'status' => 'error',
+ 'message' => __('Invalid action provided for logged in user.', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ if ('force_user_logout' == $data['action']) {
+ if (empty($data['logged_in_id'])) {
+ return array(
+ 'status' => 'error',
+ 'message' => __('No user ID was provided', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+ $user_id = strip_tags($data['logged_in_id']);
+ $error = '';
+
+ if (!is_numeric($user_id)) {
+ $error = __("Invalid user ID provided.", 'all-in-one-wp-security-and-firewall');
+ } elseif (get_current_user_id() == $user_id) {
+ $error = __("You cannot log yourself out", 'all-in-one-wp-security-and-firewall');
+ } elseif (is_super_admin($user_id)) {
+ $error = __("Super admins cannot be logged out.", 'all-in-one-wp-security-and-firewall');
+ } elseif (!AIOWPSecurity_Utility::is_user_member_of_blog($user_id)) {
+ $error = __("You cannot log out a user from a different subsite.", 'all-in-one-wp-security-and-firewall');
+ }
+ if ($error) {
+ return array(
+ 'message' => $error,
+ 'status' => 'error'
+ );
+ }
+
+ $users = esc_sql($user_id);
+ $result = $aio_wp_security->user_login_obj->delete_logged_in_user($users);
+
+ if ($result) {
+ $user_list->logout_user($users);
+ $response['message'] = __('The selected user has been logged out successfully.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $response['message'] = __('Failed to log out the selected user.', 'all-in-one-wp-security-and-firewall');
+ $response['status'] = 'error';
+ }
+
+ }
+
+ return $response;
+ }
+
+ /**
+ * Performs the action to configure manual registration approval settings.
+ *
+ * @param array $data An array containing the data to be saved.
+ * The array may contain the following key:
+ * - 'aiowps_enable_manual_registration_approval': A boolean indicating whether manual registration approval is enabled.
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_manual_approval_settings($data) {
+ global $aio_wp_security;
+
+ // Save settings
+ $aio_wp_security->configs->set_value('aiowps_enable_manual_registration_approval', isset($data["aiowps_enable_manual_registration_approval"]) ? '1' : '', true);
+
+ return array(
+ 'status' => 'success',
+ 'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'),
+ 'badges' => $this->get_features_id_and_html(array('manually-approve-registrations'))
+ );
+ }
+
+ /**
+ * Performs actions on manual approval items (e.g., approve account, delete account, block IP).
+ *
+ * @param array $data An array containing the data for the action to be performed.
+ * The array may contain the following keys:
+ * - 'action': The action to be performed on the manual approval item (e.g., 'approve_acct', 'delete_acct', 'block_ip').
+ * - 'user_id': The ID of the user for whom the action will be performed (applicable for 'approve_acct' and 'delete_acct' actions).
+ * - 'ip_address': The IP address to be blocked (applicable for 'block_ip' action).
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * and a message indicating the result of the operation.
+ */
+ public function perform_manual_approval_item_action($data) {
+ global $aio_wp_security;
+
+ include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-registered-users.php'; // For rendering the AIOWPSecurity_List_Table
+ $user_list = new AIOWPSecurity_List_Registered_Users();
+ $status = 'error';
+
+ $valid_actions = array('approve_acct', 'delete_acct', 'block_ip');
+ if (empty($data['action']) || !in_array($data['action'], $valid_actions)) { // more actions can be added
+ return array(
+ 'status' => 'error',
+ 'message' => __('Invalid action provided for registered user.', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ switch ($data['action']) {
+ case 'approve_acct':
+ if (empty($data['user_id'])) {
+ return array(
+ 'status' => 'error',
+ 'message' => __('No valid user ID was provided', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+ $user_id = esc_sql(strip_tags($data['user_id']));
+ $meta_key = 'aiowps_account_status';
+ $meta_value = 'approved'; // set account status
+
+ // Approve single account
+ $result = update_user_meta($user_id, $meta_key, $meta_value);
+ if ($result) {
+ $user = get_user_by('id', $user_id);
+ $user_list->send_email_upon_account_activation($user);
+ $message = __('The selected account was approved successfully.', 'all-in-one-wp-security-and-firewall');
+ $status = 'success';
+ } elseif (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("could not approve account ID: $user_id", 4);
+ $message = __('The selected account could not be approved.', 'all-in-one-wp-security-and-firewall');
+ }
+ break;
+ case 'delete_acct':
+ if (empty($data['user_id'])) {
+ return array(
+ 'status' => 'error',
+ 'message' => __('No valid user ID was provided', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ $user_id = esc_sql(strip_tags($data['user_id']));
+ // Delete single account
+ $result = wp_delete_user($user_id);
+ if (true === $result) {
+ $message = __('The selected account was deleted successfully.', 'all-in-one-wp-security-and-firewall');
+ $status = 'success';
+ } else {
+ $aio_wp_security->debug_logger->log_debug("could not delete account ID: $user_id", 4);
+ $message = __('The selected account could not be deleted.', 'all-in-one-wp-security-and-firewall');
+ }
+ break;
+ case 'block_ip':
+ if (empty($data['ip_address'])) {
+ return array(
+ 'status' => 'error',
+ 'message' => __('No valid IP address was provided', 'all-in-one-wp-security-and-firewall')
+ );
+ }
+
+ $ip = esc_sql(strip_tags($data['ip_address']));
+
+ if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
+ $message = __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip;
+ break;
+ }
+
+ // Block single IP
+ $result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip, 'registration_spam');
+ if (true === $result) {
+ $message = __('The selected IP was successfully added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
+ $message .= ' '.__('View Blocked IPs', 'all-in-one-wp-security-and-firewall').'';
+ $status = 'success';
+ } else {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::block_selected_ips() - could not block IP: $ip", 4);
+ $message = __('The selected IP could not be added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
+ }
+ break;
+ }
+
+ return array(
+ 'status' => $status,
+ 'message' => $message
+ );
+ }
+
+ /**
+ * Schedule weekly aios_change_auth_keys_and_salt cron event.
+ *
+ * @return Boolean|WP_Error True if event successfully scheduled. False or WP_Error on failure.
+ */
+ private function schedule_change_auth_keys_and_salt() {
+ $previous_time = wp_next_scheduled('aios_change_auth_keys_and_salt');
+
+ if (false !== $previous_time) {
+ // Clear schedule so that we don't stack up scheduled backups
+ wp_clear_scheduled_hook('aios_change_auth_keys_and_salt');
+ }
+ $gmt_offset_in_seconds = floatval(get_option('gmt_offset')) * 3600;
+ $first_time = strtotime('next Sunday '.apply_filters('aios_salt_change_schedule_time', '3:00 am')) + $gmt_offset_in_seconds;
+ return wp_schedule_event($first_time, 'weekly', 'aios_change_auth_keys_and_salt');
+ }
+
+ /**
+ * Checks if the current user should be automatically logged out based on last login time.
+ *
+ * This method compares the current time with the last login time of the user and determines
+ * if the user should be logged out based on a configured logout time period.
+ *
+ * @return bool Returns true if the user should be logged out, false otherwise.
+ */
+ private function check_logout_user() {
+ global $aio_wp_security;
+
+ // Get the current user
+ $current_user = wp_get_current_user();
+ $user_id = $current_user->ID;
+
+ // Get the current and last login times
+ $current_time = current_time('mysql', true);
+ $login_time = $aio_wp_security->user_login_obj->get_wp_user_aiowps_last_login_time($user_id);
+
+ // Return false if login time is empty (no last login recorded)
+ if (empty($login_time)) {
+ return false;
+ }
+
+ // Calculate the time difference between current time and last login time
+ $diff = strtotime($current_time) - strtotime($login_time);
+
+ // Get the configured logout time period in seconds
+ $logout_time_interval_value = $aio_wp_security->configs->get_value('aiowps_logout_time_period');
+ $logout_time_interval_val_seconds = $logout_time_interval_value * 60;
+
+ // Return true if the time difference exceeds the logout time interval, indicating the user should be logged out
+ return $diff > $logout_time_interval_val_seconds;
+ }
+
+ /**
+ * Whitelists user's IP address
+ *
+ * @return array Returns an array containing the status of the operation ('success' or 'error'),
+ * a message indicating the result of the operation,
+ * and a badge representing the updated feature details.
+ */
+ public function perform_whitelist_user_ip() {
+ $response = array(
+ 'status' => 'success'
+ );
+
+ if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ $response['status'] = 'error';
+ $response['message'] = __('You don\'t have enough permissions to whitelist your IP address.', 'all-in-one-wp-security-and-firewall');
+ return $response;
+ }
+
+ $aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
+
+ $whitelisted_ips = $aiowps_firewall_allow_list::get_ips();
+ $is_whitelisted = $aiowps_firewall_allow_list::is_ip_allowed();
+
+ if ($is_whitelisted) {
+ $response['status'] = 'error';
+ $response['message'] = __('Your IP address is already whitelisted.', 'all-in-one-wp-security-and-firewall');
+ return $response;
+ } else {
+ $user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
+
+ if (empty($user_ip)) {
+ $response['status'] = 'error';
+ $response['message'] = __('Your IP address could not be detected.', 'all-in-one-wp-security-and-firewall');
+ return $response;
+ }
+
+ $whitelisted_ips .= (empty($whitelisted_ips) ? '' : "\n") . $user_ip;
+
+ if (!$aiowps_firewall_allow_list::add_ips($whitelisted_ips)) {
+ $response['status'] = 'error';
+ $response['message'] = __('There was an error whitelisting your IP address, please try again.', 'all-in-one-wp-security-and-firewall');
+ return $response;
+ }
+
+ $response['message'] = __('Your IP address has been whitelisted successfully.', 'all-in-one-wp-security-and-firewall');
+ return $response;
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-families.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-families.php
new file mode 100755
index 00000000..4baa25b0
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-families.php
@@ -0,0 +1,13 @@
+ '6G', 'priority' => 10),
+ array('name' => 'Blacklist', 'priority' => 1),
+ array('name' => 'Bruteforce', 'priority' => 0),
+ array('name' => 'General', 'priority' => 20),
+ array('name' => 'Bots', 'priority' => 2),
+);
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-builder.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-builder.php
new file mode 100755
index 00000000..fce6d629
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-builder.php
@@ -0,0 +1,33 @@
+ $member2['priority']) ? 1 : -1;
+ });
+
+ $families = array();
+ foreach ($family_list as $member) {
+ $families[strtolower($member['name'])] = new Family($member['name'], $member['priority']);
+ }
+
+ return $families;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-collection.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-collection.php
new file mode 100755
index 00000000..5305d870
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family-collection.php
@@ -0,0 +1,49 @@
+families = $families;
+ }
+
+ /**
+ * Generator method to iterate over the families
+ *
+ * @return iterable
+ */
+ public function get_family() {
+ foreach ($this->families as $family) {
+ yield $family;
+ }
+ }
+
+ /**
+ * Adds a new rule to a family member
+ *
+ * @param Rule $rule - an active rule to add to its family
+ * @return void
+ */
+ public function add_rule_to_member(Rule $rule) {
+ $key = strtolower($rule->family);
+ if (array_key_exists($key, $this->families)) {
+ $this->families[$key]->add_rule($rule);
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family.php
new file mode 100755
index 00000000..d9631ec9
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/family/wp-security-firewall-family.php
@@ -0,0 +1,86 @@
+name = $name;
+ $this->priority = $priority;
+ $this->rules = array();
+ }
+
+ /**
+ * Adds a rule to the family
+ *
+ * @param Rule $rule
+ * @return void
+ */
+ public function add_rule(Rule $rule) {
+ $this->rules[] = $rule;
+ }
+
+ /**
+ * Applies all the rules in the family
+ *
+ * @return void
+ */
+ public function apply_all() {
+
+ if (empty($this->rules)) {
+ return;
+ }
+
+ //ensure the rules are ordered by priority
+ usort($this->rules, function(Rule $rule, Rule $rule2) {
+ if ($rule->priority == $rule2->priority) {
+ return 0;
+ }
+ return ($rule->priority > $rule2->priority) ? 1 : -1;
+ });
+
+ foreach ($this->rules as $rule) {
+ $rule->apply();
+ }
+
+ }
+
+ /**
+ * Returns the family name if used as a string
+ *
+ * @return string
+ */
+ public function __toString() {
+ return $this->name;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/traits/file-prefix-trait.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/traits/file-prefix-trait.php
new file mode 100755
index 00000000..b1ed55a1
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/traits/file-prefix-trait.php
@@ -0,0 +1,30 @@
+path = $path;
+ $this->init_file();
+ }
+
+ /**
+ * Initialise the file if it doesn't exist
+ *
+ * @return void
+ */
+ private function init_file() {
+ clearstatcache();
+ if (!file_exists($this->path)) {
+
+ $dir = dirname($this->path);
+ if (!file_exists($dir)) Utility::wp_mkdir_p($dir);
+
+ file_put_contents($this->path, self::get_file_content_prefix() . json_encode(array()));
+ }
+ }
+
+ /**
+ * Update the config file with the new prefix whenever the prefix changes.
+ *
+ * @return void
+ */
+ public function update_prefix() {
+
+ $valid_prefix = self::get_file_content_prefix();
+ $current_prefix = file_get_contents($this->path, false, null, 0, strlen($valid_prefix));
+
+ if ($current_prefix === $valid_prefix) return; // prefix is valid
+
+ $contents = file_get_contents($this->path);
+
+ $matches = array();
+ if (preg_match('/\{.*\}/', $contents, $matches)) {
+ //update settings
+ file_put_contents($this->path, $valid_prefix . $matches[0]);
+ } else {
+ //reset settings
+ file_put_contents($this->path, $valid_prefix . json_encode(array()));
+ }
+ }
+
+ /**
+ * Gets the value from the config array
+ *
+ * @param string $key
+ * @return mixed|null
+ */
+ public function get_value($key) {
+
+ $contents = $this->get_contents();
+
+ if (null === $contents) {
+ return null;
+ }
+
+ if (!isset($contents[$key])) {
+ return null;
+ }
+
+ return $contents[$key];
+
+ }
+
+ /**
+ * Sets a value in our config array
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return boolean
+ */
+ public function set_value($key, $value) {
+
+ $contents = $this->get_contents();
+
+ if (null === $contents) {
+ return false;
+ }
+
+ $contents[$key] = $value;
+
+ return (false !== file_put_contents($this->path, self::get_file_content_prefix() . json_encode($contents), LOCK_EX));
+ }
+
+ /**
+ * Loads the config array from file
+ *
+ * @return string
+ */
+ public function get_contents() {
+
+ clearstatcache();
+ if (!file_exists($this->path)) $this->init_file();
+
+ // __COMPILER_HALT_OFFSET__ doesn't define in a few PHP versions. It's a PHP bug.
+ // https://bugs.php.net/bug.php?id=70164
+ $contents = file_get_contents($this->path, false, null, strlen(self::get_file_content_prefix()));
+
+ if (false === $contents) {
+ return null;
+ }
+
+ if (empty($contents)) {
+ return array();
+ }
+
+ return json_decode($contents, true);
+ }
+
+ /**
+ * Sets entire firewall config from array.
+ *
+ * @param Array $contents
+ *
+ * @return Boolean
+ */
+ public function set_contents($contents) {
+
+ if (null === $contents) {
+ return false;
+ }
+
+ return (false !== file_put_contents($this->path, self::get_file_content_prefix() . json_encode($contents), LOCK_EX));
+ }
+
+ /**
+ * Returns the path
+ *
+ * @return string
+ */
+ public function __toString() {
+ return $this->path;
+ }
+
+}
+
+// phpcs:enable WordPress.WP.AlternativeFunctions -- WP isn't loaded here. WP API is unavailable
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-constants.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-constants.php
new file mode 100755
index 00000000..543780e7
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-constants.php
@@ -0,0 +1,213 @@
+constants = array();
+ $this->populate_constants();
+ }
+
+ /**
+ * Populates our internal constant array with the defines from wp-config
+ *
+ * @return void
+ */
+ protected function populate_constants() {
+
+ $wpconfig = Utility::get_wpconfig_path();
+
+ clearstatcache();
+ if (!file_exists($wpconfig)) return;
+
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- WP isn't loaded. WP_Filesystem cannot be used.
+ $source = file_get_contents($wpconfig);
+
+ if (false === $source) return;
+
+ $tokens = token_get_all($source);
+
+ //Filter out any unwanted tokens
+ $tokens = array_values(array_filter($tokens, function($token) {
+
+ //All tokens that are not arrays are allowed
+ if (!is_array($token)) return true;
+
+ $unwanted_tokens = array(
+ 'T_COMMENT',
+ 'T_WHITESPACE',
+ 'T_DOC_COMMENT',
+ );
+
+ return (!in_array(token_name($token[self::TOKEN]), $unwanted_tokens));
+ }));
+
+ $token_count = count($tokens);
+ for ($i = 0; $i < $token_count; $i++) {
+
+ $current = $tokens[$i];
+
+ if (!is_array($current)) continue;
+
+ if ('T_STRING' === token_name($current[self::TOKEN]) && 'define' === strtolower($current[self::CONTENT])) {
+
+ // Name of the define without the surrounding quotes
+ $name = substr($tokens[$i + self::DEFINE_NAME_OFFSET][self::CONTENT], 1, -1);
+
+ // Grabs the value of the define
+ $value = $tokens[$i + self::DEFINE_VALUE_OFFSET];
+
+ if (!is_array($value)) continue;
+
+ // We need to interpret the data type of the define's value
+ switch (token_name($value[self::TOKEN])) {
+ case 'T_CONSTANT_ENCAPSED_STRING':
+ $this->constants[$name] = substr($value[self::CONTENT], 1, -1);
+ break;
+ case 'T_LNUMBER':
+ $this->constants[$name] = intval($value[self::CONTENT]);
+ break;
+ case 'T_DNUMBER':
+ $this->constants[$name] = floatval($value[self::CONTENT]);
+ break;
+ case 'T_STRING':
+ $this->constants[$name] = filter_var($value[self::CONTENT], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ break;
+ default:
+ continue 2;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Access the constants as properties
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __get($name) {
+ return $this[$name];
+ }
+
+ /**
+ * Iterate over the constants
+ *
+ * @return iterable
+ */
+ #[\ReturnTypeWillChange]
+ public function getIterator() {
+ foreach ($this->constants as $name => $value) yield $name => $value;
+ foreach (get_defined_constants() as $name => $value) yield $name => $value;
+ }
+
+ /**
+ * Gives us array access to the constants
+ *
+ * @param mixed $offset
+ * @return mixed
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($offset) {
+ if (defined($offset)) {
+ return constant($offset);
+ } elseif (isset($this->constants[$offset])) {
+ return $this->constants[$offset];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the constant exists
+ *
+ * @param mixed $offset
+ * @return boolean
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetExists($offset) {
+ return defined($offset) || isset($this->constants[$offset]);
+ }
+
+ /**
+ * Check if constant exists
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function __isset($name) {
+ return $this->offsetExists($name);
+ }
+
+ /**
+ * Sets the constant. This is disabled as we want it read-only
+ *
+ * @param mixed $offset
+ * @param mixed $value
+ * @return void
+ * @throws \Exception - Throws an exception if called to ensure it's read-only.
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetSet($offset, $value) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
+ throw new \Exception('Constants are read-only.');
+ }
+
+ /**
+ * Unsets the constant. This is disabled as we want it read-only
+ *
+ * @param mixed $offset
+ * @return void
+ * @throws \Exception - Throws an exception if called to ensure it's read-only.
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetUnset($offset) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
+ throw new \Exception('Constants are read-only.');
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-debug.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-debug.php
new file mode 100755
index 00000000..44fc04d7
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-debug.php
@@ -0,0 +1,59 @@
+AIOS_FIREWALL_DEBUG && 'rule_triggered' !== $event) return;
+
+ $details = array(
+ 'name' => $rule->name,
+ 'family' => $rule->family,
+ 'ip' => \AIOS_Helper::get_user_ip_address(),
+ 'time' => time(),
+ );
+
+ // Get any user information
+ foreach ($_COOKIE as $key => $value) {
+ if (preg_match('/^wordpress_logged_in_/', $key)) {
+ $details['potential_user'] = stripslashes($value);
+ break;
+ }
+ }
+
+ $details['request'] = $_SERVER;
+ unset($details['request']['HTTP_COOKIE']);
+
+ // Uncomment when the firewall log issues have been resolved
+ //$aiowps_firewall_message_store->set($event, $details);
+
+ // Remove when the firewall log issues have been resolved
+ $aiowps_firewall_message_store->clear_message_store();
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-event.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-event.php
new file mode 100755
index 00000000..c308feb3
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-event.php
@@ -0,0 +1,51 @@
+messages = array();
+ $this->keys_loaded = array();
+ $this->table_name = 'aiowps_message_store';
+ }
+
+ /**
+ * Sets internal message store
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function set($key, $value) {
+
+ if (!is_string($key)) return;
+
+ if (!isset($this->messages[$key])) {
+ $this->messages[$key] = array();
+ }
+
+ $this->messages[$key][] = $value;
+ }
+
+ /**
+ * Gets the messages associated with a key
+ *
+ * @param string $key
+ * @return array
+ */
+ public function get($key) {
+
+ $is_key_loaded = in_array($key, $this->keys_loaded);
+ $can_check_database = isset($GLOBALS['wpdb']) && !$is_key_loaded && class_exists('Updraft_Semaphore_3_0');
+
+ //Load requested messages from the database
+ if ($can_check_database) {
+
+ $lock = new \Updraft_Semaphore_3_0('aios_message_store_lock_'.$key, 60);
+ $to_delete = array();
+
+ if ($lock->lock()) {
+
+ try {
+ global $wpdb;
+
+ $table = $this->get_table();
+
+ // If we can't get the table to check the DB, still check our internal store for the key
+ if (empty($table)) return isset($this->messages[$key]) ? $this->messages[$key] : array();
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $rows = $wpdb->get_results($wpdb->prepare("SELECT id, message_value FROM `{$table}` WHERE message_key = %s", $key));
+
+ if (!empty($rows)) {
+
+ foreach ($rows as $row) {
+ $values = json_decode($row->message_value, true);
+
+ foreach ($values as $value) $this->set($key, $value);
+
+ $to_delete[] = $row->id;
+ }
+
+ $this->keys_loaded[] = $key;
+ }
+ } catch (\Exception $e) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Necessary for AIOS error reporting system.
+ error_log("AIOS: Error getting database entries for key '{$key}': {$e->getMessage()}");
+
+ } catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Necessary for AIOS error reporting system.
+ error_log("AIOS: Error getting database entries for key '{$key}': {$e->getMessage()}");
+ } finally {
+
+ //Delete IDs of loaded messages
+ if (!empty($to_delete)) {
+ $ids = implode(',', $to_delete);
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $wpdb->query("DELETE FROM `{$table}` WHERE id IN ({$ids})");
+ }
+
+ $lock->release();
+ }
+
+ }
+ }
+
+ return isset($this->messages[$key]) ? $this->messages[$key] : array();
+ }
+
+ /**
+ * Dumps the message store to the database
+ *
+ * @return void
+ */
+ public function dump() {
+ //No point saving if there are no messages
+ if (empty($this->messages)) return;
+
+ if (!Utility::attempt_to_access_wpdb()) throw new Exit_Exception('Unable to save the message store to the database: wpdb is inaccessible.');
+
+ global $wpdb;
+
+ $table = $this->get_table();
+
+ if (empty($table)) throw new Exit_Exception('Unable to save messages store to the database: unable to get the correct table.');
+
+ $statement = "INSERT INTO `{$table}` (message_key, message_value, created) VALUES ";
+ $values = array();
+
+ foreach ($this->messages as $key => $value) {
+ $statement .= '(%s, %s, %s),';
+ $values[] = $table;
+ $values[] = $key;
+ $values[] = json_encode($value); // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- This method runs outside the WordPress environment and therefore cannot use WordPress functions.
+ $values[] = time();
+ }
+
+ $statement = rtrim($statement, ',');
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $wpdb->query($wpdb->prepare($statement, $values));
+ }
+
+ /**
+ * Returns the table name if it exists
+ *
+ * @return string - Table name on success; blank string otherwise
+ */
+ private function get_table() {
+ global $wpdb;
+
+ if (!$wpdb) return '';
+
+ $table = $wpdb->get_blog_prefix(0).$this->table_name;
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ if ($table != $wpdb->get_var("SHOW TABLES LIKE '{$table}'")) return '';
+
+ return $table;
+ }
+
+ /**
+ * Clears all the messages from the message store table if it contains data.
+ *
+ * @return void
+ */
+ public function clear_message_store() {
+ global $wpdb;
+
+ $table = $this->get_table();
+
+ // Check if the table exists and is accessible
+ if (empty($table)) {
+ return;
+ }
+
+ //Check if the table has any rows
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query necessary. No caching necessary.
+ $row_exists = $wpdb->get_var(
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP error. Ignore.
+ $wpdb->prepare("SELECT EXISTS (SELECT 1 FROM `{$table}` LIMIT 1)")
+ );
+
+ // If there are no rows, $row_exists will be 0
+ if (!$row_exists) {
+ return;
+ }
+
+ // Clear the table (delete all records)
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
+ $wpdb->query($wpdb->prepare("DELETE FROM `{$table}`"));
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-singleton-trait.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-singleton-trait.php
new file mode 100755
index 00000000..1cf77d83
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/libs/wp-security-firewall-singleton-trait.php
@@ -0,0 +1,36 @@
+do_action_forbid();
+ $this->do_action_exit();
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-forbid-trait.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-forbid-trait.php
new file mode 100755
index 00000000..f583a3c7
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-forbid-trait.php
@@ -0,0 +1,17 @@
+permblock_reason = $reason;
+ }
+
+ /**
+ * Sets the IP for the perm. block
+ *
+ * @param string $ip
+ * @return void
+ */
+ public function set_perm_block_ip($ip) {
+ $this->permblock_ip = $ip;
+ }
+
+ /**
+ * Permanently ban the IP and exit when the rule condition is satisfied.
+ *
+ * @return void
+ */
+ public function do_action() {
+
+ if (!Utility::attempt_to_access_wpdb()) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Part of AIOS error reporting system.
+ error_log('AIOS: Unable to access wpdb to ban IP address.');
+ $this->do_action_forbid_and_exit();
+ }
+
+ global $wpdb;
+
+ $table = $wpdb->prefix.'aiowps_permanent_block';
+
+ $ip = empty($this->permblock_ip) ? \AIOS_Helper::get_user_ip_address() : $this->permblock_ip;
+
+ $data = array(
+ 'blocked_ip' => $ip,
+ 'block_reason' => empty($this->permblock_reason) ? 'firewall_generic' : $this->permblock_reason,
+ 'blocked_date' => current_time('mysql')
+ );
+
+ // Check if the IP already exists
+ // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
+ $already_exists = $wpdb->get_var($wpdb->prepare("SELECT blocked_ip FROM `{$table}` WHERE blocked_ip = %s", $ip));
+
+ // If it does exist, no point adding it again so just forbid and exit
+ if (!is_null($already_exists)) $this->do_action_forbid_and_exit();
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
+ if (false === $wpdb->query($wpdb->prepare("INSERT INTO " .$table." (blocked_ip, block_reason, blocked_date, created) VALUES (%s, %s, %s, UNIX_TIMESTAMP())", $data['blocked_ip'], $data['block_reason'], $data['blocked_date']))) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Needed for error reporting.
+ error_log('AIOS: Unable to insert IP address into table.');
+ }
+
+ $this->do_action_forbid_and_exit();
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-and-exit-trait.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-and-exit-trait.php
new file mode 100755
index 00000000..a507e6d8
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-and-exit-trait.php
@@ -0,0 +1,23 @@
+do_action_redirect();
+ $this->do_action_exit();
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-trait.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-trait.php
new file mode 100755
index 00000000..9f3d286d
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/actions/action-redirect-trait.php
@@ -0,0 +1,24 @@
+location");
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-query-strings-6g.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-query-strings-6g.php
new file mode 100755
index 00000000..d83d9e03
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-query-strings-6g.php
@@ -0,0 +1,62 @@
+name = 'Block query strings';
+ $this->family = '6G';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
+
+ //Patterns to match against
+ $patterns = array(
+ '/[a-z0-9]{2000,}/i',
+ '/(eval\()/i',
+ '/(127\.0\.0\.1)/i',
+ '/(javascript:)(.*)(;)/i',
+ '/(base64_encode)(.*)(\()/i',
+ '/(GLOBALS|REQUEST)(=|\[|%)/i',
+ '/(<|%3C)(.*)script(.*)(>|%3)/i',
+ '#(\|\.\.\.|\.\./|~|`|<|>|\|)#i',
+ '#(boot\.ini|etc/passwd|self/environ)#i',
+ '/(thumbs?(_editor|open)?|tim(thumb)?)\.php/i',
+ '/(\'|\")(.*)(drop|insert|md5|select|union)/i',
+ );
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ return Rule_Utils::contains_pattern(rawurldecode($_SERVER['QUERY_STRING']), $patterns);
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-refs-6g.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-refs-6g.php
new file mode 100755
index 00000000..75ac3be4
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-refs-6g.php
@@ -0,0 +1,52 @@
+name = 'Block referrer strings';
+ $this->family = '6G';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['HTTP_REFERER'])) return Rule::NOT_SATISFIED;
+
+ //Patterns to match against
+ $patterns = array(
+ '/[a-z0-9]{2000,}/i',
+ '/(semalt.com|todaperfeita)/i',
+ );
+
+ return Rule_Utils::contains_pattern($_SERVER['HTTP_REFERER'], $patterns); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-request-strings-6g.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-request-strings-6g.php
new file mode 100755
index 00000000..83a7ecb2
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-request-strings-6g.php
@@ -0,0 +1,67 @@
+name = 'Block request strings';
+ $this->family = '6G';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
+
+ // ensure we get the request uri without the query string
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ $uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
+
+ if ('' == $uri) return Rule::NOT_SATISFIED;
+
+ //Patterns to match against
+ $patterns = array(
+ '/[a-z0-9]{2000,}/i',
+ '#(https?|ftp|php):/#i',
+ '#(base64_encode)(.*)(\()#i',
+ '#(=\'|=\%27|/\'/?)\.#i',
+ '#/(\$(\&)?|\*|\"|\.|,|&|&?)/?$#i',
+ '#(\{0\}|\(/\(|\.\.\.|\+\+\+|\\"\\")#i',
+ '#(~|`|<|>|:|;|,|%|\|\s|\{|\}|\[|\]|\|)#i',
+ '#/(=|\$&|_mm|cgi-|etc/passwd|muieblack)#i',
+ '#(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)#i',
+ '#\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$#i',
+ '#/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php#i',
+ );
+
+ return Rule_Utils::contains_pattern(rawurldecode($uri), $patterns);
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-user-agents-6g.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-user-agents-6g.php
new file mode 100755
index 00000000..ca11be23
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-block-user-agents-6g.php
@@ -0,0 +1,53 @@
+name = 'Block user-agents';
+ $this->family = '6G';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['HTTP_USER_AGENT'])) return Rule::NOT_SATISFIED;
+
+ //Patterns to match against
+ $patterns = array(
+ '/[a-z0-9]{2000,}/i',
+ '/(archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune)/i',
+ );
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ return Rule_Utils::contains_pattern($_SERVER['HTTP_USER_AGENT'], $patterns);
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-request-method-6g.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-request-method-6g.php
new file mode 100755
index 00000000..92552efb
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/6g/rule-request-method-6g.php
@@ -0,0 +1,53 @@
+name = 'Block request methods';
+ $this->family = '6G';
+ $this->priority = 0;
+
+ $this->blocked_methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ return !empty($this->blocked_methods);
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ return isset($_SERVER['REQUEST_METHOD']) && in_array(strtoupper($_SERVER['REQUEST_METHOD']), $this->blocked_methods);
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-ips-blacklist.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-ips-blacklist.php
new file mode 100755
index 00000000..f2c6d557
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-ips-blacklist.php
@@ -0,0 +1,65 @@
+name = 'Blocked IPs';
+ $this->family = 'Blacklist';
+ $this->priority = 0;
+ $this->blocked_ips = $aiowps_firewall_config->get_value('aiowps_blacklist_ips');
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @global Constants $aiowps_firewall_constants
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_constants;
+ if ($aiowps_firewall_constants->AIOS_DISABLE_BLACKLIST_IP_MANAGER) {
+ return false;
+ } else {
+ return !empty($this->blocked_ips);
+ }
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ $user_ip_blocked = \AIOS_Helper::is_user_ip_address_within_list($this->blocked_ips);
+
+ if (true == $user_ip_blocked) return Rule::SATISFIED;
+
+ return Rule::NOT_SATISFIED;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-user-agent-blacklist.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-user-agent-blacklist.php
new file mode 100755
index 00000000..b9c44d80
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/blacklist/rule-user-agent-blacklist.php
@@ -0,0 +1,57 @@
+name = 'Blocked user agents';
+ $this->family = 'Blacklist';
+ $this->priority = 0;
+ $this->blocked_user_agents = $aiowps_firewall_config->get_value('aiowps_blacklist_user_agents');
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ return !empty($this->blocked_user_agents) && isset($_SERVER['HTTP_USER_AGENT']);
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ foreach ($this->blocked_user_agents as $block_user_agent) {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ if (isset($_SERVER['HTTP_USER_AGENT']) && !empty($block_user_agent) && false !== stripos($_SERVER['HTTP_USER_AGENT'], $block_user_agent)) {
+ return Rule::SATISFIED;
+ }
+ }
+ return Rule::NOT_SATISFIED;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-ban-post-blank-headers.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-ban-post-blank-headers.php
new file mode 100755
index 00000000..5f046c9a
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-ban-post-blank-headers.php
@@ -0,0 +1,44 @@
+name = 'Ban POST requests with blank user-agent and referer';
+ $this->family = 'Bots';
+ $this->priority = 10;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_ban_post_blank_headers');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ $this->set_perm_block_reason('firewall_post_blank_user_agent_and_referer');
+ return isset($_SERVER['REQUEST_METHOD']) && (0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST")) && empty($_SERVER['HTTP_USER_AGENT']) && empty($_SERVER['HTTP_REFERER']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-block-fake-googlebots.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-block-fake-googlebots.php
new file mode 100755
index 00000000..a75a252c
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bots/rule-block-fake-googlebots.php
@@ -0,0 +1,101 @@
+name = 'Block fake Googlebots';
+ $this->family = 'Bots';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active.
+ *
+ * @global Config $aiowps_firewall_config
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_block_fake_googlebots');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply.
+ *
+ * @global Config $aiowps_firewall_config
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ global $aiowps_firewall_config;
+
+ $user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
+
+ if (preg_match('/Googlebot/i', $user_agent, $matches)) {
+ // If the user agent says it's a Googlebot, start doing checks.
+
+ $ip = \AIOS_Helper::get_user_ip_address();
+
+ if (empty($ip)) {
+ return Rule::NOT_SATISFIED;
+ }
+
+ try {
+ $name = gethostbyaddr($ip); // Let's get the hostname using the IP address.
+
+ if ($name == $ip || false === $name) {
+ // gethostbyaddr failed.
+ $googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
+ if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
+ return Rule::NOT_SATISFIED;
+ } else {
+ return Rule::SATISFIED;
+ }
+ }
+
+ $host_ip = gethostbyname($name); // Reverse lookup - let's get the IP address using the hostname.
+ } catch (\Exception $e) {
+ // gethostbyaddr or gethostbyname not available on site.
+ $googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
+ if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
+ return Rule::NOT_SATISFIED;
+ } else {
+ return Rule::SATISFIED;
+ }
+ } catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
+ // gethostbyaddr or gethostbyname not available on site.
+ $googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
+ if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
+ return Rule::NOT_SATISFIED;
+ } else {
+ return Rule::SATISFIED;
+ }
+ }
+
+ if (preg_match('/^(?:.+\.)?googlebot\.com$/i', $name) || preg_match('/^(?:.+\.)?google\.com$/i', $name) || preg_match('/^(?:.+\.)?googleusercontent\.com$/i', $name)) {
+ if ($host_ip == $ip) {
+ return Rule::NOT_SATISFIED;
+ } else {
+ return Rule::SATISFIED;
+ }
+ } else {
+ return Rule::SATISFIED;
+ }
+ }
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bruteforce/rule-cookie-prevent-bruteforce.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bruteforce/rule-cookie-prevent-bruteforce.php
new file mode 100755
index 00000000..13ea0c4c
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/bruteforce/rule-cookie-prevent-bruteforce.php
@@ -0,0 +1,98 @@
+name = 'Cookie based prevent bruteforce';
+ $this->family = 'Bruteforce';
+ $this->priority = 0;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config, $aiowps_firewall_constants;
+ if ($aiowps_firewall_constants->AIOS_DISABLE_COOKIE_BRUTE_FORCE_PREVENTION) {
+ return false;
+ } else {
+ return (bool) $aiowps_firewall_config->get_value('aios_enable_brute_force_attack_prevention');
+ }
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ global $aiowps_firewall_config;
+ /**
+ * This rule is not applied at AIOS plugin activation time.
+ */
+ $is_plugins_page = isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('#/wp-admin/(network/)?plugins\.php$#i', $_SERVER['SCRIPT_FILENAME']);
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
+ $is_activation_action = isset($_GET['action']) && 'activate' === $_GET['action'];
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
+ $is_target_plugin = isset($_GET['plugin']) && 'all-in-one-wp-security-and-firewall/wp-security.php' === $_GET['plugin'];
+
+
+ if ($is_plugins_page && $is_activation_action && $is_target_plugin) {
+ return Rule::NOT_SATISFIED;
+ }
+
+ $brute_force_secret_word = $aiowps_firewall_config->get_value('aios_brute_force_secret_word');
+ $brute_force_secret_cookie_name = $aiowps_firewall_config->get_value('aios_brute_force_secret_cookie_name');
+ $login_page_slug = $aiowps_firewall_config->get_value('aios_login_page_slug');
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
+ if (!isset($_GET[$brute_force_secret_word])) {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
+ $brute_force_secret_cookie_val = isset($_COOKIE[$brute_force_secret_cookie_name]) ? $_COOKIE[$brute_force_secret_cookie_name] : '';
+ $pw_protected_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_pw_protected_exception');
+ $prevent_ajax_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_ajax_exception');
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
+ if (!empty($_SERVER['REQUEST_URI']) && !hash_equals($brute_force_secret_cookie_val, \AIOS_Helper::get_hash($brute_force_secret_word))) {
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
+ $request_uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
+
+ // admin section or login page or login custom slug called
+ $is_admin_or_login = (false != strpos($request_uri, 'wp-admin') || false != strpos($request_uri, 'wp-login') || ('' != $login_page_slug && false != strpos($request_uri, $login_page_slug))) ? 1 : 0;
+
+ // admin side ajax called
+ $is_admin_ajax_request = ('1' == $prevent_ajax_exception && isset($_SERVER['SCRIPT_NAME']) && ('admin-ajax.php' === basename($_SERVER['SCRIPT_NAME']))) ? 1 : 0;
+
+ // password protected page called
+ $is_password_protected_access = ('1' == $pw_protected_exception && isset($_GET['action']) && 'postpass' == $_GET['action']) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
+
+ // logout, set password, reset password action called
+ $is_logout_resetpassword_action = (isset($_GET['action']) && ('logout' == $_GET['action'] || 'rp' == $_GET['action'] || 'resetpass' == $_GET['action'])) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
+
+ // cookie based brute force on and accessing admin without ajax and password protected then redirect
+ if ($is_admin_or_login && !$is_admin_ajax_request && !$is_password_protected_access && !$is_logout_resetpassword_action) {
+ $redirect_url = $aiowps_firewall_config->get_value('aios_cookie_based_brute_force_redirect_url');
+ $this->location = $redirect_url;
+ return Rule::SATISFIED;
+ }
+ }
+ }
+ return Rule::NOT_SATISFIED;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-advanced-character-filter.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-advanced-character-filter.php
new file mode 100755
index 00000000..61e6f022
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-advanced-character-filter.php
@@ -0,0 +1,156 @@
+name = 'Advanced character filter';
+ $this->family = 'General';
+ $this->priority = 10;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_advanced_char_string_filter');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
+
+ // ensure we get the request uri without the query string
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ $uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
+
+ return Rule_Utils::contains_pattern($uri, array_merge($this->get_general_characters(), $this->get_common_patterns(), $this->get_specific_exploits()));
+ }
+
+ /**
+ * Get the list of 'specific exploits' patterns
+ *
+ * @return array
+ */
+ private function get_specific_exploits() {
+ return array(
+ '/errors\./i',
+ '/config\./i',
+ '/include\./i',
+ '/display\./i',
+ '/register\./i',
+ '/password\./i',
+ '/maincore\./i',
+ '/authorize\./i',
+ '/macromates\./i',
+ '/head\_auth\./i',
+ '/submit\_links\./i',
+ '/change\_action\./i',
+ '/com\_facileforms\//i',
+ '/admin\_db\_utilities\./i',
+ '/admin\.webring\.docs\./i',
+ '/Table\/Latest\/index\./i',
+ );
+ }
+
+ /**
+ * Get the list of common patterns
+ *
+ * @return array
+ */
+ private function get_common_patterns() {
+ return array(
+ '/\_vpi/i',
+ '/\.inc/i',
+ '/xAou6/i',
+ '/db\_name/i',
+ '/select\(/i',
+ '/convert\(/i',
+ '/\/query\//i',
+ '/ImpEvData/i',
+ '/\.XMLHTTP/i',
+ '/proxydeny/i',
+ '/function\./i',
+ '/remoteFile/i',
+ '/servername/i',
+ '/\&rptmode\=/i',
+ '/sys\_cpanel/i',
+ '/db\_connect/i',
+ '/doeditconfig/i',
+ '/check\_proxy/i',
+ '/system\_user/i',
+ '/\/\(null\)\//i',
+ '/clientrequest/i',
+ '/option\_value/i',
+ '/ref\.outcontrol/i',
+ );
+ }
+
+ /**
+ * Get the list of general characters
+ *
+ * @return array
+ */
+ private function get_general_characters() {
+ return array(
+ '/\,/i',
+ '/\:/i',
+ '/\;/i',
+ '/\=/i',
+ '/\[/i',
+ '/\]/i',
+ '/\^/i',
+ '/\`/i',
+ '/\{/i',
+ '/\}/i',
+ '/\~/i',
+ '/\"/i',
+ '/\$/i',
+ '/\/i',
+ '/\|/i',
+ '/\.\./i',
+ '/\%0/i',
+ '/\%A/i',
+ '/\%B/i',
+ '/\%C/i',
+ '/\%D/i',
+ '/\%E/i',
+ '/\%F/i',
+ '/\%22/i',
+ '/\%27/i',
+ '/\%28/i',
+ '/\%29/i',
+ '/\%3C/i',
+ '/\%3E/i',
+ '/\%3F/i',
+ '/\%5B/i',
+ '/\%5C/i',
+ '/\%5D/i',
+ '/\%7B/i',
+ '/\%7C/i',
+ '/\%7D/i',
+ );
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-bad-query-strings.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-bad-query-strings.php
new file mode 100755
index 00000000..558102e4
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-bad-query-strings.php
@@ -0,0 +1,56 @@
+name = 'Bad query strings';
+ $this->family = 'General';
+ $this->priority = 10;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_deny_bad_query_strings');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
+
+ $patterns = array(
+ '/ftp:/i',
+ '/http:/i',
+ '/https:/i',
+ '/mosConfig/i',
+ '/^.*(globals|encode|loopback).*/i',
+ "/(\;|'|\"|%22).*(request|insert|union|declare|drop)/i",
+ );
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ return Rule_Utils::contains_pattern($_SERVER['QUERY_STRING'], $patterns);
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-block-xmlrpc.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-block-xmlrpc.php
new file mode 100755
index 00000000..3dfa24d2
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-block-xmlrpc.php
@@ -0,0 +1,44 @@
+name = 'Completely block XMLRPC';
+ $this->family = 'General';
+ $this->priority = 10;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_enable_pingback_firewall');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ return (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/xmlrpc\.php$/i', $_SERVER['SCRIPT_FILENAME']));
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-proxy-comment-posting.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-proxy-comment-posting.php
new file mode 100755
index 00000000..aa61bd31
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/rules/general/rule-proxy-comment-posting.php
@@ -0,0 +1,69 @@
+name = 'Proxy comment posting';
+ $this->family = 'General';
+ $this->priority = 10;
+ }
+
+ /**
+ * Determines whether the rule is active
+ *
+ * @return boolean
+ */
+ public function is_active() {
+ global $aiowps_firewall_config;
+ return (bool) $aiowps_firewall_config->get_value('aiowps_forbid_proxy_comments');
+ }
+
+ /**
+ * The condition to be satisfied for the rule to apply
+ *
+ * @return boolean
+ */
+ public function is_satisfied() {
+
+ //Preconditions for the rule
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ $is_comment_form = (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/wp-comments-post\.php$/i', $_SERVER['SCRIPT_FILENAME']));
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
+ $is_post = (isset($_SERVER['REQUEST_METHOD']) && 0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST"));
+
+ if (!$is_post || !$is_comment_form) return Rule::NOT_SATISFIED;
+
+ //Headers that are present if a proxy is being used
+ $headers = array(
+ 'HTTP_VIA',
+ 'HTTP_FORWARDED',
+ 'HTTP_USERAGENT_VIA',
+ 'HTTP_X_FORWARDED_FOR',
+ 'HTTP_X_FORWARDED_HOST',
+ 'HTTP_PROXY_CONNECTION',
+ 'HTTP_XPROXY_CONNECTION',
+ 'HTTP_PC_REMOTE_ADDR',
+ 'HTTP_CLIENT_IP',
+ );
+
+ foreach ($headers as $header) {
+ if (!empty($_SERVER[$header])) return Rule::SATISFIED;
+ }
+
+ return Rule::NOT_SATISFIED;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-builder.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-builder.php
new file mode 100755
index 00000000..f9791d31
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-builder.php
@@ -0,0 +1,46 @@
+is_active()) {
+ Event::raise('rule_not_active', $rule, $classname);
+ continue;
+ }
+
+ Event::raise('rule_active', $rule, $classname);
+ yield $rule;
+ }
+ }
+
+ /**
+ * Generates the classname for each rule
+ *
+ * @return iterable
+ */
+ private static function get_rule_classname() {
+ $rec_iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(AIOWPS_FIREWALL_DIR.'/rule/rules/', \FilesystemIterator::SKIP_DOTS));
+
+ foreach ($rec_iterator as $dir_iterator) {
+ $matches = array();
+ if (preg_match('/^rule-(?.*)\.php$/', $dir_iterator->getFilename(), $matches)) {
+ yield "AIOWPS\Firewall\Rule_".ucwords(str_replace('-', '_', $matches['rule_name']), '_');
+ }
+ }
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-utils.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-utils.php
new file mode 100755
index 00000000..9eb3df9b
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/rule/wp-security-firewall-rule-utils.php
@@ -0,0 +1,31 @@
+is_satisfied()) {
+
+ Event::raise('rule_triggered', $this, time());
+ $this->do_action();
+
+ }
+
+ Event::raise('rule_not_triggered', $this, time());
+ }
+
+ /**
+ * Show the rule's name
+ *
+ * @return string
+ */
+ public function __toString() {
+ return $this->name;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-context.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-context.php
new file mode 100755
index 00000000..3869aa7f
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-context.php
@@ -0,0 +1,104 @@
+ $file) {
+ if (preg_match('/aios-bootstrap\.php$/', $file)) {
+ return $index;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-loader.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-loader.php
new file mode 100755
index 00000000..2fcfe272
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-loader.php
@@ -0,0 +1,214 @@
+is_preloader_directly_accessed()) return;
+
+ $this->init();
+
+ global $aiowps_firewall_constants;
+ if ($aiowps_firewall_constants->AIOS_NO_FIREWALL) return;
+
+ //Allow list for bypassing PHP rules
+ if (Allow_List::is_ip_allowed()) return;
+
+ $families = new Family_Collection(Family_Builder::get_families());
+
+ foreach (Rule_Builder::get_active_rule() as $rule) {
+ $families->add_rule_to_member($rule);
+ }
+
+ foreach ($families->get_family() as $member) {
+ $member->apply_all();
+ }
+
+ } catch (Exit_Exception $e) {
+ $this->log_message($e->getMessage());
+ exit();
+ } catch (\Exception $e) {
+ $this->log_message($e->getMessage());
+ } catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
+ $this->log_message($e->getMessage());
+ }
+ }
+
+ /**
+ * Performs general initialisation
+ *
+ * @return void
+ */
+ public function init() {
+
+ $this->init_includes();
+ $this->init_services();
+
+ new Debug();
+ }
+
+ /**
+ * Detects whether the preloader file (wp-security-firewall.php) was directly accessed
+ *
+ * @return boolean
+ */
+ public function is_preloader_directly_accessed() {
+ return (1 === preg_match('/wp-security-firewall\.php$/', get_included_files()[0]));
+ }
+
+ /**
+ * Log our error messages
+ *
+ * @param string $message
+ * @return void
+ */
+ private function log_message($message) {
+ if (function_exists('do_action')) {
+ do_action('aios_firewall_loader_log_error', $message, $this);
+ }
+
+ error_log('AIOS firewall error: ' . $message);
+ }
+
+ /**
+ * Initialises our services
+ *
+ * @return void
+ */
+ private function init_services() {
+
+ $workspace = $this->get_firewall_workspace();
+
+ if (empty($workspace)) {
+ throw new \Exception('unable to locate workspace.');
+ }
+
+ $GLOBALS['aiowps_firewall_config'] = new Config($workspace . 'settings.php');
+ $GLOBALS['aiowps_firewall_message_store'] = Message_Store::instance();
+ $GLOBALS['aiowps_firewall_constants'] = new Constants();
+ Allow_List::set_path($workspace.'allowlist.php');
+ }
+
+ /**
+ * Get our workspace directory, i.e., where we save and load data to and from.
+ *
+ * @return string
+ */
+ private function get_firewall_workspace() {
+ global $aiowps_firewall_rules_path;
+
+ $workspace = '';
+
+ if (!empty($aiowps_firewall_rules_path)) {
+ $workspace = $aiowps_firewall_rules_path;
+ } elseif (Context::wordpress_safe()) {
+ $workspace = \AIOWPSecurity_Utility_Firewall::get_firewall_rules_path();
+ }
+
+ return $workspace;
+ }
+
+ /**
+ * Registers the autoloader
+ *
+ * @return void
+ */
+ private function init_includes() {
+
+ spl_autoload_register(function($class) {
+ if (0 === strpos($class, "AIOWPS\\Firewall\\")) { //only autoload the firewall's files
+
+ $relative_classname = substr($class, strlen("AIOWPS\\Firewall\\"), strlen($class)-1);
+
+ $classname = str_replace('_', '-', strtolower($relative_classname));
+
+ $file = "wp-security-firewall-{$classname}.php";
+ $rule = "{$classname}.php";
+
+ $paths = array(
+ AIOWPS_FIREWALL_DIR."/{$file}",
+ AIOWPS_FIREWALL_DIR."/family/{$file}",
+ AIOWPS_FIREWALL_DIR."/rule/{$file}",
+ AIOWPS_FIREWALL_DIR."/rule/actions/{$classname}.php",
+ AIOWPS_FIREWALL_DIR."/rule/rules/{$rule}",
+ AIOWPS_FIREWALL_DIR."/rule/rules/6g/{$rule}",
+ AIOWPS_FIREWALL_DIR."/rule/rules/bruteforce/{$rule}",
+ AIOWPS_FIREWALL_DIR."/rule/rules/blacklist/{$rule}",
+ AIOWPS_FIREWALL_DIR."/rule/rules/general/{$rule}",
+ AIOWPS_FIREWALL_DIR."/rule/rules/bots/{$rule}",
+ AIOWPS_FIREWALL_DIR."/libs/{$file}",
+ AIOWPS_FIREWALL_DIR."/libs/traits/{$classname}.php",
+ );
+
+ clearstatcache();
+ foreach ($paths as $path) {
+ if (file_exists($path)) {
+ include_once($path);
+ break;
+ }
+ }
+ }
+ });
+
+ // Manually include needed files
+ $classes_dir = dirname(AIOWPS_FIREWALL_DIR);
+
+ $manual_files = array(
+ $classes_dir.'/wp-security-firewall-resource-unavailable.php',
+ $classes_dir.'/wp-security-firewall-resource.php',
+ $classes_dir.'/wp-security-helper.php',
+ );
+
+ foreach ($manual_files as $file) {
+ clearstatcache();
+ if (file_exists($file)) include_once $file;
+ }
+
+ if (Context::wordpress_safe()) {
+ include_once("{$classes_dir}/wp-security-utility-file.php");
+ }
+ }
+
+ /**
+ * Gets or creates an instance of this object
+ *
+ * @return Loader
+ */
+ public static function get_instance() {
+
+ if (null === self::$instance) {
+ return new self();
+ }
+
+ return self::$instance;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-utility.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-utility.php
new file mode 100755
index 00000000..eb1a2bba
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/firewall/wp-security-firewall-utility.php
@@ -0,0 +1,218 @@
+load_firewall();
+ define('AIOWPSEC_FIREWALL_DONE', true);
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/grade-system/wp-security-feature-item-manager.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/grade-system/wp-security-feature-item-manager.php
new file mode 100755
index 00000000..ac51ee19
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/grade-system/wp-security-feature-item-manager.php
@@ -0,0 +1,800 @@
+setup_feature_list();
+ $this->initialize_features();
+ }
+
+ /**
+ * This function sets up the feature list
+ *
+ * @return void
+ */
+ private function setup_feature_list() {
+ $feature_list = array(
+ // Settings menu features
+ 'wp-generator-meta-tag' => array(
+ 'name' => __('Remove WP generator meta tag', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_remove_wp_generator_meta_info'
+ )
+ ),
+ // User Accounts menu features
+ 'user-accounts-change-admin-user' => array(
+ 'name' => __('Change admin username', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ ''
+ ),
+ 'callback' => array($this, 'check_user_accounts_change_admin_user_feature')
+ ),
+ 'user-accounts-display-name' => array(
+ 'name' => __('Change display name', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ ''
+ ),
+ 'callback' => array($this, 'check_user_accounts_display_name_feature')
+ ),
+ // User Login menu features
+ 'user-login-login-lockdown' => array(
+ 'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_login_lockdown'
+ )
+ ),
+ 'user-login-force-logout' => array(
+ 'name' => __('Force logout', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_forced_logout'
+ )
+ ),
+ 'hibp' => array(
+ 'name' => __('HIBP', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_hibp_user_profile_update',
+ 'aiowps_http_password_reset',
+ )
+ ),
+ 'disable-application-password' => array(
+ 'name' => __('Disable application password', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_disable_application_password'
+ )
+ ),
+ 'user-login-lockout-ip-whitelisting' => array(
+ 'name' => __('Login Lockout IP whitelisting', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_lockdown_enable_whitelisting'
+ )
+ ),
+ // User Registration menu features
+ 'manually-approve-registrations' => array(
+ 'name' => __('Registration approval', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_manual_registration_approval'
+ )
+ ),
+ 'user-registration-captcha' => array(
+ 'name' => __('Registration CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_registration_page_captcha'
+ )
+ ),
+ 'registration-honeypot' => array(
+ 'name' => __('Enable registration honeypot', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_registration_honeypot'
+ )
+ ),
+ 'http-authentication-admin-frontend' => array(
+ 'name' => __('HTTP authentication for admin and frontend', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_http_authentication_admin',
+ 'aiowps_http_authentication_frontend',
+ )
+ ),
+ // Database Security menu features
+ 'db-security-db-prefix' => array(
+ 'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ ''
+ ),
+ 'callback' => array($this, 'check_db_security_db_prefix_feature')
+ ),
+ // Filesystem Security menu features
+ 'filesystem-file-permissions' => array(
+ 'name' => __('File permissions', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ ''
+ ),
+ 'callback' => array($this, 'check_filesystem_permissions_feature')
+ ),
+ 'filesystem-file-editing' => array(
+ 'name' => __('File editing', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_disable_file_editing'
+ )
+ ),
+ 'auto-delete-wp-files' => array(
+ 'name' => __('WordPress files access', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_auto_delete_default_wp_files'
+ )
+ ),
+ // Blacklist Manager menu features
+ 'blacklist-manager-ip-user-agent-blacklisting' => array(
+ 'name' => __('IP and user agent blacklisting', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_enable_blacklisting'
+ )
+ ),
+ // Firewall menu features
+ 'firewall-basic-rules' => array(
+ 'name' => __('Enable basic firewall', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_basic_firewall'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
+ ),
+ 'firewall-pingback-rules' => array(
+ 'name' => __('Enable pingback vulnerability protection', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_pingback_firewall'
+ )
+ ),
+ 'firewall-block-debug-file-access' => array(
+ 'name' => __('Block access to debug log file', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_block_debug_log_file_access'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
+ ),
+ 'firewall-disable-index-views' => array(
+ 'name' => __('Disable index views', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_disable_index_views'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
+ ),
+ 'firewall-disable-trace-track' => array(
+ 'name' => __('Disable trace and track', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_disable_trace_and_track'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
+ ),
+ 'firewall-forbid-proxy-comments' => array(
+ 'name' => __('Forbid proxy comments', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_forbid_proxy_comments'
+ )
+ ),
+ 'firewall-deny-bad-queries' => array(
+ 'name' => __('Deny bad queries', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_deny_bad_query_strings'
+ )
+ ),
+ 'firewall-advanced-character-string-filter' => array(
+ 'name' => __('Advanced character string filter', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_advanced_char_string_filter'
+ )
+ ),
+ 'firewall-enable-6g' => array(
+ 'name' => __('6G firewall', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_enable_6g_firewall',
+ )
+ ),
+ 'firewall-block-fake-googlebots' => array(
+ 'name' => __('Block fake Googlebots', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_block_fake_googlebots'
+ )
+ ),
+ 'prevent-hotlinking' => array(
+ 'name' => __('Prevent image hotlinking', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_prevent_hotlinking'
+ )
+ ),
+ 'firewall-enable-404-blocking' => array(
+ 'name' => __('Enable IP blocking for 404 detection', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_404_IP_lockout'
+ )
+ ),
+ 'firewall-disable-rss-and-atom' => array(
+ 'name' => __('Disable RSS and ATOM feeds', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_disable_rss_and_atom_feeds'
+ )
+ ),
+ 'upgrade-unsafe-http-calls' => array(
+ 'name' => __('Upgrade unsafe HTTP calls', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_upgrade_unsafe_http_calls'
+ )
+ ),
+ // Brute Force menu features
+ 'bf-rename-login-page' => array(
+ 'name' => __('Enable rename login page', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_rename_login_page'
+ )
+ ),
+ 'firewall-enable-brute-force-attack-prevention' => array(
+ 'name' => __('Enable brute force attack prevention', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_enable_brute_force_attack_prevention'
+ )
+ ),
+ 'user-login-captcha' => array(
+ 'name' => __('Login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_login_captcha'
+ )
+ ),
+ 'lost-password-captcha' => array(
+ 'name' => __('Lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_lost_password_captcha'
+ )
+ ),
+ 'custom-login-captcha' => array(
+ 'name' => __('Custom login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_custom_login_captcha'
+ )
+ ),
+ 'password_protected-captcha' => array(
+ 'name' => __('Password-protected CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_password_protected_captcha'
+ )
+ ),
+ 'whitelist-manager-ip-login-whitelisting' => array(
+ 'name' => __('Login IP whitelisting', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_whitelisting'
+ )
+ ),
+ 'login-honeypot' => array(
+ 'name' => __('Enable login honeypot', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_login_honeypot'
+ )
+ ),
+ // Spam Prevention menu features
+ 'comment-form-captcha' => array(
+ 'name' => __('Comment CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_comment_captcha'
+ )
+ ),
+ 'detect-spambots' => array(
+ 'name' => __('Detect spambots', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_spambot_detecting'
+ )
+ ),
+ 'auto-block-spam-ips' => array(
+ 'name' => __('Auto block spam ips', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_autoblock_spam_ip'
+ )
+ ),
+ // Scanner menu features
+ 'scan-file-change-detection' => array(
+ 'name' => __('File change detection', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_4,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_enable_automated_fcd_scan'
+ )
+ ),
+ // Miscellaneous menu features
+ 'enable-copy-protection' => array(
+ 'name' => __('Enable Copy Protection', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_copy_protection'
+ )
+ ),
+ 'enable-frame-protection' => array(
+ 'name' => __('Enable iFrame protection', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_prevent_site_display_inside_frame'
+ )
+ ),
+ 'disable-users-enumeration' => array(
+ 'name' => __('Disable users enumeration', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_prevent_users_enumeration'
+ )
+ ),
+ 'disallow-unauthorised-requests' => array(
+ 'name' => __('Disallow unauthorized REST requests', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_disallow_unauthorized_rest_requests'
+ )
+ ),
+ 'enable-salt-postfix' => array(
+ 'name' => __('Enable salt postfix', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_3,
+ 'level' => $this->sec_level_advanced,
+ 'options' => array(
+ 'aiowps_enable_salt_postfix'
+ )
+ ),
+ // conditional features
+ 'bp-register-captcha' => array(
+ 'name' => __('BuddyPress registration CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_bp_register_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_buddypress_plugin_active'),
+ ),
+ 'bbp-new-topic-captcha' => array(
+ 'name' => __('bbPress new topic CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_bbp_new_topic_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_bbpress_plugin_active'),
+ ),
+ 'woo-login-captcha' => array(
+ 'name' => __('Woo login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_woo_login_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
+ ),
+ 'woo-lostpassword-captcha' => array(
+ 'name' => __('Woo lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_woo_lostpassword_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
+ ),
+ 'woo-register-captcha' => array(
+ 'name' => __('Woo register CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_woo_register_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
+ ),
+ 'woo-checkout-captcha' => array(
+ 'name' => __('Woo Checkout CAPTCHA', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_woo_checkout_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
+ ),
+ // Ban POST requests with blank user-agent and referer
+ 'firewall-ban-post-blank-headers' => array(
+ 'name' => __('Ban POST requests that have blank user-agent and referer headers', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_2,
+ 'level' => $this->sec_level_inter,
+ 'options' => array(
+ 'aiowps_ban_post_blank_headers'
+ )
+ ),
+ 'contact-form-7-captcha' => array(
+ /* translators: %s: Plugin name */
+ 'name' => sprintf(__('%s CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'Contact Form 7'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enable_contact_form_7_captcha'
+ ),
+ 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_contact_form_7_plugin_active'),
+ ),
+ 'enforce-strong-password' => array(
+ 'name' => __('Enforce use of strong passwords by users', 'all-in-one-wp-security-and-firewall'),
+ 'points' => $this->feature_point_1,
+ 'level' => $this->sec_level_basic,
+ 'options' => array(
+ 'aiowps_enforce_strong_password'
+ ),
+ )
+ );
+
+ $feature_list = apply_filters('aiowpsecurity_feature_list', $feature_list);
+ $this->feature_list = array_filter($feature_list, array($this, 'should_add_item'));
+ }
+
+ /**
+ * This function will create a feature item object for each feature in the feature list
+ *
+ * @return void
+ */
+ private function initialize_features() {
+ foreach ($this->feature_list as $id => $data) {
+ $callback = isset($data['callback']) ? $data['callback'] : array($this, 'is_feature_enabled');
+ $this->feature_items[$id] = new AIOWPSecurity_Feature_Item($id, $data['name'], $data['points'], $data['level'], $data['options'], $callback);
+ }
+ }
+
+ /**
+ * This function will return the feature item for the passed in ID
+ *
+ * @param string $feature_id - the id of the feature item we want to return
+ *
+ * @return boolean|AIOWPSecurity_Feature_Item - returns a feature item or false on coding error
+ */
+ public function get_feature_item_by_id($feature_id) {
+ if (isset($this->feature_items[$feature_id])) return $this->feature_items[$feature_id];
+ error_log("AIOS Feature Manager - Feature ID not found (coding error): $feature_id");
+ return false;
+ }
+
+ /**
+ * Call the callback function associated with the feature item.
+ *
+ * @param mixed $feature_item The feature item object.
+ */
+ private function call_feature_callback($feature_item) {
+ call_user_func($feature_item->callback, $feature_item);
+ }
+
+ /**
+ * This function will output the feature details badge HTML
+ *
+ * @param string $feature_id - the id of the feature we want to get the badge for
+ * @param bool $return_instead_of_echo - whether to return the HTML or echo it
+ *
+ * @return string|void
+ */
+ public function output_feature_details_badge($feature_id, $return_instead_of_echo = false) {
+ // Retrieve the feature item by ID
+ $feature_item = $this->get_feature_item_by_id($feature_id);
+
+ if (!$feature_item) return;
+
+ $this->call_feature_callback($feature_item);
+
+ // Prepare HTML for the feature badge
+ $max_security_points = $feature_item->item_points;
+ $current_security_points = $feature_item->is_active() ? $max_security_points : 0;
+ $security_level = $feature_item->get_security_level_string();
+ $protection_level = (0 == $current_security_points) ? 'none' : 'full';
+ $status_icon = (0 == $current_security_points) ? 'dashicons-unlock' : 'dashicons-lock';
+
+ $badge_html = '
';
+
+ $cust_html_code .= $cap_form;
+ return $cust_html_code;
+ break;
+ default:
+ return '';
+ break;
+ }
+ }
+
+ /**
+ * Inserts captcha into the password-protected page form.
+ *
+ * @param string $cust_html_code The HTML code for the password form.
+ * @return string The modified HTML code with the captcha inserted.
+ */
+ public function insert_captcha_password_protected($cust_html_code) {
+ global $post, $aio_wp_security;
+
+ $loginurl = esc_url(site_url('/wp-login.php?action=postpass'));
+
+ $label = 'pwbox-' . empty($post->ID) ? rand() : $post->ID;
+ $default_captcha = $aio_wp_security->configs->get_value('aiowps_default_captcha');
+
+ $cust_html_code = '
+
+
';
+ return $cust_html_code;
+ }
+
+ /**
+ * Validates the password form on password protected pages with captcha.
+ *
+ * @return void
+ */
+ public function validate_password_protected_password_form_with_captcha() {
+ // Check password protected page captcha
+ $verify = $this->verify_captcha_submit();
+ if (!$verify) {
+ wp_die(__('Captcha verification failed.', 'all-in-one-wp-security-and-firewall'). ' ' . __('Please try again.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+
+ /**
+ * Insert CAPTCHA question form on WooCommerce my account page forms or other forms.
+ *
+ * This function determines the type of CAPTCHA to display based on the configured default CAPTCHA type.
+ * It handles special cases for WooCommerce "my account" page where both login and register forms need
+ * CAPTCHAs rendered explicitly. For other forms, it renders CAPTCHA normally.
+ *
+ * @global object $aio_wp_security The global instance of the aio_wp_security class, which holds configuration settings.
+ *
+ * @return void
+ */
+ public function insert_captcha_question_form() {
+ global $aio_wp_security;
+
+ $default_captcha = $aio_wp_security->configs->get_value('aiowps_default_captcha');
+
+ switch ($default_captcha) {
+ case 'cloudflare-turnstile':
+ case 'google-recaptcha-v2':
+ // WooCommerce "my account" page needs special consideration, ie,
+ // need to display two CAPTCHA forms on same page (for login and register forms)
+ // For this case we use the "explicit" CAPTCHA display
+ $calling_hook = current_filter();
+ if ('woocommerce_login_form' == $calling_hook || 'woocommerce_lostpassword_form' == $calling_hook || 'woocommerce_after_checkout_billing_form' == $calling_hook) {
+ $this->get_captcha_form($default_captcha, 1);
+ return;
+ }
+
+ if ('woocommerce_register_form' == $calling_hook) {
+ $this->get_captcha_form($default_captcha, 1);
+ return;
+ }
+
+ // For all other forms simply display CAPTCHA as normal
+ $this->display_captcha_form($default_captcha);
+ break;
+ case 'simple-math':
+ // Display plain maths CAPTCHA form
+ $this->display_captcha_form($default_captcha);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * For WooCommerce my account page - display two separate CAPTCHA forms "explicitly"
+ *
+ * @return void
+ */
+ public function print_captcha_api_woo() {
+ global $aio_wp_security;
+
+
+ //captcha should only show for woo account and checkout page
+ if ((function_exists('is_account_page') && !is_account_page()) && (function_exists('is_checkout') && !is_checkout()) && !apply_filters('aios_print_captcha_api_woo', false)) return;
+
+ $default_captcha = $aio_wp_security->configs->get_value('aiowps_default_captcha');
+
+ if ('cloudflare-turnstile' == $default_captcha) :
+ $site_key = esc_html($aio_wp_security->configs->get_value('aiowps_turnstile_site_key'));
+ ?>
+
+ configs->get_value('aiowps_recaptcha_site_key'));
+ ?>
+
+
+ configs->get_value('aiowps_enable_bp_register_captcha') == '1' && defined('BP_VERSION')) {
+ //if buddy press feature active add action hook so buddy press can display our errors properly on bp registration form
+ do_action('bp_aiowps-captcha-answer_errors');
+ }
+
+ switch ($default_captcha) {
+ case 'cloudflare-turnstile':
+ if ('1' == $aio_wp_security->configs->get_value('aios_cloudflare_turnstile_invalid_configuration')) return;
+ if ($return_instead_of_echo) return $this->get_captcha_form($default_captcha, 0, $return_instead_of_echo);
+ $this->get_captcha_form($default_captcha);
+ break;
+ case 'google-recaptcha-v2':
+ if ('1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) return;
+ if ($return_instead_of_echo) return $this->get_captcha_form($default_captcha, 0, $return_instead_of_echo);
+ $this->get_captcha_form($default_captcha);
+ break;
+ case 'simple-math':
+ $maths_captcha_input_id = uniqid('aiowps-captcha-answer-'); // Generate a unique DOM-safe ID for the maths captcha input field to avoid duplicate IDs (when multiple forms appear on the same page).
+ $cap_form = '
';
+ echo $disabled_message;
+ }
+ }
+
+ public function process_comment_post($comment) {
+ global $aio_wp_security;
+ if (is_user_logged_in()) {
+ return $comment;
+ }
+
+ // Don't process CAPTCHA for comment replies inside admin menu
+ if (isset($_REQUEST['action']) && 'replyto-comment' == $_REQUEST['action'] && (check_ajax_referer('replyto-comment', '_ajax_nonce', false) || check_ajax_referer('replyto-comment', '_ajax_nonce-replyto-comment', false))) {
+ return $comment;
+ }
+
+ // Don't do CAPTCHA for pingback/trackback
+ if ('' != $comment['comment_type'] && 'comment' != $comment['comment_type'] && 'review' != $comment['comment_type']) {
+ return $comment;
+ }
+
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ //Wrong answer
+ wp_die(__('Error: You entered an incorrect CAPTCHA answer, please go back and try again.', 'all-in-one-wp-security-and-firewall'));
+ } else {
+ return($comment);
+ }
+ }
+
+ /**
+ * Process the main Wordpress account lost password login form post
+ * Called by wp hook "lostpassword_post"
+ */
+ public function process_lost_password_form_post() {
+ global $aio_wp_security;
+
+ // Workaround - the WooCommerce lost password form also uses the same "lostpassword_post" hook.
+ // We don't want to process woo forms here so ignore if this is a woo lost password $_POST
+ if (!array_key_exists('woocommerce-lost-password-nonce', $_POST)) {
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
+ }
+ }
+ }
+
+ public function add_lostpassword_captcha_error_msg() {
+ //Insert an error just before the password reset process kicks in
+ return new WP_Error('aiowps_captcha_error', __('ERROR: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ public function check_404_event() {
+ if (is_404()) {
+ //This means a 404 event has occurred - let's log it!
+ AIOWPSecurity_Utility::event_logger('404');
+ }
+
+ }
+
+ /**
+ * Deletes unneeded default WP files if they're regenerated after core upgrade.
+ *
+ * @param WP_Upgrader $upgrader
+ * @param array $hook_extra
+ *
+ * @return void
+ */
+ public function delete_unneeded_files_after_upgrade($upgrader, $hook_extra) {
+ if (empty($hook_extra)) {
+ return;
+ }
+
+ if (isset($hook_extra['action']) && 'update' == $hook_extra['action'] && isset($hook_extra['type']) && 'core' == $hook_extra['type']) {
+ AIOWPSecurity_Utility::delete_unneeded_default_files();
+ }
+ }
+
+ /**
+ * Sends WWW-Authenticate header for frontend or admin protection according to user configuration.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @return void
+ */
+ private function http_authentication() {
+ global $aio_wp_security;
+
+ if (defined('AIOS_DISABLE_HTTP_AUTHENTICATION') && AIOS_DISABLE_HTTP_AUTHENTICATION) return;
+
+ $request_uri = isset($_SERVER['REQUEST_URI']) ? wp_parse_url(urldecode($_SERVER['REQUEST_URI'])) : '';
+
+ $request_path = isset($request_uri['path']) ? $request_uri['path'] : '';
+ $request_query = isset($request_uri['query']) ? $request_uri['query'] : '';
+
+ $non_logged_in_admin_ajax_request = !is_user_logged_in() && defined('DOING_AJAX') && DOING_AJAX;
+
+ // Can't use defined('REST_REQUEST') && REST_REQUEST because REST_REQUEST isn't defined until after init.
+ $logged_in_rest_request = is_user_logged_in() && (1 === preg_match('/^\/'.rest_get_url_prefix().'(?:\/.*)?$/', $request_path) || 1 === preg_match('/^rest_route=.+$/', $request_query));
+
+ $is_login_page = 'wp-login.php' == $GLOBALS['pagenow'];
+
+ if ('cli' == PHP_SAPI || (defined('WP_CLI') && WP_CLI)) {
+ // CLI
+ return;
+ } elseif ((is_admin() && !$non_logged_in_admin_ajax_request) || $logged_in_rest_request || $is_login_page) {
+ // Admin
+ if ('1' != $aio_wp_security->configs->get_value('aiowps_http_authentication_admin')) {
+ return;
+ }
+ } else {
+ // Frontend
+ if ('1' != $aio_wp_security->configs->get_value('aiowps_http_authentication_frontend')) {
+ return;
+ }
+ }
+
+ $username = $aio_wp_security->configs->get_value('aiowps_http_authentication_username');
+ $password = $aio_wp_security->configs->get_value('aiowps_http_authentication_password');
+
+ // Check that the user hasn't already logged in with credentials.
+ if (!(isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER'] == $username && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW'] == $password)) {
+ header('WWW-Authenticate: Basic charset="UTF-8"');
+ header('HTTP/1.0 401 Unauthorized');
+
+ // Show failure message when the user clicks on the cancel button of the login prompt.
+ $aiowps_failure_message = $aio_wp_security->configs->get_value('aiowps_http_authentication_failure_message');
+ $aiowps_failure_message_raw = html_entity_decode($aiowps_failure_message, ENT_COMPAT, 'UTF-8');
+ echo $aiowps_failure_message_raw;
+ exit;
+ }
+ }
+
+ /**
+ * Filters whether to pass URLs through wp_http_validate_url() in an HTTP request based on whether the url is in the url exceptions config.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @param bool $pass_url Whether to pass URLs through wp_http_validate_url(). Default false.
+ * @param string $url The request URL.
+ *
+ * @return bool
+ */
+ public function http_request_reject_unsafe_urls($pass_url, $url) {
+ global $aio_wp_security;
+
+ if ($pass_url) {
+ return true;
+ }
+
+ $parsed_url = parse_url($url); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- Using the same function as WordPress in order to not preclude URLs that would be allowed by WordPress.
+
+ if (empty($parsed_url['scheme'])) { // The same weak sanity check used by the WordPress wp_remote_* functions.
+ return false;
+ }
+
+ if (empty($parsed_url['host']) || in_array($parsed_url['host'], array('localhost', '127.0.0.1', '[::1]'))) {
+ return false;
+ }
+
+ $upgrade_unsafe_http_calls_url_exceptions = $aio_wp_security->configs->get_site_value('aiowps_upgrade_unsafe_http_calls_url_exceptions');
+
+ if (!empty($upgrade_unsafe_http_calls_url_exceptions)) {
+ foreach (preg_split('/\R/', $upgrade_unsafe_http_calls_url_exceptions) as $exempt_url) {
+ $exempt_url = sanitize_url($exempt_url);
+
+ if (empty($exempt_url)) {
+ continue;
+ }
+
+ if (0 === strpos($exempt_url, '#')) {
+ continue;
+ }
+
+ if ($url === $exempt_url) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public function buddy_press_signup_validate_captcha() {
+ global $bp, $aio_wp_security;
+ // Check CAPTCHA if required
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ // wrong answer was entered
+ $bp->signup->errors['aiowps-captcha-answer'] = __('Your CAPTCHA answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall');
+ }
+ return;
+ }
+
+ public function aiowps_validate_woo_login_or_reg_captcha($errors) {
+ global $aio_wp_security;
+ $locked = $aio_wp_security->user_login_obj->check_locked_user();
+ if (!empty($locked)) {
+ $errors->add('authentication_failed', __('ERROR: Your IP address is currently locked please contact the administrator!', 'all-in-one-wp-security-and-firewall'));
+ return $errors;
+ }
+
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ // wrong answer was entered
+ $errors->add('authentication_failed', __('ERROR: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
+ }
+ return $errors;
+
+ }
+
+ /**
+ * Process the WooCommerce checkout validation
+ * Called by WooCommerce hook "woocommerce_after_checkout_validation"
+ *
+ * @param array $data An array of posted data
+ * @param WP_ERROR $errors Validation errors
+ */
+ public function aiowps_validate_woo_checkout_captcha($data, $errors) {
+ global $aio_wp_security;
+ $locked = $aio_wp_security->user_login_obj->check_locked_user();
+ if (!empty($locked)) {
+ /* translators: %s: Error notification with strong HTML tag. */
+ $errors->add('authentication_failed', sprintf(__('%s: Your IP address is currently locked.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please contact the administrator.', 'all-in-one-wp-security-and-firewall'), '' . __('ERROR', 'all-in-one-wp-security-and-firewall') . ''));
+ return $errors;
+ }
+
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ // wrong answer was entered
+ /* translators: %s: Error notification with strong HTML tag. */
+ $errors->add('authentication_failed', sprintf(__('%s: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'), '' . __('ERROR', 'all-in-one-wp-security-and-firewall') . ''));
+ }
+ return $errors;
+
+ }
+
+ /**
+ * Process the WooCommerce lost password login form post
+ * Called by wp hook "lostpassword_post"
+ */
+ public function process_woo_lost_password_form_post() {
+ global $aio_wp_security;
+
+ if (isset($_POST['woocommerce-lost-password-nonce'])) {
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
+ }
+ }
+ }
+
+ /**
+ * Displays a notice message if the entered recatcha site key is wrong.
+ */
+ public function google_recaptcha_notice() {
+ global $aio_wp_security;
+
+ if (($aio_wp_security->is_admin_dashboard_page() || $aio_wp_security->is_plugin_admin_page() || $aio_wp_security->is_aiowps_admin_page()) && !$aio_wp_security->is_aiowps_google_recaptcha_tab_page()) {
+ $recaptcha_tab_url = 'admin.php?page='.AIOWPSEC_BRUTE_FORCE_MENU_SLUG.'&tab=login-captcha';
+ echo '
';
+ /* 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 '
';
+ }
+ }
+
+ /**
+ * This is a fix for cases when the password reset URL in the email was not decoding all html entities properly
+ *
+ * @param string $message
+ * @return string
+ */
+ public function decode_reset_pw_msg($message) {
+ $message = html_entity_decode($message);
+ return $message;
+ }
+
+ public function modify_registration_page_messages($errors) {
+ if (isset($_GET['checkemail']) && 'registered' == $_GET['checkemail']) {
+ if (is_wp_error($errors)) {
+ $errors->remove('registered');
+ $pending_approval_msg = __('Your registration is pending approval.', 'all-in-one-wp-security-and-firewall');
+ $pending_approval_msg = apply_filters('aiowps_pending_registration_message', $pending_approval_msg);
+ $errors->add('registered', $pending_approval_msg, array('registered' => 'message'));
+ }
+ }
+ return $errors;
+ }
+
+ /**
+ * Checks for REST API requests
+ * Below uses the "rest_api_init" action hook to check for REST requests.
+ * It will block "unauthorized" requests whilst allowing genuine requests.
+ * REST route will not be blocked if route is whitelisted or user is logged in and user role is allowed.
+ *
+ * @return void
+ */
+ public function check_rest_api_requests() {
+ global $aio_wp_security;
+
+ $is_whitelisted_route = false;
+ $rest_route = AIOWPSecurity_Utility::get_rest_route();
+
+ if (empty($rest_route)) return; //rest_api_init is called getting rest server for non rest endpoint. example /wp-admin/post-new.php. WordPress 6.5.0 has wp_is_serving_rest_request we can not use.
+
+ $aios_whitelisted_rest_routes = apply_filters('aios_whitelisted_rest_routes', $aio_wp_security->configs->get_value('aios_whitelisted_rest_routes'));
+ foreach ($aios_whitelisted_rest_routes as $whitelisted_rest_route) {
+ $whitelisted_rest_route = preg_quote($whitelisted_rest_route, '/');
+ // The 'wc/' rest route to match for white listed 'wc' not the 'wc-admin/' or other having wc
+ if (preg_match('/^'.$whitelisted_rest_route.'\//i', $rest_route)) {
+ $is_whitelisted_route = true;
+ }
+ }
+
+ $rest_user = wp_get_current_user();
+ $is_disallowed_role = !empty($rest_user->roles) && !empty(array_intersect($rest_user->roles, $aio_wp_security->configs->get_value('aios_roles_disallowed_rest_requests'))) ? true : false;
+
+ if (!$is_whitelisted_route && (empty($rest_user->ID) || $is_disallowed_role)) {
+ $error_message = apply_filters('aiowps_rest_api_error_message', __('You are not authorized to perform this action.', 'all-in-one-wp-security-and-firewall'));
+ $aio_wp_security->debug_logger->log_debug('REST API request '.$rest_route.' was blocked, If this was unintentional whitelist "' . explode('/', $rest_route)[0] . '" the REST route.', 4);
+ wp_die($error_message, '', 403);
+ }
+ }
+
+ /**
+ * Shows the firewall notice
+ *
+ * @return void
+ */
+ public function do_firewall_notice() {
+
+ $firewall_setup = AIOWPSecurity_Firewall_Setup_Notice::get_instance();
+ $firewall_setup->start_firewall_setup();
+
+ }
+
+ /**
+ * Called by the WP filter rest_request_before_callbacks
+ *
+ * @param WP_REST_Response $response
+ *
+ * @return WP_REST_Response|WP_Error $response
+ */
+ public function rest_request_before_callbacks($response) {
+ $rest_route = !empty($_GET['rest_route']) ? $_GET['rest_route'] : (empty($_SERVER['REQUEST_URI']) ? '' : (string) parse_url(urldecode($_SERVER['REQUEST_URI']), PHP_URL_PATH));
+ $rest_route = trim($rest_route, '/');
+ if ('' != $rest_route && !current_user_can('edit_others_posts')) {
+ if (preg_match('/wp\/v2\/users$/i', $rest_route)) {
+ $error = new WP_Error('aios_user_lists_forbidden', __('Listing users is forbidden.', 'all-in-one-wp-security-and-firewall'), array('status' => 403));
+ $response = rest_ensure_response($error);
+ } elseif (preg_match('/wp\/v2\/users\/+(\d+)$/i', $rest_route, $matches)) {
+ $id = empty($matches) ? 0 : (int) $matches[1];
+ if (get_current_user_id() !== $id) {
+ $error = new WP_Error('aios_user_details_forbidden', __('Accessing user details is forbidden.', 'all-in-one-wp-security-and-firewall'), array('status' => 403));
+ $response = rest_ensure_response($error);
+ }
+ }
+ }
+ return $response;
+ }
+
+ /**
+ * Called by the WP filter oembed_response_data
+ *
+ * @param Array $data
+ *
+ * @return Array $data
+ */
+ public function oembed_response_data($data) {
+ unset($data['author_name']);
+ unset($data['author_url']);
+ return $data;
+ }
+
+ /**
+ * Sets the antibot cookie for post page comment form
+ *
+ * @return void
+ */
+ public function post_antibot_cookie() {
+ if (is_single()) {
+ AIOWPSecurity_Comment::insert_antibot_keys_in_cookie();
+ }
+ }
+
+ /**
+ * Sets the hidden fields html code for post page comment form
+ *
+ * @param string $submit_field HTML markup for the submit field
+ *
+ * @return string
+ */
+ public function comment_form_submit_field($submit_field) {
+ return $submit_field . " " . AIOWPSecurity_Comment::insert_antibot_keys_in_comment_form();
+ }
+
+ /**
+ * Filters the captcha settings templates based on specific conditions.
+ *
+ * This function checks if certain conditions (like login lockdown) are active, and filters the templates accordingly.
+ * If a template contains a display condition callback, it ensures the callback is callable and invokes it to determine
+ * whether the template should be included in the result.
+ *
+ * @param array $templates An array of captcha setting templates to filter.
+ *
+ * @return array The filtered array of captcha setting templates.
+ */
+ public function filter_captcha_settings_templates($templates) {
+ global $aio_wp_security;
+
+ if (empty($templates) || $aio_wp_security->is_login_lockdown_by_const()) return array();
+
+ return $this->filter_templates($templates);
+ }
+
+
+ /**
+ * Filters the provided templates array based on a specified callback condition.
+ *
+ * This function applies a filter to the input templates array, checking for each template
+ * if a 'display_condition_callback' is set and callable. If the condition passes, the template is retained.
+ *
+ * @param array $templates An array of templates to filter. Each template should have a 'display_condition_callback' key.
+ *
+ * @return array Filtered array of templates where the 'display_condition_callback' is valid.
+ */
+ public function filter_templates($templates) {
+ if (empty($templates)) return array();
+
+ return array_filter($templates, function ($template) {
+ return AIOWPSecurity_Utility::apply_callback_filter($template, 'display_condition_callback');
+ });
+ }
+
+ /**
+ * This filter stops exposed renamed login URL using auth_redirect
+ *
+ * @param string|null $login_url The login URL. Not HTML-encoded.
+ * @param string $redirect The path to redirect to on login, if supplied.
+ * @param bool $force_reauth Whether to force reauthorization, even if a cookie is present.
+ *
+ * @return string The filtered login URL.
+ */
+ public function login_url_reauth_redirect($login_url, $redirect, $force_reauth) {
+ // Ensure $login_url is a string to avoid deprecation warnings.
+ $login_url = isset($login_url) ? $login_url : '';
+
+ if (true === $force_reauth && !empty($redirect)) {
+ 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
+ );
+ }
+
+ return $login_url;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-helper.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-helper.php
new file mode 100755
index 00000000..767875f1
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-helper.php
@@ -0,0 +1,345 @@
+::'
+ * @return string
+ */
+ public static function get_firewall_rule_location($rule) {
+ //normalise key
+ $rule = strtolower($rule);
+
+ $basic_firewall = array(
+ 'completely block xmlrpc::general' => 'page=aiowpsec_firewall',
+ );
+ $additional_firewall = array(
+ 'advanced character filter::general' => 'page=aiowpsec_firewall&tab=additional-firewall',
+ 'bad query strings::general' => 'page=aiowpsec_firewall&tab=additional-firewall',
+ 'proxy comment posting::general' => 'page=aiowpsec_firewall&tab=additional-firewall',
+ );
+ $bruteforce = array(
+ 'cookie based prevent bruteforce::bruteforce' => 'page=aiowpsec_brute_force&tab=cookie-based-brute-force-prevention',
+ );
+ $blacklist = array(
+ 'blocked ips::blacklist' => 'page=aiowpsec_blacklist',
+ 'blocked user agents::blacklist' => 'page=aiowpsec_blacklist',
+ );
+ $firewall_6g = array(
+ 'block request methods::6g' => 'page=aiowpsec_firewall&tab=6g-firewall',
+ 'block query strings::6g' => 'page=aiowpsec_firewall&tab=6g-firewall',
+ 'block referrer strings::6g' => 'page=aiowpsec_firewall&tab=6g-firewall',
+ 'block request strings::6g' => 'page=aiowpsec_firewall&tab=6g-firewall',
+ 'block user-agents::6g' => 'page=aiowpsec_firewall&tab=6g-firewall',
+ );
+
+ // merge all the locations to one
+ $locations = array_merge($firewall_6g, $blacklist, $bruteforce, $basic_firewall, $additional_firewall);
+ return isset($locations[$rule]) ? $locations[$rule] : '';
+ }
+
+ /**
+ * Get server detected visitor IP Address.
+ *
+ * @return String visitor IP Address.
+ */
+ public static function get_server_detected_user_ip_address() {
+ $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
+
+ // check if user configured custom IP retrieval method
+ $ip_method_id = empty($aiowps_firewall_config) ? '' : $aiowps_firewall_config->get_value('aios_ip_retrieve_method');
+
+ $visitor_ip = '';
+ $ip_retrieve_methods = AIOS_Abstracted_Ids::get_ip_retrieve_methods();
+
+ if (empty($ip_method_id) || !isset($ip_retrieve_methods[$ip_method_id])) {
+ $ip_method_id = 0;
+ }
+
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress API cannot be used here as it's loaded independently of WordPress
+ $visitor_ip = isset($_SERVER[$ip_retrieve_methods[$ip_method_id]]) ? $_SERVER[$ip_retrieve_methods[$ip_method_id]] : '';
+
+ // Check if multiple IPs were given - these will be present as comma-separated list
+ if (preg_match('/^([^,]+),/', $visitor_ip, $matches)) $visitor_ip = $matches[1];
+
+ // Now remove port portion if ipv4 address with port, for ipv6 it was making issue so using fiter_var valid ip checked first.
+ if (!filter_var($visitor_ip, FILTER_VALIDATE_IP) && preg_match('/(.+):\d+$/', $visitor_ip, $matches)) $visitor_ip = $matches[1];
+
+ if (!filter_var($visitor_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && !filter_var($visitor_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress API cannot be used here as it's loaded independently of WordPress
+ $visitor_ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
+ }
+
+ return $visitor_ip;
+ }
+
+ /**
+ * Get user IP Address.
+ *
+ * @return string User IP Address.
+ */
+ public static function get_user_ip_address() {
+ static $visitor_ip;
+ if (isset($visitor_ip)) {
+ //already set in the page request
+ return $visitor_ip;
+ }
+
+ $visitor_ip = self::get_server_detected_user_ip_address();
+
+ if (in_array($visitor_ip, array('', '127.0.0.1', '::1'))) {
+ $external_ip_address = self::get_external_ip_address();
+ if (false != $external_ip_address) {
+ $visitor_ip = $external_ip_address;
+ }
+ }
+
+ return $visitor_ip;
+ }
+
+ /**
+ * Check user IP Address is with in list.
+ *
+ * @param array $ip_address_list
+ *
+ * @return boolean.
+ */
+ public static function is_user_ip_address_within_list($ip_address_list) {
+
+ if (!(include_once AIOWPS_FIREWALL_DIR.'/../../vendor/mlocati/ip-lib/ip-lib.php')) {
+ throw new \Exception("AIOS_Helper::is_user_ip_address_within_list failed to load ip-lib.php");
+ }
+
+ if (empty($ip_address_list)) return false;
+
+ $user_ip = self::get_user_ip_address();
+ $user_ip_address = \IPLib\Factory::parseAddressString($user_ip);
+ if (null != $user_ip_address) {
+ $user_ip_address_type = $user_ip_address->getAddressType();
+ $user_ipv4_address_parsed = (6 == $user_ip_address_type) ? $user_ip_address->toIPv4() : $user_ip_address;
+ // linear search used to compare ips list.
+ foreach ($ip_address_list as $ip_address) {
+ if (preg_match("/\/|\*/", $ip_address)) { // checks user ipadress with in range of ip range.
+ $range = \IPLib\Factory::parseRangeString($ip_address);
+ if (null != $range && $range->contains($user_ip_address)) return true;
+ } elseif ($ip_address == $user_ip) {
+ return true;
+ } elseif (null != $user_ipv4_address_parsed) { // check for ip matches if ipv6 to ipv4 or vice versa
+ $ip_address_parsed = \IPLib\Factory::parseAddressString($ip_address);
+ if (null != $ip_address_parsed) {
+ $ip_address_parsed_type = $ip_address_parsed->getAddressType();
+ $ipv4_address_parsed = (6 == $ip_address_parsed_type) ? $ip_address_parsed->toIPv4() : $ip_address_parsed;
+ if ((string) $user_ipv4_address_parsed == (string) $ipv4_address_parsed) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get user IP Address using an external service.
+ * This can be used as a fallback for users on localhost where
+ * get_ip_address() will be a local IP and non-geolocatable.
+ *
+ * @return string|boolean external ip address if from one of lookup service gets response otherwise false.
+ */
+ public static function get_external_ip_address() {
+ $aiowps_firewall_constants = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONSTANTS);
+ $external_ip_address = false;
+
+ //Running from cronjob REQUEST_URI is empty or DOING_CRON, if from command line cli is PHP_SAPI, constant set by user
+ if (empty($_SERVER['REQUEST_URI']) || (defined('DOING_CRON') && DOING_CRON) || 'cli' == PHP_SAPI || $aiowps_firewall_constants->AIOS_DISABLE_EXTERNAL_IP_ADDR) return $external_ip_address;
+
+ $ip_lookup_services = AIOS_Abstracted_Ids::get_ip_lookup_services();
+ $ip_lookup_services_keys = array_keys($ip_lookup_services);
+ shuffle($ip_lookup_services_keys);
+
+ foreach ($ip_lookup_services_keys as $service_name) {
+ $service_endpoint = $ip_lookup_services[$service_name];
+ $response = self::request_remote($service_endpoint);
+ if (!empty($response) && filter_var($response, FILTER_VALIDATE_IP)) {
+ $external_ip_address = $response;
+ break;
+ }
+ }
+ return $external_ip_address;
+ }
+
+ /**
+ * Remote url request.
+ *
+ * @global \AIOWPS\Firewall\Constants $aiowps_firewall_constants
+ *
+ * @param string $url url to be requested.
+ * @param array $args request args array.
+ *
+ * @return string response.
+ */
+ public static function request_remote($url, $args = array()) {
+ $aiowps_firewall_constants = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONSTANTS);
+ $response = '';
+ $aiowps_firewall_utility = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::UTILITY);
+ $root = $aiowps_firewall_utility::get_root_dir();
+ $includes = isset($aiowps_firewall_constants->WPINC) ? $aiowps_firewall_constants->WPINC : 'wp-includes';
+
+ //WP 6.2+ the request library updated to 2.0.5, class and interface files/directory moved and namespaced name used.
+ if (!class_exists('WpOrg\Requests\Autoload')) {
+ if (file_exists($root . $includes . '/Requests/src/Autoload.php')) {
+ require_once($root . $includes . '/Requests/src/Autoload.php');
+ WpOrg\Requests\Autoload::register();
+ WpOrg\Requests\Requests::set_certificate_path($root . $includes . '/certificates/ca-bundle.crt');
+ } elseif (!class_exists('Requests') && file_exists($root . $includes . '/class-requests.php')) {
+ require_once($root . $includes . '/class-requests.php');
+ Requests::register_autoloader();
+ Requests::set_certificate_path($root . $includes . '/certificates/ca-bundle.crt');
+ }
+ }
+ $timeout = isset($aiowps_firewall_constants->AIOS_REQUEST_TIMEOUT) ? $aiowps_firewall_constants->AIOS_REQUEST_TIMEOUT : 4;
+
+ try {
+ $headers = isset($args['headers']) ? $args['headers'] : array();
+ $data = isset($args['body']) ? $args['body'] : array();
+ $method = isset($args['method']) ? $args['method'] : 'GET';
+ $options = array('timeout' => $timeout);
+ //WP 6.2+ the request library 2.0.5 namespaced name WpOrg\Requests\Requests instead just Requests
+ if (class_exists('WpOrg\Requests\Requests')) {
+ $request_response = WpOrg\Requests\Requests::request($url, $headers, $data, $method, $options);
+ } elseif (class_exists('Requests')) {
+ $request_response = Requests::request($url, $headers, $data, $method, $options);
+ }
+ $response = $request_response->body;
+ } catch (\Exception $e) {
+ $error_message = $e->getMessage();
+ // timed out exception ignore it.
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Part of AIOS error reporting.
+ if (!preg_match('/timed out/i', $error_message)) error_log('AIOS_Helper::request_remote exception - ' . $error_message);
+ } catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
+ error_log('AIOS_Helper::request_remote error - ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Part of AIOS error reporting.
+ }
+
+ if (empty($response) && ini_get('allow_url_fopen')) {
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Cannot use WP API since Firewall is loaded outside WordPress.
+ $response = @file_get_contents($url, false, stream_context_create(array('http' => array("timeout" => $timeout)))); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this to silence request failed warning for IP lookup services
+ }
+ return $response;
+ }
+
+ /**
+ * Performs reverse IP lookup for the given IP address
+ *
+ * @param string $ip_address - IP address to perform reverse lookup
+ *
+ * @return array - Reverse lookup data
+ */
+ public static function get_ip_reverse_lookup($ip_address) {
+ global $aio_wp_security;
+ $reverse_lookup_data = array();
+ $ip_reverse_lookup_services = AIOS_Abstracted_Ids::get_reverse_ip_lookup_services();
+ $ip_reverse_lookup_services_keys = array_keys($ip_reverse_lookup_services);
+ shuffle($ip_reverse_lookup_services_keys);
+
+ foreach ($ip_reverse_lookup_services_keys as $service_name) {
+ $endpoint = $ip_reverse_lookup_services[$service_name];
+ $url = sprintf($endpoint, $ip_address);
+ $response = wp_safe_remote_get($url, array( 'timeout' => 2 ));
+
+ if (!is_wp_error($response) && $response['body']) {
+ $data = json_decode($response['body'], true);
+ if (!$data) {
+ $aio_wp_security->debug_logger->log_debug("Error decoding IP lookup result", 4);
+ return $reverse_lookup_data;
+ }
+ switch ($service_name) {
+ case 'ip-api':
+ $fields_to_copy = array('org', 'as');
+ foreach ($fields_to_copy as $field) {
+ $reverse_lookup_data[$field] = empty($data[$field]) ? null : $data[$field];
+ }
+ break;
+ case 'ipinfo':
+ $reverse_lookup_data['org'] = empty($data['org']) ? null : $data['org'];
+ $reverse_lookup_data['as'] = $reverse_lookup_data['org'];
+ break;
+ default:
+ break;
+ }
+
+ $reverse_lookup_data = apply_filters('aiowps_login_lockdown_lookup_result', $reverse_lookup_data, $data, $service_name);
+ break;
+ }
+ }
+
+ return $reverse_lookup_data;
+ }
+
+ /**
+ * Gets hash of given string using auth Authentication scheme
+ *
+ * @param string $data - Plain text to hash.
+ *
+ * @return string - Hash of $data
+ */
+ public static function get_hash($data) {
+ $aiowps_firewall_constants = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONSTANTS);
+ $salt = $aiowps_firewall_constants->AUTH_KEY.$aiowps_firewall_constants->AUTH_SALT;
+ return hash_hmac('md5', $data, $salt);
+ }
+
+ /**
+ * Set a message for a specific context.
+ *
+ * @param string $context The unique context identifier for the message.
+ * @param string $message The message to store for the given context.
+ * @param string $type The message type to store for the given context.
+ *
+ * @return void
+ */
+ public static function set_message($context, $message, $type = 'info') {
+ self::$messages[$context] = array('message' => $message, 'type' => $type);
+ }
+
+ /**
+ * Get a message for a specific context.
+ *
+ * @param string $context The unique context identifier for the message.
+ *
+ * @return array|null The message for the given context, or null if not found.
+ */
+ public static function get_message($context) {
+ return isset(self::$messages[$context]) ? self::$messages[$context] : null;
+ }
+
+ /**
+ * Clear messages (optional, for cleanup purposes).
+ *
+ * @return void
+ */
+ public static function clear_messages() {
+ self::$messages = array();
+ }
+
+ /**
+ * This function checks if the current request is an UpdraftCentral request by looking for a specific constant.
+ *
+ * @return boolean - True if the request is from UpdraftCentral, false otherwise.
+ */
+ public static function is_updraft_central_request() {
+ return defined('UPDRAFTCENTRAL_COMMAND') && UPDRAFTCENTRAL_COMMAND;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-hibp.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-hibp.php
new file mode 100755
index 00000000..06c34bfe
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-hibp.php
@@ -0,0 +1,83 @@
+debug_logger->log_debug('Failed to query the HIBP api: ' . $response_body->get_error_message(), 4);
+ return false;
+ }
+
+ $response_body_array = explode("\n", $response_body);
+
+ foreach ($response_body_array as $suffix_and_count) {
+ $suffix = explode(':', $suffix_and_count)[0];
+
+ if (strtolower($suffix) == $password_hash_suffix) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if a password has been pwned when updating a user profile.
+ *
+ * @param WP_Error $errors
+ * @param bool $update
+ * @param stdClass $user
+ *
+ * @return void
+ */
+ public static function user_profile_update_check(&$errors, $update, &$user) {
+ // Use get_error_code() instead of has_errors() for backward compatibility with WP 5.0.
+ if ($errors->get_error_code() || empty($user->user_pass)) {
+ return;
+ }
+
+ if (self::password_is_pwned($user->user_pass)) {
+ $errors->add('pass', __('Error: This password has been exposed in a data breach, according to Have I Been Pwned (HIBP).'));
+ }
+ }
+
+ /**
+ * Checks if a password has been pwned when resetting a password.
+ *
+ * @param WP_Error $errors
+ *
+ * @return void
+ */
+ public static function password_reset_check($errors) {
+ // Use get_error_code() instead of has_errors() for backward compatibility with WP 5.0.
+ if ($errors->get_error_code() || !isset($_POST['pass1']) || empty($_POST['pass1'])) {
+ return;
+ }
+
+ if (self::password_is_pwned($_POST['pass1'])) {
+ $errors->add('pass', __('Error: This password has been exposed in a data breach, according to Have I Been Pwned (HIBP).'));
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-installer.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-installer.php
new file mode 100755
index 00000000..4dc6d8c9
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-installer.php
@@ -0,0 +1,498 @@
+ array(
+ 'clean_audit_log_stacktraces',
+ ),
+ '2.0.9' => array(
+ 'update_table_column_to_timestamp',
+ ),
+ '2.0.10' => array(
+ 'delete_aiowps_temp_configs_option',
+ ),
+ '2.1.4' => array(
+ 'update_tables_to_innodb',
+ )
+ );
+
+ /**
+ * Run installer function.
+ *
+ * @return void
+ */
+ public static function run_installer() {
+ global $wpdb;
+ if (function_exists('is_multisite') && is_multisite() && is_main_site()) {
+ // check if it is a network activation - if so, run the activation function for each blog id
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- There doesn't seem to be a documented alternative. Possible alternative get_sites(array('fields' => 'ids', 'number' => 0) but 'number' => 0 is not documented.
+ foreach ($blogids as $blog_id) {
+ switch_to_blog($blog_id);
+ AIOWPSecurity_Installer::create_db_tables();
+ AIOWPSecurity_Installer::migrate_db_tables();
+ AIOWPSecurity_Installer::check_tasks();
+ AIOWPSecurity_Configure_Settings::add_option_values();
+ AIOWPSecurity_Configure_Settings::update_aiowpsec_db_version();
+ restore_current_blog();
+ }
+ } else {
+ AIOWPSecurity_Installer::create_db_tables();
+ AIOWPSecurity_Installer::migrate_db_tables();
+ AIOWPSecurity_Installer::check_tasks();
+ AIOWPSecurity_Configure_Settings::add_option_values();
+ AIOWPSecurity_Configure_Settings::update_aiowpsec_db_version();
+ }
+
+ AIOWPSecurity_Installer::create_db_backup_dir(); // Create a backup dir in the WP uploads directory.
+ }
+
+ /**
+ * See if any database tasks need to be run, and perform them if so.
+ *
+ * @return void
+ */
+ public static function check_tasks() {
+ $our_version = AIO_WP_SECURITY_DB_VERSION;
+ $db_version = get_option('aiowpsec_db_version');
+ // database tasks not need to be run if first time install - false check added
+ if (false != $db_version && version_compare($our_version, $db_version, '>')) {
+ foreach (self::$db_tasks as $version => $updates) {
+ if (version_compare($version, $db_version, '>')) {
+ foreach ($updates as $update) {
+ call_user_func(array(__CLASS__, $update));
+ }
+ }
+ }
+ }
+ }
+
+ public static function create_db_tables() {
+ global $wpdb;
+
+ if (!function_exists('dbDelta')) {
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+ }
+
+ if (function_exists('is_multisite') && is_multisite()) {
+ /*
+ * FIX for multisite table creation case:
+ * Although each table name is defined in a constant inside the wp-security-core.php,
+ * we need to do this step for multisite case because we need to refresh the $wpdb->prefix value
+ * otherwise it will contain the original blog id and not the current id we need.
+ *
+ */
+ $lockout_tbl_name = $wpdb->prefix.'aiowps_login_lockdown';
+ $aiowps_global_meta_tbl_name = $wpdb->prefix.'aiowps_global_meta';
+ $aiowps_event_tbl_name = $wpdb->prefix.'aiowps_events';
+ $perm_block_tbl_name = $wpdb->prefix.'aiowps_permanent_block';
+ } else {
+ $lockout_tbl_name = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
+ $aiowps_event_tbl_name = AIOWPSEC_TBL_EVENTS;
+ $perm_block_tbl_name = AIOWPSEC_TBL_PERM_BLOCK;
+ }
+
+ $message_store_log_tbl_name = AIOWPSEC_TBL_MESSAGE_STORE;
+ $audit_log_tbl_name = AIOWPSEC_TBL_AUDIT_LOG;
+ $debug_log_tbl_name = AIOWPSEC_TBL_DEBUG_LOG;
+ $logged_in_users_tbl_name = AIOWPSEC_TBL_LOGGED_IN_USERS;
+
+ $charset_collate = '';
+ if (!empty($wpdb->charset)) {
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
+ } else {
+ $charset_collate = "DEFAULT CHARSET=utf8";
+ }
+ if (!empty($wpdb->collate)) {
+ $charset_collate .= " COLLATE $wpdb->collate";
+ }
+
+ $ld_tbl_sql = "CREATE TABLE " . $lockout_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ user_id bigint(20) NOT NULL,
+ user_login VARCHAR(150) NOT NULL,
+ lockdown_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
+ created INTEGER UNSIGNED,
+ release_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
+ released INTEGER UNSIGNED,
+ failed_login_ip varchar(100) NOT NULL DEFAULT '',
+ lock_reason varchar(128) NOT NULL DEFAULT '',
+ unlock_key varchar(128) NOT NULL DEFAULT '',
+ is_lockout_email_sent tinyint(1) NOT NULL DEFAULT '1',
+ backtrace_log text NOT NULL,
+ ip_lookup_result LONGTEXT DEFAULT NULL,
+ 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 " . $charset_collate . ";";
+ dbDelta($ld_tbl_sql);
+
+ $gm_tbl_sql = "CREATE TABLE " . $aiowps_global_meta_tbl_name . " (
+ meta_id bigint(20) NOT NULL auto_increment,
+ date_time datetime NOT NULL default '1000-10-10 10:00:00',
+ created INTEGER UNSIGNED,
+ meta_key1 varchar(255) NOT NULL,
+ meta_key2 varchar(255) NOT NULL,
+ meta_key3 varchar(255) NOT NULL,
+ meta_key4 varchar(255) NOT NULL,
+ meta_key5 varchar(255) NOT NULL,
+ meta_value1 varchar(255) NOT NULL,
+ meta_value2 text NOT NULL,
+ meta_value3 text NOT NULL,
+ meta_value4 longtext NOT NULL,
+ meta_value5 longtext NOT NULL,
+ PRIMARY KEY (meta_id)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($gm_tbl_sql);
+
+ $evt_tbl_sql = "CREATE TABLE " . $aiowps_event_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ event_type VARCHAR(150) NOT NULL DEFAULT '',
+ username VARCHAR(150),
+ user_id bigint(20),
+ event_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
+ created INTEGER UNSIGNED,
+ ip_or_host varchar(100),
+ referer_info varchar(255),
+ url varchar(255),
+ country_code varchar(50),
+ event_data longtext,
+ PRIMARY KEY (id)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($evt_tbl_sql);
+
+ $pb_tbl_sql = "CREATE TABLE " . $perm_block_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ blocked_ip varchar(100) NOT NULL DEFAULT '',
+ block_reason varchar(128) NOT NULL DEFAULT '',
+ country_origin varchar(50) NOT NULL DEFAULT '',
+ blocked_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
+ created INTEGER UNSIGNED,
+ unblock tinyint(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (id),
+ KEY blocked_ip (blocked_ip)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($pb_tbl_sql);
+
+ $audit_log_tbl_sql = "CREATE TABLE " . $audit_log_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ network_id bigint(20) NOT NULL DEFAULT '0',
+ site_id bigint(20) NOT NULL DEFAULT '0',
+ username varchar(60) NOT NULL DEFAULT '',
+ ip VARCHAR(45) NOT NULL DEFAULT '',
+ level varchar(25) NOT NULL DEFAULT '',
+ event_type varchar(25) NOT NULL DEFAULT '',
+ details text NOT NULL,
+ stacktrace text NOT NULL,
+ created INTEGER UNSIGNED,
+ country_code varchar(50),
+ PRIMARY KEY (id),
+ INDEX username (username),
+ INDEX ip (ip),
+ INDEX level (level),
+ INDEX event_type (event_type)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($audit_log_tbl_sql);
+
+ $debug_log_tbl_sql = "CREATE TABLE " . $debug_log_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ created datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
+ logtime INTEGER UNSIGNED,
+ level varchar(25) NOT NULL DEFAULT '',
+ network_id bigint(20) NOT NULL DEFAULT '0',
+ site_id bigint(20) NOT NULL DEFAULT '0',
+ message text NOT NULL,
+ type varchar(25) NOT NULL DEFAULT '',
+ PRIMARY KEY (id)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($debug_log_tbl_sql);
+
+ $liu_tbl_sql = "CREATE TABLE " . $logged_in_users_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ user_id bigint(20) NOT NULL,
+ username varchar(60) NOT NULL DEFAULT '',
+ ip_address varchar(45) NOT NULL DEFAULT '',
+ site_id bigint(20) NOT NULL,
+ created integer UNSIGNED,
+ expires integer UNSIGNED,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_user_id (user_id),
+ INDEX created (created),
+ INDEX expires (expires),
+ INDEX user_id (user_id),
+ INDEX site_id (site_id)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($liu_tbl_sql);
+
+ $message_store_log_tbl_sql = "CREATE TABLE " . $message_store_log_tbl_name . " (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ message_key text NOT NULL,
+ message_value text NOT NULL,
+ created INTEGER UNSIGNED,
+ PRIMARY KEY (id)
+ ) ENGINE=InnoDB " . $charset_collate . ";";
+ dbDelta($message_store_log_tbl_sql);
+ }
+
+ /**
+ * This function will handle any database table migrations
+ *
+ * @return void
+ */
+ public static function migrate_db_tables() {
+ global $wpdb;
+
+ if (function_exists('is_multisite') && is_multisite()) {
+ /*
+ * FIX for multisite table creation case:
+ * Although each table name is defined in a constant inside the wp-security-core.php,
+ * we need to do this step for multisite case because we need to refresh the $wpdb->prefix value
+ * otherwise it will contain the original blog id and not the current id we need.
+ *
+ */
+ $failed_login_tbl_name = $wpdb->prefix.'aiowps_failed_logins';
+ $login_activity_tbl_name = $wpdb->prefix.'aiowps_login_activity';
+
+ } else {
+ $failed_login_tbl_name = AIOWPSEC_TBL_FAILED_LOGINS;
+ $login_activity_tbl_name = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
+ }
+
+ $audit_log_tbl_name = AIOWPSEC_TBL_AUDIT_LOG;
+ $network_id = get_current_network_id();
+ $site_id = get_current_blog_id();
+
+ $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($failed_login_tbl_name))); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- There doesn't seem to be an alternative.
+ if ($table_exists) {
+ $import_details = array(
+ 'failed_login' => array(
+ 'imported' => true,
+ )
+ );
+ $import_details = wp_json_encode($import_details, true);
+ $table_migration_details = array(
+ 'table_migration' => array(
+ 'success' => true,
+ 'from_table' => $failed_login_tbl_name,
+ 'to_table' => $audit_log_tbl_name
+ )
+ );
+
+ if (false === $wpdb->query($wpdb->prepare("INSERT INTO $audit_log_tbl_name (network_id, site_id, username, ip, level, event_type, details, stacktrace, created) SELECT %d AS network_id, %d AS site_id, fl.user_login AS username, fl.login_attempt_ip AS ip, 'warning' AS level, 'Failed login' AS event_type, %s AS details, '' AS stacktrace, UNIX_TIMESTAMP(fl.failed_login_date) AS created FROM $failed_login_tbl_name fl", $network_id, $site_id, $import_details))) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
+ $table_migration_details['table_migration']['success'] = false;
+ do_action('aiowps_record_event', 'table_migration', $table_migration_details, 'error');
+ } else {
+ do_action('aiowps_record_event', 'table_migration', $table_migration_details, 'info');
+ $wpdb->query("DROP TABLE IF EXISTS `$failed_login_tbl_name`"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
+ }
+ }
+
+ $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($login_activity_tbl_name))); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- There doesn't seem to be an alternative.
+ if ($table_exists) {
+ $wpdb->query("DROP TABLE IF EXISTS `$login_activity_tbl_name`"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
+ }
+ }
+
+ /**
+ * This function will run SQL to clean sensitive information from the audit log table stacktrace
+ *
+ * @return void
+ */
+ public static function clean_audit_log_stacktraces() {
+ global $wpdb;
+ $wpdb->query("UPDATE ".AIOWPSEC_TBL_AUDIT_LOG." SET stacktrace = '' WHERE event_type = 'failed_login' OR event_type = 'successful_login' OR event_type = 'user_registration'"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
+ }
+
+ /**
+ * This function will update the table datetime column to timestamp with backward compability
+ *
+ * @return void
+ */
+ public static function update_table_column_to_timestamp() {
+ $db_version = get_option('aiowpsec_db_version', '1.0');
+ if (version_compare('2.0.8', $db_version, '>')) {
+ self::update_column_to_timestamp(AIOWPSEC_TBL_EVENTS, 'event_date', 'created');
+ self::update_column_to_timestamp(AIOWPSEC_TBL_LOGIN_LOCKOUT, 'lockdown_date', 'created');
+ self::update_column_to_timestamp(AIOWPSEC_TBL_LOGIN_LOCKOUT, 'release_date', 'released');
+ }
+
+ if (version_compare('2.0.9', $db_version, '>')) {
+ self::update_column_to_timestamp(AIOWPSEC_TBL_PERM_BLOCK, 'blocked_date', 'created');
+ self::update_column_to_timestamp(AIOWPSEC_TBL_GLOBAL_META_DATA, 'date_time', 'created');
+ self::update_column_to_timestamp(AIOWPSEC_TBL_DEBUG_LOG, 'created', 'logtime');
+ }
+ }
+
+ /**
+ * Update the table column to UTC timestamp not depending on the timezone of the user or server settings
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table_name
+ * @param string $field_datetime
+ * @param string $field_timestamp
+ *
+ * @return boolean - returns the rows updated or not
+ */
+ public static function update_column_to_timestamp($table_name, $field_datetime, $field_timestamp) {
+ global $wpdb;
+ //MySQL UNIX_TIMESTAMP will convert datetime based on local timezone not UTC
+ $offset = $wpdb->get_var("SELECT TIMESTAMPDIFF(SECOND, NOW(), UTC_TIMESTAMP())"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- There doesn't seem to be an alternative.
+ if (AIOWPSEC_TBL_PERM_BLOCK == $table_name || AIOWPSEC_TBL_GLOBAL_META_DATA == $table_name || AIOWPSEC_TBL_DEBUG_LOG == $table_name) {
+ //User local settings date time saved offset timezone needs to removed for UTC correct value
+ $offset += AIOWPSecurity_Utility::get_wp_timezone()->getOffset(new DateTime('now', new DateTimeZone('UTC')));
+ }
+ if (function_exists('is_multisite') && is_multisite() && AIOWPSEC_TBL_EVENTS == $table_name) {
+ $table_name = $wpdb->prefix.'aiowps_events';
+ } elseif (function_exists('is_multisite') && is_multisite() && AIOWPSEC_TBL_LOGIN_LOCKOUT == $table_name) {
+ $table_name = $wpdb->prefix.'aiowps_login_lockdown';
+ } elseif (function_exists('is_multisite') && is_multisite() && AIOWPSEC_TBL_PERM_BLOCK == $table_name) {
+ $table_name = $wpdb->prefix.'aiowps_permanent_block';
+ } elseif (function_exists('is_multisite') && is_multisite() && AIOWPSEC_TBL_GLOBAL_META_DATA == $table_name) {
+ $table_name = $wpdb->prefix.'aiowps_global_meta';
+ } elseif (function_exists('is_multisite') && is_multisite() && AIOWPSEC_TBL_DEBUG_LOG == $table_name) {
+ $table_name = $wpdb->prefix.'aiowps_debug_log';
+ }
+ //offset to make sure UTC timestamp updated
+ $wpdb->query($wpdb->prepare("UPDATE $table_name SET $field_timestamp = (UNIX_TIMESTAMP($field_datetime) - %d)", $offset)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
+ }
+
+ /**
+ * Deletes the aiowps_temp_configs option if present.
+ *
+ * @return void
+ */
+ public static function delete_aiowps_temp_configs_option() {
+ delete_option('aiowps_temp_configs');
+ }
+
+ /**
+ * Alters all of the AIOS tables to use InnoDB.
+ *
+ * @global wpdb $wpdb
+ *
+ * @return void
+ */
+ public static function update_tables_to_innodb() {
+ global $wpdb;
+
+ if (function_exists('is_multisite') && is_multisite()) {
+ /*
+ * FIX for multisite table creation case:
+ * Although each table name is defined in a constant inside the wp-security-core.php,
+ * we need to do this step for multisite case because we need to refresh the $wpdb->prefix value
+ * otherwise it will contain the original blog id and not the current id we need.
+ *
+ */
+ $lockout_tbl_name = $wpdb->prefix.'aiowps_login_lockdown';
+ $aiowps_global_meta_tbl_name = $wpdb->prefix.'aiowps_global_meta';
+ $aiowps_event_tbl_name = $wpdb->prefix.'aiowps_events';
+ $perm_block_tbl_name = $wpdb->prefix.'aiowps_permanent_block';
+ } else {
+ $lockout_tbl_name = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
+ $aiowps_event_tbl_name = AIOWPSEC_TBL_EVENTS;
+ $perm_block_tbl_name = AIOWPSEC_TBL_PERM_BLOCK;
+ }
+
+ $message_store_log_tbl_name = AIOWPSEC_TBL_MESSAGE_STORE;
+ $audit_log_tbl_name = AIOWPSEC_TBL_AUDIT_LOG;
+ $debug_log_tbl_name = AIOWPSEC_TBL_DEBUG_LOG;
+ $logged_in_users_tbl_name = AIOWPSEC_TBL_LOGGED_IN_USERS;
+
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- No alternative.
+ $wpdb->query('ALTER TABLE ' . $lockout_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $aiowps_global_meta_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $aiowps_event_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $perm_block_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $audit_log_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $debug_log_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $logged_in_users_tbl_name . ' ENGINE=InnoDB');
+ $wpdb->query('ALTER TABLE ' . $message_store_log_tbl_name . ' ENGINE=InnoDB');
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery
+ }
+
+ public static function create_db_backup_dir() {
+ global $aio_wp_security;
+ // phpcs:disable WordPress.WP.AlternativeFunctions -- WP_Filesystem is not appropriate here.
+ //Create our folder in the "wp-content" directory
+ $aiowps_dir = WP_CONTENT_DIR . '/' . AIO_WP_SECURITY_BACKUPS_DIR_NAME;
+ if (!is_dir($aiowps_dir) && is_writable(WP_CONTENT_DIR)) {
+ mkdir($aiowps_dir, 0755, true);
+ //Let's also create an empty index.html file in this folder
+ $index_file = $aiowps_dir . '/index.html';
+ $handle = fopen($index_file, 'w'); //or die('Cannot open file: '.$index_file);
+ fclose($handle);
+ }
+ $server_type = AIOWPSecurity_Utility::get_server_type();
+ //Only create .htaccess if server is the right type
+ if ('apache' == $server_type || 'litespeed' == $server_type) {
+ $file = $aiowps_dir . '/.htaccess';
+ if (!file_exists($file)) {
+ //Create an .htacces file
+ //Write some rules which will only allow people originating from wp admin page to download the DB backup
+ $rules = '';
+ $rules .= 'order deny,allow' . PHP_EOL;
+ $rules .= 'deny from all' . PHP_EOL;
+ $write_result = file_put_contents($file, $rules);
+ if (false === $write_result) {
+ $aio_wp_security->debug_logger->log_debug("Creation of .htaccess file in " . AIO_WP_SECURITY_BACKUPS_DIR_NAME . " directory failed!", 4);
+ }
+ }
+ }
+ // phpcs:enable WordPress.WP.AlternativeFunctions -- WP_Filesystem is not appropriate here.
+ }
+
+ /**
+ * Setup AIOS cron tasks.
+ * Handles both single and multi-site (NW activation) cases.
+ *
+ * @global type $wpdb
+ *
+ * @return Void
+ */
+ public static function set_cron_tasks_upon_activation() {
+ require_once(__DIR__.'/wp-security-cronjob-handler.php');
+ // It is required because we are going to schedule a 15-minute cron event upon activation.
+ add_filter('cron_schedules', array('AIOWPSecurity_Cronjob_Handler', 'cron_schedules'));
+ if (is_multisite() && is_main_site()) {
+ global $wpdb;
+ // check if it is a network activation
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- There doesn't seem to be a documented alternative. Possible alternative get_sites(array('fields' => 'ids', 'number' => 0) but 'number' => 0 is not documented.
+ foreach ($blogids as $blog_id) {
+ switch_to_blog($blog_id);
+ AIOWPSecurity_Installer::schedule_cron_events();
+ do_action('aiowps_activation_complete');
+ restore_current_blog();
+ }
+ } else {
+ AIOWPSecurity_Installer::schedule_cron_events();
+ do_action('aiowps_activation_complete');
+ }
+ }
+
+ /**
+ * Helper function for scheduling AIOS cron events.
+ *
+ * @return Void
+ */
+ public static function schedule_cron_events() {
+ if (!wp_next_scheduled('aios_15_minutes_cron_event')) {
+ wp_schedule_event(time(), 'aios-every-15-minutes', 'aios_15_minutes_cron_event'); //schedule a 15 minutes cron event
+ }
+ if (!wp_next_scheduled('aiowps_hourly_cron_event')) {
+ wp_schedule_event(time(), 'hourly', 'aiowps_hourly_cron_event'); //schedule an hourly cron event
+ }
+ if (!wp_next_scheduled('aiowps_daily_cron_event')) {
+ wp_schedule_event(time(), 'daily', 'aiowps_daily_cron_event'); //schedule an daily cron event
+ }
+ if (!wp_next_scheduled('aiowps_weekly_cron_event')) {
+ wp_schedule_event(time(), 'weekly', 'aiowps_weekly_cron_event'); //schedule an daily cron event
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-notices.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-notices.php
new file mode 100755
index 00000000..d8f36244
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-notices.php
@@ -0,0 +1,739 @@
+debug_logger->log_debug('Notice rendering error: ' . $e->getMessage(), 4);
+ return esc_html__('An error occurred while rendering this notice, please enable and check your debug log.', 'all-in-one-wp-security-and-firewall');
+ }
+ }
+
+
+ /**
+ * Returns array_merge of notices from parent and notices in $child_notice_content.
+ *
+ * @return Array
+ */
+ protected function populate_notices_content() {
+ global $aio_wp_security;
+ $parent_notice_content = parent::populate_notices_content();
+
+ /* translators: 1. HTML text. 2. HTML text, 3. HTML text. */
+ $sale_description = $this->safe_sprintf(__('Get %1$s with %2$s. %3$s, downtime, and response time issues.', 'all-in-one-wp-security-and-firewall'), '' . __('added protection', 'all-in-one-wp-security-and-firewall') . '', '' . __('Premium', 'all-in-one-wp-security-and-firewall') . '', '' . __('Scan your site for malware', 'all-in-one-wp-security-and-firewall') . '');
+
+ /* translators: %s: HTML text. */
+ $sale_description .= ' ' . $this->safe_sprintf(__('Block traffic by country of origin, get advanced two-factor authentication, %s, and more.', 'all-in-one-wp-security-and-firewall'), '' . __('added protection', 'all-in-one-wp-security-and-firewall') . '', '' . __('Premium', 'all-in-one-wp-security-and-firewall') . '', '' . __('Scan your site for malware', 'all-in-one-wp-security-and-firewall') . '');
+
+ // Build text for firewall rules that have been upgraded
+ $firewall_upgrade_text = '
' .
+ 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 .= '
';
+
+ $active_settings = $aio_wp_security->configs->get_value('aiowps_firewall_active_upgrade');
+
+ if (!empty($active_settings)) {
+ $active_settings = json_decode($active_settings);
+ if (!empty($active_settings)) {
+
+ foreach ($active_settings as $setting) {
+ switch ($setting) {
+ case 'aiowps_enable_pingback_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 .= '
';
+ $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') .
+ '
' .
+ 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') .
+ '
' .
+ 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') .
+ '
' .
+ 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__('Thank you so much!', 'all-in-one-wp-security-and-firewall') . '
- ' . esc_html__('All-In-One Security (AIOS)', 'all-in-one-wp-security-and-firewall').'',
+ 'image' => 'plugin-logos/aios-icon.png',
+ 'button_link' => 'https://wordpress.org/support/plugin/all-in-one-wp-security-and-firewall/reviews/?rate=5#new-post',
+ 'button_meta' => 'review',
+ 'dismiss_time' => 'dismiss_review_notice',
+ 'supported_positions' => $this->dashboard_top,
+ 'validity_function' => 'show_rate_notice'
+ ),
+ 'updraftplus' => array(
+ 'prefix' => '',
+ 'title' => esc_html__('Enhance your security even more by backing up your site', 'all-in-one-wp-security-and-firewall'),
+ 'text' => esc_html__('UpdraftPlus is the world\'s most trusted backup plugin.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('From the owners of All-In-One Security (AIOS).', 'all-in-one-wp-security-and-firewall'),
+ 'image' => 'plugin-logos/updraftplus-icon.png',
+ 'button_link' => 'https://wordpress.org/plugins/updraftplus/',
+ 'button_meta' => 'updraftplus',
+ 'dismiss_time' => 'dismiss_page_notice_until',
+ 'supported_positions' => $this->dashboard_top_or_report,
+ 'validity_function' => 'updraftplus_not_installed',
+ ),
+ 'wp-optimize' => array(
+ 'prefix' => '',
+ 'title' => esc_html__('Speed up your site', 'all-in-one-wp-security-and-firewall'),
+ 'text' => esc_html__("After you've secured your site, we recommend you install our WP-Optimize plugin to streamline it for better website performance.", 'all-in-one-wp-security-and-firewall'),
+ 'image' => 'plugin-logos/wp-optimize-icon.png',
+ 'button_link' => 'https://wordpress.org/plugins/wp-optimize/',
+ 'button_meta' => 'wp-optimize',
+ 'dismiss_time' => 'dismiss_notice',
+ 'supported_positions' => $this->anywhere,
+ 'validity_function' => 'wp_optimize_not_installed',
+ ),
+
+ // The sale adverts content starts here
+ 'blackfriday' => array(
+ 'prefix' => '',
+ 'title' => esc_html__('20% off - Black Friday Sale', 'all-in-one-wp-security-and-firewall'),
+ 'text' => $sale_description,
+ 'text2' => esc_html__('at checkout.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Hurry, offer ends 2 December.', 'all-in-one-wp-security-and-firewall') . '',
+ 'image' => 'notices/sale_20.png',
+ 'button_text' => sprintf(__('Save 20%% with code %s', 'all-in-one-wp-security-and-firewall'), 'blackfridaysale2025'),
+ 'button_link' => add_query_arg(
+ array(
+ 'utm_source' => 'aios-plugin',
+ 'utm_medium' => 'referral',
+ 'utm_campaign' => 'bf25-aios-plugin-banner',
+ 'utm_content' => 'bf-sale',
+ 'utm_creative_format' => 'advert',
+ ),
+ 'https://teamupdraft.com/plugin-black-friday/?utm_source=aios-plugin&utm_medium=referral&utm_campaign=bf25-aios-plugin-banner&utm_content=bf-sale&utm_creative_format=advert'),
+ 'campaign' => 'blackfriday',
+ 'button_meta' => 'inline',
+ 'dismiss_time' => 'dismiss_season',
+ // 'discount_code' => '‘bf22aiosupgrade’',
+ 'valid_from' => '2025-11-14 00:00:00',
+ 'valid_to' => '2025-12-02 23:59:59',
+ 'supported_positions' => $this->dashboard_top_or_report,
+ )
+ );
+
+ return array_merge($parent_notice_content, $child_notice_content);
+ }
+
+ /**
+ * Decides whether to show the automated database backup notice.
+ *
+ * @return Boolean True if the automated database notice should be shown, otherwise false.
+ */
+ protected function should_show_automated_database_backup_notice() {
+ if ($this->is_database_backup_admin_page_tab()) {
+ return false;
+ }
+
+ if (defined('AIOS_FORCE_AUTOMATED_DATABASE_BACKUP_NOTICE') && AIOS_FORCE_AUTOMATED_DATABASE_BACKUP_NOTICE) {
+ return true;
+ }
+
+ if ($this->is_updraftplus_plugin_active() && $this->is_schedule_database_backup_set_in_updraftplus()) {
+ return false;
+ }
+
+ global $aio_wp_security;
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_automated_backups')) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether to show the PHP 5.6 end of support notice
+ *
+ * @return boolean
+ */
+ protected function should_show_end_of_support_php_56() {
+ return version_compare(PHP_VERSION, '7.0.0', '<');
+ }
+
+ /**
+ * Gets the text to display with the PHP 5.6 end of support notice
+ *
+ * @return string
+ */
+ protected function get_end_of_support_php_56_text() {
+ $text = '
' . 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 .= '
';
+ }
+
+ $data = apply_filters('aiowp_security_generate_report_section_below', $data);
+
+ return $data;
+ }
+
+ /**
+ * Output the section data
+ *
+ * @param array $section_data Section data to output
+ *
+ * @return string Section data
+ */
+ private static function output_section_data($section_data = array()) {
+ $output = '';
+ foreach ($section_data as $key => $value) {
+ $output .= "$key - $value\n";
+ }
+ return $output;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-sender-service.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-sender-service.php
new file mode 100755
index 00000000..794a7600
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-sender-service.php
@@ -0,0 +1,29 @@
+configs->set_value('aiowps_enable_basic_firewall', '1', true);
+
+ //Now let's write the applicable rules to the .htaccess file
+ if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) {
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
+ } else {
+ $res = true;
+ }
+
+ if ($res) {
+ $msg['updated'] = __('Settings were successfully saved.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ /* translators: %s: .htaccess path */
+ $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');
+ }
+ return $msg;
+ }
+
+ /**
+ * Disable all security features.
+ *
+ * @return array messages
+ */
+ public static function disable_all_security_features() {
+ $msg = array();
+ AIOWPSecurity_Configure_Settings::turn_off_all_security_features();
+
+ //Now let's clear the applicable rules from the .htaccess file
+ if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) {
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
+ } else {
+ $res = true;
+ }
+
+ //Now let's revert the disable editing setting in the wp-config.php file if necessary
+ $res2 = AIOWPSecurity_Utility::enable_file_edits();
+
+ if ($res) {
+ $msg['updated'] = __('All the security features have been disabled successfully.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ /* translators: %s: .htaccess path */
+ $msg['error'][] = sprintf(__('Could not write to the %s file.', 'all-in-one-wp-security-and-firewall'), AIOWPSecurity_Utility_File::get_home_path().'.htaccess') . ' ' . sprintf(__('Please restore it manually using the restore functionality in the "%s" tab.', 'all-in-one-wp-security-and-firewall'), '.htaccess ' . __('file', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ if (!$res2) {
+ /* translators: %s: wp-config.php path */
+ $msg['error'][] = sprintf(__('Could not write to the %s file.', 'all-in-one-wp-security-and-firewall'), AIOWPSecurity_Utility_File::get_home_path().'wp-config.php') . ' ' . sprintf(__('Please restore it manually using the restore functionality in the "%s" tab.', 'all-in-one-wp-security-and-firewall'), 'wp-config.php ' . __('file', 'all-in-one-wp-security-and-firewall'));
+ }
+ return $msg;
+ }
+
+ /**
+ * Disable all firewall rules.
+ *
+ * @return array messages
+ */
+ public static function disable_all_firewall_rules() {
+ $msg = array();
+ AIOWPSecurity_Configure_Settings::turn_off_firewall_configs();
+
+ //Now let's clear the applicable rules from the .htaccess file
+ if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) {
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
+ } else {
+ $res = true;
+ }
+
+ if ($res) {
+ $msg['updated'] = __('All firewall rules have been disabled successfully.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ /* translators: %s: .htaccess path, %s file tab name. */
+ $msg['error'] = sprintf(__('Could not write to the %s file.', 'all-in-one-wp-security-and-firewall'), AIOWPSecurity_Utility_File::get_home_path().'.htaccess') . ' ' . sprintf(__('Please restore it manually using the restore functionality in the "%s" tab.', 'all-in-one-wp-security-and-firewall'), '.htaccess ' . __('file', 'all-in-one-wp-security-and-firewall'));
+ }
+ return $msg;
+ }
+
+ /**
+ * Reset all settings.
+ *
+ * @return array messages
+ */
+ public static function reset_all_settings() {
+ $msg = array();
+ if (!class_exists('AIOWPSecurity_Reset_Settings')) {
+ include(AIO_WP_SECURITY_PATH . '/admin/wp-security-reset-settings.php');
+ }
+ $reset_option_res = AIOWPSecurity_Reset_Settings::reset_options();
+ if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) {
+ $delete_htaccess = AIOWPSecurity_Reset_Settings::delete_htaccess();
+ } else {
+ $delete_htaccess = true;
+ }
+ AIOWPSecurity_Reset_Settings::reset_db_tables();
+ // AIOS premium and other plugin related config settings are reset by adding below action.
+ do_action('aios_reset_all_settings');
+
+ if (false === $reset_option_res && false === $delete_htaccess) {
+ $msg['error'] = __('Deletion of aio_wp_security_configs option and .htaccess directives failed.', 'all-in-one-wp-security-and-firewall');
+ } elseif (false === $reset_option_res) {
+ $msg['error'] = __('Reset of aio_wp_security_configs option failed.', 'all-in-one-wp-security-and-firewall');
+ } elseif (false === $delete_htaccess) {
+ $msg['error'] = __('Deletion of .htaccess directives failed.', 'all-in-one-wp-security-and-firewall');
+ } else {
+ $msg['updated'] = __('All settings have been successfully reset.', 'all-in-one-wp-security-and-firewall');
+ }
+ return $msg;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-two-factor-login.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-two-factor-login.php
new file mode 100755
index 00000000..91729b0b
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-two-factor-login.php
@@ -0,0 +1,201 @@
+is_incompatible_plugin_active()) return;
+
+ if (!function_exists('mcrypt_get_iv_size') && !function_exists('openssl_cipher_iv_length')) {
+ add_action('all_admin_notices', array($this, 'admin_notice_missing_mcrypt_and_openssl'));
+ return;
+ }
+
+ $this->is_tfa_integrated = true;
+
+ // Run at a priority ensuring that this will be after AIOS has registered its translation domain
+ add_action('init', array($this, 'plugin_text_domain_loaded'), 11);
+
+ add_action('admin_menu', array($this, 'menu_entry_for_user'), 30);
+ $this->version = AIO_WP_SECURITY_VERSION;
+ $this->set_user_settings_page_slug(AIOWPSEC_TWO_FACTOR_AUTH_MENU_SLUG);
+
+ $this->set_plugin_translate_url('https://translate.wordpress.org/projects/wp-plugins/all-in-one-wp-security-and-firewall/');
+ $this->set_site_wide_administration_url(admin_url('admin.php?page=aiowpsec_settings&tab=two-factor-authentication'));
+ $this->set_premium_version_url('https://teamupdraft.com/all-in-one-security/pricing/?utm_source=aios-plugin&utm_medium=referral&utm_campaign=paac&utm_content=emergency-codes-feature&utm_creative_format=text');
+ $this->set_faq_url('https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/#faq');
+ parent::__construct();
+ }
+
+ /**
+ * Runs upon the WP action init (once the text domain has been loaded)
+ */
+ public function plugin_text_domain_loaded() {
+ $this->set_settings_page_heading(__('Two factor authentication - Admin settings', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ /**
+ * Detect plugins that cause us to self-deactivate
+ *
+ * @return Boolean|String
+ */
+ private function is_incompatible_plugin_active() {
+
+ if (defined('WORDFENCE_LS_VERSION')) return 'Wordfence Login Security';
+
+ $active_plugins = $this->get_active_plugins();
+ foreach ($active_plugins as $plugin_file_rel_to_plugins_dir) {
+ $temp_plugin_file_name = substr($plugin_file_rel_to_plugins_dir, strpos($plugin_file_rel_to_plugins_dir, '/') + 1);
+ if ('wordfence-login-security.php' == $temp_plugin_file_name) {
+ return 'Wordfence Login Security';
+ }
+ if ('wordfence.php' == $temp_plugin_file_name) {
+ return 'Wordfence';
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets an array of plugins active on either the current site, or site-wide
+ *
+ * @return Array - a list of plugin paths (relative to the plugin directory)
+ */
+ private function get_active_plugins() {
+
+ // Gets all active plugins on the current site
+ $active_plugins = get_option('active_plugins');
+
+ if (is_multisite()) {
+ $network_active_plugins = get_site_option('active_sitewide_plugins');
+ if (!empty($network_active_plugins)) {
+ $network_active_plugins = array_keys($network_active_plugins);
+ $active_plugins = array_merge($active_plugins, $network_active_plugins);
+ }
+ }
+
+ return $active_plugins;
+ }
+
+ /**
+ * Runs upon the WP actions admin_menu and network_admin_menu
+ */
+ public function menu_entry_for_user() {
+
+ global $current_user;
+ if ($this->is_activated_for_user($current_user->ID)) {
+ if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ $menu_icon_url = AIO_WP_SECURITY_URL . '/images/aios-plugin-icon.svg';
+ add_menu_page(__('AIOS', 'all-in-one-wp-security-and-firewall'), __('AIOS', 'all-in-one-wp-security-and-firewall'), apply_filters('aios_management_permission', 'manage_options'), AIOWPSEC_MAIN_MENU_SLUG, '', $menu_icon_url);
+ }
+ add_submenu_page(AIOWPSEC_MAIN_MENU_SLUG, __('Two Factor Auth', 'all-in-one-wp-security-and-firewall'), __('Two Factor Auth', 'all-in-one-wp-security-and-firewall'), 'read', AIOWPSEC_TWO_FACTOR_AUTH_MENU_SLUG, array($this, 'show_dashboard_user_settings_page'));
+ }
+ }
+
+ /**
+ * AIOS settings based user IP address
+ *
+ * @return string IP address
+ */
+ public function aios_set_user_ip_address() {
+ return AIOS_Helper::get_user_ip_address();
+ }
+
+ /**
+ * Builds Two Factor Authentication tab
+ *
+ * @param array $tabs array that contain tab name and call back function
+ * @return array Returns all tabs with callback function name
+ */
+ public function add_two_factor_setting_tab($tabs = array()) {
+ if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) return;
+
+ $tabs['two-factor-authentication'] = array(
+ 'title' => __('Two factor authentication', 'all-in-one-wp-security-and-firewall'),
+ 'render_callback' => array($this, 'render_two_factor_authentication'),
+ 'display_condition_callback' => 'is_main_site',
+ );
+ return $tabs;
+ }
+
+ /**
+ * Display the Two Factor Authentication tab & handle the operations
+ */
+ public function render_two_factor_authentication() {
+ $plugin = $this->is_incompatible_plugin_active();
+ if (false !== $plugin) {
+ global $aio_wp_security;
+ $aio_wp_security->include_template('admin/incompatible-plugin.php', false, array(
+ 'incompatible_plugin' => $plugin,
+ ));
+ return;
+ }
+
+ $this->show_admin_settings_page();
+ }
+
+ /**
+ * Include the admin settings page code.
+ */
+ public function show_admin_settings_page() {
+
+ if (!is_admin() || !AIOWPSecurity_Utility_Permissions::has_manage_cap()) return;
+
+ // Check if there are any settings errors and display them (this is needed because the forms from this template submit to the TFA options page not AIOS, so we need to grab them and output them manually).
+ $settings_errors = get_settings_errors();
+ foreach ($settings_errors as $error) {
+ $type = 'success' == $error['type'] ? 'updated' : 'error';
+ $this->show_admin_warning($error['message'], $type);
+ }
+
+ // The value for totp_controller is already set by versions of the TFA plugin after 3 Oct 2022
+ $this->include_template('admin-settings.php', array(
+ 'totp_controller' => $this->get_controller('totp'),
+ 'settings_page_heading' => $this->get_settings_page_heading(),
+ 'admin_settings_links' => array(),
+ ));
+ }
+
+ /**
+ * Runs conditionally on the WP action all_admin_notices.
+ */
+ public function admin_notice_missing_mcrypt_and_openssl() {
+ $this->show_admin_warning(''.__('PHP OpenSSL or mcrypt module required', 'all-in-one-wp-security-and-firewall').' '.__('The All-In-One Security plugin\'s Two Factor Authentication module requires either the PHP openssl (preferred) or mcrypt module to be installed.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please ask your web hosting company to install one of them.', 'all-in-one-wp-security-and-firewall'), 'error');
+ }
+}
+
+if (false === AIOWPSecurity_Utility::is_incompatible_tfa_premium_version_active() && false === AIOWPSecurity_Utility::is_tfa_or_self_plugin_activating()) {
+ $GLOBALS['simba_two_factor_authentication'] = new AIO_WP_Security_Simba_Two_Factor_Authentication_Plugin();
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-uninstallation-tasks.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-uninstallation-tasks.php
new file mode 100755
index 00000000..8c70157b
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-uninstallation-tasks.php
@@ -0,0 +1,83 @@
+prefix.'aiowps_login_lockdown',
+ $wpdb->prefix.'aiowps_failed_logins',
+ $wpdb->prefix.'aiowps_login_activity',
+ $wpdb->prefix.'aiowps_global_meta',
+ $wpdb->prefix.'aiowps_events',
+ $wpdb->prefix.'aiowps_permanent_block',
+ $wpdb->prefix.'aiowps_debug_log',
+ $wpdb->prefix.'aiowps_audit_log',
+ $wpdb->prefix.'aiowps_logged_in_users',
+ $wpdb->prefix.'aiowps_message_store',
+ );
+
+ $aio_wp_security->configs->load_config();
+
+ // check and drop database tables
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_on_uninstall_delete_db_tables')) {
+ foreach ($database_tables as $table_name) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $wpdb->query("DROP TABLE IF EXISTS `$table_name`");
+ }
+ }
+
+ // check and delete configurations
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_on_uninstall_delete_configs')) {
+ if (is_main_site()) {
+ $firewall_rules_path = AIOWPSecurity_Utility_Firewall::get_firewall_rules_path();
+ AIOWPSecurity_Utility_File::remove_local_directory($firewall_rules_path);
+
+ delete_metadata('user', '0', 'aiowps_account_status', '', true);
+ delete_metadata('user', '0', 'aiowps_registrant_ip', '', true);
+ }
+
+ delete_option('aio_wp_security_configs');
+ delete_option('aiowpsec_db_version');
+ delete_option('aiowpsec_firewall_version');
+ delete_option('aios_antibot_key_map_info');
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-login.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-login.php
new file mode 100755
index 00000000..a809416d
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-login.php
@@ -0,0 +1,1022 @@
+key_login_msg = 'aiowps_login_msg_id';
+ // As a first authentication step, check if user's IP is locked.
+ add_filter('authenticate', array($this, 'block_ip_if_locked'), 1, 1);
+ // Check whether user needs to be manually approved after default WordPress authenticate hooks (with priority 20).
+ add_filter('authenticate', array($this, 'check_manual_registration_approval'), 30, 1);
+ // Check login CAPTCHA
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha')) {
+ add_filter('authenticate', array($this, 'check_captcha'), 20, 1);
+ }
+ // As a last authentication step, perform post authentication steps
+ add_filter('authenticate', array($this, 'post_authenticate'), 100, 3);
+ add_action('aiowps_force_logout_check', array($this, 'aiowps_force_logout_action_handler'));
+ add_action('wp_logout', array($this, 'wp_logout_action_handler'), 10, 1);
+ add_filter('login_message', array($this, 'aiowps_login_message')); //WP filter to add or modify messages on the login page
+
+ // Display disable lockdown message
+ if (is_admin() && AIOWPSecurity_Utility_Permissions::has_manage_cap() && $aio_wp_security->is_login_lockdown_by_const() && $this->is_admin_page_to_display_disable_login_lockdown_by_const_notice()) {
+ add_action('all_admin_notices', array($this, 'disable_login_lockdown_by_const_notice'));
+ }
+
+ add_action('set_auth_cookie', array($this, 'handle_logged_in_user'), 10, 4);
+
+ //cron job to remove expired users from logged_in table
+ add_action('delete_expired_logged_in_users_event', array($this, 'delete_expired_logged_in_users'));
+
+ add_filter('retrieve_password_message', array($this, 'aiowps_retrieve_password_message'), 10, 1);
+ }
+
+ /**
+ * Check whether the admin page is to display disable login lockdown by const notice.
+ *
+ * @return boolean True if the notice will be displayed, Otherwise false.
+ */
+ private function is_admin_page_to_display_disable_login_lockdown_by_const_notice() {
+ global $pagenow;
+ if (in_array($pagenow, array('index.php', 'plugins.php'))) {
+ return true;
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. Ignore.
+ } elseif (('admin.php' == $pagenow && isset($_GET['page']) && false !== strpos(sanitize_title(wp_unslash($_GET['page'])), AIOWPSEC_MENU_SLUG_PREFIX)) && !$this->is_locked_ip_addresses_tab_admin_page()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check whether the admin page is Locked IP Addresses Tab page.
+ *
+ * @return boolean True if is Locked IP Addresses Tab page, Otherwise false.
+ */
+ private function is_locked_ip_addresses_tab_admin_page() {
+ global $pagenow;
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ return ('admin.php' == $pagenow && isset($_GET['page']) && 'aiowpsec' == $_GET['page'] && isset($_GET['tab']) && 'locked-ip' == $_GET['tab']);
+ }
+
+ /**
+ * Displays admin to disable lockdown message.
+ *
+ * @return Void
+ */
+ public function disable_login_lockdown_by_const_notice() {
+
+ if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ return;
+ }
+
+ echo '
+
'.
+ 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') . ''
+ ).
+ '
+
';
+ }
+
+ /**
+ * Terminate the execution via wp_die with 503 status code, if current
+ * user's IP is currently locked.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @param WP_Error|WP_User $user
+ * @return WP_User
+ */
+ public function block_ip_if_locked($user) {
+ global $aio_wp_security;
+
+ // Allow users to login when disable AIOWPS_DISABLE_LOCK_DOWN defined true
+ if ($aio_wp_security->is_login_lockdown_by_const()) {
+ return $user;
+ }
+
+ $user_locked = $this->check_locked_user();
+ if (null != $user_locked) {
+ $aio_wp_security->debug_logger->log_debug("Login attempt from blocked IP range - ".$user_locked['failed_login_ip'], 2);
+ // Allow the error message to be filtered.
+ /* translators: %s: Error notification with strong HTML tag. */
+ $error_msg = apply_filters('aiowps_ip_blocked_error_msg', sprintf(__('%s: Access from your IP address has been blocked for security reasons.', 'all-in-one-wp-security-and-firewall'), '' . __('ERROR', 'all-in-one-wp-security-and-firewall') . '') . ' ' . __('Please contact the administrator.', 'all-in-one-wp-security-and-firewall'));
+ // If unlock requests are allowed, add the "Request Unlock" button to the message.
+ $unlock_form = '';
+ if ($aio_wp_security->configs->get_value('aiowps_allow_unlock_requests') == '1') {
+ $unlock_form = $this->get_unlock_request_form();
+ $error_msg .= $unlock_form;
+ }
+ $error_msg = apply_filters('aiowps_ip_blocked_output_page', $error_msg, $unlock_form); //filter the complete output of the locked page
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Can not escape form html inside $error_msg.
+ wp_die($error_msg, esc_html__('Service temporarily unavailable', 'all-in-one-wp-security-and-firewall'), 503);
+ } else {
+ return $user;
+ }
+ }
+
+ /**
+ * Check login CAPTCHA (if enabled).
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @param WP_Error|WP_User $user
+ * @return WP_Error|WP_User
+ */
+ public function check_captcha($user) {
+ global $aio_wp_security;
+ if (is_wp_error($user) || $aio_wp_security->is_login_lockdown_by_const()) {
+ // Authentication has failed already at some earlier step.
+ return $user;
+ }
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. No nonce.
+ if (! (isset($_POST['log']) && isset($_POST['pwd']))) {
+ // XML-RPC authentication (not via wp-login.php), nothing to do here.
+ return $user;
+ }
+
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') != '1') {
+ // CAPTCHA not enabled, nothing to do here.
+ return $user;
+ }
+
+ /* translators: %s: Error notification with strong HTML tag. */
+ $captcha_error = new WP_Error('authentication_failed', sprintf(__('%s: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'), '' . __('ERROR', 'all-in-one-wp-security-and-firewall') . ''));
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ return $captcha_error;
+ }
+ return $user;
+ }
+
+ /**
+ * Check, whether $user needs to be manually approved by site admin yet.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @param WP_Error|WP_User $user
+ * @return WP_Error|WP_User
+ */
+ public function check_manual_registration_approval($user) {
+ global $aio_wp_security;
+ if (!($user instanceof WP_User)) {
+ // Not a WP_User - nothing to do here.
+ return $user;
+ }
+ //Check if auto pending new account status feature is enabled
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
+ $aiowps_account_status = get_user_meta($user->ID, 'aiowps_account_status', true);
+ if ('pending' == $aiowps_account_status) {
+ // Account needs to be activated yet
+ /* translators: %s: Notification with strong HTML tag. */
+ return new WP_Error('account_pending', sprintf(__('%s: Your account is currently not active.', 'all-in-one-wp-security-and-firewall'), '' . __('ACCOUNT PENDING', 'all-in-one-wp-security-and-firewall') . '') . ' '. __('An administrator needs to activate your account before you can login.', 'all-in-one-wp-security-and-firewall'));
+ }
+ }
+ return $user;
+ }
+
+ /**
+ * Handle post authentication steps (in case of failed login):
+ * - increment number of failed logins for $username
+ * - (optionally) lock the user
+ * - (optionally) display a generic error message
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @param WP_Error|WP_User $user
+ * @param string $username
+ * @param string $password
+ * @return WP_Error|WP_User
+ */
+ public function post_authenticate($user, $username, $password) {
+ global $aio_wp_security;
+ if (!is_wp_error($user)) {
+ // Authentication has been successful, there's nothing to do here.
+ return $user;
+ }
+ if (empty($username) || empty($password)) {
+ // Neither log nor block login attempts with empty username or password.
+ return $user;
+ }
+ if ($user->get_error_code() === 'account_pending') {
+ // Neither log nor block users attempting to log in before their registration is approved.
+ return $user;
+ }
+ // Login failed for non-trivial reason
+ AIOWPSecurity_Audit_Events::event_failed_login($username);
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_lockdown') == '1') {
+ $is_whitelisted = false;
+ //check if lockout whitelist enabled
+ if ($aio_wp_security->configs->get_value('aiowps_lockdown_enable_whitelisting') == '1') {
+ $whitelisted_ips = $aio_wp_security->configs->get_value('aiowps_lockdown_allowed_ip_addresses');
+ $is_whitelisted = AIOWPSecurity_Utility_IP::is_userip_whitelisted($whitelisted_ips);
+ }
+
+ if (false === $is_whitelisted) {
+ // Too many failed logins from user's IP?
+ $login_attempts_permitted = absint($aio_wp_security->configs->get_value('aiowps_max_login_attempts'));
+ $too_many_failed_logins = $login_attempts_permitted <= $this->get_login_fail_count();
+
+ // Is an invalid username or email the reason for login error?
+ $invalid_username = ($user->get_error_code() === 'invalid_username' || $user->get_error_code() == 'invalid_email');
+ // Should an invalid username be immediately locked?
+ $invalid_username_lockdown = $aio_wp_security->configs->get_value('aiowps_enable_invalid_username_lockdown') == '1';
+ $lock_invalid_username = $invalid_username && $invalid_username_lockdown;
+
+ // Should an invalid username be blocked as per blacklist?
+ $instant_lockout_users_list = $aio_wp_security->configs->get_value('aiowps_instantly_lockout_specific_usernames');
+ if (!is_array($instant_lockout_users_list)) {
+ $instant_lockout_users_list = array();
+ }
+ $username_blacklisted = $invalid_username && in_array($username, $instant_lockout_users_list);
+
+ $lock_reasons = array();
+ if ($too_many_failed_logins) {
+ $lock_reasons[] = 'too_many_failed_logins';
+ }
+ if ($lock_invalid_username) {
+ $lock_reasons[] = 'invalid_username';
+ }
+ if ($username_blacklisted) {
+ $lock_reasons[] = 'username_blacklisted';
+ }
+ if ($lock_reasons) {
+ $this->lock_the_user($username, implode(',', $lock_reasons));
+ }
+ }
+ }
+
+ if ($aio_wp_security->configs->get_value('aiowps_set_generic_login_msg') == '1') {
+ // Return generic error message if configured
+ return new WP_Error('authentication_failed', __('ERROR: Invalid login credentials.', 'all-in-one-wp-security-and-firewall'));
+ }
+ return $user;
+ }
+ /**
+ * This function queries the aiowps_login_lockdown table.
+ * If the release_date has not expired AND the current visitor IP addr matches
+ * it will return a record
+ */
+ public function check_locked_user() {
+ global $wpdb;
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
+ if (empty($ip)) return false;
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $locked_user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $login_lockdown_table WHERE `released` > UNIX_TIMESTAMP() AND `failed_login_ip` = %s", $ip), ARRAY_A);
+ return $locked_user;
+ }
+ /**
+ * This function queries the aiowps_audit_log table and returns the number of failures for current IP range within allowed failure period
+ */
+ public function get_login_fail_count() {
+
+ global $wpdb, $aio_wp_security;
+
+ $audit_log_table = AIOWPSEC_TBL_AUDIT_LOG;
+ $login_retry_interval = $aio_wp_security->configs->get_value('aiowps_retry_time_period') * 60;
+ $now = time();
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); // Get the users IP address
+
+ if (empty($ip)) return false;
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $login_failures = $wpdb->get_var("SELECT COUNT(ID) FROM $audit_log_table " . "WHERE created + " . esc_sql($login_retry_interval) . " > '" . esc_sql($now) . "' AND " . "ip = '" . esc_sql($ip) . "' AND event_type = 'failed_login'");
+ return $login_failures;
+ }
+
+ /**
+ * Get lockout time dynamically multiplied with default lockout time
+ *
+ * @return Integer get lockout time length.
+ */
+ public function get_dynamic_lockout_time_length() {
+ global $aio_wp_security;
+
+ $login_fail_count = $this->get_login_fail_count();
+ $lockout_time_default = $aio_wp_security->configs->get_value('aiowps_lockout_time_length');
+ if (!is_numeric($lockout_time_default)) {
+ $lockout_time_default = 5;
+ }
+ $lockout_time_max = $aio_wp_security->configs->get_value('aiowps_max_lockout_time_length');
+ if (!is_numeric($lockout_time_max)) {
+ $lockout_time_max = 60;
+ }
+ $lockout_time_length = (int) ($login_fail_count > 0 ? (3 * $lockout_time_default * ($login_fail_count + 1)) : $lockout_time_default);
+
+ return $lockout_time_length >= $lockout_time_max ? $lockout_time_max : $lockout_time_length;
+ }
+
+ /**
+ * Adds an entry to the `aiowps_login_lockdown` table.
+ *
+ * @param string $username User's username or email
+ * @param string $lock_reason
+ * @param bool $is_lockout_email_sent flag for lockout email send
+ */
+ public function lock_the_user($username, $lock_reason = 'login_fail', $is_lockout_email_sent = 0) {
+ global $aio_wp_security;
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ $lock_minutes = $this->get_dynamic_lockout_time_length();
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
+ if (empty($ip)) return;
+ $ip_range = AIOWPSecurity_Utility_IP::get_sanitized_ip_range($ip); //Get the IP range of the current user
+ $user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username); //Returns WP_User object if exists
+ $ip_range = apply_filters('aiowps_before_lockdown', $ip_range);
+ if ($user) {
+ //If the login attempt was made using a valid user set variables for DB storage later on
+ $user_id = $user->ID;
+ } else {
+ //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
+ $user_id = 0;
+ }
+
+ $lock_time = current_time('mysql', true);
+ $date = new DateTime($lock_time);
+ $add_interval = 'PT'.absint($lock_minutes).'M';
+ $date->add(new DateInterval($add_interval));
+ $release_time = $date->format('Y-m-d H:i:s');
+ $backtrace_log = '';
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_php_backtrace_in_email')) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace, PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection -- PCP and compatibility warnings. Safe to ignore.
+ $backtrace_log = AIOWPSecurity_Utility::normalise_call_stack_args(debug_backtrace());
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- PCP warning. Ignore.
+ $backtrace_log = print_r($backtrace_log, true);
+ }
+ $is_lockout_email_sent = (1 == $aio_wp_security->configs->get_value('aiowps_enable_email_notify') ? 0 : -1);
+ $ip_lookup_result = AIOS_Helper::get_ip_reverse_lookup($ip);
+ $ip_lookup_result = wp_json_encode($ip_lookup_result);
+ if (false === $ip_lookup_result) $ip_lookup_result = null;
+
+ $lock_seconds = $lock_minutes * MINUTE_IN_SECONDS;
+
+ $data = array(
+ 'user_id' => $user_id,
+ 'user_login' => $username,
+ 'lockdown_date' => $lock_time,
+ 'release_date' => $release_time,
+ 'failed_login_IP' => $ip,
+ 'lock_reason' => $lock_reason,
+ 'is_lockout_email_sent' => $is_lockout_email_sent,
+ 'backtrace_log' => $backtrace_log,
+ 'ip_lookup_result' => $ip_lookup_result,
+ 'lock_seconds' => $lock_seconds
+ );
+
+ $result = AIOWPSecurity_Utility::add_lockout($data);
+
+ if (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_lockdown_table, 4);
+ } else {
+ do_action('aiowps_lockdown_event', $ip_range, $username);
+ $aio_wp_security->debug_logger->log_debug("The following IP address range has been locked out for exceeding the maximum login attempts: ".$ip_range, 2);
+ }
+ }
+
+ /**
+ * Send IP Lock notification.
+ *
+ * @param Array $lockout_ips_list have username, ip_range, ip
+ * @param String $backtrace_filepath
+ *
+ * @return Boolean True if mail sent otherwise false.
+ */
+ private function send_ip_lock_notification_email($lockout_ips_list = array(), $backtrace_filepath = '') {
+ global $aio_wp_security;
+ $send_mail = false;
+ if (0 != count($lockout_ips_list)) {
+ $email_notification_enabled = $aio_wp_security->configs->get_value('aiowps_enable_email_notify');
+ if (1 == $email_notification_enabled) {
+ $to_email_address = AIOWPSecurity_Utility::get_array_from_textarea_val($aio_wp_security->configs->get_value('aiowps_email_address'));
+ if (empty($to_email_address)) {
+ $to_email_address = array(get_site_option('admin_email'));
+ }
+ $subject = '['.get_option('home').'] '. __('Site Lockout Notification', 'all-in-one-wp-security-and-firewall');
+ $email_msg = __('User login lockout events had occurred due to too many failed login attempts or invalid username:', 'all-in-one-wp-security-and-firewall')."\n\n";
+
+ foreach ($lockout_ips_list as $lockout_ip) {
+ /* translators: %s: User name. */
+ $email_msg .= sprintf(__('Username: %s', 'all-in-one-wp-security-and-firewall'), $lockout_ip['username']) . "\n";
+
+ /* translators: %s: IP Address. */
+ $email_msg .= sprintf(__('IP address: %s', 'all-in-one-wp-security-and-firewall'), $lockout_ip['ip']) . "\n";
+ if ('' != $lockout_ip['ip_range']) {
+ /* translators: %s: IP Range. */
+ $email_msg .= sprintf(__('IP range: %s', 'all-in-one-wp-security-and-firewall'), $lockout_ip['ip_range']) . '.*' . "\n";
+ }
+ if (!empty($lockout_ip['ip_lookup_result'])) {
+ $ip_lookup_result = json_decode($lockout_ip['ip_lookup_result'], true);
+
+ $org = empty($ip_lookup_result['org']) ? __('Not Found', 'all-in-one-wp-security-and-firewall') : $ip_lookup_result['org'];
+ $as = empty($ip_lookup_result['as']) ? __('Not Found', 'all-in-one-wp-security-and-firewall') : $ip_lookup_result['as'];
+
+ /* translators: %s: Org. */
+ $email_msg .= sprintf(__('Org: %s', 'all-in-one-wp-security-and-firewall'), $org) . "\n";
+ /* translators: %s: AS. */
+ $email_msg .= sprintf(__('AS: %s', 'all-in-one-wp-security-and-firewall'), $as) . "\n";
+
+ $email_msg = apply_filters('aiowps_login_lockdown_email_message', $email_msg, $ip_lookup_result);
+ }
+ $email_msg .= "\n";
+ }
+
+ $email_msg .= __("Log into your site WordPress administration panel to see the duration of the lockout or to unlock the user.", 'all-in-one-wp-security-and-firewall') . "\n";
+
+ $email_header = '';
+ $send_mail = wp_mail($to_email_address, $subject, $email_msg, $email_header, $backtrace_filepath);
+
+ if (false === $send_mail) {
+ $ips_list = implode(', ', wp_list_pluck($lockout_ips_list, 'ip'));
+ $aio_wp_security->debug_logger->log_debug("Lockout notification email failed to send to " . implode(', ', $to_email_address) . " for IPs ".$ips_list, 4);
+ }
+ }
+ }
+ return $send_mail;
+ }
+
+ /**
+ * Generates and returns an unlock request link which will be used to send to the user.
+ *
+ * @global type $wpdb
+ * @global AIO_WP_Security $aio_wp_security
+ * @param type $ip_range
+ * @return string or false on failure
+ */
+ public static function generate_unlock_request_link($ip_range) {
+ //Get the locked user row from locout table
+ global $wpdb, $aio_wp_security;
+ $unlock_link = '';
+ $lockout_table_name = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ $secret_rand_key = (md5(uniqid(wp_rand(), true)));
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP wanting. Ignore.
+ $res = $wpdb->query($wpdb->prepare("UPDATE $lockout_table_name SET unlock_key = %s WHERE released > UNIX_TIMESTAMP() AND failed_login_ip LIKE %s", $secret_rand_key, "%" . esc_sql($ip_range) . "%"));
+ if (null == $res) {
+ $aio_wp_security->debug_logger->log_debug("No locked user found with IP range ".$ip_range, 4);
+ return false;
+ } else {
+ // Check if unlock request or submitted from a WooCommerce account login page
+ if (isset($_POST['aiowps-woo-login'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. No nonce.
+ $date_time = current_time('mysql');
+ $data = array('date_time' => $date_time, 'meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $secret_rand_key);
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
+ // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder, WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare("INSERT INTO ".$aiowps_global_meta_tbl_name." (date_time, meta_key1, meta_value1, created) VALUES ('%s', '%s', '%s', UNIX_TIMESTAMP())", $data['date_time'], $data['meta_key1'], $data['meta_value1']);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $result = $wpdb->query($sql);
+ if (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("generate_unlock_request_link() - Error inserting woo_unlock_request_key to AIOWPSEC_TBL_GLOBAL_META_DATA table for secret key ".$secret_rand_key, 4);
+ }
+ }
+ $query_param = array('aiowps_auth_key' => $secret_rand_key);
+ $wp_site_url = AIOWPSEC_WP_URL;
+ $unlock_link = esc_url(add_query_arg($query_param, $wp_site_url));
+ }
+ return $unlock_link;
+ }
+
+ /**
+ * This function will process an unlock request when someone clicks on the special URL
+ * It will check if the special random code matches that in lockdown table for the relevant user
+ * If so, it will unlock the user
+ *
+ * @param string $unlock_key
+ * @return void
+ */
+ public static function process_unlock_request($unlock_key) {
+ global $wpdb, $aio_wp_security;
+ $lockout_table_name = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $unlock_command = $wpdb->prepare("UPDATE ".$lockout_table_name." SET released = UNIX_TIMESTAMP() WHERE unlock_key = %s", $unlock_key);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $result = $wpdb->query($unlock_command);
+ if (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("Error unlocking user with unlock_key ".$unlock_key, 4);
+ } else {
+ // Now check if this unlock operation is for a WooCommerce login
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1=%s AND meta_value1=%s", 'woo_unlock_request_key', $unlock_key);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $woo_result = $wpdb->get_row($sql, OBJECT);
+ if (empty($woo_result)) {
+ $woo_unlock = false;
+ } else {
+ $woo_unlock = true;
+ }
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')=='1') {
+ if (get_option('permalink_structure')) {
+ $home_url = trailingslashit(home_url());
+ } else {
+ $home_url = trailingslashit(home_url()) . '?';
+ }
+ if ($woo_unlock) {
+ $login_url = wc_get_page_permalink('myaccount'); //redirect to woo login page if applicable
+ //Now let's cleanup after ourselves and delete the woo-related row in the AIOWPSEC_TBL_GLOBAL_META_DATA table
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore
+ $delete = $wpdb->delete($aiowps_global_meta_tbl_name, array('meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $unlock_key));
+ if (false === $delete) {
+ $aio_wp_security->debug_logger->log_debug("process_unlock_request(): Error deleting row from AIOWPSEC_TBL_GLOBAL_META_DATA for meta_key1=woo_unlock_request_key and meta_value1=".$unlock_key, 4);
+ }
+ } else {
+ $login_url = $home_url.$aio_wp_security->configs->get_value('aiowps_login_page_slug');
+ }
+
+ AIOWPSecurity_Utility::redirect_to_url($login_url);
+ } else {
+ AIOWPSecurity_Utility::redirect_to_url(wp_login_url());
+ }
+ }
+ }
+
+ /**
+ * This function sends an unlock request email to a locked out user
+ *
+ * @param string $email
+ * @param string $unlock_link
+ * @return void
+ */
+ public static function send_unlock_request_email($email, $unlock_link) {
+ global $aio_wp_security;
+ $subject = '['.network_site_url().'] '. __('Unlock request notification', 'all-in-one-wp-security-and-firewall');
+ /* translators: 1: Email 2: Link */
+ $email_msg = sprintf(__('You have requested for the account with email address %s to be unlocked.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please press the link below to unlock your account:', 'all-in-one-wp-security-and-firewall'), $email) . "\n" . sprintf(__('Unlock link: %s', 'all-in-one-wp-security-and-firewall'), $unlock_link) . "\n\n" . __('After pressing the above link you will be able to login to the WordPress administration panel.', 'all-in-one-wp-security-and-firewall') . "\n";
+
+ $sendMail = wp_mail($email, $subject, $email_msg);
+ if (false === $sendMail) {
+ $aio_wp_security->debug_logger->log_debug("Unlock Request Notification email failed to send to " . $email, 4);
+ }
+ }
+
+ /**
+ * Check the settings and log the user after the configured time period
+ *
+ * @param bool $return_url Optional. If true, the function returns the logout URL with a nonce.
+ * Otherwise, it redirects to the logout URL. Default is false.
+ *
+ * @return void|string
+ */
+ public function aiowps_force_logout_action_handler($return_url = false) {
+ global $aio_wp_security;
+ //$aio_wp_security->debug_logger->log_debug("Force Logout - Checking if any user need to be logged out...");
+ //if this feature is enabled then do something
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_forced_logout')) {
+ if (is_user_logged_in()) {
+ $current_user = wp_get_current_user();
+ $user_id = $current_user->ID;
+ $current_time = current_time('mysql', true);
+ $login_time = $this->get_wp_user_aiowps_last_login_time($user_id);
+ if (empty($login_time)) {
+ return;
+ }
+ $diff = strtotime($current_time) - strtotime($login_time);
+ $logout_time_interval_value = $aio_wp_security->configs->get_value('aiowps_logout_time_period');
+ $logout_time_interval_val_seconds = $logout_time_interval_value * 60;
+ if ($diff > $logout_time_interval_val_seconds) {
+ $aio_wp_security->debug_logger->log_debug("Force Logout - This user logged in more than (".$logout_time_interval_value.") minutes ago. Doing a force log out for the user with username: ".$current_user->user_login);
+ $this->wp_logout_action_handler($user_id); //this will register the logout time/date in the logout_date column
+
+
+ $curr_page_url = AIOWPSecurity_Utility::get_current_page_url();
+ $after_logout_payload = array('redirect_to' => $curr_page_url, 'msg' => $this->key_login_msg.'=session_expired');
+ //Save some of the logout redirect data to a transient
+ is_multisite() ? set_site_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60) : set_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60);
+ $logout_url = AIOWPSEC_WP_URL.'?aiowpsec_do_log_out=1';
+ $logout_url = AIOWPSecurity_Utility::add_query_data_to_url($logout_url, 'al_additional_data', '1');
+ $logout_url_with_nonce = html_entity_decode(wp_nonce_url($logout_url, 'aio_logout'));
+ if ($return_url) {
+ return $logout_url_with_nonce;
+ }
+ AIOWPSecurity_Utility::redirect_to_url($logout_url_with_nonce);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get last logged in time of given user id.
+ *
+ * @param integer $user_id
+ * @return mixed Last login time. False for an invalid $user_id (non-numeric, zero, or negative value). An empty string if a valid but non-existing user ID is passed.
+ */
+ public function get_wp_user_aiowps_last_login_time($user_id) {
+ $last_login = apply_filters('aiowps_get_last_login_time', get_user_meta($user_id, 'aiowps_last_login_time', true), $user_id);
+ return $last_login;
+ }
+
+ /**
+ * Updates the last login time in user meta, the login activity table.
+ *
+ * @global wpdb $wpdb
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @param string $user_login
+ * @param WP_User $user
+ *
+ * @return void
+ */
+ private static function update_login_activity($user_login, $user) {
+ AIOWPSecurity_Audit_Events::event_successful_login($user_login);
+ $login_date_time = current_time('mysql', true);
+
+ update_user_meta($user->ID, 'aiowps_last_login_time', $login_date_time); //store last login time in meta table
+ }
+
+ /**
+ * Remove the last login time for all users from meta table on deactivation.
+ *
+ * @return void
+ */
+ public static function remove_login_activity() {
+ delete_metadata('user', '0', 'aiowps_last_login_time', '', true); //remove from meta table for all users last login time
+ }
+
+ public static function wp_login_action_handler($user_login, $user = '') {
+ global $aio_wp_security;
+
+ if ('' == $user) {
+ //Try and get user object
+ $user = get_user_by('login', $user_login); //This should return WP_User obj
+ if (!$user) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_User_Login::wp_login_action_handler: Unable to get WP_User object for login ".$user_login, 4);
+ return;
+ }
+ }
+
+ if (is_super_admin($user->ID)) {
+ $logging_into_correct_site = true;
+ } else {
+ $user_sites = get_blogs_of_user($user->ID);
+
+ $current_site_id = get_current_blog_id();
+
+ $logging_into_correct_site = false;
+
+ foreach ($user_sites as $site) {
+ if ($site->userblog_id == $current_site_id) {
+ $logging_into_correct_site = true;
+ break;
+ }
+ }
+ }
+
+ if ($logging_into_correct_site) {
+ self::update_login_activity($user_login, $user);
+ } else {
+ $user_primary_site = get_active_blog_for_user($user->ID);
+ switch_to_blog($user_primary_site->blog_id);
+ self::update_login_activity($user_login, $user);
+
+ restore_current_blog();
+ }
+ }
+
+ /**
+ * Handles logout events and modifies the login activity record for the current user.
+ *
+ * @param int $user_id - ID of user logging out
+ * @param boolean $force_logout - if user is force logged out
+ *
+ * @return void
+ */
+ public function wp_logout_action_handler($user_id, $force_logout = false) {
+ global $aio_wp_security;
+ $user = get_userdata($user_id);
+
+ if (false === $user) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_User_Login::wp_logout_action_handler: Unable to get WP_User object", 4);
+ return;
+ }
+
+ $this->delete_logged_in_user($user->ID);
+
+ if (is_super_admin($user->ID)) {
+ $logging_out_of_correct_site = true;
+ } else {
+ $user_sites = get_blogs_of_user($user->ID);
+
+ $current_site_id = get_current_blog_id();
+
+ $logging_out_of_correct_site = false;
+
+ foreach ($user_sites as $site) {
+ if ($site->userblog_id == $current_site_id) {
+ $logging_out_of_correct_site = true;
+ break;
+ }
+ }
+ }
+
+ if ($logging_out_of_correct_site) {
+ AIOWPSecurity_Audit_Events::event_successful_logout($user->user_login, $force_logout);
+ } else {
+ $user_primary_site = get_active_blog_for_user($user->ID);
+ switch_to_blog($user_primary_site->blog_id);
+ AIOWPSecurity_Audit_Events::event_successful_logout($user->user_login, $force_logout);
+
+ restore_current_blog();
+ }
+ }
+
+ /**
+ * The handler for the WP "login_message" filter
+ * Adds custom messages to the other messages that appear above the login form.
+ *
+ * NOTE: This method is automatically called by WordPress for displaying
+ * text above the login form.
+ *
+ * @param string $message the output from earlier login_message filters
+ * @return string
+ */
+ public function aiowps_login_message($message = '') {
+ global $aio_wp_security;
+ $msg = '';
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce.
+ if (isset($_GET[$this->key_login_msg]) && !empty($_GET[$this->key_login_msg])) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce.
+ $logout_msg = wp_strip_all_tags(sanitize_title(wp_unslash($_GET[$this->key_login_msg])));
+ }
+ if (!empty($logout_msg)) {
+ switch ($logout_msg) {
+ case 'session_expired':
+ /* translators: %s: Minute count */
+ $msg = sprintf(__('Your session has expired because it has been over %d minutes since your last login.', 'all-in-one-wp-security-and-firewall'), $aio_wp_security->configs->get_value('aiowps_logout_time_period'));
+ $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
+ break;
+ case 'admin_user_changed':
+ $msg = __('You were logged out because you just changed the "admin" username.', 'all-in-one-wp-security-and-firewall');
+ $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
+ break;
+ default:
+ }
+ }
+ if (!empty($msg)) {
+ $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
+ $message .= '
'. $msg . '
';
+ }
+ return $message;
+ }
+ /**
+ * This function will generate an unlock request form to be inserted inside
+ * error message when user gets locked out.
+ *
+ * @return string
+ */
+ public function get_unlock_request_form() {
+ global $aio_wp_security;
+ $unlock_request_form = '';
+ //Let's encode some hidden data and make a form
+ $unlock_secret_string = $aio_wp_security->configs->get_value('aiowps_unlock_request_secret_key');
+ $current_time = time();
+ $enc_result = base64_encode($current_time.$unlock_secret_string);
+ $unlock_request_form .= '';
+ return $unlock_request_form;
+ }
+
+ /**
+ * Returns all logged in users for specific subsite of multisite installation.
+ *
+ * @param bool $sitewide - checks if logged in users should be fetched sitewide
+ *
+ * @return array
+ */
+ public static function get_logged_in_users($sitewide = true) {
+ global $wpdb;
+
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+ if ($sitewide) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $users_online = $wpdb->get_results("SELECT * FROM `{$logged_in_users_table}`", 'ARRAY_A');
+ } else {
+ $current_blog_id = get_current_blog_id();
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $users_online = $wpdb->get_results($wpdb->prepare("SELECT * FROM `{$logged_in_users_table}` WHERE site_id = %d", $current_blog_id), 'ARRAY_A');
+ }
+
+ if (empty($users_online)) return array();
+
+ return $users_online;
+ }
+
+ /**
+ * Send email notification to an user that has flag is_lockout_email_sent is 0.
+ *
+ * @return Void
+ */
+ public function send_login_lockout_emails() {
+ global $wpdb, $aio_wp_security;
+ // if user enabled notification email then only have to send
+ $email_notification_enabled = $aio_wp_security->configs->get_value('aiowps_enable_email_notify');
+ if (0 == $email_notification_enabled) {
+ return;
+ }
+ // get recent lockout records on top to notify
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required.
+ $sql = $wpdb->prepare('SELECT id, user_login, failed_login_ip, backtrace_log, ip_lookup_result FROM ' .AIOWPSEC_TBL_LOGIN_LOCKOUT. ' WHERE is_lockout_email_sent = %d ORDER BY id DESC', 0);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $result = $wpdb->get_results($sql);
+ if (empty($result)) {
+ return;
+ }
+ $login_lockout_ids_send_emails = array();
+ $lockout_ips_backtrace_log = array();
+ $lockout_ips_list = array();
+ $backtrace_filepath = '';
+ foreach ($result as $row) {
+ $ip_range = AIOWPSecurity_Utility_IP::get_sanitized_ip_range($row->failed_login_ip);
+ $lockout_ips_list[] = array('username' => $row->user_login, 'ip' => $row->failed_login_ip, 'ip_range' => $ip_range, 'ip_lookup_result' => $row->ip_lookup_result);
+ $login_lockout_ids_send_emails[] = $row->id;
+ if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_php_backtrace_in_email') && '' != $row->backtrace_log) {
+ $lockout_ips_backtrace_log[] = array('backtrace_log' => $row->backtrace_log);
+ }
+ }
+
+ if (0 != count($lockout_ips_backtrace_log)) {
+ $backtrace_filepath = AIOWPSecurity_Utility::login_lockdown_email_backtrace_log_file($lockout_ips_backtrace_log);
+ }
+
+ $this->send_ip_lock_notification_email($lockout_ips_list, $backtrace_filepath);
+
+ if ('' != $backtrace_filepath) {
+ wp_delete_file($backtrace_filepath);
+ }
+
+ if (!empty($login_lockout_ids_send_emails)) {
+ $aio_wp_security->debug_logger->log_debug(sprintf('The IP lock notification emails of login lockout ids [%s] are sent.', implode(', ', $login_lockout_ids_send_emails)), 4);
+ // update all email to as sent.
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare('UPDATE '.AIOWPSEC_TBL_LOGIN_LOCKOUT.' SET is_lockout_email_sent = %d WHERE is_lockout_email_sent = %d', 1, 0);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
+ $update_result = $wpdb->query($sql);
+ if (false === $update_result) {
+ $error_msg = empty($wpdb->last_error) ? 'Could not receive the reason for the failure' : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug_cron("Lockout email flag is not updated in database due to error: {$error_msg}", 4);
+ }
+ }
+ }
+
+ /**
+ * Stores logged-in user in the logged_in_user table
+ *
+ * @param int $user_id - id of user logging in
+ * @param int $expiration - expiration timestamp of cookie
+ *
+ * @return void
+ */
+ public function store_logged_in_user($user_id, $expiration) {
+ global $wpdb, $aio_wp_security;
+
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+ $ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
+ $userdata = get_userdata($user_id);
+ $username = $userdata->user_login;
+ $login_time = time();
+
+ // Check if a record with the given user_id already exists
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $existing_record = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . $logged_in_users_table . " WHERE user_id = %d", $user_id));
+
+ if ($existing_record) {
+ // Update the existing record
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $result = $wpdb->update(
+ $logged_in_users_table,
+ array(
+ 'ip_address' => $ip_address,
+ 'site_id' => get_current_blog_id(),
+ 'username' => $username,
+ 'expires' => $expiration
+ ),
+ array('user_id' => $user_id)
+ );
+ } else {
+ // Create a new record
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $result = $wpdb->insert(
+ $logged_in_users_table,
+ array(
+ 'user_id' => $user_id,
+ 'ip_address' => $ip_address,
+ 'expires' => $expiration,
+ 'site_id' => get_current_blog_id(),
+ 'username' => $username,
+ 'created' => $login_time
+ )
+ );
+ }
+
+ if (false === $result) {
+ $generic_error_message = $existing_record ? "Error updating record in " . $logged_in_users_table : "Error inserting record into ".$logged_in_users_table;
+ $error_message = empty($wpdb->last_error) ? $generic_error_message : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug($error_message, 4);
+ }
+ }
+
+ /**
+ * Handles the data coming from the 'set_auth_cookie' hook
+ *
+ * @param string $auth_cookie - the generated auth_cookie
+ * @param int $expire - expiration timestamp of cookie if remember is marked
+ * @param int $expiration - expiration timestamp of cookie
+ * @param int $user_id - id of user logging in
+ *
+ * @return void
+ */
+ public function handle_logged_in_user($auth_cookie, $expire, $expiration, $user_id) {
+
+ if (empty($auth_cookie)) return; //check if auth cookie is empty, meaning login was not successful
+ $expiration = $expire > 0 ? $expire : $expiration;
+
+ if (is_multisite() && !is_super_admin()) {
+ $user_blog = get_active_blog_for_user($user_id);
+ switch_to_blog($user_blog->blog_id); // switch to user blog incase they try to log in from wrong subsite
+
+ $this->store_logged_in_user($user_id, $expiration);
+ restore_current_blog();
+ } else {
+ $this->store_logged_in_user($user_id, $expiration);
+ }
+ }
+
+ /**
+ * Deletes logged-in user from the logged_in_user table
+ *
+ * @param int $user_id
+ * @return bool
+ */
+ public function delete_logged_in_user($user_id) {
+ global $wpdb, $aio_wp_security;
+
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+
+ if (empty($user_id)) return true;
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $result = $wpdb->delete(
+ $logged_in_users_table,
+ array('user_id' => $user_id)
+ );
+
+
+ if (false === $result) {
+ $error_message = empty($wpdb->last_error) ? "Error deleting record from " . $logged_in_users_table : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug($error_message, 4);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Cron job function for removing data with expired session from the logged-in user table
+ *
+ * @return void
+ */
+ public function delete_expired_logged_in_users() {
+ global $wpdb, $aio_wp_security;
+ $logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
+
+ // Delete data with expired cookie
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query required,
+ $result = $wpdb->query(
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $wpdb->prepare("DELETE FROM " . $logged_in_users_table . " WHERE expires < %d", time())
+ );
+
+ if (false === $result) {
+ $error_message = empty($wpdb->last_error) ? "Error deleting records from ".$logged_in_users_table : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug($error_message, 4);
+ }
+ }
+
+ /**
+ * This function rewrites the password reset message
+ *
+ * @param string $message - The password reset email message to be edited
+ *
+ * @return string - Email message to be sent for password reset
+ */
+ public function aiowps_retrieve_password_message($message) {
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
+
+ // Find the position of the IP Address string in the message
+ $ip_string = isset($_SERVER['REMOTE_ADDR']) ? rest_is_ip_address(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
+ $ip_pos = strpos($message, $ip_string);
+
+ // If the IP Address string is found in the message and not the same as AIOWPS ip, replace it with the replacement string
+ if (false !== $ip_pos && $ip !== $ip_string) {
+ $replacement = "$ip.\r\n\r\n";
+ $message = substr_replace($message, $replacement, $ip_pos);
+ }
+
+ return $message;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-registration.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-registration.php
new file mode 100755
index 00000000..879b2dfe
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-user-registration.php
@@ -0,0 +1,100 @@
+configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
+ add_filter("woocommerce_registration_auth_new_customer", array($this, 'aios_registration_auth_new_customer'));
+ }
+
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
+ add_filter('registration_errors', array($this, 'aiowps_validate_registration_with_captcha'), 10, 3);
+ }
+ }
+
+ /**
+ * This public function will add a special meta string in the users table
+ * Meta field name: 'aiowps_account_status'
+ * Meta field value: 'pending'
+ *
+ * @param int $user_id
+ * @return void
+ */
+ public function aiowps_user_registration_action_handler($user_id) {
+ global $aio_wp_security;
+ //Check if auto pending new account status feature is enabled
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
+ if (AIOWPSecurity_Utility_Permissions::has_manage_cap() || (defined('WP_CLI') && WP_CLI)) {
+ AIOWPSecurity_Audit_Events::event_user_registration($user_id, 'admin');
+ return; //if the user has been added from admin side don't put in pending state
+ }
+ $res = add_user_meta($user_id, 'aiowps_account_status', 'pending');
+ if (!$res) {
+ $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_account_status", 4);
+ }
+ $user_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
+ $res = add_user_meta($user_id, 'aiowps_registrant_ip', $user_ip_address);
+ if (!$res) {
+ $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_registrant_ip", 4);
+ }
+ AIOWPSecurity_Audit_Events::event_user_registration($user_id, 'pending');
+ } else {
+ if (AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ AIOWPSecurity_Audit_Events::event_user_registration($user_id, 'admin');
+ } else {
+ AIOWPSecurity_Audit_Events::event_user_registration($user_id, 'registered');
+ }
+ }
+ }
+
+ /**
+ * This public function will set the special meta string in the usermeta table so that the account becomes active
+ * Meta field name: 'aiowps_account_status'
+ * Meta field values: 'active', 'pending', etc
+ *
+ * @param int $user_id
+ * @param string $status
+ * @return void
+ */
+ public function aiowps_set_user_account_status($user_id, $status) {
+ global $aio_wp_security;
+ $res = update_user_meta($user_id, 'aiowps_account_status', $status);
+ if (!$res) {
+ $aio_wp_security->debug_logger->log_debug("aiowps_set_user_account_status: Error updating user meta data: aiowps_account_status", 4);
+ }
+ }
+
+ public function aiowps_validate_registration_with_captcha($errors) {
+ global $aio_wp_security;
+
+ $locked = $aio_wp_security->user_login_obj->check_locked_user();
+ if (null == $locked) {
+ //user is not locked continue
+ } else {
+ $errors->add('authentication_failed', __('ERROR: You are not allowed to register because your IP address is currently locked!', 'all-in-one-wp-security-and-firewall'));
+ return $errors;
+ }
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
+ if (false === $verify_captcha) {
+ // wrong answer was entered
+ $errors->add('authentication_failed', __('ERROR: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
+ return $errors;
+ }
+ return $errors;
+ }
+
+ /**
+ * This function serves the purpose of preventing login in certain plugins that enable user registration, such as WooCommerce and others.
+ *
+ * @return bool Returns false means do not authenticate on registration
+ */
+ public function aios_registration_auth_new_customer() {
+ return false;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-api.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-api.php
new file mode 100755
index 00000000..02860efa
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-api.php
@@ -0,0 +1,121 @@
+debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() - Invalid request method. Only GET and POST are supported.", 4);
+ return new WP_Error('aios_api_invalid_method', 'Invalid request method. Only GET and POST are supported.');
+ }
+
+ // Validate the URL
+ if ('' !== $url && !filter_var($url, FILTER_VALIDATE_URL)) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() - Invalid or missing request URL.", 4);
+ return new WP_Error('aios_api_invalid_url', 'Invalid or missing request URL.');
+ }
+
+ // Set up default arguments
+ $default_args = array(
+ 'headers' => array(),
+ 'body' => array(),
+ 'timeout' => 10,
+ );
+
+ // Merge default arguments with provided arguments
+ $request_args = wp_parse_args($args, $default_args);
+
+ // Make the request
+ if ('POST' === $method) {
+ $response = wp_remote_post($url, $request_args);
+ } else {
+ $response = wp_remote_get($url, $request_args);
+ }
+
+ // Check for errors
+ if (is_wp_error($response)) {
+ // Get error code and message
+ $error_code = $response->get_error_code();
+ $error_message = $response->get_error_message();
+ $error_data = $response->get_error_data(); // Optional additional error data
+
+ // Log the error details
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() | Response error - Code: {$error_code}, Message: {$error_message}", 4);
+
+ // Log any additional error data (could be useful for debugging)
+ if ($error_data) {
+ if (is_array($error_data) || is_object($error_data)) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() | Response error - Additional Error Data: " . json_encode($error_data), 4);
+ } else {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() | Response error - Additional Error Data: {$error_data}", 4);
+ }
+ }
+
+ return $response;
+ }
+
+ // Get the response body
+ $response_body = wp_remote_retrieve_body($response);
+
+ // Check for JSON response
+ $content_type = wp_remote_retrieve_header($response, 'content-type');
+ if (false !== strpos($content_type, 'application/json')) {
+
+ // Decode the response body if it's JSON
+ $decoded_body = json_decode($response_body, true);
+
+ // Log JSON decoding error if any
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_API::make_api_request() - JSON decode error: " . json_last_error_msg(), 4);
+ return new WP_Error('aios_api_json_decode_error', json_last_error_msg());
+ }
+
+ // Return the decoded JSON response body
+ return $decoded_body;
+ }
+
+ // Return raw response body if it's not JSON
+ return $response_body;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-file.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-file.php
new file mode 100755
index 00000000..07d1b6a7
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility-file.php
@@ -0,0 +1,522 @@
+ 'root directory', 'path' => ABSPATH, 'permissions' => '0755'),
+ array('name' => 'wp-includes/', 'path' => ABSPATH."wp-includes", 'permissions' => '0755'),
+ array('name' => '.htaccess', 'path' => $home_path.".htaccess", 'permissions' => '0644'),
+ array('name' => 'wp-admin/index.php', 'path' => ABSPATH."wp-admin/index.php", 'permissions' => '0644'),
+ array('name' => 'wp-admin/js/', 'path' => ABSPATH."wp-admin/js/", 'permissions' => '0755'),
+ array('name' => 'wp-content/themes/', 'path' => WP_CONTENT_DIR."/themes", 'permissions' => '0755'),
+ array('name' => 'wp-content/plugins/', 'path' => WP_PLUGIN_DIR, 'permissions' => '0755'),
+ array('name' => 'wp-admin/', 'path' => ABSPATH."wp-admin", 'permissions' => '0755'),
+ array('name' => 'wp-content/', 'path' => WP_CONTENT_DIR, 'permissions' => '0755'),
+ array('name' => 'wp-config.php', 'path' => $wp_config_path, 'permissions' => '0640'),
+ //Add as many files or dirs as needed by following the convention above
+ );
+
+ return apply_filters('aiowpsecurity_file_permission_list', $file_list);
+ }
+
+ /**
+ * Returns full path to mu-plugin directory
+ *
+ * @return string
+ */
+ public static function get_mu_plugin_dir() {
+ return WPMU_PLUGIN_DIR;
+ }
+
+ /**
+ * Returns path to wp-config
+ *
+ * @return string
+ */
+ public static function get_wp_config_file_path() {
+ $wp_config_file = ABSPATH . 'wp-config.php';
+ if (file_exists($wp_config_file)) {
+ return $wp_config_file;
+ } elseif (file_exists(dirname(ABSPATH) . '/wp-config.php')) {
+ return dirname(ABSPATH) . '/wp-config.php';
+ }
+ return $wp_config_file;
+ }
+
+ public static function write_content_to_file($file_path, $new_contents) {
+ // Get the file permissions so we can revert back to it when we are done
+ $permissions = octdec(substr(sprintf('%o', fileperms($file_path)), -4));
+ @chmod($file_path, 0777);
+ if (is_writeable($file_path)) {
+ $handle = fopen($file_path, 'w');
+ foreach ($new_contents as $line) {
+ fwrite($handle, $line);
+ }
+ fclose($handle);
+ @chmod($file_path, $permissions); //Let's change the file back to it's original permission setting
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static function backup_and_rename_wp_config($src_file_path, $prefix = 'backup') {
+ global $aio_wp_security;
+
+ //Check to see if the main "backups" directory exists - create it otherwise
+ $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("backup_and_rename_wp_config - Creation of backup directory failed!", 4);
+ return false;
+ }
+
+ $src_parts = pathinfo($src_file_path);
+ $backup_file_name = $prefix . '.' . $src_parts['basename'];
+
+ $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name;
+ if (!copy($src_file_path, $backup_file_path)) {
+ //Failed to make a backup copy
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Backs up and renames the .htaccess file.
+ *
+ * This function creates a backup of the specified .htaccess file by copying it
+ * to a designated backup directory with a randomly generated filename.
+ *
+ * @param string $src_file_path The path to the source .htaccess file to be backed up.
+ *
+ * @return string|false The name of the backup file on success, or false on failure.
+ */
+ public static function backup_and_rename_htaccess($src_file_path) {
+ global $aio_wp_security;
+
+ // Define the backup directory path
+ $aiowps_backup_dir = WP_CONTENT_DIR . '/' . AIO_WP_SECURITY_BACKUPS_DIR_NAME;
+
+ // Ensure the backup directory exists or create it
+ if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) {
+ $aio_wp_security->debug_logger->log_debug("backup_and_rename_htaccess - Creation of backup directory failed!", 4);
+ return false;
+ }
+
+ // Generate a random prefix for the backup file name
+ $random_prefix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
+ $backup_file_name = $random_prefix . '_htaccess_backup';
+
+ // Define the backup file path
+ $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name .'.txt';
+
+ // Copy the source file to the backup location
+ if (!copy($src_file_path, $backup_file_path)) {
+ // Failed to make a backup copy
+ return false;
+ }
+
+ // Return the backup file name on success
+ return $backup_file_name;
+ }
+
+ /**
+ * This function will perform a recursive search for files in the path that match the passed in pattern
+ *
+ * @param string $pattern - the file pattern to search for
+ * @param integer $flags - flags to apply on the search
+ * @param string $path - the path we want to search
+ *
+ * @return boolean|array - an array of files matching the pattern or false if there was an error (directory traversal in path) or none found
+ */
+ public static function recursive_file_search($pattern = '*', $flags = 0, $path = '') {
+ $paths = glob($path.'*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT);
+ if (false === $paths) {
+ return false;
+ }
+ $files = glob($path.$pattern, $flags);
+ if (false === $files) {
+ return false;
+ }
+ foreach ($paths as $path) {
+ $files = array_merge($files, AIOWPSecurity_Utility_File::recursive_file_search($pattern, $flags, $path));
+ }
+ return $files;
+ }
+
+ /**
+ * Useful when wanting to echo file contents to screen with tags
+ *
+ * @param string $src_file
+ * @return string
+ */
+ public static function get_file_contents_with_br($src_file) {
+ $file_contents = file_get_contents($src_file);
+ return nl2br($file_contents);
+ }
+
+ /**
+ * Useful when wanting to echo file contents inside textarea
+ *
+ * @param string $src_file
+ * @return string
+ */
+ public static function get_file_contents($src_file) {
+ $file_contents = file_get_contents($src_file);
+ return $file_contents;
+ }
+
+ /**
+ * Returns the file's permission value eg, "0755"
+ *
+ * @param string $filepath
+ * @return string
+ */
+ public static function get_file_permission($filepath) {
+ if (!function_exists('fileperms')) {
+ $perms = '-1';
+ } else {
+ clearstatcache();
+ $perms = substr(sprintf("%o", @fileperms($filepath)), -4);
+ }
+ return $perms;
+ }
+
+ /**
+ * Checks if a write operation is possible for the file in question
+ *
+ * @param string $filepath
+ * @return boolean
+ */
+ public static function is_file_writable($filepath) {
+ $test_string = ""; //We will attempt to append an empty string at the end of the file for the test
+ $write_result = @file_put_contents($filepath, $test_string, FILE_APPEND | LOCK_EX);
+ if (false === $write_result) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * This function will compare the current permission value for a file or dir with the recommended value.
+ * It will compare the individual "execute", "write" and "read" bits for the "public", "group" and "owner" permissions.
+ * If the permissions for an actual bit value are greater than the recommended value it returns '0' (=less secure)
+ * Otherwise it returns '1' which means it is secure
+ * Accepts permission value parameters in octal, ie, "0777" or "777"
+ *
+ * @param string $recommended
+ * @param string $actual
+ * @return boolean
+ */
+ public static function is_file_permission_secure($recommended, $actual) {
+ $result = 1; //initialize return result
+
+ //Check "public" permissions
+ $public_value_actual = substr($actual, -1, 1); //get dec value for actual public permission
+ $public_value_rec = substr($recommended, -1, 1); //get dec value for recommended public permission
+
+ $pva_bin = sprintf('%04b', $public_value_actual); //Convert value to binary
+ $pvr_bin = sprintf('%04b', $public_value_rec); //Convert value to binary
+ //Compare the "executable" bit values for the public actual versus the recommended
+ if (substr($pva_bin, -1, 1)<=substr($pvr_bin, -1, 1)) {
+ //The "execute" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "write" bit values for the public actual versus the recommended
+ if (substr($pva_bin, -2, 1)<=substr($pvr_bin, -2, 1)) {
+ //The "write" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "write" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "read" bit values for the public actual versus the recommended
+ if (substr($pva_bin, -3, 1)<=substr($pvr_bin, -3, 1)) {
+ //The "read" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "read" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Check "group" permissions
+ $group_value_actual = substr($actual, -2, 1);
+ $group_value_rec = substr($recommended, -2, 1);
+ $gva_bin = sprintf('%04b', $group_value_actual); //Convert value to binary
+ $gvr_bin = sprintf('%04b', $group_value_rec); //Convert value to binary
+
+ //Compare the "executable" bit values for the group actual versus the recommended
+ if (substr($gva_bin, -1, 1)<=substr($gvr_bin, -1, 1)) {
+ //The "execute" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "write" bit values for the public actual versus the recommended
+ if (substr($gva_bin, -2, 1)<=substr($gvr_bin, -2, 1)) {
+ //The "write" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "write" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "read" bit values for the public actual versus the recommended
+ if (substr($gva_bin, -3, 1)<=substr($gvr_bin, -3, 1)) {
+ //The "read" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "read" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Check "owner" permissions
+ $owner_value_actual = substr($actual, -3, 1);
+ $owner_value_rec = substr($recommended, -3, 1);
+ $ova_bin = sprintf('%04b', $owner_value_actual); //Convert value to binary
+ $ovr_bin = sprintf('%04b', $owner_value_rec); //Convert value to binary
+
+ //Compare the "executable" bit values for the group actual versus the recommended
+ if (substr($ova_bin, -1, 1)<=substr($ovr_bin, -1, 1)) {
+ //The "execute" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "write" bit values for the public actual versus the recommended
+ if (substr($ova_bin, -2, 1)<=substr($ovr_bin, -2, 1)) {
+ //The "write" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "write" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ //Compare the "read" bit values for the public actual versus the recommended
+ if (substr($ova_bin, -3, 1)<=substr($ovr_bin, -3, 1)) {
+ //The "read" bit is the same or less as the recommended value
+ $result = 1*$result;
+ } else {
+ //The "read" bit is switched on for the actual value - meaning it is less secure
+ $result = 0*$result;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Checks if a directory exists and creates one if it does not
+ *
+ * @param string $dirpath
+ * @return boolean
+ */
+ public static function create_dir($dirpath = '') {
+ $res = true;
+ if ('' != $dirpath) {
+ //TODO - maybe add some checks to make sure someone is not passing a path with a filename, ie, something which has "." at the end
+ //$path_parts = pathinfo($dirpath);
+ //$dirpath = $path_parts['dirname'] . '/' . $path_parts['basename'];
+ if (!file_exists($dirpath)) {
+ $res = mkdir($dirpath, 0755);
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Remove a directory from the local filesystem
+ *
+ * @param string $dir - the directory
+ * @param boolean $contents_only - if set to true, then do not remove the directory, but only empty it of contents
+ *
+ * @return boolean - success/failure
+ */
+ public static function remove_local_directory($dir, $contents_only = false) {
+
+ $handle = opendir($dir);
+ if ($handle) {
+ while (false !== ($entry = readdir($handle))) {
+ if ('.' !== $entry && '..' !== $entry) {
+ if (is_dir($dir.'/'.$entry)) {
+ self::remove_local_directory($dir.'/'.$entry, false);
+ } else {
+ @unlink($dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore warning and proceed to try and remove the rest of the files
+ }
+ }
+ }
+ if (is_resource($handle)) closedir($handle);
+ }
+
+ return $contents_only ? true : rmdir($dir);
+ }
+
+ /**
+ * Get home path.
+ *
+ * @return string
+ */
+ public static function get_home_path() {
+ // Make the scope of $wp_file_descriptions global, so that when wp-admin/includes/file.php assigns to it, it is adjusting the global variable as intended
+ global $wp_file_descriptions; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- We need to make this global see above comment
+ if (!function_exists('get_home_path')) require_once(ABSPATH. '/wp-admin/includes/file.php');
+ return wp_normalize_path(get_home_path());
+ }
+
+ /**
+ * Check if wp config file.
+ *
+ * @param string $file_contents File contents
+ *
+ * @return bool
+ */
+ public static function check_if_wp_config_contents($file_contents) {
+ return !empty($file_contents) && preg_match("/define\(\s*['\"]DB_NAME['\"]/i", $file_contents);
+ }
+
+ /**
+ * Check if valid aios settings text
+ *
+ * @param string $text - Settings text
+ *
+ * @return boolean
+ */
+ public static function check_is_aiowps_settings($text) {
+ return (false !== strpos($text, 'aiowps_enable_login_lockdown'));
+ }
+
+ /**
+ * Checks if valid AIOS settings file contents and returns contents as string
+ *
+ * @param string $file_contents File contents
+ *
+ * @return int|string
+ */
+ public static function check_if_valid_aiowps_settings_content($file_contents) {
+ // Check a known AIOS config strings to see if it is contained within this file
+ return !empty($file_contents) && self::check_is_aiowps_settings($file_contents);
+ }
+
+ /**
+ * Scans WP key core files and directory permissions and populates a wp wide_fat table
+ * Displays a red background entry with a "Fix" button for permissions which are "777"
+ * Displays a yellow background entry with a "Fix" button for permissions which are less secure than the recommended
+ * Displays a green entry for permissions which are as secure or better than the recommended
+ *
+ * @param string $name - file name
+ * @param string $path - file path
+ * @param string $recommended - file permission
+ *
+ * @return void
+ */
+ public static function show_wp_filesystem_permission_status($name, $path, $recommended) {
+ $fix = false;
+ $configmod = self::get_file_permission($path);
+ if (self::is_file_world_writable($configmod)) {
+ $trclass = "aio_table_row_red"; // Display a red background if permissions are set as least secure ("777")
+ $fix = true;
+ } elseif ($configmod != $recommended) {
+ // $res = $this->is_file_permission_secure($recommended, $configmod);
+ $res = self::is_file_permission_secure($recommended, $configmod);
+ if ($res) {
+ $trclass = "aio_table_row_green"; //If the current permissions are even tighter than recommended then display a green row
+ } else {
+ $trclass = "aio_table_row_yellow"; // Display a yellow background if permissions are set to something different than recommended
+ $fix = true;
+ }
+ } else {
+ $trclass = "aio_table_row_green";
+ }
+ echo "
+ ';
+
+ // Check if an array is multidimensional
+ $is_multi_dimensional = function($array) {
+ if (!is_array($array)) {
+ return false;
+ }
+ foreach ($array as $item) {
+ if (is_array($item)) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // Check if the input data is a multidimensional array
+ if ($is_multi_dimensional($data)) {
+ // Add table headers based on the keys of the first array element
+ $table_html .= '
';
+
+ // Recursively format the multidimensional array
+ $table_html .= self::format_data_recursive($data);
+ } else {
+ // If the input data is not a multidimensional array, treat it as a single key-value pair
+ $table_html .= self::format_data_recursive(array($data));
+ }
+
+ $table_html .= '';
+
+ return $table_html;
+ }
+
+ /**
+ * Recursively format data as a table
+ *
+ * @param array $data Data to be formatted
+ *
+ * @return string Formatted data as a table
+ */
+ private static function format_data_recursive($data) {
+ $html = '';
+ foreach ($data as $key => $value) {
+ if (is_array($value)) {
+ // If the value is an array, recursively format it
+ $html .= self::format_data_recursive($value);
+ } else {
+ // If the value is not an array, format it as a table row
+ $escaped_key = esc_html($key);
+ $escaped_value = esc_html($value);
+ $html .= '
' . $escaped_key . '
' . $escaped_value . '
';
+ }
+ }
+ return $html;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility.php
new file mode 100755
index 00000000..7a1a9837
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-utility.php
@@ -0,0 +1,1578 @@
+Error! The URL value is empty. Please specify a correct URL value to redirect to!";
+ exit;
+ }
+ if (!headers_sent()) {
+ header('Location: ' . $url);
+ } else {
+ echo '';
+ }
+ if ('1' == $exit) {
+ exit;
+ }
+ }
+
+ /**
+ * Checks if a particular username exists in the WP Users table
+ *
+ * @global type $wpdb
+ * @param type $username
+ * @return boolean
+ */
+ public static function check_user_exists($username) {
+ global $wpdb;
+
+ //if username is empty just return false
+ if ('' == $username) {
+ return false;
+ }
+
+ //If multisite
+ if (is_multisite()) {
+ $blog_id = get_current_blog_id();
+ $admin_users = get_users('blog_id=' . $blog_id . '&orderby=login&role=administrator');
+ foreach ($admin_users as $user) {
+ if ($user->user_login == $username) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //check users table
+ $sanitized_username = sanitize_user($username);
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query required
+ $user_login = $wpdb->get_var(
+ $wpdb->prepare("SELECT user_login FROM $wpdb->users WHERE user_login=%s", $sanitized_username)
+ );
+
+ if ($user_login == $sanitized_username) {
+ return true;
+ } else {
+ //make sure that the sanitized username is an integer before comparing it to the users table's ID column
+ $sanitized_username_is_an_integer = (1 === preg_match('/^\d+$/', $sanitized_username));
+ if ($sanitized_username_is_an_integer) {
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query required
+ $userid = $wpdb->get_var(
+ $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE ID=%d", intval($sanitized_username))
+ );
+ return ($userid == $sanitized_username);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * This function will return a list of user accounts which have login and nick names which are identical
+ *
+ * @global type $wpdb
+ * @return type
+ */
+ public static function check_identical_login_and_nick_names() {
+ global $wpdb;
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query required.
+ $accounts_found = $wpdb->get_results("SELECT ID,user_login FROM `" . $wpdb->users . "` WHERE user_login<=>display_name;", ARRAY_A);
+ return $accounts_found;
+ }
+
+
+ public static function add_query_data_to_url($url, $name, $value) {
+ if (strpos($url, '?') === false) {
+ $url .= '?';
+ } else {
+ $url .= '&';
+ }
+ $url .= $name . '=' . urlencode($value);
+ return $url;
+ }
+
+
+ /**
+ * Generates a random alpha-numeric number
+ *
+ * @param type $string_length
+ * @return string
+ */
+ public static function generate_alpha_numeric_random_string($string_length) {
+ //Characters present in table prefix
+ $allowed_chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ $string = '';
+ //Generate random string
+ for ($i = 0; $i < $string_length; $i++) {
+ $string .= $allowed_chars[wp_rand(0, strlen($allowed_chars) - 1)];
+ }
+ return $string;
+ }
+
+
+ /**
+ * Generates a random string using a-z characters
+ *
+ * @param type $string_length
+ * @return string
+ */
+ public static function generate_alpha_random_string($string_length) {
+ //Characters present in table prefix
+ $allowed_chars = 'abcdefghijklmnopqrstuvwxyz';
+ $string = '';
+ //Generate random string
+ for ($i = 0; $i < $string_length; $i++) {
+ $string .= $allowed_chars[wp_rand(0, strlen($allowed_chars) - 1)];
+ }
+ return $string;
+ }
+
+ /**
+ * Sets cookie
+ *
+ * @param type $cookie_name
+ * @param type $cookie_value
+ * @param type $expiry_seconds
+ * @param type $path
+ * @param string $cookie_domain
+ */
+ public static function set_cookie_value($cookie_name, $cookie_value, $expiry_seconds = 86400, $path = '/', $cookie_domain = '') {
+ $expiry_time = time() + intval($expiry_seconds);
+ if (empty($cookie_domain)) {
+ $cookie_domain = COOKIE_DOMAIN;
+ }
+ return setcookie($cookie_name, $cookie_value, $expiry_time, $path, $cookie_domain, is_ssl(), true);
+ }
+
+ /**
+ * Get brute force secret cookie name.
+ *
+ * @return String Brute force secret cookie name.
+ */
+ public static function get_brute_force_secret_cookie_name() {
+ return 'aios_brute_force_secret_' . COOKIEHASH;
+ }
+
+ /**
+ * Gets cookie
+ *
+ * @param type $cookie_name
+ * @return string
+ */
+ public static function get_cookie_value($cookie_name) {
+ if (isset($_COOKIE[$cookie_name])) {
+ return sanitize_text_field(wp_unslash($_COOKIE[$cookie_name]));
+ }
+ return "";
+ }
+
+ /**
+ * Checks if installation is multisite or not.
+ *
+ * @return Boolean True if the site is network multisite, false otherwise.
+ */
+ public static function is_multisite_install() {
+ return function_exists('is_multisite') && is_multisite();
+ }
+
+ /**
+ * This is a general yellow box message for when we want to suppress a feature's config items on multisite because current user is not super admin.
+ *
+ * @return void
+ */
+ public static function display_multisite_super_admin_message() {
+ echo '
';
+ echo '
' . 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 '
';
+ }
+
+ /**
+ * Modifies the wp-config.php file to disable PHP file editing from the admin panel
+ * This function will add the following code:
+ * define('DISALLOW_FILE_EDIT', false);
+ *
+ * NOTE: This function will firstly check if the above code already exists
+ * and it will modify the bool value, otherwise it will insert the code mentioned above
+ *
+ * @global type $aio_wp_security
+ * @return boolean
+ */
+ public static function disable_file_edits() {
+ global $aio_wp_security;
+ $edit_file_config_entry_exists = false;
+
+ //Config file path
+ $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
+
+ //Get wp-config.php file contents so we can check if the "DISALLOW_FILE_EDIT" variable already exists
+ $config_contents = file($config_file);
+
+ foreach ($config_contents as $line_num => $line) {
+ if (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
+ $config_contents[$line_num] = str_replace('false', 'true', $line);
+ $edit_file_config_entry_exists = true;
+ //$this->show_msg_updated(__('Settings Saved - The ability to edit PHP files via the admin the panel has been DISABLED.', 'all-in-one-wp-security-and-firewall'));
+ } elseif (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
+ $edit_file_config_entry_exists = true;
+ //$this->show_msg_updated(__('Your system config file is already configured to disallow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
+ return true;
+
+ }
+
+ //For wp-config.php files originating from early WP versions we will remove the closing php tag
+ if (strpos($line, "?>") !== false) {
+ $config_contents[$line_num] = str_replace("?>", "", $line);
+ }
+ }
+
+ if (!$edit_file_config_entry_exists) {
+ //Construct the config code which we will insert into wp-config.php
+ $new_snippet = '//Disable File Edits' . PHP_EOL;
+ $new_snippet .= 'if (!defined(\'DISALLOW_FILE_EDIT\')) { define(\'DISALLOW_FILE_EDIT\', true); }';
+ $config_contents[] = $new_snippet; //Append the new snippet to the end of the array
+ }
+
+ //Make a backup of the config file
+ if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('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'));
+ //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Failed to make a backup of the wp-config.php file.",4);
+ return false;
+ } else {
+ //$this->show_msg_updated(__('A backup copy of your wp-config.php file was created successfully....', 'all-in-one-wp-security-and-firewall'));
+ }
+
+ //Now let's modify the wp-config.php file
+ if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
+ //$this->show_msg_updated(__('Settings Saved - Your system is now configured to not allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
+ return true;
+ } else {
+ //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
+ $aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php", 4);
+ return false;
+ }
+ }
+
+ /**
+ * Modifies the wp-config.php file to allow PHP file editing from the admin panel
+ * This func will modify the following code by replacing "true" with "false":
+ * define('DISALLOW_FILE_EDIT', true);
+ *
+ * @global type $aio_wp_security
+ * @return boolean
+ */
+ public static function enable_file_edits() {
+ $edit_file_config_entry_exists = false;
+
+ //Config file path
+ $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
+
+ //Get wp-config.php file contents
+ $config_contents = file($config_file);
+ foreach ($config_contents as $line_num => $line) {
+ if (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
+ $config_contents[$line_num] = str_replace('true', 'false', $line);
+ $edit_file_config_entry_exists = true;
+ } elseif (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
+ $edit_file_config_entry_exists = true;
+ //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
+ return true;
+ }
+ }
+
+ if (!$edit_file_config_entry_exists) {
+ //if the DISALLOW_FILE_EDIT settings don't exist in wp-config.php then we don't need to do anything
+ //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
+ return true;
+ } else {
+ //Now let's modify the wp-config.php file
+ if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
+ //$this->show_msg_updated(__('Settings Saved - Your system is now configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
+ return true;
+ } else {
+ //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
+ //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php",4);
+ return false;
+ }
+ }
+ }
+
+
+ /**
+ * Inserts event logs to the database
+ * For now we are using for 404 events but in future will expand for other events
+ * Event types: 404 (...add more as we expand this)
+ *
+ * @param string $event_type :Event type, eg, 404 (see below for list of event types)
+ * @param string $username (optional): username
+ * @return bool
+ */
+ public static function event_logger($event_type, $username = '') {
+ global $wpdb, $aio_wp_security;
+
+ //Some initialising
+ $url = '';
+ $referer_info = '';
+
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
+
+ $ip_or_host = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
+ $username = sanitize_user($username);
+ $user = get_user_by('login', $username); //Returns WP_User object if exists
+ if ($user) {
+ //If valid user set variables for DB storage later on
+ $user_id = (absint($user->ID) > 0) ? $user->ID : 0;
+ } else {
+ //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
+ $user_id = 0;
+ }
+
+ if ('404' == $event_type || 'spam_discard' == $event_type) {
+ //if 404 event get some relevant data
+ $url = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
+ $referer_info = isset($_SERVER['HTTP_REFERER']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_REFERER'])) : '';
+ }
+
+ $current_time = current_time('mysql', true);
+ $data = array(
+ 'event_type' => $event_type,
+ 'username' => $username,
+ 'user_id' => $user_id,
+ 'event_date' => $current_time,
+ 'ip_or_host' => $ip_or_host,
+ 'referer_info' => $referer_info,
+ 'url' => $url,
+ 'event_data' => '',
+ );
+
+ $data = apply_filters('aiowps_filter_event_logger_data', $data);
+ //log to database
+ $country_code = isset($data['country_code']) ? $data['country_code'] : '';
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. irect query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare("INSERT INTO ".$events_table_name." (event_type, username, user_id, event_date, ip_or_host, referer_info, url, event_data, country_code, created) VALUES (%s, %s, %d, %s, %s, %s, %s, %s, %s, UNIX_TIMESTAMP())", $data['event_type'], $data['username'], $data['user_id'], $data['event_date'], $data['ip_or_host'], $data['referer_info'], $data['url'], $data['event_data'], $country_code);
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- PCP warning. Query prepared above.
+ $result = $wpdb->query($sql);
+ if (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("event_logger: Error inserting record into " . $events_table_name, 4);//Log the highly unlikely event of DB error
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if an IP address is locked.
+ *
+ * @param string $ip The IP address to be checked.
+ * @param string $lock_reason Optional. Defaults to any lockout reason if not provided.
+ *
+ * @return bool True if locked, false otherwise.
+ **/
+ public static function check_locked_ip($ip, $lock_reason = null) {
+ global $wpdb;
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ if (null === $lock_reason) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $locked_ip = $wpdb->get_row($wpdb->prepare("SELECT * FROM `$login_lockdown_table` WHERE released > UNIX_TIMESTAMP() AND failed_login_ip = %s", $ip), ARRAY_A);
+ } else {
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $locked_ip = $wpdb->get_row($wpdb->prepare("SELECT * FROM `$login_lockdown_table` WHERE released > UNIX_TIMESTAMP() AND failed_login_ip = %s AND lock_reason = %s", $ip, $lock_reason), ARRAY_A);
+ }
+
+ return null != $locked_ip;
+ }
+
+ /**
+ * Check if an IP address is blacklisted.
+ *
+ * @param string $ip The IP address to check.
+ * @return bool True if the IP address is blacklisted, false otherwise.
+ */
+ public static function check_blacklist_ip($ip) {
+ global $aio_wp_security;
+ $blacklisted_ips = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
+ $blacklisted_ips_array = explode("\n", $blacklisted_ips);
+ if (in_array($ip, $blacklisted_ips_array)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns list of IP addresses locked out
+ *
+ * @global type $wpdb
+ * @return array of addresses found or false otherwise
+ */
+ public static function get_locked_ips() {
+ global $wpdb;
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $locked_ips = $wpdb->get_results("SELECT * FROM $login_lockdown_table WHERE released > UNIX_TIMESTAMP()", ARRAY_A);
+ if (empty($locked_ips)) {
+ return false;
+ } else {
+ return $locked_ips;
+ }
+ }
+
+
+ /**
+ * Locks an IP address - Adds an entry to the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @global wpdb $wpdb
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @param String $ip
+ * @param String $lock_reason
+ * @param String $username
+ *
+ * @return Void
+ */
+ public static function lock_ip($ip, $lock_reason, $username = '') {
+ global $wpdb, $aio_wp_security;
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ if ('404' == $lock_reason) {
+
+ // Query for existing lockouts record with that ip and 404 reason.
+ $existing_lock_query = $wpdb->prepare(
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP warning. Direct query required. Table name cannot be prepared pre WP 6.2.
+ "SELECT * FROM {$login_lockdown_table} WHERE failed_login_IP = %s AND lock_reason = %s AND released > UNIX_TIMESTAMP() LIMIT 1",
+ $ip,
+ $lock_reason
+ );
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- PCP warning. Prepared above.
+ $existing_lock_count = $wpdb->get_var($existing_lock_query);
+
+ if ($existing_lock_count) return; // IP is already blocked for '404', return.
+
+ $lock_minutes = $aio_wp_security->configs->get_value('aiowps_404_lockout_time_length');
+ } elseif ('audit-log' == $lock_reason) {
+ $lock_minutes = 24 * 60;
+ } else {
+ $lock_minutes = $aio_wp_security->user_login_obj->get_dynamic_lockout_time_length();
+ }
+
+ $username = sanitize_user($username);
+ $user = get_user_by('login', $username); //Returns WP_User object if exists
+
+ if (false == $user) {
+ // Not logged in.
+ $username = '';
+ $user_id = 0;
+ } else {
+ // Logged in.
+ $username = sanitize_user($user->user_login);
+ $user_id = $user->ID;
+ }
+
+ $ip = esc_sql($ip);
+
+ $lock_seconds = $lock_minutes * MINUTE_IN_SECONDS;
+ $lock_time = current_time('mysql', true);
+ $ip_lookup_result = AIOS_Helper::get_ip_reverse_lookup($ip);
+ $ip_lookup_result = wp_json_encode($ip_lookup_result);
+ if (false === $ip_lookup_result) $ip_lookup_result = null;
+
+ $release_time = gmdate('Y-m-d H:i:s', time() + ($lock_seconds));
+ $data = array(
+ 'user_id' => $user_id,
+ 'user_login' => $username,
+ 'lockdown_date' => $lock_time,
+ 'release_date' => $release_time,
+ 'failed_login_IP' => $ip,
+ 'lock_reason' => $lock_reason,
+ 'lock_seconds' => $lock_seconds,
+ 'ip_lookup_result' => $ip_lookup_result
+ );
+
+ $result = AIOWPSecurity_Utility::add_lockout($data);
+
+ if (false === $result) {
+ $error_msg = empty($wpdb->last_error) ? "lock_ip: Error inserting record into " . $login_lockdown_table : $wpdb->last_error;
+ $aio_wp_security->debug_logger->log_debug($error_msg, 4);//Log the highly unlikely event of DB error
+ }
+ }
+
+ /**
+ * Adds an entry to the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
+ *
+ * @global wpdb $wpdb
+ *
+ * @param Array $data
+ *
+ * @return Boolean
+ */
+ public static function add_lockout($data) {
+ global $wpdb;
+ if (!isset($data['is_lockout_email_sent'])) $data['is_lockout_email_sent'] = 0;
+ if (!isset($data['backtrace_log'])) $data['backtrace_log'] = '';
+ if (!isset($data['ip_lookup_result'])) $data['ip_lookup_result'] = '';
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+ // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder, WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare("INSERT INTO ".$login_lockdown_table." (user_id, user_login, lockdown_date, created, release_date, released, failed_login_IP, lock_reason, is_lockout_email_sent, backtrace_log, ip_lookup_result) VALUES ('%d', '%s', '%s', UNIX_TIMESTAMP(), '%s', UNIX_TIMESTAMP()+%d, '%s', '%s', '%d', '%s', '%s')", $data['user_id'], $data['user_login'], $data['lockdown_date'], $data['release_date'], $data['lock_seconds'], $data['failed_login_IP'], $data['lock_reason'], $data['is_lockout_email_sent'], $data['backtrace_log'], $data['ip_lookup_result']);
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- PCP warning. Prepared above.
+ $result = $wpdb->query($sql);
+ return $result;
+ }
+
+ /**
+ * Returns an array of blog_ids for a multisite install
+ *
+ * @global type $wpdb
+ * @global type $wpdb
+ * @return array or empty array if not multisite
+ */
+ public static function get_blog_ids() {
+ global $wpdb;
+ if (is_multisite()) {
+ global $wpdb;
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query required.
+ $blog_ids = $wpdb->get_col("SELECT blog_id FROM " . $wpdb->prefix . "blogs");
+ } else {
+ $blog_ids = array();
+ }
+ return $blog_ids;
+ }
+
+ /**
+ * Purges old records of table
+ *
+ * @global type $wpdb WP Database object
+ * @global type $aio_wp_security AIO WP Security object
+ * @param type $table_name Table name
+ * @param type $purge_records_after_days Records after days to be deleted
+ * @param type $date_field Date field of table
+ * @return void
+ */
+ public static function purge_table_records($table_name, $purge_records_after_days, $date_field) {
+ global $wpdb, $aio_wp_security;
+
+ $older_than_date_time = strtotime('-' . $purge_records_after_days . ' days', time());
+ if ('created' != $date_field) $older_than_date_time = gmdate('Y-m-d H:i:s', $older_than_date_time);
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $sql = $wpdb->prepare('DELETE FROM ' . $table_name . ' WHERE '.$date_field.' < %s', $older_than_date_time);
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- PCP warning. Prepared above.
+ $ret_deleted = $wpdb->query($sql);
+ if (false === $ret_deleted) {
+ $err_db = !empty($wpdb->last_error) ? ' ('.$wpdb->last_error.' - '.$wpdb->last_query.')' : '';
+ // Status level 4 indicates failure status.
+ $aio_wp_security->debug_logger->log_debug_cron('Purge records error - failed to purge older records for ' . $table_name . '.' . $err_db, 4);
+ } else {
+ $aio_wp_security->debug_logger->log_debug_cron(sprintf('Purge records - %d records were deleted for ' . $table_name . '.', $ret_deleted));
+ }
+ }
+
+ /**
+ * This function will delete the oldest rows from a table which are over the max amount of rows specified
+ *
+ * @global type $wpdb WP Database object
+ * @global type $aio_wp_security AIO WP Security object
+ * @param type $table_name Table name
+ * @param type $max_rows More than max to be deleted
+ * @param type $id_field Primary field of table
+ * @return bool
+ */
+ public static function cleanup_table($table_name, $max_rows = '10000', $id_field = 'id') {
+ global $wpdb, $aio_wp_security;
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $num_rows = $wpdb->get_var("select count(*) from $table_name");
+ $result = true;
+ if ($num_rows > $max_rows) {
+ //if the table has more than max entries delete oldest rows
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP error. Direct query necessary. Table name cannot be prepared pre WP 6.2.
+ $del_sql = $wpdb->prepare("DELETE FROM $table_name WHERE ".$id_field." <= (SELECT ".$id_field." FROM (SELECT ".$id_field." FROM $table_name ORDER BY ".$id_field." DESC LIMIT 1 OFFSET $max_rows) foo_tmp)");
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery -- PCP warning. Prepared above.
+ $result = $wpdb->query($del_sql);
+ if (false === $result) {
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility::cleanup_table failed for table name: " . $table_name, 4);
+ }
+ }
+ return (false === $result) ? false : true;
+ }
+
+ /**
+ * Add backquotes to tables and db-names in SQL queries. Taken from phpMyAdmin.
+ *
+ * @param string $a_name - the table name
+ * @return string - the quoted table name
+ */
+ public static function backquote($a_name) {
+ if (!empty($a_name) && '*' != $a_name) {
+ if (is_array($a_name)) {
+ $result = array();
+ foreach ($a_name as $key => $val) {
+ $result[$key] = '`'.$val.'`';
+ }
+ return $result;
+ } else {
+ return '`'.$a_name.'`';
+ }
+ } else {
+ return $a_name;
+ }
+ }
+
+ /**
+ * Replace the first, and only the first, instance within a string
+ *
+ * @param String $needle - the search term
+ * @param String $replace - the replacement term
+ * @param String $haystack - the string to replace within
+ *
+ * @return String - the filtered string
+ */
+ public static function str_replace_once($needle, $replace, $haystack) {
+ $pos = strpos($haystack, $needle);
+ return (false !== $pos) ? substr_replace($haystack, $replace, $pos, strlen($needle)) : $haystack;
+ }
+
+ /**
+ * Delete expired CAPTCHA info option
+ *
+ * Note: A unique instance these option is created everytime the login page is loaded with CAPTCHA enabled
+ * This function will help prune the options table of old expired entries.
+ *
+ * @global wpdb $wpdb
+ */
+ public static function delete_expired_captcha_options() {
+ global $wpdb;
+ $current_unix_time = current_time('timestamp', true);
+ $previous_hour = $current_unix_time - 3600;
+ $tbl = is_multisite() ? $wpdb->sitemeta : $wpdb->prefix . 'options';
+ $key_name = is_multisite() ? 'meta_key' : 'option_name';
+ $key_val = is_multisite() ? 'meta_value' : 'option_value';
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery -- PCP warning. Direct query required. Table name cannot be prepared pre WP 6.2.
+ $query = $wpdb->prepare("SELECT * FROM {$tbl} WHERE {$key_name} LIKE 'aiowps_captcha_string_info_time_%' AND {$key_val} < %s", $previous_hour);
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- PCP warning. Prepared above.
+ $res = $wpdb->get_results($query, ARRAY_A);
+ if (!empty($res)) {
+ foreach ($res as $item) {
+ $option_name = $item[$key_name];
+ if (is_multisite()) {
+ delete_site_option($option_name);
+ delete_site_option(str_replace('time_', '', $option_name));
+ } else {
+ delete_option($option_name);
+ delete_option(str_replace('time_', '', $option_name));
+ }
+ }
+ }
+ }
+
+ /**
+ * Get server type.
+ *
+ * @return string|integer Server type or -1 if server is not supported
+ */
+ public static function get_server_type() {
+ if (!isset($_SERVER['SERVER_SOFTWARE'])) {
+ return apply_filters('aios_server_type', -1);
+ }
+
+ // Figure out what server they're using.
+ $server_software = strtolower(sanitize_text_field(wp_unslash(($_SERVER['SERVER_SOFTWARE']))));
+
+ if (strstr($server_software, 'apache')) {
+ $server_type = 'apache';
+ } elseif (strstr($server_software, 'nginx')) {
+ $server_type = 'nginx';
+ } elseif (strstr($server_software, 'litespeed')) {
+ $server_type = 'litespeed';
+ } elseif (strstr($server_software, 'iis')) {
+ $server_type = 'iis';
+ } elseif (strstr($server_software, 'lighttpd')) {
+ $server_type = 'lighttpd';
+ } else { // Unsupported server
+ $server_type = -1;
+ }
+
+ return apply_filters('aios_server_type', $server_type);
+ }
+
+ /**
+ * Checks if the string exists in the array key value of the provided array.
+ * If it doesn't exist, it returns the first key element from the valid values.
+ *
+ * @param type $to_check
+ * @param type $valid_values
+ * @return type
+ */
+ public static function sanitize_value_by_array($to_check, $valid_values) {
+ $keys = array_keys($valid_values);
+ $keys = array_map('strtolower', $keys);
+ if (in_array(strtolower($to_check), $keys)) {
+ return $to_check;
+ }
+ return reset($keys); //Return the first element from the valid values
+ }
+
+ /**
+ * Get textarea string from array or string.
+ *
+ * @param String|Array $vals value to render as textarea val
+ * @return String value to render in textarea.
+ */
+ public static function get_textarea_str_val($vals) {
+ if (empty($vals)) {
+ return '';
+ }
+
+ if (is_array($vals)) {
+ return implode("\n", array_filter(array_map('trim', $vals)));
+ }
+
+ return $vals;
+ }
+
+ /**
+ * Get array from textarea val.
+ *
+ * @param String|Array $vals value from textarea val
+ * @return Array value to from textarea value.
+ */
+ public static function get_array_from_textarea_val($vals) {
+ if (empty($vals)) {
+ return array();
+ }
+
+ if (is_array($vals)) {
+ return $vals;
+ }
+
+ return array_filter(array_map('trim', explode("\n", $vals)));
+ }
+
+ /**
+ * Partially or fully masks a string using '*' to replace original characters
+ *
+ * @param type string $str
+ * @param type int $chars_unmasked
+ * @return type string
+ */
+ public static function mask_string($str, $chars_unmasked = 0) {
+ $str_length = strlen($str);
+ $chars_unmasked = absint($chars_unmasked);
+
+ if (0 == $chars_unmasked) {
+ if (8 < $str_length) {
+ // mask all but last 4 characters
+ return preg_replace("/(.{4}$)(*SKIP)(*F)|(.)/u", "*", $str);
+ } elseif (3 < $str_length) {
+ // mask all but last 2 characters
+ return preg_replace("/(.{2}$)(*SKIP)(*F)|(.)/u", "*", $str);
+ } else {
+ // return whole string masked
+ return str_pad("", $str_length, "*", STR_PAD_LEFT);
+ }
+ }
+ if ($chars_unmasked >= $str_length) return $str;
+ return preg_replace("/(.{".$chars_unmasked."}$)(*SKIP)(*F)|(.)/u", "*", $str);
+ }
+
+ /**
+ * Create a php backtrace log file for login lockdown email
+ *
+ * @param Array $logs
+ * @global AIO_WP_Security $aio_wp_security
+ * @return string
+ */
+ public static function login_lockdown_email_backtrace_log_file($logs = array()) {
+ global $aio_wp_security;
+
+ $temp_dir = get_temp_dir();
+ $backtrace_filename = wp_unique_filename($temp_dir, 'log_backtrace_' . time() . '.txt');
+ $backtrace_filepath = $temp_dir.$backtrace_filename;
+ if (count($logs) > 0) {
+ $dbg = "";
+ foreach ($logs as $log) {
+ $dbg.= "############ BACKTRACE STARTS ########\n";
+ $dbg.= $log['backtrace_log'];
+ $dbg.= "############ BACKTRACE ENDS ########\n\n";
+ }
+ } else {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace, PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection -- PCP and compatibility warnings. Safe to ignore.
+ $dbg = debug_backtrace();
+ }
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- PCP warning. Ignore
+ $is_log_file_written = file_put_contents($backtrace_filepath, print_r($dbg, true));
+ if ($is_log_file_written) {
+ return $backtrace_filepath;
+ } else {
+ $aio_wp_security->debug_logger->log_debug("Error in writing php backtrace file " . $backtrace_filepath . " to attach in email.", 4);
+ return '';
+ }
+ }
+
+ /**
+ * Normalise call stacks by clearing out unnecessary objects from their arguments list, leaving only the first arguments as a string. The call stacks should be one that is generated by debug_backtrace() function.
+ *
+ * @param array $backtrace The output of the debug_backtrace() function
+ * @return array An array of associative arrays after being normalised
+ */
+ public static function normalise_call_stack_args($backtrace) {
+ foreach ($backtrace as $index => $element) {
+ if (!isset($element['args']) || !is_array($element['args']) || !isset($element['args'][0])) $backtrace[$index]['args'] = array('');
+ foreach ($backtrace[$index]['args'] as $key => $arg) {
+ if (is_object($arg)) {
+ $backtrace[$index]['args'][$key] = array(get_class($backtrace[$index]['args'][$key]));
+ } elseif (!is_string($arg)) {
+ $backtrace[$index]['args'][$key] = array('');
+ }
+ }
+
+ if ('apply_filters' == $backtrace[$index]['function'] && 'authenticate' == $backtrace[$index]['args'][0]) {
+ $backtrace[$index]['args'] = array('authenticate');
+ }
+
+ if ('do_action' == $backtrace[$index]['function'] && 'password_reset' == $backtrace[$index]['args'][0]) {
+ $backtrace[$index]['args'] = array('password_reset');
+ }
+
+ $keys_to_filter = array('wp_create_user', 'wpmu_create_user', 'wp_authenticate', 'post_authenticate', 'reset_password');
+ if (in_array($backtrace[$index]['function'], $keys_to_filter)) {
+ $backtrace[$index]['args'] = array();
+ }
+ }
+ return $backtrace;
+ }
+
+ /**
+ * Check whether the WooCommerce plugin is active.
+ *
+ * @return Boolean True if the WooCommerce plugin is active, otherwise false.
+ */
+ public static function is_woocommerce_plugin_active() {
+ return is_plugin_active('woocommerce/woocommerce.php');
+ }
+
+ /**
+ * Check whether incompatible TFA premium plugin version active.
+ *
+ * @return boolean True if the incompatible TFA premium plugin version active, otherwise false.
+ */
+ public static function is_incompatible_tfa_premium_version_active() {
+ if (!function_exists('get_plugin_data')) {
+ require_once(ABSPATH . '/wp-admin/includes/plugin.php');
+ }
+
+ $active_plugins = wp_get_active_and_valid_plugins();
+
+ foreach ($active_plugins as $plugin_file) {
+ if ('two-factor-login.php' == basename($plugin_file) && is_dir(dirname($plugin_file) . '/simba-tfa/premium') && version_compare(get_plugin_data($plugin_file, false, false)['Version'], AIOS_TFA_PREMIUM_LATEST_INCOMPATIBLE_VERSION, '<=')) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check whether TFA plugin activating.
+ *
+ * @return boolean True if the TFA plugin activating, otherwise false.
+ */
+ public static function is_tfa_or_self_plugin_activating() {
+ // The $GLOBALS['pagenow'] doesn't set in the network admin plugins page and it throws the warning "Notice: Undefined index: pagenow in ..." so we can't use it.
+ // https://core.trac.wordpress.org/ticket/42656
+ return is_admin() &&
+ isset($_SERVER['PHP_SELF']) && preg_match('#/wp-admin/plugins.php$#i', sanitize_text_field(wp_unslash($_SERVER['PHP_SELF']))) && isset($_GET['plugin']) && (preg_match("/\/two-factor-login.php/", sanitize_text_field(wp_unslash($_GET['plugin']))) || preg_match("/all-in-one-wp-security-and-firewall/", sanitize_text_field(wp_unslash($_GET['plugin'])))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. Ignore.
+ }
+
+ /**
+ * Check whether the site is running on localhost or not.
+ *
+ * @return Boolean True if the site is on localhost, otherwise false.
+ */
+ public static function is_localhost() {
+ if (defined('AIOS_IS_LOCALHOST')) {
+ return AIOS_IS_LOCALHOST;
+ }
+
+ if (empty($_SERVER['REMOTE_ADDR'])) {
+ return false;
+ }
+ return in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')) ? true : false;
+ }
+
+ /**
+ * Get server software.
+ *
+ * @return string Server software or empty.
+ */
+ public static function get_server_software() {
+ static $server_software;
+ if (!isset($server_software)) {
+ $server_software = (isset($_SERVER['SERVER_SOFTWARE']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE'])) : '');
+ }
+ return $server_software;
+ }
+
+ /**
+ * Check whether the server is apache or not.
+ *
+ * @return Boolean True the server is apache, otherwise false.
+ */
+ public static function is_apache_server() {
+ return (false !== strpos(self::get_server_software(), 'Apache'));
+ }
+
+ /**
+ * Change salt postfixes.
+ *
+ * @return boolean True if the salt postfixes are changed otherwise false.
+ */
+ public static function change_salt_postfixes() {
+ global $aio_wp_security;
+
+ $salt_postfixes_scheme = array('auth', 'secure_auth', 'logged_in', 'nonce', 'wpcf7_submission');
+ $salt_postfixes_scheme = apply_filters('aios_salt_postfixes_scheme', $salt_postfixes_scheme);
+ $salt_postfixes = array();
+ foreach ($salt_postfixes_scheme as $scheme) {
+ $salt_postfixes[$scheme] = wp_generate_password(64, true, true);
+ }
+ return $aio_wp_security->configs->set_value('aiowps_salt_postfixes', $salt_postfixes, true);
+ }
+
+ /**
+ * This function checks to see if there is a display condition for the item and if so runs it otherwise it returns true to display the item
+ *
+ * @param array $item_info - the item information array
+ *
+ * @return boolean - true if the item should be displayed or false to hide it
+ */
+ public static function should_display_item($item_info) {
+ if (!empty($item_info['display_condition_callback']) && is_callable($item_info['display_condition_callback'])) {
+ return call_user_func($item_info['display_condition_callback']);
+ } elseif (!empty($item_info['display_condition_callback']) && !is_callable($item_info['display_condition_callback'])) {
+ $item = isset($item_info['page_title']) ? $item_info['page_title'] : '';
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Ignore.
+ error_log("Callback function set but not callable (coding error). Item: " . $item);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Verify the username is valid based on logged_in cookie information
+ *
+ * @see https://developer.wordpress.org/reference/functions/wp_validate_auth_cookie/
+ * @param string $info - Cookie info
+ * @param int $grace - A grace period for the expiration in seconds
+ * @return string - Username if valid; blank string otherwise
+ */
+ public static function verify_username($info, $grace = 3600) {
+
+ if (!is_string($info)) return '';
+
+ $elements = wp_parse_auth_cookie($info, 'logged_in');
+
+ if (empty($elements)) return '';
+
+ $username = $elements['username'];
+ $expiration = $elements['expiration'];
+ $token = $elements['token'];
+ $hmac = $elements['hmac'];
+ $scheme = $elements['scheme'];
+
+ // Add a grace period to the expiration check since there may be a delay in processing the user data
+ if (!empty($grace) && ($expiration + absint($grace)) < time()) return '';
+
+ $user = get_user_by('login', $username);
+
+ if (false === $user) return '';
+
+ $pass_frag = substr($user->user_pass, 8, 4);
+
+ $key = wp_hash($username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme);
+
+ // Use sha1, if sha256 is not available
+ $algo = function_exists('hash') ? 'sha256' : 'sha1';
+ $hash = hash_hmac($algo, $username . '|' . $expiration . '|' . $token, $key);
+
+ if (hash_equals($hash, $hmac)) {
+ return $username;
+ }
+
+ return '';
+ }
+
+ /**
+ * Get the blog ID from the provided request
+ *
+ * @param array $request
+ * @return int - returns the blog_id or 0 if it cannot be found
+ */
+ public static function get_blog_id_from_request($request) {
+
+ if (!is_multisite()) return get_current_blog_id();
+
+ $can_get_blog_id = isset($request['REQUEST_SCHEME']) && isset($request['HTTP_HOST']) && isset($request['REQUEST_URI']);
+ if (!$can_get_blog_id) return 0;
+
+ $site_url = $request['REQUEST_SCHEME'].'://'.$request['HTTP_HOST'].$request['REQUEST_URI'];
+ $components = wp_parse_url(trailingslashit($site_url));
+
+ $can_get_blog_id = isset($components['host']) && isset($components['path']);
+ if (!$can_get_blog_id) return 0;
+
+ $default_path = defined('PATH_CURRENT_SITE') ? constant('PATH_CURRENT_SITE') : '/';
+
+ $domain = $components['host'];
+ $path = SUBDOMAIN_INSTALL ? $default_path : ($default_path === $components['path'] ? $components['path'] : '/'.explode('/', $components['path'])[1].'/');
+
+ $blog_id = get_blog_id_from_url($domain, $path);
+
+ // On a subdirectory installation, if the blog_id cannot be found for the subdirectory given, we assume it's a path belonging to the main site
+ // So use the main site's blog_id.
+ if (0 === $blog_id && !SUBDOMAIN_INSTALL) $blog_id = get_blog_id_from_url($domain, $default_path);
+
+ return $blog_id;
+ }
+
+ /**
+ * Checks if the bbPress plugin is active.
+ *
+ * @return Boolean True if the bbPress plugin is active, otherwise false.
+ */
+ public static function is_bbpress_plugin_active() {
+ return is_plugin_active('bbpress/bbpress.php');
+ }
+
+ /**
+ * Checks if the Buddypress plugin is active.
+ *
+ * @return Boolean True if the Buddypress plugin is active, otherwise false.
+ */
+ public static function is_buddypress_plugin_active() {
+ return is_plugin_active('buddypress/bp-loader.php');
+ }
+
+ /**
+ * Checks if the Contact Form 7 plugin is active.
+ *
+ * @return Boolean - True if the Contact Form 7 plugin is active, otherwise false.
+ */
+ public static function is_contact_form_7_plugin_active() {
+ return is_plugin_active('contact-form-7/wp-contact-form-7.php');
+ }
+
+ /**
+ * Checks if the Memberpress plugin is active.
+ *
+ * @return Boolean - True if the Memberpress plugin is active, otherwise false.
+ */
+ public static function is_memberpress_plugin_active() {
+ return is_plugin_active('memberpress/memberpress.php');
+ }
+
+ /**
+ * Retrieves and returns current WP general settings date time format.
+ *
+ * @return string
+ */
+ public static function get_wp_datetime_format() {
+ return get_option('date_format') . ' ' . get_option('time_format');
+ }
+
+ /**
+ * This function gets the timezone of the site as a DateTimeZone object
+ *
+ * @see https://developer.wordpress.org/reference/functions/wp_timezone/
+ *
+ * @return DateTimeZone - the timezone of the site as a DateTimeZone object
+ */
+ public static function get_wp_timezone() {
+ return new DateTimeZone(self::get_wp_timezone_string());
+ }
+
+ /**
+ * This function gets the timezone of the site as a string
+ *
+ * @see https://developer.wordpress.org/reference/functions/wp_timezone_string/
+ *
+ * @return string - PHP timezone name or a ±HH:MM offset
+ */
+ public static function get_wp_timezone_string() {
+ $timezone_string = get_option('timezone_string');
+
+ if ($timezone_string) return $timezone_string;
+
+ $offset = (float) get_option('gmt_offset');
+ $hours = (int) $offset;
+ $minutes = ($offset - $hours);
+ $sign = ($offset < 0) ? '-' : '+';
+ $abs_hour = abs($hours);
+ $abs_mins = abs($minutes * 60);
+ $tz_offset = sprintf('%s%02d:%02d', $sign, $abs_hour, $abs_mins);
+
+ return $tz_offset;
+ }
+
+ /**
+ * Converts a Unix timestamp to WP general settings timezone and format. It will also translate with wp_date if available.
+ *
+ * @param string $timestamp Optional. Will default to time() if not provided.
+ * @param string $format Optional. Will default to WP general settings format if not provided.
+ *
+ * @return string
+ */
+ public static function convert_timestamp($timestamp = null, $format = null) {
+
+ if (!$format) $format = self::get_wp_datetime_format();
+
+ if (!$timestamp) $timestamp = time();
+
+ return function_exists('wp_date') ? wp_date($format, $timestamp) : get_date_from_gmt(gmdate('Y-m-d H:i:s', $timestamp), $format);
+ }
+
+ /**
+ * Deletes unneeded default WP files.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ *
+ * @param bool $echo_results
+ *
+ * @return array
+ */
+ public static function delete_unneeded_default_files($echo_results = false) {
+ global $aio_wp_security;
+
+ $files = array('readme.html', 'wp-config-sample.php', 'license.txt');
+ $info = array();
+ $error = array();
+ foreach ($files as $file_name) {
+ $file_path = ABSPATH . $file_name;
+
+ if (file_exists($file_path)) {
+ if (@wp_delete_file($file_path)) {
+ /* translators: %s: File name */
+ $success_message = sprintf(__('Successfully deleted the %s file.', 'all-in-one-wp-security-and-firewall'), $file_name);
+ $aio_wp_security->debug_logger->log_debug($success_message, 0);
+
+ if ($echo_results) {
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st($success_message);
+ }
+ } else {
+ /* translators: %s: File name */
+ $failure_message = sprintf(__('Failed to delete the %s file.', 'all-in-one-wp-security-and-firewall'), $file_name) . ' ' . sprintf(__('Check the file/directory permissions at: %s', 'all-in-one-wp-security-and-firewall'), $file_path);
+ $error[] = $file_name;
+ $aio_wp_security->debug_logger->log_debug($failure_message, 4);
+
+ if ($echo_results) {
+ AIOWPSecurity_Admin_Menu::show_msg_error_st($failure_message);
+ }
+ }
+ } else {
+ /* translators: %s: File name */
+ $message = sprintf(__('The %s file has already been deleted.', 'all-in-one-wp-security-and-firewall'), $file_name);
+ $info[] = $message;
+ $aio_wp_security->debug_logger->log_debug($message, 0);
+
+ if ($echo_results) {
+ AIOWPSecurity_Admin_Menu::show_msg_updated_st($message);
+ }
+ }
+ }
+
+
+ return array(
+ 'info' => $info,
+ 'error' => empty($error) ? '' : implode(', ', $error)
+ );
+ }
+
+ /**
+ * Convert a number of bytes into a suitable textual string
+ *
+ * @param Integer $size - the number of bytes
+ *
+ * @return String - the resulting textual string
+ */
+ public static function convert_numeric_size_to_text($size) {
+ if ($size > 1073741824) {
+ return round($size / 1073741824, 1).' GB';
+ } elseif ($size > 1048576) {
+ return round($size / 1048576, 1).' MB';
+ } elseif ($size > 1024) {
+ return round($size / 1024, 1).' KB';
+ } else {
+ return round($size, 1).' B';
+ }
+ }
+
+ /**
+ * Updates the Googlebot IP ranges config.
+ *
+ * @return array|WP_Error
+ */
+ public static function get_googlebot_ip_ranges() {
+ $response = wp_safe_remote_get('https://developers.google.com/static/search/apis/ipranges/googlebot.json');
+
+ $body = wp_remote_retrieve_body($response);
+ $json_array = json_decode($body, true);
+
+ $ip_list_array = array();
+
+ foreach ($json_array['prefixes'] as $prefix) {
+ $ip_list_array[] = array_key_exists('ipv4Prefix', $prefix) ? $prefix['ipv4Prefix'] : $prefix['ipv6Prefix'];
+ }
+
+ return AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'whitelist');
+ }
+
+ /**
+ * This function creates and outputs the csv file for download
+ *
+ * @param array $items - the content
+ * @param array $export_keys - the keys for the content
+ * @param string $filename - the filename
+ *
+ * @return void
+ */
+ public static function output_csv($items, $export_keys, $filename = 'data.csv') {
+ header("Content-Type: text/csv; charset=utf-8");
+ header("Content-Disposition: attachment; filename=".$filename);
+ header("Pragma: no-cache");
+ header("Expires: 0");
+ $output = fopen('php://output', 'w'); //open output stream
+
+ fputcsv($output, $export_keys, ',', '"', '\\'); // let's put column names first
+
+ foreach ($items as $item) {
+ $csv_line = array();
+
+ foreach ($export_keys as $key => $value) {
+ if (isset($item[$key])) {
+ $csv_line[] = ('created' == $key) ? AIOWPSecurity_Utility::convert_timestamp($item[$key]) : $item[$key];
+ }
+ }
+ fputcsv($output, $csv_line, ',', '"', '\\');
+ }
+ }
+
+ /**
+ * Check if a user is a member of the current blog ID in a multisite environment.
+ *
+ * @param int $user_id - User Id to check.
+ *
+ * @return bool Whether the user is a member of the current blog ID.
+ */
+ public static function is_user_member_of_blog($user_id) {
+ $current_user_id = get_current_user_id();
+
+ if (is_multisite() && !is_super_admin($current_user_id)) {
+ $blog_id = get_current_blog_id();
+ return is_user_member_of_blog($user_id, $blog_id);
+ }
+
+ // Non-multisite or super admin, consider the user a member
+ return true;
+ }
+
+ /**
+ * Blacklists an IP address.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @global AIOWPS\Firewall\Config $aiowps_firewall_config
+ *
+ * @param string $ip The IP address to be blacklisted.
+ *
+ * @return void|WP_Error
+ */
+ public static function blacklist_ip($ip) {
+ global $aio_wp_security;
+ $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
+
+ $blacklisted_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
+
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($blacklisted_ip_addresses);
+ $ip_list_array[] = $ip;
+
+ $validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
+
+ if (is_wp_error($validated_ip_list_array)) {
+ return $validated_ip_list_array;
+ } else {
+ $banned_ip_data = implode("\n", $validated_ip_list_array);
+
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '1'); // Force blacklist feature to be enabled.
+ $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', $banned_ip_data);
+ $aio_wp_security->configs->save_config();
+
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
+ }
+ }
+
+ /**
+ * Unlocks an IP address.
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $ip The IP address to be blacklisted.
+ *
+ * @return boolean
+ */
+ public static function unlock_ip($ip) {
+ global $wpdb;
+
+ $lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
+
+ // Unlock single record.
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
+ $result = $wpdb->query($wpdb->prepare("UPDATE $lockout_table SET `released` = UNIX_TIMESTAMP() WHERE `failed_login_ip` = %s", $ip));
+
+ return null != $result;
+ }
+
+ /**
+ * Unblacklists an IP address.
+ *
+ * @global AIO_WP_Security $aio_wp_security
+ * @global AIOWPS\Firewall\Config $aiowps_firewall_config
+ *
+ * @param string $ip The IP address to be unblacklisted.
+ *
+ * @return boolean
+ */
+ public static function unblacklist_ip($ip) {
+ global $aio_wp_security;
+ $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
+
+ $blacklisted_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
+
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($blacklisted_ip_addresses);
+
+ if (!in_array($ip, $ip_list_array)) {
+ return false;
+ }
+
+ $ip_list_array = array_diff($ip_list_array, array($ip));
+
+ $banned_ip_data = implode("\n", $ip_list_array);
+
+ $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', $banned_ip_data);
+ $aio_wp_security->configs->save_config();
+
+ $aiowps_firewall_config->set_value('aiowps_blacklist_ips', $ip_list_array);
+
+ return true;
+ }
+
+ /**
+ * Determines if the .htaccess file can be written to.
+ *
+ * This function checks if the current user has the necessary permissions
+ * (is the main site and super admin) and whether the server type is supported
+ * for writing to the .htaccess file. It prevents modifications on unsupported
+ * server types such as Nginx and IIS.
+ *
+ * @return bool True if .htaccess can be written to, false otherwise.
+ */
+ public static function allow_to_write_to_htaccess() {
+ if (!AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin()) return false;
+ $serverType = self::get_server_type();
+
+ return !in_array($serverType, array('-1', 'nginx', 'iis'));
+ }
+
+ /**
+ * Render the 5G Legacy Tab.
+ *
+ * This function checks if the current site is the main site and if the user is a super admin.
+ * If these conditions are met, it checks whether the 5G firewall is enabled or not.
+ *
+ * @global object $aio_wp_security The global instance of the All-In-One WP Security & Firewall plugin.
+ *
+ * @return bool returns true if the 5G firewall is enabled, false otherwise.
+ */
+ public static function render_5g_legacy_tab() {
+ global $aio_wp_security;
+ if (!AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin()) return false;
+
+ return '1' == $aio_wp_security->configs->get_value('aiowps_enable_5g_firewall');
+ }
+
+ /**
+ * Filters an array item based on a specified callback key.
+ *
+ * This function checks if a specified callback is present and callable within the array item.
+ * If the callback is callable, it executes the callback and returns the result.
+ * If the callback is set but not callable, it logs an error and returns false.
+ * If no callback is set, the function returns true.
+ *
+ * @param array $item The array item to filter.
+ * @param string $callback_key The key in the array to check for a callable function.
+ *
+ * @return bool|mixed Returns the result of the callback if callable, false if the callback is not callable,
+ * or true if no callback is set.
+ */
+ public static function apply_callback_filter($item, $callback_key) {
+ if (isset($item[$callback_key])) {
+ if (is_callable($item[$callback_key])) {
+ return call_user_func($item[$callback_key]);
+ } else {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Required for AIOS error reporting.
+ error_log("Callback function set but not callable (coding error)");
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Checks if other specific form-related plugins are active.
+ *
+ * @return bool Returns `true` if any of the specified plugins (bbPress, BuddyPress,
+ * or Contact Form 7) are active, or `false` if none of them are active.
+ */
+ public static function is_other_form_plugins_active() {
+ return self::is_bbpress_plugin_active() || self::is_buddypress_plugin_active() || self::is_contact_form_7_plugin_active();
+ }
+
+ /**
+ * Unserialize data while maintaining compatibility across PHP versions due to different number of arguments required by PHP's "unserialize" function
+ *
+ * @param string $serialized_data Data to be unserialized, should be one that is already serialized
+ * @param boolean|array $allowed_classes Either an array of class names which should be accepted, false to accept no classes, or true to accept all classes
+ * @param integer $max_depth The maximum depth of structures permitted during unserialization, and is intended to prevent stack overflows
+ *
+ * @return mixed Unserialized data can be any of types (integer, float, boolean, string, array or object)
+ */
+ public static function unserialize($serialized_data, $allowed_classes = false, $max_depth = 0) {
+ if (version_compare(PHP_VERSION, '7.0', '<')) {
+ $result = unserialize($serialized_data);
+ } else {
+ $result = unserialize($serialized_data, array('allowed_classes' => $allowed_classes, 'max_depth' => $max_depth)); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound -- This is the method used to unserialize data instead of the default unserialize method
+ }
+ return $result;
+ }
+
+ /**
+ * Gets the rest route starting with namespace from the REST API endpoint
+ * It excludes rest url prefix 'wp-json' and multisite folder from the endpoint
+ * For example 'wc/store/v1/cart', 'contact-form-7/v1/contact-forms/45/feedback'
+ *
+ * @return string rest route starting with namespace
+ */
+ public static function get_rest_route() {
+ $rest_route = !empty($_GET['rest_route']) ? sanitize_text_field(stripslashes($_GET['rest_route'])) : '';
+ // If route is not found in query parameter, extract from REQUEST_URI
+ if (empty($rest_route)) {
+ $request_uri = !empty($_SERVER['REQUEST_URI']) ? urldecode($_SERVER['REQUEST_URI']) : '';
+ $parsed_url = parse_url(trim($request_uri, '/'));
+ $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
+ if (false !== strpos($path, rest_get_url_prefix())) {
+ $path = preg_replace('/index\.php\//', '', $path); // index.php from path removed.
+ $rest_route = preg_replace('/(.*)\/?'.rest_get_url_prefix().'\/?/', '', $path); // wp-json rest prefix and multisite folder excluded
+ $rest_route = trim($rest_route, '/');
+ if (empty($rest_route)) $rest_route = '/'; // "wp-json" rest request without name space called.
+ } else {
+ $rest_route = '';
+ }
+ }
+ return $rest_route;
+ }
+
+ /**
+ * Get the registered namespace for REST routes end points 'wc', 'contact-form-7'
+ *
+ * @return array namespace.
+ */
+ public static function get_rest_namespaces() {
+ $rest_server = rest_get_server();
+ $namespaces = $rest_server->get_namespaces();
+ $rest_route_namespaces = array();
+ foreach ($namespaces as $namesapce) {
+ $rest_route_namespaces[] = explode('/', $namesapce)[0]; // Namespace 'wc' only to consider instead 'wc/v1', 'wc/v2', 'wc/v3', 'wc/store'
+ }
+ $route_namespaces = array_unique($rest_route_namespaces);
+ sort($route_namespaces);
+ return $route_namespaces;
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-wp-footer-content.php b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-wp-footer-content.php
new file mode 100755
index 00000000..97bf1dde
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/classes/wp-security-wp-footer-content.php
@@ -0,0 +1,57 @@
+configs->get_value('aiowps_enable_woo_login_captcha') || '1' == $aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') || '1' == $aio_wp_security->configs->get_value('aiowps_enable_woo_checkout_captcha') || '1' == $aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha')) {
+ $aio_wp_security->captcha_obj->print_captcha_api_woo();
+ }
+ }
+
+ // Activate the copy protection feature for non-admin users
+ $copy_protection_active = $aio_wp_security->configs->get_value('aiowps_copy_protection') == '1';
+ if ($copy_protection_active && !AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
+ $this->output_copy_protection_code();
+ }
+
+ //TODO - add other footer output content here
+ }
+
+ public function output_copy_protection_code() {
+ ?>
+
+
+ configs->get_value('aiowps_enable_rename_login_page') == '1') {
+ include_once(AIO_WP_SECURITY_PATH . '/classes/wp-security-process-renamed-login-page.php');
+ new AIOWPSecurity_Process_Renamed_Login_Page();
+ AIOWPSecurity_Process_Renamed_Login_Page::renamed_login_init_tasks();
+ } else {
+ add_action('login_init', array($this, 'aiowps_login_init'));
+ }
+
+ $this->do_lockout_tasks();
+
+ do_action('aiowps_wp_loaded_tasks_end', $this);
+
+ }
+
+ /**
+ * Perform lockout task if it is applicable.
+ *
+ * @return void
+ */
+ private function do_lockout_tasks() {
+ global $aio_wp_security;
+
+ if (1 != $aio_wp_security->configs->get_value('aiowps_site_lockout')) {
+ return;
+ }
+
+ if ('admin-ajax.php' == $GLOBALS['pagenow']) {
+ return;
+ }
+
+ // Show login screen to all non-logged in users.
+ if ('wp-login.php' == $GLOBALS['pagenow']) {
+ return;
+ }
+
+ // WP CLI and cronjob do not required site lockout.
+ if ((defined('DOING_CRON') && DOING_CRON) || 'cli' == PHP_SAPI) {
+ return;
+ }
+
+ // The lockout message should not be displayed to an administrator user.
+ if (is_user_logged_in() && current_user_can('manage_options')) {
+ return;
+ }
+
+ // Non administrator users to lockout accessing admin area.
+ if (is_user_logged_in() && !current_user_can('manage_options') && is_admin()) {
+ wp_redirect(home_url());
+ }
+
+ // Non-logged in users try access admin area, redirect to login page.
+ if (is_admin()) {
+ return;
+ }
+
+ self::site_lockout_tasks();
+ }
+
+ /**
+ * Render lockout output.
+ *
+ * @return void
+ */
+ public static function site_lockout_tasks() {
+ $lockout_output = apply_filters('aiowps_site_lockout_output', '');
+ if (empty($lockout_output)) {
+ nocache_headers();
+ header("HTTP/1.0 503 Service Unavailable");
+ remove_action('wp_head', 'head_addons', 7);
+ $template = apply_filters('aiowps_site_lockout_template_include', AIO_WP_SECURITY_PATH . '/other-includes/wp-security-visitor-lockout-page.php');
+ include_once($template);
+ } else {
+ echo wp_kses_post($lockout_output);
+ }
+
+ exit();
+ }
+
+ public static function aiowps_login_init() {
+ //if user is logged in and tries to access login page - redirect them to wp-admin
+ //this will prevent issues such as the following:
+ //https://wordpress.org/support/topic/already-logged-in-no-captcha
+ if (is_user_logged_in()) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ $redirect_to = (isset($_REQUEST['redirect_to'])) ? sanitize_text_field(wp_unslash($_REQUEST['redirect_to'])) : admin_url();
+ wp_safe_redirect($redirect_to);
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
+ } elseif (!(isset($_GET['action']) && 'postpass' == $_GET['action'])) {
+ AIOWPSecurity_Utility_IP::check_login_whitelist_and_forbid();
+ }
+ }
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/css/index.html b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/index.html
new file mode 100755
index 00000000..e69de29b
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-admin-styles.css b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-admin-styles.css
new file mode 100755
index 00000000..4ffeaaa6
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-admin-styles.css
@@ -0,0 +1,1211 @@
+.aio_bold {
+ font-weight: bold;
+}
+
+.aio_half_width {
+ width: 50%;
+}
+
+.aio_one_third_width {
+ width: 33%;
+}
+
+.aio_width_80 {
+ width: 80%;
+}
+
+.aio_max_500 {
+ max-width: 500px;
+}
+
+.aio_spacer_15 {
+ margin-top: 15px;
+}
+
+.aio_spacer_10_tb {
+ margin: 10px 0;
+}
+
+.aio_spacer_10_tblr {
+ margin: 10px;
+}
+
+.aio_clear_float {
+ clear: both;
+}
+
+.aio_float_left {
+ float: left;
+}
+
+.aio_padding_10 {
+ padding: 10px !important;
+}
+
+.aio_section_separator_1 {
+ border-bottom: 1px solid #DEDEDE;
+ height: 10px;
+}
+
+.aiowps_admin_ul_grp1 {
+ list-style: circle;
+ padding: 0 0 0 30px;
+}
+
+.aio_grey_box {
+ margin: 10px 0 15px 0;
+ background-color: #ECECEC;
+ border: 1px solid #CFCFCF;
+ padding: 0 0 0 1em;
+}
+
+.aio_yellow_box {
+ margin: 10px 0 15px 0;
+ background-color: #FFFFE0;
+ border-color: #E6DB55;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 0 0 1em;
+}
+
+.aio_blue_box {
+ margin: 10px 0 15px 0;
+ background-color: #F0F9FF;
+ border-color: #16B;
+ color: #16B;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 0 0 1em;
+ line-height: 20px;
+ overflow-wrap: break-word;
+}
+
+.aio_green_box {
+ margin: 10px 0 15px 0;
+ background-color: #CCF4D6;
+ border-color: #059B53;
+ color: #043B14;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 1em;
+}
+
+.aio_red_box {
+ margin: 10px 0 15px 0;
+ background-color: #FFEBE8;
+ border-color: #C00;
+ color: #333;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 1em;
+}
+
+.aio_orange_box {
+ margin: 10px 0 15px 0;
+ background-color: #FFB900;
+ border-color: #D64500;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 1em;
+}
+
+.aio_success_with_icon {
+ background-image: url("../images/success.png");
+ background-repeat: no-repeat;
+ color: #529901;
+ padding-left: 20px;
+ font-size: 14px;
+}
+
+.aio_error_with_icon {
+ color: #F00;
+ background-image: url("../images/error.png");
+ background-repeat: no-repeat;
+ padding-left: 20px;
+ font-size: 14px;
+}
+
+.aio_info_with_icon {
+ background-image: url("../images/info-icon.png");
+ background-repeat: no-repeat;
+ color: #16B;
+ padding-left: 20px;
+ font-size: 14px;
+}
+
+.file_permission_table {
+ margin: 20px 0;
+}
+
+.file_permission_table thead tr th {
+ background: #CCC;
+}
+
+.file_permission_table td {
+ padding: 7px;
+ font-family: "Courier 10 Pitch",courier,monospace;
+ color: #262626;
+ border-bottom: 1px solid #F2F2F2;
+ border-top: none;
+}
+
+.aio_table_row_red {
+ background-color: #FD6D73;
+}
+
+.aio_table_row_yellow {
+ background-color: #F5E679;
+}
+
+.aio_table_row_green {
+ background-color: #C8F18B;
+}
+
+.aiowps_loading_1 {
+ margin: 0 5px;
+}
+
+.aio_text_area_file_output {
+ background: none repeat scroll 0 0 #F9F9F9;
+ font-family: consolas,monaco,monospace;
+ font-size: 12px;
+ outline: 0 none;
+}
+
+.aiowps_more_info_anchor {
+ display: inline-block;
+ background-color: #D9D9D9;
+ color: #21759B;
+ font: 0.9em/1.455em "Lucida Grande","Lucida Sans Unicode",tahoma,verdana,sans-serif;
+ text-decoration: none;
+ padding: 3px 5px;
+}
+
+.aiowps_more_info_anchor:hover {
+ color: #333;
+ cursor: pointer;
+}
+
+.aiowps_more_info_toggle_char {
+ display: inline-block;
+ margin-right: 3px;
+ padding: 0 3px;
+ text-align: center;
+ background-color: #EDEDED;
+ width: 10px;
+}
+
+.aiowps_more_info_body {
+ margin: 10px 0 15px 0;
+ background-color: #FFFFE0;
+ border-color: #E6DB55;
+ border-radius: 3px;
+ border-style: solid;
+ border-width: 1px;
+ padding: 0 0 0 1em;
+}
+
+.aiowps_dashboard_box_small {
+ float: left;
+ max-width: 350px;
+ margin-right: 15px;
+}
+
+#canvas-holder {
+ width: 300px;
+ margin: auto;
+ padding-top: 20px;
+}
+
+#website-strength-text {
+ text-align: center !important;
+ font-size: 1.5em !important;
+ padding-bottom: 20px !important;
+}
+
+#security_strength_chart_div table {
+ margin-right: auto !important;
+ margin-left: auto !important;
+}
+
+.aiowps_dashboard_widget_footer {
+ background-color: #E6E6E6;
+ padding: 10px;
+}
+
+.aiowps_feature_status_bar {
+ display: block;
+ float: left;
+ width: 120px;
+ height: 26px;
+ position: relative;
+ background: rgba(0, 0, 0, 0.25);
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1); /* phpcs:ignore Squiz.CSS.ForbiddenStyles.FoundWithAlternative -- This is a fallback for older browsers */
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1);
+}
+
+.aiowps_feature_status_name {
+ width: 50%;
+ font-weight: bold;
+ float: left;
+ padding: 5px 10px 5px 0;
+}
+
+.aiowps_feature_status_label {
+ display: block;
+ float: left;
+ padding: 4px;
+ text-align: center;
+ width: 52px;
+ color: #F7F7F7;
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+.aiowps_feature_status_on {
+ color: #043B14;
+ background: #65BD63;
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, #9DD993, #65BD63); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Safari and Chrome */
+ background-image: -moz-linear-gradient(top, #9DD993, #65BD63); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ background-image: -o-linear-gradient(top, #9DD993, #65BD63); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Opera */
+ background-image: linear-gradient(top bottom, #9DD993, #65BD63); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- Previous definitions are for outdated browsers */
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2); /* phpcs:ignore Squiz.CSS.ForbiddenStyles.FoundWithAlternative -- This is a fallback for older browsers */
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+}
+
+.aiowps_feature_status_off {
+ color: #4D0000;
+ background: #BD6363;
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, #D99393, #BD6363); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Safari and Chrome */
+ background-image: -moz-linear-gradient(top, #D99393, #BD6363); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ background-image: -o-linear-gradient(top, #D99393, #BD6363); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Opera */
+ background-image: linear-gradient(top bottom, #D99393, #BD6363); /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- Previous definitions are for outdated browsers */
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2); /* phpcs:ignore Squiz.CSS.ForbiddenStyles.FoundWithAlternative -- This is a fallback for older browsers */
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+}
+
+.aiowps_features_grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ grid-gap: 0 10px;
+ margin: 10px 0;
+}
+
+.aiowps_critical_feature_link,
+.aiowps_critical_feature_link:hover {
+ text-decoration: none;
+ color: inherit;
+}
+
+.aiowps_critical_feature_status_container {
+ display: flex;
+ align-items: center;
+ padding: 5px 8px;
+ min-height: 30px;
+ transition: all 0.2s ease;
+}
+
+.aiowps_critical_feature_status_name {
+ flex: 1.5;
+ font-weight: bold;
+ margin-right: 8px;
+}
+
+.aiowps_feature_status_circle {
+ width: 24px;
+ height: 24px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex: 1;
+}
+
+.aiowps_feature_status_circle_on,
+.aiowps_feature_status_circle_off {
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ transition: transform 0.2s ease;
+}
+
+.aiowps_feature_status_circle_on {
+ background-color: #4CD964;
+}
+
+.aiowps_feature_status_circle_off {
+ background-color: #E4584F;
+}
+
+.aiowps_critical_feature_status_container:hover .aiowps_feature_status_circle_on,
+.aiowps_critical_feature_status_container:hover .aiowps_feature_status_circle_off {
+ transform: scale(1.1);
+}
+
+@media (max-width: 768px) {
+
+ .aiowps_features_grid {
+ grid-template-columns: 1fr;
+ }
+
+}
+
+.aiowps_feature_details_badge {
+ width: 100%;
+ font-size: 14px;
+}
+
+.aiowps_feature_details_badge_difficulty, .aiowps_feature_details_badge_points {
+ display: inline-block;
+ padding: 7px;
+}
+
+.aiowps_feature_details_badge_difficulty {
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ margin-right: 0;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
+}
+
+.aiowps_feature_details_badge_points {
+ background: #F1F1F1;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ margin-left: -3px;
+}
+
+.aiowps_feature_protection_none {
+ background: #6D797A;
+ color: #FFF;
+}
+
+.aiowps_feature_protection_full {
+ background: #5C3682;
+ color: #FFF;
+}
+
+#aiowps_pw_tool_main {
+ padding-top: 10px;
+}
+
+.aiowps_password_tool_field {
+ padding: 20px 0;
+}
+
+#aiowps_password_crack_info_text, #aiowps_password_hibp_info_text {
+ display: none;
+ line-height: 1.16667em;
+ max-width: 40%;
+}
+
+#aiowps_password_crack_time_calculation {
+ line-height: 1.16667em;
+ color: darkorange;
+}
+
+/* bootstrap type labels */
+.aiowps_dashboard_table {
+ table-layout: fixed;
+}
+
+.aiowps-label-danger {
+ background-color: #D9534F;
+}
+
+.aiowps-label-warning {
+ background-color: #F0AD4E;
+}
+
+.aiowps-label-primary {
+ background-color: #337AB7;
+}
+
+.aiowps-label-success {
+ background-color: #5CB85C;
+}
+
+.aiowps-label {
+ border-radius: 0.25em;
+ color: #FFF;
+ display: inline;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ padding: 0.2em 0.6em 0.3em;
+ text-align: center;
+ vertical-align: baseline;
+ white-space: nowrap;
+}
+
+/* Fix for wp list table nav buttons style messed up in 5.1 */
+.tablenav .tablenav-pages .pagination-links a {
+ display: inline-block;
+ padding: 4px 5px 6px 5px;
+ font-size: 16px;
+ line-height: 1;
+ text-align: center;
+ text-decoration: none;
+ min-width: 17px;
+ border: 1px solid #CCC;
+ background: #F7F7F7;
+}
+
+svg > g > g.google-visualization-tooltip {
+ pointer-events: none;
+}
+
+.wp-security_page_aiowpsec_settings h2, .wp-security_page_aiowpsec_settings #poststuff h2 {
+ padding-left: 0;
+}
+
+.aio_hidden {
+ display: none;
+}
+
+/* Fix for WordPress thickbox not respecting the set width and height */
+/* Open issue for 8 years : https://core.trac.wordpress.org/ticket/27473 */
+#TB_ajaxContent {
+ width: 95% !important;
+ height: 95% !important;
+}
+
+.aiowps_switch {
+ position: relative;
+ display: inline-block;
+ width: 38px;
+ height: 18px;
+ margin-right: 6px;
+ box-sizing: border-box;
+}
+
+.aiowps_switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.aiowps_switch .aiowps_slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #F2F4F5;
+ transition: 0.2s;
+ /* Rounded sliders */
+}
+
+.aiowps_switch .aiowps_slider::before {
+ position: absolute;
+ content: "";
+ height: 8px;
+ width: 8px;
+ left: 2px;
+ bottom: 2px;
+ background-color: #555D66;
+ border: 1px solid #555D66;
+ transition: all 0.2s;
+}
+
+.aiowps_switch .aiowps_slider::after {
+ content: "";
+ display: block;
+ position: absolute;
+ height: 4px;
+ width: 3px;
+ right: 4px;
+ top: 4px;
+ border-radius: 50%;
+ border: 1px solid #72777C;
+ box-sizing: content-box;
+}
+
+.aiowps_switch .aiowps_slider.round {
+ border-radius: 23px;
+ border: 2px solid #555D66;
+}
+
+.aiowps_switch .aiowps_slider.round::before {
+ border-radius: 50%;
+}
+
+.aiowps_switch input:checked + .aiowps_slider {
+ background: #5C3682;
+ border-color: #6F30C9;
+}
+
+.aiowps_switch input:checked + .aiowps_slider::before {
+ background: #FFF;
+ border-color: #FFF;
+ transform: translatex(20px);
+}
+
+.aiowps_switch input:checked + .aiowps_slider::after {
+ content: "";
+ display: block;
+ position: absolute;
+ height: 6px;
+ width: 2px;
+ left: 7px;
+ top: 4px;
+ background: #FFF;
+ border: none;
+}
+
+.aiowps_switch input:disabled + .aiowps_slider,
+.aiowps_switch input:disabled:checked + .aiowps_slider {
+ background: rgba(85, 93, 102, 0.5);
+ border-color: #555D66;
+ opacity: 0.3;
+}
+
+.aiowps_switch input:focus + .aiowps_slider {
+ box-shadow: 0 0 0 2px #F2F4F5, 0 0 0 3px #555D66;
+}
+
+.aiowps_switch input:disabled {
+ display: none;
+ /* Hide default HTML checkbox when it's disabled*/
+}
+
+.aiowps_next_scheduled_scan_wrapper {
+ display: flex;
+ background: #FFF;
+ justify-items: center;
+ flex-wrap: wrap;
+}
+
+.aiowps_next_scheduled_scan_wrapper > div {
+ width: 50%;
+ background: #FFF;
+ height: auto;
+ padding: 33px;
+ box-sizing: border-box;
+}
+
+.aiowps_next_scheduled_entity {
+ width: 50%;
+ display: inline-block;
+ float: left;
+}
+
+.aiowps_next_scheduled_entity .dashicons {
+ color: #CCC;
+ font-size: 20px;
+}
+
+.aiowps_next_scheduled_entity strong {
+ font-size: 20px;
+}
+
+.aiowps_next_scheduled_heading {
+ margin-bottom: 10px;
+}
+
+.aiowps_time_now_wrapper {
+ margin-top: 68px;
+ width: 100%;
+}
+
+.aiowps_time_now_label, .aiowps_time_now {
+ display: inline-block;
+ padding: 7px;
+}
+
+.aiowps_time_now_label {
+ background: #6D797A;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ color: #FFF;
+ margin-right: 0;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
+}
+
+.aiowps_time_now {
+ background: #F1F1F1;
+ color: #3C434A;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ margin-left: -3px;
+}
+
+.aiowps_scan_btn_wrapper {
+ text-align: center;
+ border-left: 1px solid #F1F1F1;
+ justify-content: center;
+ align-items: center;
+}
+
+.aiowps_scan_btn_wrapper .button-large {
+ font-size: 1.3em !important;
+}
+
+.aiowps_next_scheduled_date_time {
+ color: #46A84B;
+}
+
+#aiowps_activejobs_table {
+ overflow: hidden;
+ width: 100%;
+ background: #FAFAFA;
+ padding: 0;
+}
+
+#aiowps_activejobs_table p {
+ text-align: center;
+}
+
+#aiowps_previous_scan_wrapper {
+ overflow: hidden;
+ width: 100%;
+ background: #FAFAFA;
+ padding: 0;
+}
+
+.aiowps_table_container {
+ max-height: 300px;
+ overflow-y: scroll;
+ margin-top: 20px;
+ border: 1px solid #C3C4C7;
+}
+
+.aiowps_scan_result_table {
+ width: 100%;
+ border: none !important;
+}
+
+.aiowps_scan_result_table_header {
+ position: sticky;
+ top: 0;
+ background-color: #FFF;
+ z-index: 1;
+}
+
+.aiowps_spinner.spinner {
+ padding-left: 25px;
+ float: none;
+}
+
+.aiowps_spinner.spinner.visible {
+ visibility: visible;
+ width: auto;
+}
+
+.button-link.aios-toggle-advanced-options {
+ text-decoration: none;
+}
+
+.button-link.aios-toggle-advanced-options:hover {
+ background-color: #FFF;
+}
+
+.button-link.aios-toggle-advanced-options:focus {
+ background-color: #FFF;
+}
+
+button.button-link.aios-toggle-advanced-options.advanced-options-disabled, button.button-link.aios-toggle-advanced-options.advanced-options-disabled span.dashicons-arrow-down-alt2:before {
+ color: #A7AAAD!important;
+ box-shadow: none!important;
+ cursor: default;
+ transform: none!important;
+}
+
+.aios-toggle-advanced-options {
+ display: block;
+ width: 100%;
+ margin-left: -20px;
+ margin-right: -20px;
+ padding-left: 20px;
+ padding-right: 20px;
+ position: relative;
+ text-decoration: none;
+}
+
+.aios-toggle-advanced-options span.text {
+ background: #FFF;
+ z-index: 1;
+ position: relative;
+ padding-right: 5px;
+}
+
+.aios-toggle-advanced-options span.dashicons {
+ text-decoration: none;
+ font-size: 16px;
+ height: 16px;
+ vertical-align: middle;
+ transition: .2s all;
+ color: #444;
+}
+
+.aios-toggle-advanced-options.opened::before {
+ content: '';
+ border-top: 1px solid #CCC;
+ width: calc(100% + 13px);
+ position: absolute;
+ top: 16px;
+ left: -5px;
+}
+
+.aios-toggle-advanced-options.opened span.dashicons {
+ transform: rotate(180deg);
+}
+
+.aios-toggle-advanced-options.opened .aios-toggle-advanced-options__text-hide {
+ display: inline-block;
+}
+
+.aios-toggle-advanced-options.opened .aios-toggle-advanced-options__text-show {
+ display: none;
+}
+
+.aios-toggle-advanced-options .aios-toggle-advanced-options__text-show {
+ display: inline-block;
+}
+
+.aios-toggle-advanced-options .aios-toggle-advanced-options__text-hide {
+ display: none;
+}
+
+.aios-advanced-options-panel {
+ display: none;
+}
+
+.aios-toggle-advanced-options.opened + div.aios-advanced-options-panel {
+ display: block;
+}
+
+.aios-advanced-options-panel h3 {
+ font-size: 14px;
+ display: inline-block;
+}
+
+.aios-advanced-options-panel span.dashicons.dashicons-editor-help {
+ vertical-align: middle;
+ margin-bottom: 10px;
+}
+
+[data-tooltip] {
+ cursor: pointer;
+ position: relative;
+}
+
+[data-tooltip]:hover[data-tooltip]::before, [data-tooltip]:hover[data-tooltip]::after {
+ visibility: visible;
+ filter: opacity(100);
+ opacity: 1;
+ pointer-events: all;
+}
+
+[data-tooltip]::before, [data-tooltip]::after {
+ visibility: hidden;
+ filter: opacity(0);
+ opacity: 0;
+ pointer-events: none;
+}
+
+[data-tooltip]::before {
+ position: absolute;
+ bottom: 150%;
+ left: 50%;
+ margin-bottom: 5px;
+ margin-left: -110px;
+ padding: 12px;
+ width: 275px;
+ z-index: 9999;
+ border-radius: 3px;
+ background-color: hsla(0,0%,20%,0.95);
+ color: #FFF;
+ content: attr(data-tooltip);
+ text-align: center;
+ font-size: .85rem;
+ font-weight: 400;
+ line-height: 1.4;
+}
+
+[data-tooltip]::after {
+ position: absolute;
+ bottom: 150%;
+ left: 50%;
+ margin-left: -5px;
+ width: 0;
+ border-top: 5px solid hsla(0,0%,20%,0.9);
+ border-right: 5px solid transparent;
+ border-left: 5px solid transparent;
+ content: " ";
+ font-size: 0;
+ line-height: 0;
+}
+
+.dep-warning {
+ background-color: #EED202;
+ padding: 1.2em;
+ margin-right: 20px;
+ margin-left: 20px;
+ margin-top: 10px;
+ line-height: 1.2em;
+ color: #111E2A;
+}
+
+.dep-warning span {
+ vertical-align: middle;
+}
+
+@media only screen and (max-width: 782px) {
+
+ .aiowps_next_scheduled_scan_wrapper > .aiowps_scan_btn_wrapper {
+ padding-top: 0;
+ }
+
+ .aiowps_next_scheduled_scan_wrapper {
+ flex-direction: column;
+ }
+
+ .aiowps_next_scheduled_scan_wrapper > div {
+ width: 100%;
+ }
+
+ #aiowps_manual_fcd_scan {
+ margin: 0;
+ display: block;
+ width: 100%;
+ }
+
+}
+
+@media screen and (max-width: 600px) {
+
+ .aiowps_next_scheduled_entity {
+ float: none;
+ width: 100%;
+ margin-bottom: 2em;
+ }
+
+ .aiowps_time_now_wrapper {
+ margin-top: 0;
+ }
+
+}
+
+.details.column-details {
+ max-height: 100px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ display: block;
+ word-wrap: break-word;
+}
+
+.blockUI.blockOverlay.ui-widget-overlay {
+ background: #000;
+}
+
+.aios_success_popup {
+ text-align: center;
+ padding-bottom: 30px;
+}
+
+.aios_success_popup > .dashicons {
+ font-size: 100px;
+ width: 100px;
+ height: 100px;
+ line-height: 100px;
+ padding: 0;
+ border-radius: 50%;
+ margin-top: 30px;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ background: #E2E6E5;
+}
+
+.aios_success_popup > .dashicons.dashicons-yes {
+ text-indent: -5px;
+}
+
+.aios_success_popup.success > .dashicons {
+ color: #008000;
+}
+
+.aios_success_popup.warning > .dashicons {
+ color: #888;
+}
+
+.aios_success_popup--message {
+ padding: 20px;
+}
+
+.button.aios-close-overlay .dashicons {
+ text-decoration: none;
+ font-size: 20px;
+ margin-left: -5px;
+ padding: 0;
+ transform: translatey(5px);
+}
+
+.aios_saving_popup img {
+ animation-name: aios_blink;
+ animation-duration: 610ms;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+ animation-timing-function: ease-out;
+}
+
+.aios-modal-info {
+ text-align: justify;
+ display: inline-block;
+}
+
+@keyframes aios_blink {
+
+ from {
+ opacity: 1;
+ transform: scale(1);
+ }
+
+ to {
+ opacity: 0.4;
+ transform: scale(0.85);
+ }
+
+}
+
+#aios_ajax_moreoptions {
+ max-height: 150px; /* Set the maximum height */
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 6px 10px;
+ margin: 4px 16px 6px 16px;
+}
+
+.aios_password_meter {
+ width: 100%;
+}
+
+.aios_meter_bar {
+ width: 40%;
+ background-color: #EEE;
+ border-radius: 10px;
+ overflow: hidden;
+ height: 10px;
+ margin: 10px 10px 0 0;
+}
+
+#aios_meter_fill {
+ height: 100%;
+ width: 0;
+ background-color: #F00;
+ border-radius: 5px;
+ transition: width 0.5s ease-in-out;
+}
+
+#aiowps_password_test {
+ width: 40%;
+}
+
+.simbaotp_qr_container img {
+ border-collapse: collapse;
+ max-width: 150px;
+ width: 100%;
+ max-height: 150px;
+}
+
+.aiowps-postbox-container {
+ display: flex;
+ background: #FFF;
+ border: 1px solid #D3D3D3;
+ padding: 5px;
+}
+
+.aiowps-postbox-container .postbox {
+ border: none;
+ box-shadow: none;
+}
+
+.aiowps-postbox-container h4 {
+ margin: 1em 0;
+ padding: 5px;
+}
+
+.aiowps-postbox-container .aiowps_switch_container .aiowps_more_info_anchor {
+ margin: 10px 0px;
+ display: block;
+ position: relative;
+ width: fit-content;
+}
+
+.aiowps-rule-list {
+ list-style: none;
+ max-height: 450px;
+ overflow-y: auto;
+ padding: 5px;
+ border-top: 0.5px solid #D3D3D3;
+ margin-bottom: 0;
+}
+
+.aiowps-rule-list li {
+ padding: 5px 0px;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: unset;
+}
+
+.aiowps-rule-list li .aiowps-rule-title {
+ cursor: pointer;
+ padding: 10px 5px;
+ border-radius: 3px;
+ width: 100%;
+}
+
+.aiowps-rule-list li:not(:last-child) {
+ border-bottom: 0.5px solid #D3D3D3;
+}
+
+.aiowps-rule-list li .aiowps-rule-title:hover {
+ background: #F8F9FA;
+}
+
+.aiowps-active .aiowps-rule-title {
+ font-weight: bold;
+ background: #5C3682 !important;
+ color: #FFF !important;
+}
+
+.aiowps-rules {
+ margin-right: 5px;
+ width: 20%;
+ border-right: 1px solid #D3D3D3;
+}
+
+.aiowps-settings {
+ width: 80%;
+}
+
+#aiowps-rule-search {
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+
+#aiowps-rule-search .aiowps-search {
+ flex: 1;
+ background-image: none;
+ position: relative;
+ padding-right: 25px;
+ padding-left: 25px;
+ display: inline-flex;
+ align-items: center;
+ align-items: -moz-center; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ -webkit-align-items: center;
+ width: fill-available;
+ width: -webkit-fill-available; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Safari & Chrome */
+ width: -moz-available; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ max-width: fill-available;
+ max-width: -webkit-fill-available; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Safari & Chrome */
+ max-width: -moz-available; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ margin-right: 5px;
+}
+
+#aiowps-rule-search .dashicons-search {
+ font-family: dashicons;
+ font-size: 18px;
+ line-height: 1;
+ font-weight: 400;
+ font-style: normal;
+ display: inline-block;
+ text-transform: none;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ position: absolute;
+ vertical-align: middle;
+ margin-right: 5px;
+ top: 50%;
+ left: 5px;
+ z-index: 999;
+ transform: translatey(-50%);
+}
+
+#aiowps-rule-search .clear-search {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ transform: translatey(-50%);
+ cursor: pointer;
+}
+
+#aiowps-rule-search .clear-search:hover {
+ color: #000;
+}
+
+.aiowps-actions {
+ background: #FFF;
+ min-height: 60px;
+ margin-top: 0px;
+ border: 1px solid #D3D3D3;
+ border-top: none;
+ align-content: center;
+ padding-right: 15px;
+ text-align: right;
+ text-align: -webkit-right; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Safari & Chrome */
+ text-align: -moz-right; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- For Mozilla */
+ justify-content: end;
+ align-items: center;
+ display: flex;
+}
+
+@media only screen and (max-width: 768px) {
+
+ .aiowps-postbox-container {
+ flex-direction: column;
+ }
+
+ .aiowps-settings {
+ width: 100%;
+ }
+
+ .aiowps-rules {
+ width: 100%;
+ margin-bottom: 10px;
+ border-right: none;
+ border-bottom: 1px solid #D3D3D3;
+ }
+
+ .aiowps-rule-list {
+ max-height: 390px;
+ }
+
+}
+
+#simba-tfa-admin-wrapper form {
+ padding: 10px;
+ position: relative;
+ min-width: 255px;
+ border: 1px solid #C3C4C7;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
+ background: #FFF;
+}
+
+.aios-data-table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+.aios-data-table td, .aios-data-table th {
+ border: 1px solid #DDD;
+ padding: 8px;
+}
+
+.aios-data-table tr:nth-child(even) {
+ background-color: #F2F2F2;
+}
+
+.aios-data-table tr:hover {
+ background-color: #DDD;
+}
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-notices.css b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-notices.css
new file mode 100755
index 00000000..88a6e74d
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-notices.css
@@ -0,0 +1,121 @@
+/* CSS for adverts */
+
+.aiowps_notice_container {
+ height: auto;
+ overflow: hidden;
+}
+
+.aiowps_review_notice_container {
+ padding: 12px;
+ display: flex;
+}
+
+.aiowps_advert_button_container {
+ margin-bottom: 10px;
+ display: flex;
+ align-items: center;
+}
+
+.aiowps_advert_button_container .dashicons {
+ margin-left: 10px;
+}
+
+.aiowps_advert_content_left {
+ float: none;
+ width: 65px;
+ padding-top: 9px;
+ margin-right: 9px;
+}
+
+.aiowps_advert_content_left_extra {
+ float: none;
+ width: 100px;
+ padding-right: 15px;
+ display: flex;
+ align-items: center;
+}
+
+.updraft_advert_content_left img {
+ min-height: 72px;
+ min-width: 72px;
+}
+
+.aiowps_advert_content_right {
+ float: none;
+ width: auto;
+ overflow: hidden;
+ font-size: 16px;
+}
+
+.updraft_advert_content_right p {
+ font-size: 16px !important;
+}
+
+.aiowps_advert_bottom {
+ margin: 10px 0;
+ padding: 10px;
+ font-size: 140%;
+ background-color: rgb(255, 255, 255);
+ border-color: #E6DB55;
+ border: 1px solid;
+ border-radius: 4px;
+}
+
+.aiowps_advert_dismiss {
+ float: right;
+ font-size: 13px;
+ font-weight: normal;
+}
+
+h3.aiowps_advert_heading {
+ margin-top: 5px !important;
+ margin-bottom: 5px !important;
+}
+
+h4.aiowps_advert_heading {
+ margin-top: 2px !important;
+ margin-bottom: 3px !important;
+}
+
+.aiowps_center_content {
+ text-align: center;
+ margin-bottom: 5px;
+}
+
+.aiowps_text_center {
+ text-align: center;
+}
+
+#aiowps-dashnotice #aiowps-dashnotice_wrapper ul {
+ list-style: disc inside;
+ text-indent: -18px;
+ margin-left: 18px;
+}
+
+@media screen and (min-width: 560px) {
+
+ .aiowps_advert_content_left, .aiowps_advert_content_left_extra {
+ float: left;
+ }
+
+}
+
+#aiowps-notice-logo {
+ border: 0;
+ float: right;
+ width: 150px;
+ height: auto;
+ margin-right: 10px;
+ margin-top: 10px;
+}
+
+@media (min-width: 768px) {
+
+ #aiowps-notice-logo {
+ width: 250px;
+ height: auto;
+ margin-right: 40px;
+ margin-top: 40px;
+ }
+
+}
\ No newline at end of file
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-premium-upgrade.css b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-premium-upgrade.css
new file mode 100755
index 00000000..afc9b5d8
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-premium-upgrade.css
@@ -0,0 +1,241 @@
+.aiowps_col {
+ display: block;
+ float: left;
+ margin: 1% 0 1% 1%;
+}
+
+.aiowps_col:first-child {
+ margin-left: 0;
+}
+
+.aiowps_half_width {
+ width: 48%;
+}
+
+@media screen and (max-width: 768px) {
+
+ .aiowps_col {
+ margin: 1% 0;
+ }
+
+ .aiowps_half_width {
+ width: 100%;
+ }
+
+}
+
+img.addons {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 20px;
+ max-width: 40%;
+ max-height: 100%;
+}
+
+.postbox.aiowps-tab-postbox {
+ padding: 25px;
+}
+
+.aiowps-plugin-family__plugins {
+ display: -ms-flexbox;
+ display: flex; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- first definition is for IE */
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ padding-left: 1px;
+ padding-bottom: 1px;
+}
+
+.aiowps-plugin-family__plugin {
+ -ms-flex: auto;
+ flex: auto;
+ width: 100%;
+ padding: 30px;
+ box-sizing: border-box;
+ border: 1px solid #E3E4E7;
+ margin-left: -1px;
+ margin-bottom: -1px;
+}
+
+@media (min-width: 782px) {
+
+ .aiowps-plugin-family__plugin {
+ width: 50%;
+ }
+
+ .aiowps-plugin-family__free .aiowps-plugin-family__plugin {
+ width: 100%;
+ }
+
+}
+
+@media (max-width: 1300px) {
+
+ .aiowps-plugin-family__free .aiowps-plugin-family__plugin {
+ width: 50%;
+ }
+
+}
+
+@media (max-width: 782px) {
+
+ .aiowps-plugin-family__free .aiowps-plugin-family__plugin {
+ width: 100%;
+ }
+
+}
+
+.aiowps_feature_cont {
+ width: 64.5%;
+}
+
+.aiowps_plugin_family_cont {
+ width: 34.5%;
+}
+
+@media (max-width: 1300px) {
+
+ .aiowps_feature_cont,
+ .aiowps_plugin_family_cont {
+ width: 100%;
+ float: none;
+ margin: 0;
+ }
+
+}
+
+.aiowps_feature_cont header,
+.aiowps_plugin_family_cont header {
+ padding: 20px;
+}
+
+@media (max-width: 1300px) {
+
+ .aiowps_feature_cont header,
+ .aiowps_plugin_family_cont header {
+ padding: 40px;
+ }
+
+}
+
+.aiowps_feature_cont header p,
+.aiowps_plugin_family_cont header p {
+ margin-bottom: 0;
+}
+
+.aiowps_feat_table,
+.aiowps_feat_table td {
+ border: 0;
+ border-collapse: collapse;
+ background-color: #FFF;
+ font-size: 120%;
+ text-align: center;
+}
+
+.aiowps_feat_table td {
+ border: 1px solid #F1F1F1;
+ border-bottom-width: 4px;
+ padding: 15px;
+}
+
+.aiowps_feat_table td:nth-child(2),
+.aiowps_feat_table td:nth-child(3) {
+ background: rgba(241, 241, 241, 0.38);
+}
+
+.aiowps_feat_table p {
+ padding: 0 10px;
+ margin: 5px 0;
+ font-size: 13px;
+}
+
+.aiowps_feat_table h4 {
+ padding-left: 10px;
+ margin: 5px 0;
+}
+
+.aiowps_feat_table .dashicons {
+ width: 25px;
+ height: 25px;
+ font-size: 25px;
+ line-height: 1;
+}
+
+.aiowps_feat_table .dashicons-yes {
+ color: #008000;
+}
+
+.aiowps_feat_table .dashicons-no-alt {
+ color: #FD0000;
+}
+
+.aiowps_feat_table tr td.aiowps-feature-text {
+ text-align: left;
+}
+
+.aiowps_feat_table tr.aiowps-main-feature-row td {
+ background: #F1F1F1;
+ border-bottom-color: #FAFAFA;
+}
+
+.aiowps-premium-image {
+ display: none;
+}
+
+@media screen and (min-width: 720px) {
+
+ .aiowps-premium-image {
+ display: block;
+ float: left;
+ padding: 16px 18px;
+ width: 64px;
+ height: auto;
+ }
+
+}
+
+@media screen and (min-width: 1220px) {
+
+ .aiowps_feat_table td:nth-child(2),
+ .aiowps_feat_table td:nth-child(3) {
+ width: 110px;
+ }
+
+}
+
+.other-plugin-title {
+ text-decoration: none;
+}
+
+@media screen and (max-width: 782px) {
+
+ table.aiowps_feat_table {
+ display: block;
+ }
+
+ table.aiowps_feat_table tr {
+ display: -ms-flexbox;
+ display: flex; /* phpcs:ignore Squiz.CSS.DuplicateStyleDefinition.Found -- first definition is for IE */
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ }
+
+ table.aiowps_feat_table td {
+ display: block;
+ }
+
+ table.aiowps_feat_table td:first-child {
+ width: 100%;
+ border-bottom: 0;
+ }
+
+ table.aiowps_feat_table td:not(:first-child) {
+ width: 50%;
+ box-sizing: border-box;
+ }
+
+ table.aiowps_feat_table td:first-child:empty {
+ display: none;
+ }
+
+}
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-site-lockout-page.css b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-site-lockout-page.css
new file mode 100755
index 00000000..05c07768
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/css/wp-security-site-lockout-page.css
@@ -0,0 +1,20 @@
+body {
+ background-color: #404040 !important;
+}
+
+.aiowps-site-lockout-box {
+ margin-right: auto;
+ margin-left: auto;
+ max-width: 800px;
+ margin-top: 100px;
+ padding: 30px;
+ border: 2px solid #FFE20A;
+}
+
+.aiowps-site-lockout-msg {
+ color: #FFE20A;
+ font-size: 48px;
+ font-weight: bold;
+ text-align: center;
+}
+
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/images/aios-plugin-icon.svg b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/aios-plugin-icon.svg
new file mode 100755
index 00000000..b10e4032
--- /dev/null
+++ b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/aios-plugin-icon.svg
@@ -0,0 +1,8 @@
+
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/images/error.png b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/error.png
new file mode 100755
index 0000000000000000000000000000000000000000..cf4526e85c987a5af8b4373d91f9e462b423b726
GIT binary patch
literal 786
zcmV+t1MU2YP)T1%m=@F~Syl2(l;>>7j=niij91d=SMY
z6H~~vP+KUJgiNRmL^G+d7z0z&CT+1KGr^^(Cd(P;_At}9km3L3KAd~*`JMl{2PXla
zC+X&vp^Eas%aM_3SU_d61OV6p@JfH9`SHHJqm{niZRjY-YyA1}{
z<^jN2PCdz`5(5An2BIG%CN}jPJtFRGO1xdFYLd84r!_gpM+hAohSB-MCnX^~)AVaR
zwtmEx2EYaYz4mF{O{3xX%DA|E7T`b7Tv4^v>~ORI0MY@?t@t%t+P7`&ccg9*lL^7j
zi736W`0`#eh*uG(s~+i;SJtQqQ6Ca=DH+fLK$*9f3$IX7JgC=Ip4A_spZE|Ui+2Vt
z?#i^Ul~a3{B0H-%EdqcN&hTGdpd|Q)hE;bdL_DVu7QkM~Xv#wOJx&!%8~`vXF`JkY
zy6GtayAzNpxR#NfSd0!S@{$Hh208&@A^3fT(G#sIb9^*OqC}SR0N@mv*Fv`Js+=S7
zpnHV8?*>FCC8A1VWdLwm;cMT9YQ7Ff>%Zm8d<6hx%zi|;&ss*FbpWDAf~b{Q^XwuS
zjIVzar4tSQN(%s-Ve=?1GE)A6Kv-2O+Vy-qU*=(dW9h_2SfNS>h9dMLhtT9X$ytn<
zEJ3EveLCiRZInf!%*+6g;WiZjvMC1u(&(o&bq8v#y8$(mx+$)OElnESzsvDy^)m4?
zR22ZoLMF!orZ$7}y-t;4JY$@se9U`Y{8Zrf&2R(-&9-HZav4JpFlMzmj!~zG^#tMp
zxiNK5+sOG`ado+Ck%~3{{%yHzX2BYinHEuC@C|r+Fg50!(NBv-s>VJ3KlZuSd0y~D
Q6aWAK07*qoM6N<$f*#RYU;qFB
literal 0
HcmV?d00001
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/images/index.html b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/index.html
new file mode 100755
index 00000000..e69de29b
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/images/info-icon.png b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/info-icon.png
new file mode 100755
index 0000000000000000000000000000000000000000..40d49cdbe486ffa81c1472159253c8a13e2e6910
GIT binary patch
literal 797
zcmV+&1LFLNP)ySlVo@+g9zqma9wrS7jZq^+iSdOI6HVNxYZnyb!nh&qG)7xY)P#i_
zQDb~0n&3`hr4j^6B2Xg)6G1Id3&mkdTRPskQyOuSo5?x%Ki~b&nYjf2J(b71%LyT^
zAhe-yW4LF75YP4TTxa-2%eQ~^Bv*Lsp&Nv>mlYTKYds}MXJjmDX{@AH0S?hL
z9dofbG+hsJUB~#-=7k&}Tim;Em&cdqa${s-8G6cq%fW^9pd`N
zvByUjNY-|M7yGG_kC90|izRp$tQGDKUK!_lBJz~KQ!5%0%dy~S_u)2T_PnjQaH`t7
z9UsOtt5}FR;C77&4_*BtVv^09Phx2v>C{REsXFl}aHP@aADT=H+iS&y@kJ?L1jbq}
z_XaYl73lG3kW@848E!gI@9PiiRx!0i1NZ83ldiiI29qc#vmmAi6@0MqNQmsc*ke>w
zlp{QyLWXZGCk-Ui2B^&N^}$X7sJ}b`CQ}X}!jajhiy2sqMnU#m=rKx5%MhMPBlc%i
z*p^iWSz#FOvWB?(+7u)nOA@u(;*0{-KxAef#B=J|aE-T;w~z$o0#hif5)_++&v(57
zu)pKGfSP-hS%9rh1H;49A>wU$9@t#8#Xl8Q0LHA-IY8xrkvkp%XuSSI02Q7$TTyr`
zZs-^c%?640^viP9=9mK8gjmu72(ev8C{QT?O}8RY9WqqAB;Y%WfRUkD{QRX=h>u!*
z=2bvZ3j7JfiB;LMKYG7<-5ojEwE&w_MpcP|_`HVqA7_J~ZhG1*z}eSsLRl|pfiEpP
zAqfY(4er7`*_J26v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$
zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ
zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE
znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b
zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_*
zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k?
z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe
zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5
z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj
z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH
z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es
zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E
zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4
zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R
zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo
z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6
z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS
zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD
EAHN$8j{pDw
literal 0
HcmV?d00001
diff --git a/wp-content/plugins/all-in-one-wp-security-and-firewall/images/notices/black_friday.png b/wp-content/plugins/all-in-one-wp-security-and-firewall/images/notices/black_friday.png
new file mode 100755
index 0000000000000000000000000000000000000000..96beec18067862030cb015fe22d8a6791917e604
GIT binary patch
literal 4678
zcmd6r-+gc>*}Zx;nU#*001HlbrrpTy!_WSTcVLhPUZ50SdsVAX&8|B!14
zAIm=ves?_`eE{J;&dr*9e+U=FIS}Sbdwf-F$Evqb`?6VWqypZNU}=;Wo%Jg9!y7Y6
z?^EU53jlyjNkc^u?7eclf{HIxAO&n4?e{(lS5#$Sq{MmC^K{|ZNKm3Iy;PoLwR4Rq
z*BCzSB;EMGygWBH_zLk`T29%m0tRqF&-&c3x)FM$@ic{o~PO4=eQS1HA?YiX&`{
z=mu9ac20GwGb{qc@6;fMl<1y~x7G_l1ItWvn(T|Q3kahsUhE*oI0m~-tnebyk6Rg!
z>^r>0!%w0!#6@G2KKPpn}i?bka_bt}5DdZO-;@2wVE;FH1E
z>imiCKsQyM4Fp-dxSA+wNdHTtPEahqy=i`;$7aLCppyxHy2RrJ-qGQ@6HX1O2w&7E
z!Ku1EV6C>ugm1!os$AMgef{2J1-0#n#h4bLeJW)#KGY$JrWc!fmX>^H#jsHkk7X3(
z5E@J3pn}(&Nh==1_nr?xS&tjd)lB=sJkn-2B4Z=pqpJ?y#7O9f~?84PkP^)xOy1bZY
z0Uhu~-)V?;DL&_*YMq&`G&|z4tG8yZ>%)Ojfy#A&LL-)~ySCfmw%MD*)7L`zwB+=~
z@2KMS4~yGUTHf?LxbU;99V$2W2ej6?0KJ(eLj5eT$2m3&9!^Y^(c}Lic}7ygsOp3)
zA7lyHWJVbdTuf)k+{sg}qVb2B8R~jAncdno>f})qj{b#&7r
z7ZE%&p04pXi>rG)?!1npJN||OOW_5=h<81?pul6-sUhNXPbdB2R?9Jy@U(~8n2cq@
zkK{Fz!dF8r;6K~>*Ycp)*&p(->{ZwALZn|fh6ZqjmY#p7%O1f|io1H8Ud;Tasf5X1
zK6KeNF{C5&)y(TjcIisBNIHMyT??Np9TQ!L7s}E8GAV^7U`-}96#iIfU93+*jAm=%
zj~6SN57V1s>T^9jyhUmGJGV0GK}D|y*g)1sbODT)6f9H9`gfhJLy`P*rf%mgS&8sf
zrkp#Ha5KIwjYJwzwP=V5L7?4-zqA<6SwWs