Add in software files and templates

This commit is contained in:
2023-06-21 14:19:40 +01:00
parent f42fdb947c
commit 5228fc5e9f
143 changed files with 23175 additions and 2 deletions

View File

@@ -0,0 +1,271 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2023 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script is for checking configuration.
*
* The script can be useful for checking your configuration.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Core;
use Liuch\DmarcSrg\Mail\MailBoxes;
use Liuch\DmarcSrg\Directories\DirectoryList;
use Liuch\DmarcSrg\Exception\SoftException;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
const RESULT_SUCCESS = 1;
const RESULT_WARNING = 2;
const RESULT_ERROR = 3;
const RESULT_FATAL = 4;
const CONFIG_FILE = 'config/conf.php';
$e_cnt = 0;
$w_cnt = 0;
$m_str = '';
$startChecking = function (string $message, int $margin = 0) use (&$m_str): void {
$col_w = 35;
$m_str = str_repeat(' ', $margin);
$s = "{$m_str} * {$message}";
echo $s, str_repeat('.', max($col_w - strlen($s), 0)), ' ';
};
$endChecking = function (string $message = '', int $result = 0) use (&$e_cnt, &$w_cnt, &$m_str): void {
if ($result === 0) {
$result = empty($message) ? RESULT_SUCCESS : RESULT_ERROR;
}
switch ($result) {
case RESULT_SUCCESS:
echo 'Ok', PHP_EOL;
break;
case RESULT_WARNING:
++$w_cnt;
echo 'Warning', PHP_EOL;
break;
case RESULT_ERROR:
++$e_cnt;
echo 'Fail', PHP_EOL;
break;
case RESULT_FATAL:
echo 'Fail', PHP_EOL;
throw new SoftException($message);
}
if (!empty($message)) {
echo "{$m_str} Message: ", $message, PHP_EOL;
}
};
$core = Core::instance();
ob_start(null, 0, PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE);
$core->config('debug'); // Just in order to load the config file
$empty_buf = empty(ob_get_flush());
try {
echo '=== GENERAL INFORMATION ===', PHP_EOL;
$uname = implode(' ', array_map(function ($mode) {
return php_uname($mode);
}, [ 's', 'r', 'v', 'm' ]));
echo ' * OS information: ', $uname, PHP_EOL;
echo ' * PHP version: ', phpversion(), PHP_EOL;
echo PHP_EOL, '=== EXTENSIONS ===', PHP_EOL;
foreach ([ 'pdo_mysql', 'xmlreader', 'zip', 'json' ] as $ext) {
$startChecking($ext);
if (extension_loaded($ext)) {
$endChecking();
} else {
$endChecking('The extension is not loaded');
}
}
echo PHP_EOL, '=== CONFIG FILE ===', PHP_EOL;
$startChecking('Checking if the file exists');
if (is_file(CONFIG_FILE)) {
$endChecking();
} else {
$endChecking('The configuration file `config/conf.php` not found', RESULT_FATAL);
}
$startChecking('Checking read permission');
if (is_readable(CONFIG_FILE)) {
$endChecking();
} else {
$endChecking('The configuration file is not readable', RESULT_FATAL);
}
$startChecking('Checking write permission');
if (!is_writable(CONFIG_FILE)) {
$endChecking();
} else {
$endChecking('The configuration file is writable', RESULT_WARNING);
}
$startChecking('Checking access by other users');
$r = fileperms(CONFIG_FILE);
if ($r !== false) {
if (($r & 0x6) !== 0) {
$endChecking('The configuration file is accessible to other users', RESULT_WARNING);
} else {
$endChecking();
}
} else {
$endChecking('Fileperms failed', RESULT_ERROR);
}
$startChecking('Checking the output buffer');
if ($empty_buf) {
$endChecking();
} else {
$endChecking('There are extra characters before the "<?php" string');
}
echo PHP_EOL, '=== DATABASE ===', PHP_EOL;
$startChecking('Accessibility check');
try {
$db_s = $core->database()->state();
$endChecking();
} catch (RuntimeException $e) {
$db_s = null;
$endChecking($e->getMessage());
}
if ($db_s) {
$startChecking('Checking for integrity');
if ($db_s) {
$endChecking();
} else {
$endChecking($db_s['message'], ($db_s['needs_upgrade'] ?? false) ? RESULT_WARNING : RESULT_ERROR);
}
}
echo PHP_EOL, '=== MAILBOXES ===', PHP_EOL;
$startChecking('Checking mailboxes config');
try {
$mb_list = new MailBoxes();
$mb_lcnt = $mb_list->count();
if ($mb_lcnt === 0) {
$endChecking('No mailboxes found', RESULT_SUCCESS);
} else {
$endChecking("{$mb_lcnt} mailbox" . ($mb_lcnt > 1 ? 'ex' : '') . ' found', RESULT_SUCCESS);
$startChecking('Imap extension');
if (extension_loaded('imap')) {
$endChecking();
echo " * Checking mailboxes ({$mb_lcnt})", PHP_EOL;
for ($mb_num = 1; $mb_num <= $mb_lcnt; ++$mb_num) {
$mb = $mb_list->mailbox($mb_num);
echo " - {$mb->name()}", PHP_EOL;
$startChecking('Accessibility', 2);
$res = $mb->check();
if (!$res['error_code']) {
$endChecking();
} else {
$endChecking($res['message'] ?? null);
}
}
} else {
$endChecking('The extension is not loaded');
}
}
} catch (RuntimeException $e) {
$endChecking($e->getMessage());
}
echo PHP_EOL, '=== DIRECTORIES ===', PHP_EOL;
$startChecking('Checking directories config');
try {
$dir_list = (new DirectoryList())->list();
$dir_lcnt = count($dir_list);
if ($dir_lcnt === 0) {
$endChecking('No directories found', RESULT_SUCCESS);
} else {
$endChecking("{$dir_lcnt} director" . ($dir_lcnt > 1 ? 'ies' : 'y') . ' found', RESULT_SUCCESS);
echo " * Checking directories ({$dir_lcnt})", PHP_EOL;
foreach ($dir_list as $dir) {
$dir_a = $dir->toArray();
echo " - {$dir_a['name']}", PHP_EOL;
$startChecking('Accessibility', 2);
$res = $dir->check();
if (!$res['error_code']) {
$endChecking();
$startChecking('Security', 2);
try {
$perms = fileperms($dir_a['location']);
if ($perms === false) {
throw new RuntimeException('Fileperms failed', RESULT_ERROR);
}
if ($perms & 0x2) {
throw new RuntimeException(
'Other users have write access to the directory',
RESULT_WARNING
);
}
$endChecking();
} catch (RuntimeException $e) {
$endChecking($e->getMessage(), $e->getCode());
} catch (\ErrorException $e) {
$endChecking($e->getMessage());
}
} else {
$endChecking($res['message'] ?? null);
}
}
}
} catch (SoftException $e) {
$endChecking($e->getMessage());
}
echo PHP_EOL, '===', PHP_EOL;
if ($e_cnt === 0 && $w_cnt === 0) {
echo 'Success!', PHP_EOL;
} else {
echo 'There ', $e_cnt + $w_cnt === 1 ? 'is' : 'are', ' ';
$strs = [];
foreach ([ [$e_cnt, 'error' ], [ $w_cnt, 'warning' ] ] as &$it) {
$cnt = $it[0];
if ($cnt > 0) {
$strs[] = $cnt . ' ' . $it[1] . ($cnt > 1 ? 's' : '');
}
}
unset($it);
echo implode(' and ', $strs), '!', PHP_EOL;
}
} catch (SoftException $e) {
echo 'Fatal error: ', $e->getMessage(), PHP_EOL;
exit(1);
}
if ($e_cnt > 0) {
exit(2);
}
exit(0);

