Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File System Journal #272

Merged
merged 28 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
97604d5
Gathering to csv.
svfcode Nov 5, 2023
93e1a13
New. FSWatcher. Analyze WIP.
svfcode Nov 11, 2023
437d890
Fix. Codestyle.
alexandergull Nov 14, 2023
238cb0a
Fix. Logger.
alexandergull Nov 14, 2023
25c3d80
New. FSW table template.
alexandergull Nov 14, 2023
4130569
Fix. Compare. Delete unzipped files.
alexandergull Nov 15, 2023
7cae9d8
New. Settings. FS Watcher on/off. Enabled by defaults.
alexandergull Nov 16, 2023
c82fb7f
Ref. FWWatcher. Lot of improvements.
alexandergull Nov 16, 2023
6905f4c
JS docs and refactoring.
alexandergull Nov 16, 2023
f3dafde
PHPCS fixes.
alexandergull Nov 16, 2023
e4a871f
PSALM fixes.
alexandergull Nov 16, 2023
3049648
Merge branch 'dev' into fswatcher
alexandergull Nov 16, 2023
7452da2
PSALM Fixes after dev merge.
alexandergull Nov 16, 2023
f18a7af
Merge remote-tracking branch 'origin/dev' into fswatcher
Glomberg Dec 6, 2023
a31df7b
Fix. FS Watcher. Logs directory listing prevented.
Glomberg Dec 6, 2023
5a31b86
Fix. FS Watcher. Selectors rendering fixed.
Glomberg Dec 6, 2023
bc341e9
Upd. Code. Gitignore updated.
Glomberg Dec 6, 2023
d945685
Fix. Code. Code style fixed.
Glomberg Dec 6, 2023
801868f
Fix: Code. Doc-blocks added, psalm notices fixed.
Glomberg Dec 6, 2023
7afe77f
Upd. FS Watcher. Manual creating snapshot button and logic implemented.
Glomberg Dec 6, 2023
6acf3a9
Upd. FS Watcher. Phrases moved to the separated class.
Glomberg Dec 6, 2023
3757764
Upd. FS Watcher. Ajax url fixed.
Glomberg Dec 7, 2023
613d0c3
Upd. FS Watcher. Layout fixed.
Glomberg Dec 7, 2023
ae18595
Upd. FS Watcher. Ajax url fixed #2.
Glomberg Dec 8, 2023
23d5933
Merge branch 'dev' into fswatcher
alexandergull Dec 18, 2023
a6c2da3
Mod. FS Watcher updates.
alexandergull Dec 19, 2023
633808f
Merge branch 'dev' into fswatcher
alexandergull Jan 17, 2024
cbb7c63
Fix. FSWatcher. Logs path protected.
alexandergull Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions inc/spbc-scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -1836,11 +1836,12 @@ function spbc_scanner_analysis_log_delete_from_log($direct_call = false)

if ( is_array($file_ids) ) {
// Validate if the ID is hash (SQL-clear)
$file_ids_clean = array_map( function($id) {
$file_ids_clean = array_map(function ($id) {
if ( \Cleantalk\ApbctWP\Validate::isHash($id) ) {
return $id;
}
}, $file_ids );
return 'none';
}, $file_ids);
}

$output = array('error' => false);
Expand Down
31 changes: 26 additions & 5 deletions inc/spbc-settings.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use CleantalkSP\Common\FSWatcher\View\View;
use CleantalkSP\SpbctWP\Scanner\ScanningLog\ScanningLogFacade;
use CleantalkSP\Variables\Post;
use CleantalkSP\Variables\Server;
Expand Down Expand Up @@ -682,6 +683,11 @@ function spbc_settings__register()
'title' => __('Important File Monitoring', 'security-malware-firewall'),
'description' => __('Monitoring of the individual most important files of the site.', 'security-malware-firewall'),
),
'scanner__fs_watcher' => array(
'type' => 'field',
'title' => __('File System Journal', 'security-malware-firewall'),
'description' => View::getFSWatcherDescription(),
),
),
),

Expand Down Expand Up @@ -906,6 +912,16 @@ function spbc_settings__register()
'ajax' => false,
'callback' => 'spbc_tab__summary',
),
// FSWatcher
'fswatcher' => array(
'type' => 'tab',
'title' => __('FS journal', 'security-malware-firewall'),
'icon' => 'spbc-icon-info',
'class_prefix' => 'spbc',
'ajax' => true,
'callback' => 'spbc_tab__fswatcher',
'display' => $spbc->settings['scanner__fs_watcher']
),
// Debug
'debug' => array(
'type' => 'tab',
Expand Down Expand Up @@ -1594,6 +1610,13 @@ function spbc_tab__summary()
echo '<br>';
}

function spbc_tab__fswatcher()
{
echo "<div class='spbc_wrapper_field'>";
echo \CleantalkSP\Common\FSWatcher\View\View::renderSelectors();
echo '</div>';
}

