Automatic WordPress security: local firewall, malware and file-integrity scanning, vulnerability protection, quarantine, scheduled backups, an optional page cache, and automatic global threat intelligence. See README.md for installation, update, and uninstall instructions.
156 lines
4.3 KiB
PHP
156 lines
4.3 KiB
PHP
<?php
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class Argus_Events {
|
|
|
|
const DEFAULT_MAX_ROWS = 50000;
|
|
|
|
public static function record( $type, $severity, $summary, array $payload = array(), $ip = null ) {
|
|
global $wpdb;
|
|
|
|
$wpdb->insert(
|
|
Argus_DB::table( 'events' ),
|
|
array(
|
|
'event_type' => $type,
|
|
'severity' => $severity,
|
|
'ip' => $ip,
|
|
'summary' => $summary,
|
|
'payload' => wp_json_encode( $payload ),
|
|
'created_at' => current_time( 'mysql', true ),
|
|
),
|
|
array( '%s', '%s', '%s', '%s', '%s', '%s' )
|
|
);
|
|
|
|
return (int) $wpdb->insert_id;
|
|
}
|
|
|
|
public static function recent( $limit = 50, $type = null ) {
|
|
global $wpdb;
|
|
$table = Argus_DB::table( 'events' );
|
|
|
|
if ( $type ) {
|
|
$rows = $wpdb->get_results(
|
|
$wpdb->prepare( "SELECT * FROM {$table} WHERE event_type = %s ORDER BY created_at DESC LIMIT %d", $type, $limit ) // phpcs:ignore
|
|
);
|
|
} else {
|
|
$rows = $wpdb->get_results(
|
|
$wpdb->prepare( "SELECT * FROM {$table} ORDER BY created_at DESC LIMIT %d", $limit ) // phpcs:ignore
|
|
);
|
|
}
|
|
|
|
foreach ( $rows as &$row ) {
|
|
$row->payload = json_decode( $row->payload, true );
|
|
}
|
|
|
|
return $rows;
|
|
}
|
|
|
|
public static function counts_since( $since_mysql ) {
|
|
global $wpdb;
|
|
$table = Argus_DB::table( 'events' );
|
|
|
|
return $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT event_type, severity, COUNT(*) AS cnt FROM {$table} WHERE created_at >= %s GROUP BY event_type, severity", // phpcs:ignore
|
|
$since_mysql
|
|
)
|
|
);
|
|
}
|
|
|
|
const PER_PAGE = 10;
|
|
|
|
public static function paginated( $page = 1, array $filters = array(), $per_page = self::PER_PAGE ) {
|
|
global $wpdb;
|
|
$table = Argus_DB::table( 'events' );
|
|
$page = max( 1, (int) $page );
|
|
$offset = ( $page - 1 ) * $per_page;
|
|
|
|
$where = array( '1=1' );
|
|
$args = array();
|
|
|
|
if ( ! empty( $filters['search'] ) ) {
|
|
$where[] = 'summary LIKE %s';
|
|
$args[] = '%' . $wpdb->esc_like( $filters['search'] ) . '%';
|
|
}
|
|
if ( ! empty( $filters['severity'] ) ) {
|
|
$where[] = 'severity = %s';
|
|
$args[] = $filters['severity'];
|
|
}
|
|
if ( ! empty( $filters['type'] ) ) {
|
|
$where[] = 'event_type = %s';
|
|
$args[] = $filters['type'];
|
|
}
|
|
if ( ! empty( $filters['since'] ) ) {
|
|
$where[] = 'created_at >= %s';
|
|
$args[] = $filters['since'];
|
|
}
|
|
|
|
$where_sql = implode( ' AND ', $where );
|
|
|
|
$count_sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}"; // phpcs:ignore
|
|
$total = (int) ( $args ? $wpdb->get_var( $wpdb->prepare( $count_sql, $args ) ) : $wpdb->get_var( $count_sql ) ); // phpcs:ignore
|
|
|
|
$list_sql = "SELECT * FROM {$table} WHERE {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d"; // phpcs:ignore
|
|
$list_args = array_merge( $args, array( $per_page, $offset ) );
|
|
$rows = $wpdb->get_results( $wpdb->prepare( $list_sql, $list_args ) ); // phpcs:ignore
|
|
|
|
foreach ( $rows as &$row ) {
|
|
$row->payload = json_decode( $row->payload, true );
|
|
}
|
|
|
|
return array(
|
|
'rows' => $rows,
|
|
'total' => $total,
|
|
'total_pages' => max( 1, (int) ceil( $total / $per_page ) ),
|
|
'page' => $page,
|
|
);
|
|
}
|
|
|
|
public static function distinct_types() {
|
|
global $wpdb;
|
|
$table = Argus_DB::table( 'events' );
|
|
return $wpdb->get_col( "SELECT DISTINCT event_type FROM {$table} ORDER BY event_type ASC" ); // phpcs:ignore
|
|
}
|
|
|
|
const RETENTION_DAYS_BY_SEVERITY = array(
|
|
'info' => 30,
|
|
'low' => 90,
|
|
'medium' => 365,
|
|
'high' => 365,
|
|
'critical' => 365,
|
|
);
|
|
|
|
public static function prune() {
|
|
global $wpdb;
|
|
$table = Argus_DB::table( 'events' );
|
|
|
|
$retention = apply_filters( 'argus_wpd_event_retention_days', self::RETENTION_DAYS_BY_SEVERITY );
|
|
$deleted = 0;
|
|
foreach ( $retention as $severity => $days ) {
|
|
$cutoff = gmdate( 'Y-m-d H:i:s', time() - ( (int) $days * DAY_IN_SECONDS ) );
|
|
$deleted += (int) $wpdb->query(
|
|
$wpdb->prepare( "DELETE FROM {$table} WHERE severity = %s AND created_at < %s", $severity, $cutoff ) // phpcs:ignore
|
|
);
|
|
}
|
|
|
|
$max_rows = (int) apply_filters( 'argus_wpd_max_event_rows', self::DEFAULT_MAX_ROWS );
|
|
$total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table}" ); // phpcs:ignore
|
|
if ( $total <= $max_rows ) {
|
|
return $deleted;
|
|
}
|
|
|
|
$overflow = $total - $max_rows;
|
|
$deleted += (int) $wpdb->query(
|
|
$wpdb->prepare(
|
|
"DELETE FROM {$table} ORDER BY created_at ASC LIMIT %d", // phpcs:ignore
|
|
$overflow
|
|
)
|
|
);
|
|
|
|
return $deleted;
|
|
}
|
|
}
|