View File

@@ -0,0 +1,117 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script performs some administration functions with the database.
* It has one required parameter, it can has follow values: `status`, `init`, `upgrade`, `drop`.
* `status` - Will display the database status.
* `init` - Will create all the required tables in the database.
* The database must contain no tables.
* `upgrade` - Will upgrade the database structure if it is necessary.
* `drop` - Will remove all tables from the database.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Database\Database;
use Liuch\DmarcSrg\Database\DatabaseUpgrader;
use Liuch\DmarcSrg\Settings\SettingString;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
$action = $argv[1] ?? '';
$res = null;
try {
switch ($action) {
case 'status':
$res = Core::instance()->database()->state();
$tcn = 0;
if (isset($res['tables'])) {
foreach ($res['tables'] as &$t) {
if (isset($t['exists']) && $t['exists'] === true) {
++$tcn;
}
}
unset($t);
}
echo 'Version: ', ($res['version'] ?? 'n/a'), PHP_EOL;
echo 'Tables: ', $tcn, PHP_EOL;
break;
case 'init':
$res = Core::instance()->database()->initDb();
break;
case 'upgrade':
$cur_ver = (new SettingString('version'))->value();
if ($cur_ver === '') {
$cur_ver = 'n/a';
}
$db = Core::instance()->database();
echo "Current version: {$cur_ver}", PHP_EOL;
echo 'Required version: ', $db::REQUIRED_VERSION, PHP_EOL;
if ($cur_ver !== $db::REQUIRED_VERSION) {
$db->getMapper('upgrader')->go($db::REQUIRED_VERSION);
$res = [
'error_code' => 0,
'message' => 'Upgrated successfully'
];
} else {
$res = [
'error_code' => 0,
'message' => 'No upgrade required'
];
}
break;
case 'drop':
$res = Core::instance()->database()->cleanDb();
break;
default:
echo "Usage: {$argv[0]} status|init|upgrade|drop", PHP_EOL;
exit(1);
}
} catch (RuntimeException $e) {
$res = ErrorHandler::exceptionResult($e);
}
$error = ($res['error_code'] ?? 0) ? 'Error! ' : '';
echo "Message: {$error}{$res['message']}", PHP_EOL;
if (isset($res['debug_info'])) {
$debug_info = $res['debug_info'];
echo "Debug info:", PHP_EOL;
echo '-----', PHP_EOL;
echo "[{$debug_info['code']}]", PHP_EOL;
echo '-----', PHP_EOL;
echo "{$debug_info['content']}", PHP_EOL;
}
exit(0);

