PluginProbe
WP Admin Audit / 1.2.17
WP Admin Audit v1.2.17
1.2.9 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 All 26 releases
wp-admin-audit / wp-admin-audit.php

wp-admin-audit.php in WP Admin Audit 1.2.17, at wp-admin-audit.php

301 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Plugin Name: WP Admin Audit
4 * Plugin URI: https://wpadminaudit.com/
5 * Description: Monitor the security-relevant activities on your site and get notified when something out of the ordinary happens. Browse the event log to find out who did what at which time.
6 * Version: 1.2.17
7 * Author: brandtoss
8 * Author URI: https://wpadminaudit.com/
9 * License: GPL2
10 * License URI: https://www.gnu.org/licenses/gpl-2.0.txt
11 * Requires at least: 5.5
12 * Requires PHP: 7.0
13 *
14 * Text Domain: wp-admin-audit
15 * Domain Path: /languages
16 *
17 */
18
19
20 /*
21 WP Admin Audit is free software; you can redistribute it and/or modify
22 it under the terms of the GNU General Public License, version 2, as
23 published by the Free Software Foundation.
24
25 WP Admin Audit is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with WP Admin Audit. If not, see <http://www.gnu.org/licenses/>.
32 */
33
34
35 if ( ! class_exists( 'WpAdminAudit' ) ) {
36 class WpAdminAudit
37 {
38 public $version = '1.2.17';
39 protected $eventListener;
40
41 public function __construct()
42 {
43 self::errorLog('construct');
44 if (self::onFrontend()) {
45 add_action('wp_loaded', array($this, 'setupWADA'), 0);
46 }else{
47 add_action('plugins_loaded', array($this, 'setupWADA'), 8);
48 }
49
50 register_activation_hook(__FILE__, array($this, 'installWADA'));
51 register_deactivation_hook(__FILE__, array($this, 'deactivateWADA'));
52 add_filter('cron_schedules', array($this, 'addCronSchedules'));
53 }
54
55 protected static function errorLog($msg){
56 if(self::isHeartbeatRequest()) return;
57 //$remoteAddress = array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : '';
58 //$remotePort = array_key_exists('REMOTE_PORT', $_SERVER) ? $_SERVER['REMOTE_PORT'] : '';
59 //$reqTime = array_key_exists('REQUEST_TIME', $_SERVER) ? $_SERVER['REQUEST_TIME'] : '';
60 //$requestId = sprintf("%08x", abs(crc32($remoteAddress . $reqTime . $remotePort)));
61 //error_log($requestId."\t".$msg);
62 }
63
64 public static function getInstance() {
65 static $instance = null;
66 if (!$instance) {
67 $instance = new self();
68 }
69 return $instance;
70 }
71
72 public function setupWADA(){
73 self::errorLog('setupWADA');
74 if(self::isHeartbeatRequest()){
75 return; // do not set up in that scenario
76 }
77
78 // Find out what kind of fun WP was having
79 //add_action ( 'shutdown', function() {
80 // self::errorLog('WP->shutdown actions: '.print_r($GLOBALS['wp_actions'], true));
81 //} );
82
83 if(!self::onFrontend() || (self::loadOnFrontend()) || (is_user_logged_in())){
84 self::errorLog('Go ahead');
85 $this->loadPluginDependencies();
86 $this->setupHooksAndFilters();
87 $this->completePendingUpdates();
88
89 if(is_admin()){
90 $lastActivityWidget = new WADA_Widget_LastActivities();
91 $loginAttemptsWidget = new WADA_Widget_LoginAttempts();
92 }
93
94 if(did_action('init')){
95 $this->initWADA();
96 }
97 }else{
98 self::errorLog('Skip WADA setup because Frontend: '.(self::onFrontend() ? 'y':'n').', Logged in: '.(is_user_logged_in() ? 'y':'n').', Rest API: '.(self::isRequestForRestAPI()?'y':'n'));
99 }
100 }
101
102 public function loadOnFrontend(){ // the frontend activities that are (potentially) relevant for our sensors
103 if(array_key_exists('login', $_REQUEST)) return true;
104 if(array_key_exists('register', $_REQUEST)) return true;
105 if(array_key_exists('reset_key', $_REQUEST)) return true;
106 if(array_key_exists('reset_login', $_REQUEST)) return true;
107 if(array_key_exists('wc_reset_password', $_REQUEST)) return true;
108 return false;
109 }
110
111 protected function loadSetupDependencies(){
112 require_once __DIR__ . '/classes/Setup.php';
113 }
114
115 public function loadPluginDependencies(){
116 $baseDir = __DIR__ . '/classes/';
117 require_once $baseDir . 'Constants.php';
118 require_once $baseDir . 'Setup.php';
119 require_once $baseDir . 'Application/BackendSum.php';
120 require_once $baseDir . 'Application/BackendWoosl.php';
121 require_once $baseDir . 'Application/Database.php';
122 require_once $baseDir . 'Application/EventListener.php';
123 require_once $baseDir . 'Application/Extensions.php';
124 require_once $baseDir . 'Application/Log.php';
125 require_once $baseDir . 'Application/Maintenance.php';
126 require_once $baseDir . 'Application/Router.php';
127 require_once $baseDir . 'Application/Settings.php';
128 require_once $baseDir . 'Application/Updater.php';
129 require_once $baseDir . 'Application/Version.php';
130 require_once $baseDir . 'Utils/CommentUtils.php';
131 require_once $baseDir . 'Utils/CompUtils.php';
132 require_once $baseDir . 'Utils/DateUtils.php';
133 require_once $baseDir . 'Utils/FileUtils.php';
134 require_once $baseDir . 'Utils/PHPUtils.php';
135 require_once $baseDir . 'Utils/PluginUtils.php';
136 require_once $baseDir . 'Utils/PostUtils.php';
137 require_once $baseDir . 'Utils/ScriptUtils.php';
138 require_once $baseDir . 'Utils/TermUtils.php';
139 require_once $baseDir . 'Utils/UserUtils.php';
140 require_once $baseDir . 'Utils/UpgraderUtils.php';
141 if(is_admin()){
142 require_once $baseDir . 'Application/Menu.php';
143 require_once $baseDir . 'Utils/HtmlUtils.php';
144 }
145 }
146
147 public function setupHooksAndFilters(){
148 if(count($_REQUEST)>0) {
149 WADA_Log::debug('WADA Setup REQUEST: ' . print_r($_REQUEST, true));
150 }
151 add_action( 'init', array( $this, 'initWADA' ), 5 );
152 add_action( 'admin_menu', array( 'WADA_Menu', 'adminMenu' ) );
153 add_action( 'admin_enqueue_scripts', array( 'WADA_Menu', 'adminAssets' ) );
154
155 // Schedules
156 add_action( 'wp_admin_audit_maintenance', array( 'WADA_Maintenance', 'scheduledRun' ) );
157 add_action( 'wp_admin_audit_queue_work', array( 'WADA_Notification_Queue', 'workOnQueue' ), 10 );
158 add_action( 'wp_admin_audit_queue_work', array( 'WADA_Replicator_Worker', 'workOnPendingReplications' ), 9 ); // same hook, higher priority for replications
159
160 // Internal hooks
161 add_action( 'wp_admin_audit_new_event', array( 'WADA_Notification_Queue', 'matchAndQueueEvent' ), 10, 2 );
162
163 WADA_BackendSum::autoResetExtensionCacheOnPluginLifecycleActivities();
164 add_filter('plugins_api', array('WADA_BackendSum', 'injectPluginInfos'), 25, 3);
165
166 // Ajax
167 WADA_Router::setupAjaxHooks();
168 }
169
170 public function completePendingUpdates(){
171 $this->loadSetupDependencies();
172 $setup = new WADA_Setup();
173 if($setup->isDatabaseUpdateNeeded()){
174 WADA_Log::info('completePendingUpdates');
175 $setup->installOrUpdate();
176 }
177 }
178
179 public function addCronSchedules($schedules){
180 if(!is_array($schedules)){
181 $schedules = array();
182 }
183 $schedules['15min'] = array(
184 'interval' => 900,
185 'display' => __('Every 15 minutes', 'wp-admin-audit'),
186 );
187 $schedules['5min'] = array(
188 'interval' => 300,
189 'display' => __('Every 5 minutes', 'wp-admin-audit'),
190 );
191 $schedules['1min'] = array(
192 'interval' => 60,
193 'display' => __('Every minute', 'wp-admin-audit'),
194 );
195 return $schedules;
196 }
197
198 function autoload($className){
199 $inclPath = null;
200 if(strpos($className , 'WADA_Layout_' ) === 0){
201 $namePart = substr($className, strlen('WADA_Layout_'));
202 $inclPath = 'classes/Views/Layouts/'.$namePart.'.php';
203 }elseif(strpos($className , 'WADA_Widget_' ) === 0) {
204 $namePart = substr($className, strlen('WADA_Widget_'));
205 $inclPath = 'classes/Views/Widgets/' . $namePart . '.php';
206 }elseif($className === 'WADA_HtmlUtils') {
207 $inclPath = 'classes/Utils/HtmlUtils.php';
208 }else{
209 $folders = array('Model', 'Sensor', 'View', 'Notification', 'Replicator');
210 if(strpos($className, 'WADA_') === 0) {
211 foreach($folders as $folder) {
212 if(strpos($className, 'WADA_' . $folder . '_') === 0) {
213 $namePart = substr($className, strlen('WADA_' . $folder . '_'));
214 $inclPath = 'classes/' . $folder . 's/' . $namePart . '.php';
215 //self::errorLog('WADA->autoload ' . $folder . ' ' . $namePart . ' via ' . $inclPath);
216 break; // no need to look further
217 }
218 }
219 }
220 }
221 if($inclPath){
222 //error_log('WADA autoload '.$className .' at '.$inclPath);
223 if(is_file(__DIR__.'/'.$inclPath)){
224 require_once __DIR__.'/'.$inclPath;
225 }
226 }
227 }
228
229 public function initWADA(){
230 self::errorLog('initWADA');
231 do_action( 'wp_admin_audit_loaded_pre_sensors', $this );
232 //WADA_Log::info('initWADA hey hey');
233 if(class_exists('WADA_EventListener')) {
234 $eventListener = new WADA_EventListener();
235 $this->eventListener = $eventListener;
236 $this->eventListener->startListening();
237 }
238
239 // Done initializing, tell whoever is interested
240 do_action( 'wp_admin_audit_loaded_post_sensors', $this );
241 }
242
243 public function installWADA(){
244 $this->loadSetupDependencies();
245 $setup = new WADA_Setup();
246 $setup->installOrUpdate();
247 }
248
249 public function deactivateWADA(){ // we do some cleanup or notifications if needed
250 $this->loadSetupDependencies();
251 $setup = new WADA_Setup();
252 $setup->unscheduleEvents();
253 // TODO ONCE WE HAVE REPLICATION MAKE SURE THE PLUGIN DEACTIVATION EVENT GETS SENT
254 }
255
256 public static function onFrontend(){
257 $requestUri = array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : '';
258 $onLoginScreen = parse_url(site_url('wp-login.php'), PHP_URL_PATH) === parse_url($requestUri, PHP_URL_PATH);
259 $isAdmin = is_admin();
260 $restApi = self::isRequestForRestAPI();
261 $isCron = wp_doing_cron();
262 $isWPCli = (defined('WP_CLI') && WP_CLI);
263 if($isAdmin || $restApi || $onLoginScreen || $isCron || $isWPCli){
264 return false;
265 }
266 return true;
267 }
268
269 public static function isRequestForRestAPI(){
270 $isWpJsonV2 = false;
271 $isRestUrlPath = false;
272 $isRestRoute = isset($_GET['rest_route']);
273 if (!empty($_SERVER['REQUEST_URI'])) {
274 $isWpJsonV2 = (array_key_exists('REQUEST_URI', $_SERVER) && (strpos($_SERVER['REQUEST_URI'], 'wp-json/wp/v2') !== false));
275 $restUrlPath = trim(parse_url(home_url('/wp-json/'), PHP_URL_PATH), '/');
276 $requestUrl = trim($_SERVER['REQUEST_URI'], '/');
277 $isRestUrlPath = (strpos($requestUrl, $restUrlPath) === 0);
278 }
279 return ($isWpJsonV2 || $isRestUrlPath || $isRestRoute);
280 }
281
282 public static function isHeartbeatRequest(){
283 if(array_key_exists('action', $_POST) && $_POST['action'] === 'heartbeat'){
284 return true;
285 }
286
287 /* */
288
289 return false;
290 }
291
292 } // class end
293
294 $adminAudit = WpAdminAudit::getInstance(); // init and run
295
296 spl_autoload_register(array($adminAudit, 'autoload')); // register autoloader
297
298 /* */
299
300 }
301