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 +56 -113 5.5.1 → 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 -
168 - if ( count( $data ) ) {
169 - $ret = $this->curl_to_api( $data );
170 - if ( ! is_wp_error( $ret ) ) {
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.
@@ -183,24 +171,36 @@
183 171 */
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 - $date_from = ( new DateTime() )->setTimezone( wp_timezone() )
188 - ->sub( new DateInterval( 'P1Y' ) )
189 - ->setTime( 0, 0, 0 );
190 - $date_to = ( new DateTime() )->setTimezone( wp_timezone() )
191 - ->sub( new DateInterval( $interval ) );
175 + // Since v5.7.0.
176 + $interval = apply_filters( 'wpdef_audit_logs_store_backward', $interval );
177 + $interval = is_string( $interval ) ? $interval : (string) $interval;
192 178
179 + try {
180 + $interval_obj = new DateInterval( $interval );
181 + } catch ( Exception ) {
182 + // Fallback if the filter supplied an incorrect value.
183 + $interval_obj = new DateInterval( 'P6M' );
184 + }
185 +
186 + $date_from = ( new DateTime() )->setTimezone( wp_timezone() )
187 + ->sub( new DateInterval( 'P1Y' ) )
188 + ->setTime( 0, 0, 0 );
189 + $date_to = ( new DateTime() )->setTimezone( wp_timezone() )
190 + ->sub( $interval_obj );
191 +
193 192 if ( $date_from < $date_to ) {
194 193 // Count the logs that should be deleted.
195 194 $logs_count = Audit_Log::count( $date_from->getTimestamp(), $date_to->getTimestamp() );
196 195 if ( $logs_count > 0 ) {
197 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 );
197 + // Since v5.0.0.
198 + $delete_count = apply_filters( 'wpdef_audit_limit_deleted_logs', 50 );
198 199 Audit_Log::delete_old_logs(
199 200 $date_from->getTimestamp(),
200 201 $date_to->getTimestamp(),
201 - // Since v5.0.0.
202 - (int) apply_filters( 'wpdef_audit_limit_deleted_logs', 50 )
202 + is_int( $delete_count ) ? $delete_count : (int) $delete_count,
203 203 );
204 204 }
205 205 }
206 206 }
@@ -229,84 +229,8 @@
229 229 return $ret;
230 230 }
231 231
232 232 /**
233 - * Sends data to the API using a socket connection.
234 - *
235 - * @param array $data Data to be sent to the API.
236 - *
237 - * @return bool Returns true on success, false on failure.
238 - */
239 - public function socket_to_api( $data ) {
240 - $sockets = Array_Cache::get( 'sockets', 'audit', array() );
241 - // We will need to wait a bit.
242 - if ( 0 === ( is_array( $sockets ) || $sockets instanceof Countable ? count( $sockets ) : 0 ) ) {
243 - // Fall back.
244 - return false;
245 - }
246 - $this->log(
247 - sprintf( 'Flush %s to cloud', is_array( $data ) || $data instanceof Countable ? count( $data ) : 0 ),
248 - self::AUDIT_LOG
249 - );
250 - $start_time = microtime( true );
251 - $sks = $sockets;
252 - $r = null;
253 - $e = null;
254 - if ( ( false === stream_select( $r, $sks, $e, 1 ) ) ) {
255 - // This case error happen.
256 - return false;
257 - }
258 -
259 - $fp = array_shift( $sockets );
260 -
261 - $uri = '/logs/add_multiple';
262 - $vars = http_build_query( $data );
263 - $this->attach_behavior( WPMUDEV::class, WPMUDEV::class );
264 - // We're sending data to the server, so we're not manipulating files. Ignore the error.
265 - // @codingStandardsIgnoreStart
266 - fwrite( $fp, 'POST ' . $uri . " HTTP/1.1\r\n" );
267 - fwrite( $fp, 'Host: ' . $this->strip_protocol( $this->get_endpoint() ) . "\r\n" );
268 - fwrite( $fp, "Content-Type: application/x-www-form-urlencoded\r\n" );
269 - fwrite( $fp, 'Content-Length: ' . strlen( $vars ) . "\r\n" );
270 - fwrite( $fp, 'apikey: ' . $this->get_apikey() . "\r\n" );
271 - fwrite( $fp, "Connection: close\r\n" );
272 - fwrite( $fp, "\r\n" );
273 - fwrite( $fp, $vars );
274 - stream_set_timeout( $fp, 5 );
275 - $res = '';
276 - while ( ! feof( $fp ) ) {
277 - $res .= fgets( $fp, 1024 );
278 - // Check if the transfer has taken too long.
279 - $end_time = microtime( true );
280 - if ( $end_time - $start_time > 3 ) {
281 - fclose( $fp );
282 - break;
283 - }
284 - }
285 - // @codingStandardsIgnoreEnd
286 - return true;
287 - }
288 -
289 - /**
290 - * Open a socket to API for faster transmit.
291 - */
292 - public function open_socket() {
293 - $sockets = Array_Cache::get( 'sockets', 'audit', array() );
294 - $endpoint = $this->strip_protocol( $this->get_endpoint() );
295 - if ( empty( $sockets ) ) {
296 - $fp = stream_socket_client(
297 - 'ssl://' . $endpoint . ':443',
298 - $errno,
299 - $errstr,
300 - 5
301 - );
302 - if ( is_resource( $fp ) ) {
303 - Array_Cache::set( 'sockets', array( $fp ), 'audit' );
304 - }
305 - }
306 - }
307 -
308 - /**
309 233 * Strips the protocol from a URL.
310 234 *
311 235 * @param string $url URL to process.
312 236 *
@@ -340,11 +264,15 @@
340 264 new Component\Audit\Comment_Audit(),
341 265 new Component\Audit\Core_Audit(),
342 266 new Component\Audit\Media_Audit(),
343 267 new Component\Audit\Post_Audit(),
344 - new Component\Audit\Users_Audit(),
268 + new Component\Audit\User_Audit(),
345 269 new Component\Audit\Options_Audit(),
346 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(),
347 275 );
348 276
349 277 foreach ( $events_class as $class ) {
350 278 // since 2.4.7.
@@ -394,9 +322,9 @@
394 322 $model = new Audit_Log();
395 323
396 324 if ( ( is_array( $events ) || $events instanceof Countable ? count( $events ) : 0 ) > 1 ) {
397 325 if ( $model->has_method( 'mass_insert' ) ) {
398 - $model->mass_insert( $events );
326 + $model->mass_insert( $events, 0 );
399 327
400 328 return;
401 329 }
402 330 }
@@ -405,6 +333,21 @@
405 333 $model->import( $event );
406 334 $model->synced = 0;
407 335 $model->save();
408 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 );
409 352 }
410 353 }