View File

@@ -0,0 +1,225 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script fetches DMARC reports from mailboxes and server local directories and saves them to the DB.
* The parameters of mailboxes and directories must be specified in the configuration file.
* The mailboxes and directories accessibility can be checked on the administration page in the web interface.
* The script has one optional parameter: `source` - the type of the source. The valid types are `email`, `directory`.
*
* Some examples:
* $ utils/fetch_reports
* will fetch reports from both the mailboxes and the local server directories.
*
* $ utils/fetch_reports source=email
* will only fetch reports from the mailboxes.
*
* The best place to use it is cron.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Mail\MailBoxes;
use Liuch\DmarcSrg\Report\ReportFetcher;
use Liuch\DmarcSrg\Sources\Source;
use Liuch\DmarcSrg\Sources\MailboxSource;
use Liuch\DmarcSrg\Sources\DirectorySource;
use Liuch\DmarcSrg\Directories\DirectoryList;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
$usage = false;
$source = null;
if (isset($argv)) {
for ($i = 1; $i < count($argv); ++$i) {
$av = explode('=', $argv[$i]);
if (count($av) !== 2) {
echo 'Invalid parameter format' . PHP_EOL;
$usage = true;
break;
}
switch ($av[0]) {
case 'source':
$source = $av[1];
break;
default:
echo 'Unknown parameter "' . $av[0] . '"' . PHP_EOL;
$usage = true;
break;
}
}
if ($source && $source !== 'email' && $source !== 'directory') {
echo 'Invalid source type "' . $source . '". "email" or "directory" expected.' . PHP_EOL;
exit(1);
}
}
if ($usage) {
echo PHP_EOL;
echo 'Usage: ' . basename(__FILE__) . ' [source=email|directory]' . PHP_EOL;
exit(1);
}
$sou_list = [];
$problems = [];
$addError = function (\Throwable $e, array &$errors): void {
$err_r = ErrorHandler::exceptionResult($e);
$errors['messages'][] = $err_r['message'];
if (!$errors['debug_info'] && isset($err_r['debug_info'])) {
$errors['debug_info'] = $err_r['debug_info']['content'];
}
};
const MAILBOX_LIST = 1;
const DIRECTORY_LIST = 2;
const FETCHER = 3;
$state = MAILBOX_LIST;
if (!$source || $source === 'email') {
$errors = [ 'messages' => [], 'debug_info' => null ];
$mb_list = new MailBoxes();
for ($mb_num = 1; $mb_num <= $mb_list->count(); ++$mb_num) {
try {
$sou_list[] = new MailboxSource($mb_list->mailbox($mb_num));
} catch (RuntimeException $e) {
$addError($e, $errors);
}
}
if (count($errors['messages']) > 0) {
$problems[] = [
'state' => $state,
'messages' => $errors['messages'],
'debug_info' => $errors['debug_info']
];
}
}
$state = DIRECTORY_LIST;
if (!$source || $source === 'directory') {
$errors = [ 'messages' => [], 'debug_info' => null ];
foreach ((new DirectoryList())->list() as $dir) {
try {
$sou_list[] = new DirectorySource($dir);
} catch (RuntimeException $e) {
$addError($e, $errors);
}
}
if (count($errors['messages']) > 0) {
$problems[] = [
'state' => $state,
'messages' => $errors['messages'],
'debug_info' => $errors['debug_info']
];
}
}
$state = FETCHER;
try {
foreach ($sou_list as $source) {
$results = (new ReportFetcher($source))->fetch();
foreach ($results as &$res) {
$messages = [];
if (isset($res['source_error'])) {
$messages[] = $res['source_error'];
}
if (isset($res['post_processing_message'])) {
$messages[] = $res['post_processing_message'];
}
if (isset($res['error_code']) && $res['error_code'] !== 0 && isset($res['message'])) {
$messages[] = $res['message'];
}
if (count($messages) > 0) {
$pr = [ 'state' => $state, 'messages' => $messages ];
foreach ([ 'report_id', 'emailed_from', 'emailed_date' ] as $it) {
if (isset($res[$it])) {
$pr[$it] = $res[$it];
}
}
if ($source->type() === Source::SOURCE_MAILBOX) {
$cont = $source->container();
$pr['mailbox'] = $cont->mailbox() . ' (' . $cont->name() . ')';
}
$problems[] = $pr;
}
}
unset($res);
}
} catch (RuntimeException $e) {
$problems[] = [ 'state' => $state, 'messages' => [ $e->getMessage() ] ];
}
if (count($problems) > 0) {
$debug_info = null;
foreach ($problems as $i => $pr) {
if ($i > 0) {
echo PHP_EOL;
}
switch ($pr['state']) {
case MAILBOX_LIST:
echo 'Failed to get mailbox list:';
break;
case DIRECTORY_LIST:
echo 'Failed to get directory list:';
break;
case FETCHER:
echo 'Failed to get incoming report:';
break;
}
echo PHP_EOL;
echo ' Error message:', PHP_EOL;
$messages = array_map(function ($msg) {
return " - {$msg}";
}, $pr['messages']);
echo implode(PHP_EOL, $messages), PHP_EOL;
if (isset($pr['report_id'])) {
echo " Report ID: {$pr['report_id']}", PHP_EOL;
}
if (isset($pr['emailed_from']) || isset($pr['emailed_date']) || isset($pr['mailbox'])) {
echo ' Email message metadata:', PHP_EOL;
echo ' - From: ' . ($pr['emailed_from'] ?? '-'), PHP_EOL;
echo ' - Date: ' . ($pr['emailed_date'] ?? '-'), PHP_EOL;
echo ' - Mailbox: ' . ($pr['mailbox'] ?? '-'), PHP_EOL;
}
if (!$debug_info && !empty($pr['debug_info'])) {
$debug_info = $pr['debug_info'];
}
}
if ($debug_info) {
echo PHP_EOL;
echo 'Debug information:', PHP_EOL, $debug_info, PHP_EOL;
}
exit(1);
}
exit(0);

