generated from jric11/baseProject
Chat's updates for security, db and workflow
Security and workflow regressions / regression (push) Has been cancelled
Security and workflow regressions / regression (push) Has been cancelled
This commit is contained in:
+39
-41
@@ -13,7 +13,7 @@ class Base {
|
||||
// Constants
|
||||
// =========
|
||||
|
||||
const APPLICATION_NAME = "Hunting Club Roster";
|
||||
const APPLICATION_NAME = "My Hunting Club Roster";
|
||||
const APPLICATION_MNEMONIC = "HUNTINGCLUBROSTER";
|
||||
const VERSION = "1.00";
|
||||
const TIMEZONE = "America/New_York";
|
||||
@@ -136,11 +136,16 @@ class Base {
|
||||
|
||||
$dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $host, (int) ($settings->DatabasePort ?? 3306), $database);
|
||||
|
||||
return new PDO($dsn, $username, $password,
|
||||
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
$options=[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::ATTR_PERSISTENT => false,]);
|
||||
PDO::ATTR_PERSISTENT => false,];
|
||||
$ca=getenv('HCR_DB_TLS_CA')?:'';
|
||||
if((string)$settings->Environment==='Production'&&!in_array(strtolower($host),['localhost','127.0.0.1','::1'],true)&&!$ca)throw new RuntimeException('Remote production database connections require HCR_DB_TLS_CA and verified TLS.');
|
||||
if($ca){if(!is_readable($ca))throw new RuntimeException('The database TLS CA file is not readable.');$options[PDO::MYSQL_ATTR_SSL_CA]=$ca;$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT]=true;}
|
||||
$db=new PDO($dsn,$username,$password,$options);
|
||||
if($ca){$cipher=$db->query("SHOW SESSION STATUS LIKE 'Ssl_cipher'")->fetch();if(!$cipher||empty($cipher['Value']))throw new RuntimeException('The database connection did not negotiate TLS.');}
|
||||
return $db;
|
||||
} catch (PDOException $e) {
|
||||
|
||||
error_log("Database Connection Failed: " . $e->getMessage());
|
||||
@@ -216,9 +221,7 @@ class Base {
|
||||
// =====================
|
||||
|
||||
public function displayHome() {
|
||||
|
||||
$content = $this->applyXSL("", $this->getXSL("home"));
|
||||
$this->displayContent($content);
|
||||
(new Roster())->home();
|
||||
}
|
||||
|
||||
// =======================
|
||||
@@ -250,6 +253,7 @@ class Base {
|
||||
}
|
||||
}
|
||||
$action = strtolower(trim($_POST['action'] ?? $_GET['Xaction'] ?? $_GET['action'] ?? ''));
|
||||
if($action==='verifyemail'){(new EmailVerification())->page();return;}
|
||||
if ($action === 'signout') {
|
||||
if ($method !== 'POST') {
|
||||
http_response_code(405);
|
||||
@@ -275,9 +279,9 @@ class Base {
|
||||
if (in_array($action, ['signin', 'signin.login', 'users.login'], true)) {
|
||||
(new SignIn())->login();
|
||||
}
|
||||
|
||||
|
||||
$user = (new AuthService())->currentUser();
|
||||
|
||||
|
||||
if (!$user) {
|
||||
$ajax = $_SESSION[self::AJAX];
|
||||
if (!empty($_SESSION[self::USER_AUTHENTICATED])) {
|
||||
@@ -296,6 +300,7 @@ class Base {
|
||||
(new Users())->changePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
// Only named, reviewed entry points are routable. Helpers are never endpoints.
|
||||
$routes = [
|
||||
'' => [Base::class, 'displayHome', false],
|
||||
@@ -306,24 +311,31 @@ class Base {
|
||||
'validatedate' => [Base::class, 'validateDate', false],
|
||||
'getage' => [Base::class, 'getAge', false],
|
||||
'users.changepassword' => [Users::class, 'changePassword', false],
|
||||
'print' => [Base::class, 'print', true],
|
||||
'print_all_permitsbybuilder.print' => ['Print_All_PermitsByBuilder', 'print', true],
|
||||
'export_allpermitsbybuildercsv.export' => ['Export_AllPermitsByBuilderCSV', 'export', true],
|
||||
'export_allpermitsbybuilderexcel.export' => ['Export_AllPermitsByBuilderExcel', 'export', true],
|
||||
'roster.workspace' => [Roster::class,'workspace',false],
|
||||
'roster.help' => [Roster::class,'help',false],
|
||||
'rosterreports.ledger' => [RosterReports::class,'ledger',true],
|
||||
'rosterreports.csv' => [RosterReports::class,'csv',true],
|
||||
'rosterreports.excel' => [RosterReports::class,'excel',true],
|
||||
'rosterreports.pdf' => [RosterReports::class,'pdf',true],
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
||||
$adminRoutes = [
|
||||
'Users' => ['setupUsers', 'addUser', 'editUser', 'deleteUser', 'resetPassword', 'userExists', 'getUser_AJAX', 'updateActiveStatus', 'userActive'],
|
||||
'Users' => ['setupUsers', 'userSummary', 'addUser', 'editUser', 'deleteUser', 'resetPassword', 'userExists', 'getUser_AJAX', 'updateActiveStatus', 'userActive'],
|
||||
'Alerts' => ['setupAlerts', 'addAlert', 'editAlert', 'deleteAlert'],
|
||||
'Dropdowns' => ['setupDropdowns', 'setupDropdowntypes', 'addDropdown', 'editDropdown', 'deleteDropdown', 'addDropdowntype', 'editDropdowntype', 'deleteDropdowntype', 'dropdownExists', 'dropdowntypeExists', 'dropdowntypetitleExists', 'dropdownActive', 'dropdowntypeActive', 'updateDropdownActive', 'updateDropdownDefault'],
|
||||
'Popovers' => ['setupPopovers', 'addPopover', 'editPopover', 'deletePopover', 'popoverExists'],
|
||||
'Reports' => ['setupReports', 'addReport', 'editReport', 'deleteReport', 'selectReport', 'reportExists'],
|
||||
'Reports' => ['setupReports', 'selectReport'],
|
||||
'Statuses' => ['setupStatuses', 'addStatus', 'editStatus', 'deleteStatus', 'statusExists', 'statusActive'],
|
||||
'Journal' => ['viewJournal', 'clearJournal'],
|
||||
'Notes' => ['addNote', 'editNote', 'deleteNote', 'addNoteQuick'],
|
||||
'Journal' => ['viewJournal'],
|
||||
'Notes' => ['addNote', 'editNote', 'deleteNote'],
|
||||
];
|
||||
foreach ($adminRoutes as $class => $methods) {
|
||||
foreach ($methods as $entry)
|
||||
foreach ($methods as $entry) {
|
||||
$routes[strtolower($class . '.' . $entry)] = [$class, $entry, true];
|
||||
}
|
||||
}
|
||||
if (!isset($routes[$action])) {
|
||||
http_response_code(404);
|
||||
@@ -334,11 +346,15 @@ class Base {
|
||||
http_response_code(403);
|
||||
exit('You do not have permission to perform this action.');
|
||||
}
|
||||
if ($method !== 'POST' && !in_array($action, ['', './', 'displayhome', 'users.changepassword'], true)) {
|
||||
if ($method !== 'POST' && !in_array($action, ['', './', 'displayhome', 'users.changepassword','roster.workspace','roster.help'], true)) {
|
||||
http_response_code(405);
|
||||
exit('Use POST for this action.');
|
||||
}
|
||||
(new $class())->$entry();
|
||||
ob_start();
|
||||
try{(new $class())->$entry();$body=ob_get_clean();}
|
||||
catch(Throwable $e){ob_end_clean();throw $e;}
|
||||
if($_SESSION[self::AJAX]??false){header('Content-Type: application/json');echo trim($body)===''?json_encode(['ok'=>true]):$body;}
|
||||
else echo $body;
|
||||
}
|
||||
|
||||
public function csrfToken(): string {
|
||||
@@ -420,7 +436,7 @@ class Base {
|
||||
|
||||
public function getSettings() {
|
||||
|
||||
$path = getenv('HCR_SETTINGS_FILE') ?: (is_file(__DIR__ . '/../xml/settings.local.xml') ? __DIR__ . '/../xml/settings.local.xml' : __DIR__ . '/../xml/settings.xml');
|
||||
$path = getenv('HCR_SETTINGS_FILE') ?: (getenv('HCR_ENVIRONMENT')!=='Production' && is_file(__DIR__ . '/../xml/settings.local.xml') ? __DIR__ . '/../xml/settings.local.xml' : __DIR__ . '/../xml/settings.xml');
|
||||
$settings = simplexml_load_file($path, SimpleXMLElement::class, LIBXML_NONET);
|
||||
if (!$settings)
|
||||
throw new RuntimeException('Unable to load application settings.');
|
||||
@@ -673,12 +689,8 @@ class Base {
|
||||
// ============
|
||||
|
||||
public function logError($error_message = "") {
|
||||
|
||||
(new Journal())->journalEntry($error_message);
|
||||
|
||||
$this->displayHome();
|
||||
|
||||
exit();
|
||||
error_log($error_message);
|
||||
throw new AppException('The requested record is invalid or unavailable.',404);
|
||||
}
|
||||
|
||||
// ==========================
|
||||
@@ -725,20 +737,6 @@ class Base {
|
||||
// Print a Report
|
||||
// ==============
|
||||
|
||||
public function print() {
|
||||
|
||||
$_SESSION[self::REPORTS_GET] = $_GET;
|
||||
$_SESSION[self::REPORTS_POST] = $_POST;
|
||||
|
||||
$report = filter_input(INPUT_POST, "report") ?: "";
|
||||
|
||||
if ($report !== 'Print_All_PermitsByBuilder') {
|
||||
http_response_code(404);
|
||||
exit('Report not found.');
|
||||
}
|
||||
(new $report())->print();
|
||||
}
|
||||
|
||||
// =================
|
||||
// Sanitize a string
|
||||
// =================
|
||||
|
||||
Reference in New Issue
Block a user