diff --git a/dev/tools/secalert.php b/dev/tools/secalert.php new file mode 100755 index 00000000000..69accfa8aa5 --- /dev/null +++ b/dev/tools/secalert.php @@ -0,0 +1,377 @@ +#!/usr/bin/env php + + * + * 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, or + * (at your option) any later version. + * + * 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 . + */ + +/** + * \file dev/tools/secalert.php + * \brief Script to show alert when a new security bug has been fixed. + */ + + +$sapi_type = php_sapi_name(); +$script_file = basename(__FILE__); +$path = dirname(__FILE__) . '/'; + +// Test si mode batch +$sapi_type = php_sapi_name(); +if (substr($sapi_type, 0, 3) == 'cgi') { + echo "Error: You are using PHP for CGI. To execute " . $script_file . " from command line, you must use PHP for CLI mode.\n"; + exit(); +} + +error_reporting(E_ALL & ~E_DEPRECATED); +define('PRODUCT', "secalert"); +define('VERSION', "1.0"); + +$phpstanlevel = 3; + + +print '***** '.constant('PRODUCT').' - '.constant('VERSION').' *****'."\n"; +if (empty($argv[1])) { + print 'You must run this tool being into the root of the project.'."\n"; + print 'Usage: '.constant('PRODUCT').'.php pathto/outputfile.html'."\n"; + print 'Example: '.constant('PRODUCT').'.php documents/apstats/index.html'; + exit(0); +} + +$outputpath = $argv[1]; +$outputdir = dirname($outputpath); +$outputfile = basename($outputpath); + +if (!is_dir($outputdir)) { + print 'Error: dir '.$outputdir.' does not exists or is not writable'."\n"; + exit(1); +} + +$i = 0; +while ($i < $argc) { + $reg = array(); + if (preg_match('/--max=(.*)$/', $argv[$i], $reg)) { + $dirscc = $reg[1]; + } + /* + if (preg_match('/--dir-phpstan=(.*)$/', $argv[$i], $reg)) { + $dirphpstan = $reg[1]; + } + */ + $i++; +} + + +// Include Dolibarr environment +require_once $path.'../../htdocs/master.inc.php'; +require_once $path.'../../htdocs/core/lib/files.lib.php'; +require_once $path.'../../htdocs/core/lib/geturl.lib.php'; + +// After this $db is an opened handler to database. We close it at end of file. + +// Load main language strings +$langs->load("main"); + + +/* + * Main + */ + +$timestart = time(); + +// Count lines of code of Dolibarr itself +/* + $commandcheck = 'cloc . --exclude-dir=includes --exclude-dir=custom --ignore-whitespace --vcs=git'; + $resexec = shell_exec($commandcheck); + $resexec = (int) (empty($resexec) ? 0 : trim($resexec)); + + + // Count lines of code of external dependencies + $commandcheck = 'cloc htdocs/includes --ignore-whitespace --vcs=git'; + $resexec = shell_exec($commandcheck); + $resexec = (int) (empty($resexec) ? 0 : trim($resexec)); + */ + +// Retrieve the .git information +$urlgit = 'https://api.github.com/search/issues?q=is:pr+repo:Dolibarr/dolibarr+created:>'.dol_print_date(dol_now() - (3*3600*24*30), "%Y-%m"); + + +$arrayofalerts = array(); +$arrayofalerts1 = $arrayofalerts2 = $arrayofalerts3 = array(); + +// Count lines of code of application +$newurl = $urlgit.'+CVE'; +$result = getURLContent($newurl); +print 'Execute GET on github for '.$newurl."\n"; +if ($result && $result['http_code'] == 200) { + $arrayofalerts1 = json_decode($result['content']); + + foreach ($arrayofalerts1->items as $val) { + $tmpval = cleanVal($val); + if (preg_match('/CVE/i', $tmpval['title'])) { + $arrayofalerts[$tmpval['number']] = $tmpval; + } + } +} else { + print 'Error: failed to get github response'; + exit(-1); +} + +$newurl = $urlgit.'+yogosha'; +$result = getURLContent($newurl); +print 'Execute GET on github for '.$newurl."\n"; +if ($result && $result['http_code'] == 200) { + $arrayofalerts2 = json_decode($result['content']); + + foreach ($arrayofalerts2->items as $val) { + $tmpval = cleanVal($val); + if (preg_match('/yogosha:/i', $tmpval['title'])) { + $arrayofalerts[$tmpval['number']] = $tmpval; + } + } +} else { + print 'Error: failed to get github response'; + exit(-1); +} + +$newurl = $urlgit.'+Sec:'; +$result = getURLContent($newurl); +print 'Execute GET on github for '.$newurl."\n"; +if ($result && $result['http_code'] == 200) { + $arrayofalerts3 = json_decode($result['content']); + foreach ($arrayofalerts3->items as $val) { + $tmpval = cleanVal($val); + if (preg_match('/Sec:/i', $tmpval['title'])) { + $arrayofalerts[$tmpval['number']] = $tmpval; + } + } +} else { + print 'Error: failed to get github response'; + exit(-1); +} + +$timeend = time(); + + +/* + * View + */ + +$html = ''."\n"; +$html .= ''."\n"; +$html .= ''."\n"; +$html .= ''."\n"; +$html .= ''."\n"; +$html .= ''."\n"; +$html .= ' +'."\n"; + +$html .= ''."\n"; + + +// Header + +$html .= '
'."\n"; +$html .= '

Sec Alert

'."\n"; +$currentDate = date("Y-m-d H:i:s"); // Format: Year-Month-Day Hour:Minute:Second +$html .= 'Generated on '.$currentDate.' in '.($timeend - $timestart).' seconds'."\n"; +$html .= '
'."\n"; + + +// Lines of code + +$html .= '
'."\n"; +$html .= '

Last security alerts

'."\n"; + +foreach ($arrayofalerts as $alert) { + $html .= '

'.$alert['number'].' - '; + $html .= $alert['title'].'


'; + $html .= $alert['created_at'].'
'; + $html .= '
'."\n"; +} + +$html .= ''; +$html .= ''; + +// Output report into a HTML file +$fh = fopen($outputpath, 'w'); +if ($fh) { + fwrite($fh, $html); + fclose($fh); + + print 'Generation of output file '.$outputfile.' done.'."\n"; +} else { + print 'Failed to open '.$outputfile.' for output.'."\n"; +} + + +/** + * function to format a number + * + * @param string|int $number Number to format + * @param int $nbdec Number of decimal digits + * @return string Formatted string + */ +function formatNumber($number, $nbdec = 0) +{ + return number_format($number, 0, '.', ' '); +} + +/** + * cleanVal + * + * @param array $val Array of a PR + * @return Array of a PR + */ +function cleanVal($val) +{ + $tmpval = array(); + + $tmpval['url'] = $val->url; + $tmpval['number'] = $val->number; + $tmpval['title'] = $val->title; + $tmpval['created_at'] = $val->created_at; + $tmpval['updated_at'] = $val->updated_at; + + return $tmpval; +}