View File

@@ -0,0 +1,163 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script deletes old DMARC report email messages in mailboxes.
* The mailbox parameters and conditions for removal must be specified
* in the configuration file. The mailbox accessibility can be checked
* on the administration page in the web interface.
* The best place to use it is cron.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Mail\MailBoxes;
use Liuch\DmarcSrg\Sources\SourceAction;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
$core = Core::instance();
$days = $core->config('cleaner/mailboxes/days_old', -1);
if (gettype($days) !== 'integer' || $days < 0) {
exit(0);
}
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
$maximum = $core->config('cleaner/mailboxes/delete_maximum', 0);
if (gettype($maximum) !== 'integer' || $maximum < 0) {
exit(0);
}
$leave = $core->config('cleaner/mailboxes/leave_minimum', 0);
if (gettype($leave) !== 'integer' || $leave < 0) {
exit(0);
}
// Get a list of the configured email boxes
$mb_list = new MailBoxes();
$mb_cnt = $mb_list->count();
if ($mb_cnt === 0) {
// There are no configured mailboxes
exit(0);
}
// Get the names of mailboxes where processed messages are moved to.
$dirs = [];
foreach ([ [ 'done', '', 1 ], [ 'failed', 'failed', 0 ] ] as $it) {
$opt_nm = $it[0];
$def_opt = $it[1];
$def_cri = $it[2];
$actions = SourceAction::fromSetting($core->config("fetcher/mailboxes/when_{$opt_nm}", ''), 0, '');
if (count($actions) === 0) {
$dir = $def_opt;
} else {
$dir = null;
foreach ($actions as $act) {
if ($act->type === SourceAction::ACTION_MOVE) {
$dir = $act->param;
break;
}
}
if (is_null($dir)) {
continue;
}
}
switch (strtolower($core->config("cleaner/mailboxes/{$opt_nm}", ''))) {
case 'any':
$cri = 2;
break;
case 'seen':
$cri = 1;
break;
case '':
$cri = $def_cri;
break;
default:
$cri = 0;
break;
}
if (empty($dir) && $cri > 1) {
$cri = 1;
}
$dirs[$dir] = min(($dirs[$dir] ?? $cri), $cri);
}
try {
for ($mb_idx = 1; $mb_idx <= $mb_cnt; ++$mb_idx) {
foreach ($dirs as $dir_name => $i_criteria) {
if ($i_criteria > 0) {
$criteria = $i_criteria === 2 ? 'ALL' : 'SEEN';
$mbox = $mb_list->mailbox($mb_idx);
if (!empty($dir_name)) {
if (!($mbox = $mbox->childMailbox($dir_name))) {
continue;
}
}
$s_res = $mbox->sort(SORTDATE, $criteria, false);
$max = $maximum > 0 ? $maximum : -1;
$lv = $leave === 0 ? count($s_res) : count($s_res) - $leave;
$i = 0;
while ($lv-- > 0) {
$m_num = $s_res[$i++];
$msg = $mbox->message($m_num);
$mo = $msg->overview();
if (isset($mo->date)) {
try {
$md = new DateTime($mo->date);
} catch (\Exception $e) {
$md = false;
}
if ($md !== false) {
if ($md > $days_date) {
break;
}
$mbox->deleteMessage($m_num);
if ($max > 0) {
if (--$max === 0) {
break;
}
}
}
}
}
}
}
}
} catch (RuntimeException $e) {
echo ErrorHandler::exceptionText($e);
exit(1);
}
exit(0);

