193 lines
5.1 KiB
PHP
193 lines
5.1 KiB
PHP
|
<?
|
||
|
/*
|
||
|
TODO:
|
||
|
- Audit collapse animation is jerky and lame
|
||
|
- Suppress errors in cron script and schedule
|
||
|
- Cron script shouldn't wallop json files while it's running
|
||
|
- Update styles and icons in UI when files are (un)ignored
|
||
|
- Add option to show all ignores/acks
|
||
|
- Add option to clear all ignores/acks
|
||
|
- Adding directory aknowlegement could be useful for plugin
|
||
|
updates and new sites.
|
||
|
*/
|
||
|
require_once('template.php');
|
||
|
|
||
|
$errors = array();
|
||
|
$sites = array();
|
||
|
$slugs = array();
|
||
|
$audits = array();
|
||
|
$ignores = array();
|
||
|
|
||
|
$changed_files = array();
|
||
|
$unacked_files = array();
|
||
|
$unacked_scripts = array();
|
||
|
$unacked_sites = array();
|
||
|
|
||
|
$audit_dir = 'json';
|
||
|
|
||
|
$warn_age = 1 * 24 * 60 * 60; # 1 day, 24 hours, or seconds
|
||
|
|
||
|
# need to keep this in sync with vhost-audit.pl
|
||
|
$scripts = array('/.php$/', '/.htaccess$/', '/.js$/');
|
||
|
|
||
|
|
||
|
$sites_file = 'sites.txt';
|
||
|
if ( ($sites = @file($sites_file, FILE_IGNORE_NEW_LINES)) !== FALSE ) {
|
||
|
$site_count = count($sites);
|
||
|
sort($sites);
|
||
|
}
|
||
|
else {
|
||
|
$errors[] = 'Could not open sites file, ' . $sites_file;
|
||
|
}
|
||
|
|
||
|
foreach ($sites as $site) {
|
||
|
$parts = explode('/', $site);
|
||
|
$hostname = $parts[count($parts) -2];
|
||
|
$slugs[$site] = preg_replace('/\./', '_', $hostname);
|
||
|
$audit_file = $audit_dir . '/' . $hostname . '.json';
|
||
|
$ignore_file = $audit_dir . '/' . $hostname . '-ignore.json';
|
||
|
|
||
|
# pull in a site's ignore file
|
||
|
if ( file_exists($ignore_file) ) {
|
||
|
if ( ($ignore_json = @file_get_contents($ignore_file)) !== FALSE ) {
|
||
|
$ignore_json = utf8_encode($ignore_json);
|
||
|
$ignore = @json_decode($ignore_json, true);
|
||
|
if ($ignore === null) {
|
||
|
$ignore = array();
|
||
|
}
|
||
|
$ignores[$site] = $ignore;
|
||
|
}
|
||
|
else {
|
||
|
$errors[] = 'Could not open ignore file, ' . $ignore_file;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# pull in a site's audit file
|
||
|
if ( file_exists($audit_file) ) {
|
||
|
if ( ($audit_json = @file_get_contents($audit_file)) !== FALSE ) {
|
||
|
$audit_json = utf8_encode($audit_json);
|
||
|
$audit = @json_decode($audit_json, true);
|
||
|
if ($audit === null) {
|
||
|
$audit = array('data' => array());
|
||
|
}
|
||
|
ksort($audit['data']);
|
||
|
foreach ( array_keys($audit['data']) as $date) {
|
||
|
if ( is_array($audit['data'][$date]['files']) ) {
|
||
|
ksort($audit['data'][$date]['files']);
|
||
|
}
|
||
|
else {
|
||
|
$audit['data'][$date]['files'] = array();
|
||
|
}
|
||
|
|
||
|
foreach ( $audit['data'][$date]['files'] as $file => $action ) {
|
||
|
$dir = dirname($file);
|
||
|
if (substr($dir, -1) !== '/') {
|
||
|
$dir .= '/';
|
||
|
}
|
||
|
$audit['data'][$date]['files'][$file]
|
||
|
= array('action' => $action);
|
||
|
if ( isset($ignores[$site][$file]) ) {
|
||
|
if ( $ignores[$site][$file]['action'] == 'acknowledge' ) {
|
||
|
if ( $ignores[$site][$file]['date'] > $date ) {
|
||
|
$audit['data'][$date]['files'][$file]['status']
|
||
|
= 'acknowledge';
|
||
|
}
|
||
|
}
|
||
|
elseif ( $ignores[$site][$file]['action'] == 'ignore_file' ) {
|
||
|
$audit['data'][$date]['files'][$file]['status']
|
||
|
= 'ignore_file';
|
||
|
}
|
||
|
}
|
||
|
elseif ( isset($ignores[$site][$dir]['action']) ) {
|
||
|
$audit['data'][$date]['files'][$file]['status']
|
||
|
= 'ignore_dir';
|
||
|
}
|
||
|
else {
|
||
|
$unacked_files[] = $site . $file;
|
||
|
|
||
|
$is_script = false;
|
||
|
foreach ($scripts AS $script) {
|
||
|
if ( preg_match($script, $file) ) {
|
||
|
$is_script = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ( $is_script ) {
|
||
|
$unacked_scripts[] = $site . $file;
|
||
|
$unacked_sites[$site] = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
$lastrun = $audit['lastrun'];
|
||
|
|
||
|
$audits[$site] = $audit;
|
||
|
}
|
||
|
else {
|
||
|
$errors[] = 'Could not open audit file, ' . $audit_file;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$errors[] = "Audit file ($audit_file) not found";
|
||
|
}
|
||
|
|
||
|
$tot_changes += $audit['changes'];
|
||
|
$tot_scripts += $audit['scripts'];
|
||
|
}
|
||
|
|
||
|
#print_r($unacked_scripts);exit;
|
||
|
$tot_unacked_changes = count($unacked_files);
|
||
|
$tot_unacked_scripts = count($unacked_scripts);
|
||
|
$unacked_sites = array_keys($unacked_sites);
|
||
|
|
||
|
#echo('<pre>Audits: ');
|
||
|
#print_r($audits);
|
||
|
#echo('Ignores: ');
|
||
|
#print_r($ignores);
|
||
|
#echo('</pre>');
|
||
|
#exit;
|
||
|
|
||
|
if ( $_SERVER['HTTP_ACCEPT'] == 'application/json' || $_SERVER['CONTENT_TYPE'] == 'application/json') {
|
||
|
if ( $tot_unacked_scripts == 0 ) {
|
||
|
$message = 'OK';
|
||
|
}
|
||
|
else {
|
||
|
$message = 'Unacknowledged script changes in: ' . join(', ', $unacked_sites);
|
||
|
}
|
||
|
|
||
|
header('Content-type: application/json');
|
||
|
$response = array(
|
||
|
'sites' => $site_count,
|
||
|
'changes' => $tot_changes,
|
||
|
'scripts' => $tot_scripts,
|
||
|
'unacked_changes' => $tot_unacked_changes,
|
||
|
'unacked_scripts' => $tot_unacked_scripts,
|
||
|
'unacked_sites' => $unacked_sites,
|
||
|
'message' => $message
|
||
|
);
|
||
|
echo(json_encode($response, JSON_PRETTY_PRINT));
|
||
|
exit;
|
||
|
}
|
||
|
else {
|
||
|
$T = new Template('templates/index.php');
|
||
|
$T->set('errors', $errors);
|
||
|
$T->set('message', $message);
|
||
|
$T->set('sites', $sites);
|
||
|
$T->set('site_count', $site_count);
|
||
|
$T->set('slugs', $slugs);
|
||
|
$T->set('ignores', $ignores);
|
||
|
$T->set('audits', $audits);
|
||
|
$T->set('warn_age', $warn_age);
|
||
|
$T->set('scripts', $scripts);
|
||
|
$T->set('tot_changes', $tot_changes);
|
||
|
$T->set('tot_scripts', $tot_scripts);
|
||
|
$T->set('tot_unacked_changes', $tot_unacked_changes);
|
||
|
$T->set('tot_unacked_scripts', $tot_unacked_scripts);
|
||
|
$T->set('unacked_sites', $unacked_sites);
|
||
|
echo($T->fetch());
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
?>
|