PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/component/class-audit.php +41 -109 5.7.0 → 6.3.0 View file →
@@ -39,15 +39,19 @@
39 39 * @param array $events Specific events to fetch.
40 40 * @param string $user_id User ID to filter logs.
41 41 * @param string $ip IP address to filter logs.
42 42 * @param int $paged Pagination page number.
43 + * @param int $per_page Number of logs per page.
43 44 *
44 45 * @return Audit_Log[]|WP_Error Returns an array of Audit_Log objects or WP_Error on failure.
45 46 * @throws Exception Throws exception on failure.
46 47 */
47 - public function fetch( $date_from, $date_to, $events = array(), $user_id = '', $ip = '', $paged = 1 ) {
48 - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged );
48 + public function fetch( $date_from, $date_to, $events = array(), $user_id = '', $ip = '', $paged = 1, $per_page = 10 ) {
49 + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page );
49 50 $this->log( sprintf( 'Found %s from local', count( $internal ) ), self::AUDIT_LOG );
51 + if ( ! wd_di()->get( WPMUDEV::class )->is_pro() ) {
52 + return $internal;
53 + }
50 54 $checkpoint = get_site_option( self::CACHE_LAST_CHECKPOINT );
51 55 if ( false === $checkpoint ) {
52 56 // This case where user install the plugin, have some local data but never reach to Logs page, then check point will be today.
53 57 $checkpoint = time();
@@ -52,9 +56,9 @@
52 56 // This case where user install the plugin, have some local data but never reach to Logs page, then check point will be today.
53 57 $checkpoint = time();
54 58 }
55 59 $checkpoint = (int) $checkpoint;
56 - $date_from = (int) $date_from;
60 + $date_from = ! is_int( $date_from ) ? (int) $date_from : $date_from;
57 61 if ( 0 === count( $internal ) && $checkpoint > $date_from ) {
58 62 // Have to fetch from API.
59 63 $this->log( 'fetch from cloud', self::AUDIT_LOG );
60 64 // Todo:need $paged as 'nopaging'-arg?
@@ -67,9 +71,9 @@
67 71 if ( count( $cloud ) ) {
68 72 // No data from cloud too.
69 73 Audit_Log::mass_insert( $cloud );
70 74 // Because this is roughly fetch, so we have to filter out again using the local data.
71 - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged );
75 + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page );
72 76 }
73 77 // Cache the last time fetch, this will be useful in case of mixed data.
74 78 update_site_option( self::CACHE_LAST_CHECKPOINT, $date_from );
75 79 // This case we have the data, however, maybe it can be out of the cached range, so we have to check.
@@ -92,9 +96,9 @@
92 96 }
93 97 if ( is_array( $cloud ) ) {
94 98 // Silence the error here, as we actually have data.
95 99 Audit_Log::mass_insert( $cloud );
96 - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged );
100 + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page );
97 101 // Cache the last time fetch, this will be useful in case of mixed data.
98 102 update_site_option( self::CACHE_LAST_CHECKPOINT, $date_from );
99 103 }
100 104 }
@@ -148,33 +152,17 @@
148 152
149 153 return $data['data'];
150 154 }
151 155
156 +
152 157 /**
153 - * Flushes logs that need to be synced with the cloud.
158 + * Delete all local audit log entries from database and reset checkpoint.
159 + *
160 + * @return void
154 161 */
155 - public function flush() {
156 - $logs = Audit_Log::get_logs_need_flush();
157 - // Build the data.
158 - $data = array();
159 - foreach ( $logs as $log ) {
160 - $item = $log->export();
161 - unset( $item['synced'] );
162 - unset( $item['safe'] );
163 - unset( $item['id'] );
164 - $item['msg'] = addslashes( $item['msg'] );
165 - $data[] = $item;
166 - }
167 - if ( count( $data ) ) {
168 - $ret = $this->curl_to_api( $data );
169 - if ( ! is_wp_error( $ret ) ) {
170 - $this->log( sprintf( 'API sync successful, marking %s logs as synced', count( $data ) ), self::AUDIT_LOG );
171 - foreach ( $logs as $log ) {
172 - $log->synced = 1;
173 - $log->save();
174 - }
175 - }
176 - }
162 + public function reset(): void {
163 + Audit_Log::truncate();
164 + delete_site_option( self::CACHE_LAST_CHECKPOINT );
177 165 }
178 166
179 167 /**
180 168 * Cleans up old logs based on storage settings.
@@ -184,9 +172,10 @@
184 172 public function audit_clean_up_logs() {
185 173 $audit_settings = wd_di()->get( Audit_Logging::class );
186 174 $interval = $this->calculate_date_interval( $audit_settings->storage_days );
187 175 // Since v5.7.0.
188 - $interval = (string) apply_filters( 'wpdef_audit_logs_store_backward', $interval );
176 + $interval = apply_filters( 'wpdef_audit_logs_store_backward', $interval );
177 + $interval = is_string( $interval ) ? $interval : (string) $interval;
189 178
190 179 try {
191 180 $interval_obj = new DateInterval( $interval );
192 181 } catch ( Exception ) {
@@ -205,13 +194,13 @@
205 194 $logs_count = Audit_Log::count( $date_from->getTimestamp(), $date_to->getTimestamp() );
206 195 if ( $logs_count > 0 ) {
207 196 $this->log( 'Cleaning up old logs from ' . $date_from->format( 'Y-m-d H:i:s' ) . ' to ' . $date_to->format( 'Y-m-d H:i:s' ), self::AUDIT_LOG );
208 197 // Since v5.0.0.
209 - $delete_count = (int) apply_filters( 'wpdef_audit_limit_deleted_logs', 50 );
198 + $delete_count = apply_filters( 'wpdef_audit_limit_deleted_logs', 50 );
210 199 Audit_Log::delete_old_logs(
211 200 $date_from->getTimestamp(),
212 201 $date_to->getTimestamp(),
213 - $delete_count,
202 + is_int( $delete_count ) ? $delete_count : (int) $delete_count,
214 203 );
215 204 }
216 205 }
217 206 }
@@ -240,84 +229,8 @@
240 229 return $ret;
241 230 }
242 231
243 232 /**
244 - * Sends data to the API using a socket connection.
245 - *
246 - * @param array $data Data to be sent to the API.
247 - *
248 - * @return bool Returns true on success, false on failure.
249 - */
250 - public function socket_to_api( $data ) {
251 - $sockets = Array_Cache::get( 'sockets', 'audit', array() );
252 - // We will need to wait a bit.
253 - if ( 0 === ( is_array( $sockets ) || $sockets instanceof Countable ? count( $sockets ) : 0 ) ) {
254 - // Fall back.
255 - return false;
256 - }
257 - $this->log(
258 - sprintf( 'Flush %s to cloud', is_array( $data ) || $data instanceof Countable ? count( $data ) : 0 ),
259 - self::AUDIT_LOG
260 - );
261 - $start_time = microtime( true );
262 - $sks = $sockets;
263 - $r = null;
264 - $e = null;
265 - if ( ( false === stream_select( $r, $sks, $e, 1 ) ) ) {
266 - // This case error happen.
267 - return false;
268 - }
269 -
270 - $fp = array_shift( $sockets );
271 -
272 - $uri = '/logs/add_multiple';
273 - $vars = http_build_query( $data );
274 - $this->attach_behavior( WPMUDEV::class, WPMUDEV::class );
275 - // We're sending data to the server, so we're not manipulating files. Ignore the error.
276 - // @codingStandardsIgnoreStart
277 - fwrite( $fp, 'POST ' . $uri . " HTTP/1.1\r\n" );
278 - fwrite( $fp, 'Host: ' . $this->strip_protocol( $this->get_endpoint() ) . "\r\n" );
279 - fwrite( $fp, "Content-Type: application/x-www-form-urlencoded\r\n" );
280 - fwrite( $fp, 'Content-Length: ' . strlen( $vars ) . "\r\n" );
281 - fwrite( $fp, 'apikey: ' . $this->get_apikey() . "\r\n" );
282 - fwrite( $fp, "Connection: close\r\n" );
283 - fwrite( $fp, "\r\n" );
284 - fwrite( $fp, $vars );
285 - stream_set_timeout( $fp, 5 );
286 - $res = '';
287 - while ( ! feof( $fp ) ) {
288 - $res .= fgets( $fp, 1024 );
289 - // Check if the transfer has taken too long.
290 - $end_time = microtime( true );
291 - if ( $end_time - $start_time > 3 ) {
292 - fclose( $fp );
293 - break;
294 - }
295 - }
296 - // @codingStandardsIgnoreEnd
297 - return true;
298 - }
299 -
300 - /**
301 - * Open a socket to API for faster transmit.
302 - */
303 - public function open_socket() {
304 - $sockets = Array_Cache::get( 'sockets', 'audit', array() );
305 - $endpoint = $this->strip_protocol( $this->get_endpoint() );
306 - if ( empty( $sockets ) ) {
307 - $fp = stream_socket_client(
308 - 'ssl://' . $endpoint . ':443',
309 - $errno,
310 - $errstr,
311 - 5
312 - );
313 - if ( is_resource( $fp ) ) {
314 - Array_Cache::set( 'sockets', array( $fp ), 'audit' );
315 - }
316 - }
317 - }
318 -
319 - /**
320 233 * Strips the protocol from a URL.
321 234 *
322 235 * @param string $url URL to process.
323 236 *
@@ -351,11 +264,15 @@
351 264 new Component\Audit\Comment_Audit(),
352 265 new Component\Audit\Core_Audit(),
353 266 new Component\Audit\Media_Audit(),
354 267 new Component\Audit\Post_Audit(),
355 - new Component\Audit\Users_Audit(),
268 + new Component\Audit\User_Audit(),
356 269 new Component\Audit\Options_Audit(),
357 270 new Component\Audit\Menu_Audit(),
271 + new Component\Audit\Theme_Audit(),
272 + new Component\Audit\Feature_Audit(),
273 + new Component\Audit\Password_Audit(),
274 + new Component\Audit\Application_Password_Audit(),
358 275 );
359 276
360 277 foreach ( $events_class as $class ) {
361 278 // since 2.4.7.
@@ -405,9 +322,9 @@
405 322 $model = new Audit_Log();
406 323
407 324 if ( ( is_array( $events ) || $events instanceof Countable ? count( $events ) : 0 ) > 1 ) {
408 325 if ( $model->has_method( 'mass_insert' ) ) {
409 - $model->mass_insert( $events );
326 + $model->mass_insert( $events, 0 );
410 327
411 328 return;
412 329 }
413 330 }
@@ -416,6 +333,21 @@
416 333 $model->import( $event );
417 334 $model->synced = 0;
418 335 $model->save();
419 336 }
337 + }
338 +
339 + /**
340 + * Get audit events per week.
341 + */
342 + public static function get_audit_events_per_week(): int {
343 + $timezone = wp_timezone();
344 + $date_to = ( new DateTime( 'now', $timezone ) )
345 + ->setTime( 23, 59, 59 )
346 + ->getTimestamp();
347 + $date_from = ( new DateTime( '-7 days', $timezone ) )
348 + ->setTime( 0, 0, 0 )
349 + ->getTimestamp();
350 +
351 + return Audit_Log::count( $date_from, $date_to );
420 352 }
421 353 }