View File

@@ -0,0 +1,84 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script deletes old log entries from the database.
* The conditions for removal must be specified in the configuration file.
* The best place to use it is cron.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\ReportLog\ReportLog;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
$core = Core::instance();
$days = $core->config('cleaner/reportlog/days_old', -1);
if (gettype($days) !== 'integer' || $days < 0) {
exit(0);
}
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
$maximum = $core->config('cleaner/reportlog/delete_maximum', 0);
if (gettype($maximum) !== 'integer' || $maximum < 0) {
exit(0);
}
$leave = $core->config('cleaner/reportlog/leave_minimum', 0);
if (gettype($leave) !== 'integer' || $leave < 0) {
exit(0);
}
try {
$log = new ReportLog(null, null);
$cnt = $log->count() - $leave;
if ($cnt > 0) {
$log = new ReportLog(null, $days_date);
if ($leave * $maximum !== 0) {
if ($maximum > 0 && $cnt > $maximum) {
$cnt = $maximum;
}
$log->setOrder(ReportLog::ORDER_ASCENT);
$log->setMaxCount($cnt);
}
$log->delete();
}
} catch (RuntimeException $e) {
echo ErrorHandler::exceptionText($e);
exit(1);
}
exit(0);

View File

@@ -0,0 +1,85 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script deletes old reports from DB.
* The conditions for removal must be specified in the configuration file.
* The best place to use it is cron.
* Note: You must leave enough reports if you want to get correct summary report.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Report\ReportList;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden';
exit(1);
}
$core = Core::instance();
$days = $core->config('cleaner/reports/days_old', -1);
if (gettype($days) !== 'integer' || $days < 0) {
exit(0);
}
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
$maximum = $core->config('cleaner/reports/delete_maximum', 0);
if (gettype($maximum) !== 'integer' || $maximum < 0) {
exit(0);
}
$leave = $core->config('cleaner/reports/leave_minimum', 0);
if (gettype($leave) !== 'integer' || $leave < 0) {
exit(0);
}
try {
$rl = new ReportList();
$cnt = $rl->count() - $leave;
if ($cnt > 0) {
$rl->setFilter([ 'before_time' => $days_date ]);
if ($leave * $maximum !== 0) {
if ($maximum > 0 && $cnt > $maximum) {
$cnt = $maximum;
}
$rl->setMaxCount($cnt);
$rl->setOrder(ReportList::ORDER_BEGIN_TIME, ReportList::ORDER_ASCENT);
}
$rl->delete();
}
} catch (RuntimeException $e) {
echo ErrorHandler::exceptionText($e);
exit(1);
}
exit(0);