/**
* Admin callback function - Displays current statistics
*/
Expand Down Expand Up @@ -2463,16 +2486,15 @@ function spbc_field_scanner__prepare_data__files(&$table)
$ws_string .= '</p>';
}
}
if ( ! empty($weak_spots['DENIED_HASH'])) {
if ( !empty($weak_spots['DENIED_HASH']) ) {
// collecting all kinds of code
$all_unique_weak_spots = array();
foreach ($weak_spots['DENIED_HASH'] as $_string => $weak_spot_in_string) {
$all_unique_weak_spots[] = $weak_spot_in_string[0];
$all_unique_weak_spots[] = $weak_spot_in_string[0];
}
$all_unique_weak_spots = array_unique($all_unique_weak_spots);
foreach ($all_unique_weak_spots as $weak_spot_in_string) {

$ws_string .= '<p style="margin: 0;"><span class="spbcRed"><i setting="hash_' . str_replace(' ', '_', $weak_spot_in_string) . '" class="spbc_long_description__show spbc-icon-help-circled"></i> Hash: </span>'
$ws_string .= '<p style="margin: 0;"><span class="spbcRed"><i setting="hash_' . str_replace(' ', '_', $weak_spot_in_string) . '" class="spbc_long_description__show spbc-icon-help-circled"></i> Hash: </span>'
. 'denied';

$ws_string .= '</p>';
Expand All @@ -2486,7 +2508,6 @@ function spbc_field_scanner__prepare_data__files(&$table)
}
$all_unique_weak_spots = array_unique($all_unique_weak_spots);
foreach ($all_unique_weak_spots as $weak_spot_in_string) {

$ws_string .= '<p style="margin: 0;"><span class="spbcRed"><i setting="danger_' . str_replace(' ', '_', $weak_spot_in_string) . '" class="spbc_long_description__show spbc-icon-help-circled"></i> Danger: </span>'
. (strlen($weak_spot_in_string) > 30
? substr($weak_spot_in_string, 0, 30) . '...'
Expand Down
Empty file modified lib/CleantalkSP/Common/CleantalkTools.php
100644 → 100755
Empty file.
125 changes: 125 additions & 0 deletions lib/CleantalkSP/Common/FSWatcher/Analyzer/Analyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

namespace CleantalkSP\Common\FSWatcher\Analyzer;

use CleantalkSP\Common\FSWatcher\Logger;
use CleantalkSP\Common\FSWatcher\Controller;

class Analyzer
{
public static function getCompareResult()
{
$first = filter_var($_POST['fswatcher__first_date'], FILTER_VALIDATE_INT);
$second = filter_var($_POST['fswatcher__second_date'], FILTER_VALIDATE_INT);

if ($first > $second) {
$tmp = $first;
$first = $second;
$second = $tmp;
}

$first_journal = Controller::$storage::getJournal($first);
$second_journal = Controller::$storage::getJournal($second);

if (!$first_journal || !$second_journal) {
return false;
}

if (Controller::$debug) {
Logger::log('first journal ' . $first_journal);
Logger::log('second journal ' . $second_journal);
}

return self::compare($first_journal, $second_journal);
}

private static function compare($first_journal, $second_journal)
{
$result = array(
'added' => array(),
'deleted' => array(),
'changed' => array(),
);

//return no diff if csv names is equal
if ( $first_journal === $second_journal) {
return $result;
}

//return no diff if md5 sums is equal
if (md5(@file_get_contents($first_journal)) === md5(@file_get_contents($second_journal))) {
return $result;
}

$first_journal = self::uncompress($first_journal);
$second_journal = self::uncompress($second_journal);

if ( !$first_journal || !$second_journal) {
return false;
}

$first_array = [];
$second_array = [];

try {
$fp_first = fopen($first_journal, 'r');
while ($first = fgetcsv($fp_first)) {
$first_array[$first[0]] = $first[1];
}
fclose($fp_first);
@unlink($first_journal);

$fp_second = fopen($second_journal, 'r');
while ($second = fgetcsv($fp_second)) {
$second_array[$second[0]] = $second[1];
}
fclose($fp_second);
@unlink($second_journal);

foreach ($first_array as $path => $time) {
if ((isset($second_array[$path]) && $time !== $second_array[$path])) {
$result['changed'][] = [$path, $second_array[$path]];
}
}

$keys_differ = array_merge(array_diff_key($first_array, $second_array), array_diff_key($second_array, $first_array));

foreach ($keys_differ as $path => $time) {
if ( in_array($path, array_keys($first_array)) && !in_array($path, array_keys($second_array))) {
$result['deleted'][] = [$path,$time];
}

if ( !in_array($path, array_keys($first_array)) && in_array($path, array_keys($second_array))) {
$result['added'][] = [$path,$time];
}
}

return $result;
} catch (\Exception $e) {
return false;
}
}

private static function uncompress($file)
{
if ( substr($file, -3) === '.gz' ) {
$content = @gzopen($file, 'r');
if ( false === $content ) {
return false;
}
$gz_result = @gzread($content, 1024 * 1024 * 10);
if ( !is_string($gz_result) ) {
@gzclose($content);
return false;
}
$write_result = @file_put_contents(substr($file, 0, -3), $gz_result);
gzclose($content);
if ( false === $write_result ) {
return false;
}
$file = substr($file, 0, -3);
}

return $file;
}
}
92 changes: 92 additions & 0 deletions lib/CleantalkSP/Common/FSWatcher/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace CleantalkSP\Common\FSWatcher;

use CleantalkSP\Common\FSWatcher\Analyzer\Analyzer;
use CleantalkSP\Common\FSWatcher\Scan\Scan;

class Controller
{
public static $debug;
const STATUS_STOPPED = 'stopped';
const STATUS_RUNNING = 'running';

const EXECUTION_MIN_INTERVAL = 6000;

public static $storage;
public static $repository;

private static $status = self::STATUS_STOPPED;

private static function getDebugState()
{
if ( defined('SPBC_FSWATCHER_DEBUG') ) {
return SPBC_FSWATCHER_DEBUG;
} else {
return false;
}
}

public static function work($params)
{
self::getDebugState();

if (self::$debug) {
Logger::log('check remote call = ' . (int)Service::isRC());
}

Service::setStorage(isset($params['storage']) ? $params['storage'] : 'file');

if (self::status() === self::STATUS_STOPPED && Service::isRC() && Service::isCompareRequest()) {
if (self::$debug) {
Logger::log('run compare file system');
}
$compare_result = Analyzer::getCompareResult();
if (false === $compare_result) {
Logger::log('Can not compare logs');
echo json_encode(array('error' => 'Can not compare logs'));
} else {
echo json_encode($compare_result);
}
die();
}

if (self::status() === self::STATUS_STOPPED && Service::isRC()) {
if (self::$debug) {
Logger::log('run scan file system');
}
self::run($params);
die('OK');
}

if (self::status() === self::STATUS_STOPPED && Service::isMinIntervalPassed(self::EXECUTION_MIN_INTERVAL)) {
if (self::$debug) {
Logger::log('attach js to make remote request');
}
ob_start(['CleantalkSP\Common\FSWatcher\Service', 'attachJS']);
}
}

private static function run($params)
{
self::$status = self::STATUS_RUNNING;
Scan::run($params);
self::stop();
}

private static function stop()
{
self::$status = self::STATUS_STOPPED;
Service::setAllJournalsAsCompleted();
}

private static function status()
{
$is_exist = Service::getProcessingJournal();
if (!is_null($is_exist)) {
self::$status = self::STATUS_RUNNING;
}

return self::$status;
}
}
60 changes: 60 additions & 0 deletions lib/CleantalkSP/Common/FSWatcher/Logger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace CleantalkSP\Common\FSWatcher;

class Logger
{
private static $logger_dir = __DIR__ . DIRECTORY_SEPARATOR . 'logs';

private static function getCurrentDayLogPath()
{
$path = self::getLoggerDir();
return $path
? $path . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log'
: false;
}

private static function setLoggerDir()
{
return mkdir(self::$logger_dir);
}

private static function getLoggerDir()
{
if ( !is_dir(self::$logger_dir) ) {
if ( !self::setLoggerDir() ) {
return false;
}
}
return self::$logger_dir;
}

public static function log($msg)
{
$current_day_log_path = self::getCurrentDayLogPath();

if ( !$current_day_log_path ) {
error_log('Cant write log.');
return;
}

$message = '[' . date('H:i:s') . ']' . ' ';

$message .= debug_backtrace()[1]['class']
. debug_backtrace()[1]['type']
. debug_backtrace()[1]['function']
. PHP_EOL;

if (is_string($msg)) {
$message .= $msg . PHP_EOL;
}

if (is_array($msg)) {
foreach ($msg as $key => $value) {
$message .= $key . ': ' . $value . PHP_EOL;
}
}

error_log($message, 3, $current_day_log_path);
}
}
13 changes: 13 additions & 0 deletions lib/CleantalkSP/Common/FSWatcher/Repository/FileRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace CleantalkSP\Common\FSWatcher\Repository;

use CleantalkSP\Common\FSWatcher\Controller;

class FileRepository implements Repository
{
public static function getAvailableJournals()
{
return Controller::$storage::getAvailableJournals();
}
}
12 changes: 12 additions & 0 deletions lib/CleantalkSP/Common/FSWatcher/Repository/Repository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace CleantalkSP\Common\FSWatcher\Repository;

interface Repository
{
/**
* @return mixed
* @psalm-suppress PossiblyUnusedMethod
*/
public static function getAvailableJournals();
}
Loading