View File

@@ -0,0 +1,210 @@
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This script creates a summary report and sends it by email.
* The email addresses must be specified in the configuration file.
* The script have two required parameters: `domain` and `period`, and two optional: `emailto` and `format`.
* The `domain` parameter must contain a domain name, a comma-separated list of domains, or `all`.
* The `period` parameter must have one of these values:
* `lastmonth` - to make a report for the last month;
* `lastweek` - to make a report for the last week;
* `lastndays:N` - to make a report for the last N days;
* The `emailto` parameter is optional. Set it if you want to use a different email address to sent the report to.
* The `format` parameter is optional. It provides the ability to specify the email message format.
* Possible values are: `text`, `html`, `text+html`. The default value is `text`.
*
* Some examples:
*
* $ php utils/summary_report.php domain=example.com period=lastweek
* will send a weekly summary report by email for the domain example.com
*
* $ php utils/summary_report.php domain=example.com period=lastndays:10
* will send a summary report by email for last 10 days for the domain example.com
*
* The best place to use it is cron.
* Note: the current directory must be the one containing the classes directory.
*
* @category Utilities
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Mail\MailBody;
use Liuch\DmarcSrg\Domains\Domain;
use Liuch\DmarcSrg\Domains\DomainList;
use Liuch\DmarcSrg\Report\SummaryReport;
use Liuch\DmarcSrg\Exception\SoftException;
use Liuch\DmarcSrg\Exception\RuntimeException;
require 'init.php';
if (php_sapi_name() !== 'cli') {
echo 'Forbidden' . PHP_EOL;
exit(1);
}
$domain = null;
$period = null;
$emailto = null;
$format = 'text';
for ($i = 1; $i < count($argv); ++$i) {
$av = explode('=', $argv[$i]);
if (count($av) == 2) {
switch ($av[0]) {
case 'domain':
$domain = $av[1];
break;
case 'period':
$period = $av[1];
break;
case 'emailto':
$emailto = $av[1];
break;
case 'format':
$format = $av[1];
break;
}
}
}
try {
if (!$domain) {
throw new SoftException('Parameter "domain" is not specified');
}
if (!$period) {
throw new SoftException('Parameter "period" is not specified');
}
if (!in_array($format, [ 'text', 'html', 'text+html' ], true)) {
throw new SoftException('Unknown email message format: ' . $format);
}
if (!$emailto) {
$emailto = Core::instance()->config('mailer/default');
}
if ($domain === 'all') {
$domains = (new DomainList())->getList()['domains'];
} else {
$domains = array_map(function ($d) {
return new Domain($d);
}, explode(',', $domain));
}
$rep = new SummaryReport($period);
switch ($format) {
case 'text':
$text = [];
$html = null;
break;
case 'html':
$text = null;
$html = [];
break;
default:
$text = [];
$html = [];
break;
}
if (!is_null($html)) {
$html[] = '<html><body>';
}
$dom_cnt = count($domains);
for ($i = 0; $i < $dom_cnt; ++$i) {
if ($i > 0) {
if (!is_null($text)) {
$text[] = '-----------------------------------';
$text[] = '';
}
if (!is_null($html)) {
$html[] = '<hr style="margin:2em 0;" />';
}
}
$domain = $domains[$i];
if ($domain->exists()) {
$rep->setDomain($domain);
if (!is_null($text)) {
foreach ($rep->text() as &$row) {
$text[] = $row;
}
unset($row);
}
if (!is_null($html)) {
foreach ($rep->html() as &$row) {
$html[] = $row;
}
unset($row);
}
} else {
$nf_message = "Domain \"{$domain->fqdn()}\" does not exist";
if ($dom_cnt === 1) {
throw new SoftException("Domain \"{$domain->fqdn()}\" does not exist");
}
if (!is_null($text)) {
$text[] = "# {$nf_message}";
$text[] = '';
}
if (!is_null($html)) {
$html[] = '<h2>' . htmlspecialchars($nf_message) . '</h2>';
}
}
}
if ($dom_cnt === 1) {
$subject = "{$rep->subject()} for {$domain->fqdn()}";
} else {
$subject = "{$rep->subject()} for {$dom_cnt} domains";
}
$mbody = new MailBody();
if (!is_null($text)) {
$mbody->setText($text);
}
if (!is_null($html)) {
$html[] = '</body></html>';
$mbody->setHtml($html);
}
$headers = [
'From' => Core::instance()->config('mailer/from'),
'MIME-Version' => '1.0',
'Content-Type' => $mbody->contentType()
];
mail(
$emailto,
mb_encode_mimeheader($subject, 'UTF-8'),
implode("\r\n", $mbody->content()),
$headers
);
} catch (SoftException $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
exit(1);
} catch (RuntimeException $e) {
echo ErrorHandler::exceptionText($e);
exit(1);
}
exit(0);