diff --git a/docs/TODO.md b/docs/TODO.md
index cc75ff2..97cf701 100644
--- a/docs/TODO.md
+++ b/docs/TODO.md
@@ -7,6 +7,10 @@
[x] → Encrypted/Compressed Sessions
+ [ ] → Ensure JS error reporting works
+
+ [ ] → Force Database methods to try Cache First and Save Cache Data
+
[ ] → Kernels
[ ] → HTTP → Requests, Responce
@@ -41,11 +45,17 @@
[x] → End/Open Tag Matching
- [x] → UUIDv7 for APIs, etc...
-
[ ] → Rate Limiting
- [?] → PHP Mailer / Access Token
+ [x] → PHP Mailer
+
+ [ ] → Access Tokens (like for emails)
+
+ [x] → UUIDv7 (like Database IDs)
+
+ [x] → CSRF Tokens in security.php...
+
+ [x] → Password Hashing/Verify in security.php
[x] → Twilio Support
@@ -53,10 +63,6 @@
[x] → Error Handler
- [x] → CSRF Tokens
-
- [x] → Password Hashing/Verify
-
[ ] → Sane Config/Service file defaults
[ ] → Sane Folder Structure and Documentation
@@ -68,6 +74,4 @@
[ ] → Tests
- [x] → RSS Feed
-
- [x] → Private API for Sensitive Transactions:
+ [x] → RSS Feed
\ No newline at end of file
diff --git a/src/bootstrap/safer_io.php b/src/bootstrap/safer_io.php
index 2097b4e..5fe86e3 100644
--- a/src/bootstrap/safer_io.php
+++ b/src/bootstrap/safer_io.php
@@ -521,9 +521,9 @@ final class safer_io {
$safer_db_data = $safer_data;
} else {
if (isset($a->use_db_filter) && $a->use_db_filter == DB_FILTER::ON) {
- $safe_for_db = \tts\extras\safer_sql::get_safer_sql_text($safer_data);
+ $safe_for_db = \CodeHydrater\safer_sql::get_safer_sql_text($safer_data);
$text = $safe_for_db["text"];
- $meta[$input_field_name]['db_filter_status'] = $safe_for_db["status"] ?? \tts\SQL_SAFETY_FLAG::filtered;
+ $meta[$input_field_name]['db_filter_status'] = $safe_for_db["status"] ?? \CodeHydrater\SQL_SAFETY_FLAG::filtered;
} else {
$text = $safer_data;
}
diff --git a/src/classes/apis/api.php b/src/classes/apis/api.php
index 61b2d1e..b0d5e98 100644
--- a/src/classes/apis/api.php
+++ b/src/classes/apis/api.php
@@ -231,7 +231,7 @@ class api {
$data['code'] = $long_code;
- $memory_check = bootstrap\common::get_bool(\tts\misc::request_var('debug'));
+ $memory_check = bootstrap\common::get_bool(\CodeHydrater\misc::request_var('debug'));
if ($memory_check) {
$echo = false;
$data['memory_used'] = memory_usage::get_memory_stats($echo);
diff --git a/src/classes/app.php b/src/classes/app.php
index c38d27f..c07262e 100644
--- a/src/classes/app.php
+++ b/src/classes/app.php
@@ -12,14 +12,6 @@ namespace CodeHydrater;
use Exception;
-/**
- *
- * @todo Ensure JS error reporting works
- * @todo Finish Session MGT, Encrypted Sessions
- * @todo Make Cached Sessions
- * @todo Force Database methods to try Cache First and Save Cache Data
- */
-
class app {
private $file;
private $class;
diff --git a/src/classes/assets.php b/src/classes/assets.php
index 5573370..48b6e9b 100644
--- a/src/classes/assets.php
+++ b/src/classes/assets.php
@@ -112,13 +112,13 @@ final class assets {
}
if ($scope === 'project' || $scope === 'app') {
$path = PROJECT_ASSETS_DIR . "/";
- $tts = self::is_minified($path, $file);
- return ($tts !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $tts : false;
+ $ism = self::is_minified($path, $file);
+ return ($ism !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $ism : false;
}
if ($scope === 'assets') {
$path = ASSETS_DIR . "/";
- $tts = self::is_minified($path, $file);
- return ($tts !== false) ? ASSETS_BASE_REF . "/" . $tts : false;
+ $ism = self::is_minified($path, $file);
+ return ($ism !== false) ? ASSETS_BASE_REF . "/" . $ism : false;
}
return $file;
}
diff --git a/src/classes/exceptions/DB_Exception.php b/src/classes/exceptions/DB_Exception.php
index cb957d8..8e72026 100644
--- a/src/classes/exceptions/DB_Exception.php
+++ b/src/classes/exceptions/DB_Exception.php
@@ -53,8 +53,8 @@ class DB_Exception extends \Exception {
if (empty($message)) {
$message = self::$error_message;
}
- $live = (\main_tts\is_live());
- if ($live === false || \tts\session_management::has_user_right('debugger')) {
+ $live = (\CodeHydrater\bootstrap\is_live());
+ if ($live === false || \CodeHydrater\session_management::has_user_right('debugger')) {
$msg = ($debug == DEBUGGER::basic ||
(self::$debug === DEBUGGER::basic &&
$debug === DEBUGGER::static)
diff --git a/src/classes/php_file_cache.php b/src/classes/php_file_cache.php
index dfde1ee..e7ae93e 100644
--- a/src/classes/php_file_cache.php
+++ b/src/classes/php_file_cache.php
@@ -18,7 +18,12 @@ class php_file_cache {
protected $cache_path;
public function __construct($path) {
- $this->cache_path = rtrim($path, '/') . '/';
+ $is_safe_path = bootstrap\requires::is_dangerous($path);
+ if ($is_safe_path === false) {
+ throw new \Exception("Bad cache path");
+ }
+ $safer_path = bootstrap\requires::filter_dir_path($path);
+ $this->cache_path = rtrim($safer_path, '/') . '/';
if (!is_dir($this->cache_path)) {
mkdir($this->cache_path, 0775, true);
}
diff --git a/src/classes/random_engine.php b/src/classes/random_engine.php
index 06fbfb7..1681977 100644
--- a/src/classes/random_engine.php
+++ b/src/classes/random_engine.php
@@ -61,7 +61,7 @@ class random_engine {
}
private function select_from_array(array $a, int $num ): array {
- $array_count = \bs_tts\common::get_count($a) - 1;
+ $array_count = \CodeHydrater\bootstrap\common::get_count($a) - 1;
if ($array_count < 1) {
return [];
}
diff --git a/src/classes/safer_sql.php b/src/classes/safer_sql.php
new file mode 100644
index 0000000..1bd22d3
--- /dev/null
+++ b/src/classes/safer_sql.php
@@ -0,0 +1,465 @@
+
+ * @copyright Copyright (c) 2022, Robert Strutts.
+ * @license MIT
+ */
+
+/**
+ * @todo This is just for PLAY for now!!!!
+ * Too many FALSE positives and too many FALSE Negatives!!!
+ */
+
+namespace CodeHydrater;
+
+enum SQL_SAFETY_FLAG {
+ case good; // All Okey
+ case filtered; // Found isseues but tried to filter them out
+ case dangerious; // May still be bad
+}
+
+class safer_sql {
+
+ /**
+ * List of SQL attacks:
+ * @link https://github.com/payloadbox/sql-injection-payload-list
+ * @link https://www.neuralegion.com/blog/sql-injection-payloads/
+ * @link https://ismailtasdelen.medium.com/sql-injection-payload-list-b97656cfd66b
+ */
+
+ // NoSQL attacks and now SQL attacks as JSON is used EveryWhere
+ private static function found_bad_json(string $string): bool {
+ if (function_exists("str_contains")) {
+ if (str_contains($string, '[]') === true) return true; // GET Array
+ }
+ if (preg_match('/.match/', $string) === 1) return true;
+ if (preg_match('/&&/', $string) === 1) return true;
+ if (preg_match('/\|\|/', $string) === 1) return true;
+ if (preg_match('/\$where/', $string) === 1) return true;
+ if (preg_match("/mapReduce/", $string) === 1) return true;
+ if (preg_match('/\$group/', $string) === 1) return true;
+ if (preg_match('/\$regex/', $string) === 1) return true;
+ if (preg_match('/\$exists/', $string) === 1) return true;
+ if (preg_match('/\$ne/', $string) === 1) return true;
+ if (preg_match('/\$gt/', $string) === 1) return true;
+ if (preg_match('/\$lt/', $string) === 1) return true;
+ if (preg_match('/\$eq/', $string) === 1) return true;
+ if (preg_match('/\$nin/', $string) === 1) return true;
+ if (preg_match('/\$where/', $string) === 1) return true;
+ if (preg_match('/\$or/', $string) === 1) return true;
+ if (preg_match('/\$and/', $string) === 1) return true;
+ if (preg_match('/\$in/', $string) === 1) return true;
+ if (preg_match('/\$accumulator/', $string) === 1) return true;
+ if (preg_match('/\$function/', $string) === 1) return true;
+ if (preg_match("/:/", $string) === 1 &&
+ preg_match("/{/", $string) === 1) return true;
+ return false;
+ }
+
+ // Stacked queries can be used to execute multiple queries in succession.
+ private static function found_sql_stacker(string $string): bool {
+ if (preg_match("/;/", $string) === 1) return true;
+ return false;
+ }
+
+ private static function found_sql_compair(string $string): bool {
+ if (preg_match("/=/", $string) === 1) return true;
+ return false;
+ }
+
+ private static function found_quotes_in(string $string): bool {
+ if (preg_match("/'/", $string) === 1) return true;
+ if (preg_match("/\"/", $string) === 1) return true;
+ return false;
+ }
+
+ private static function found_sql_comment(string $string): bool {
+ if (preg_match("/\#/", $string) === 1) return true; // Hash
+ if (preg_match("/\/\*/", $string) === 1) return true; // C-style comment
+ if (preg_match("/--/", $string) === 1) return true; // SQL comment
+ if (preg_match("/\`/", $string) === 1) return true; // Backtick
+ //if (preg_match("/\x00/", $string) === 1) return true; // NULL Byte, !errors out!
+ return false;
+ }
+
+ private static function found_string_cat(string $string): bool {
+ if (preg_match("/\+/i", $string) === 1) return true; // addition, concatenate (or space in url)
+ if (preg_match("/\|\|/i", $string) === 1) return true; // (double pipe) concatenate
+ if (preg_match("/\%/", $string) === 1) return true; // wildcard attribute indicator
+ return false;
+ }
+
+ private static function found_sql_time_based_attack(string $string): bool {
+ if (preg_match("/union/i", $string) === 1) {
+ if (preg_match("/all/i", $string) === 1) {
+ return true;
+ }
+ if (preg_match("/select/i", $string) === 1) {
+ return true;
+ }
+ if (preg_match("/null/i", $string) === 1) {
+ return true;
+ }
+ }
+ if (preg_match("/sleep\s*\(/i", $string) === 1) return true;
+ if (preg_match("/waitfor delay/i", $string) === 1) return true;
+ if (preg_match("/benchmark\s*\(/i", $string) === 1) return true;
+ if (preg_match("/pg_sleep\s*\(/i", $string) === 1) return true;
+ if (preg_match("/randomblob/i", $string) === 1) return true;
+
+ if (preg_match("/convert/i", $string) === 1) {
+ if (preg_match("/int/i", $string) === 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static function found_sql_suspicious(string $string): bool {
+ if (self::found_sql_compair($string) === true) return true;
+ if (self::found_sql_stacker($string) === true) return true;
+ if (self::found_sql_comment($string) === true) return true;
+ if (self::found_quotes_in($string) === true) return true;
+ if (self::found_string_cat($string) === true) return true;
+ return false;
+ }
+
+ private static function found_sql_admin_attack(string $string): bool {
+ if (preg_match("/admin/i", $string) === 1) {
+ if (preg_match("/ or /i", $string) === 1) {
+ if (preg_match("/1/", $string) === 1) {
+ return true;
+ }
+ if (preg_match("/0/", $string) === 1) {
+ return true;
+ }
+ }
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ return false;
+ }
+
+ private static function found_sql_statement(string $string): bool {
+ if (preg_match("/or/i", $string) === 1 || preg_match("/and/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ if (preg_match("/drop database/i", $string) === 1) return true;
+ if (preg_match("/drop table/i", $string) === 1) return true;
+ if (preg_match("/drop user/i", $string) === 1) return true;
+ if (preg_match("/drop view/i", $string) === 1) return true;
+ if (preg_match("/drop column/i", $string) === 1) return true;
+ if (preg_match("/drop procedure/i", $string) === 1) return true;
+ if (preg_match("/drop/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ if (preg_match("/where/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ if (preg_match("/select/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ if (preg_match("/having/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ if (preg_match("/distinct/i", $string) === 1) {
+ if (self::found_sql_suspicious($string) === true) return true;
+ }
+ // NOTE: \s* is for no-space or spaces!!! /i is to ignore Case!
+ if (preg_match("/\'\s*or/i", $string) === 1) return true;
+ if (preg_match("/\'\)\s*or/i", $string) === 1) return true;
+ if (preg_match("/\'\s*and/i", $string) === 1) return true;
+ if (preg_match("/\'\)\s*and/i", $string) === 1) return true;
+ if (preg_match("/or\s*true\-\-/", $string) === 1) return true;
+ if (preg_match("/if\s*\(/i", $string) === 1) return true;
+ if (preg_match("/\@\@version/i", $string) === 1) return true; // Get DB Ver
+ if (preg_match("/\@\@hostname/i", $string) === 1) return true;
+ if (preg_match("/\@\@datadir/i", $string) === 1) return true;
+ if (preg_match("/connection_id/i", $string) === 1) return true; // MySQL DB ID
+ if (preg_match("/crc32\s*\(/i", $string) === 1) return true; // MySQL DB ID
+ if (preg_match("/conv\s*\(/i", $string) === 1) return true; // MySQL DB ID
+ if (preg_match("/\@\@connections/i", $string) === 1) return true; // MSSQL DB ID
+ if (preg_match("/\@\@cpu_busy/i", $string) === 1) return true; // MSSQL DB ID
+ if (preg_match("/user_id\s*\(/i", $string) === 1) return true; // MSSQL DB ID
+ if (preg_match("/rownum/i", $string) === 1) return true; // Oracle DB ID
+ if (preg_match("/rawtohex\s*\(/i", $string) === 1) return true; // Oracle DB ID
+ if (preg_match("/lnnvl\s*\(/i", $string) === 1) return true; // Oracle DB ID
+ if (preg_match("/::int/i", $string) === 1) return true; // PostgreSQL DB ID
+ if (preg_match("/pg_client_encoding\s*\(/i", $string) === 1) return true; // PostgreSQL DB ID
+ if (preg_match("/get_current_ts_config\s*\(/i", $string) === 1) return true; // PostgreSQL DB ID
+ if (preg_match("/quote_literal\s*\(/i", $string) === 1) return true; // PostgreSQL DB ID
+ if (preg_match("/current_database\s*\(/i", $string) === 1) return true; // PostgreSQL DB ID
+ if (preg_match("/sqlite_version\s*\(/i", $string) === 1) return true; // SQLite DB ID
+ if (preg_match("/last_insert_rowid\s*\(/i", $string) === 1) return true; // SQLite DB ID
+ if (preg_match("/last_insert_rowid\s*\(/i", $string) === 1) return true; // SQLite DB ID
+ if (preg_match("/val\s*\(/i", $string) === 1) return true; // MSAccess DB ID
+ if (preg_match("/cvar\s*\(/i", $string) === 1) return true; // MSAccess DB ID
+ if (preg_match("/iif\s*\(/i", $string) === 1) return true; // MSAccess DB ID
+ if (preg_match("/atn\s*\(/i", $string) === 1) return true; // MSAccess DB ID
+ if (preg_match("/cdbl\s*\(/i", $string) === 1) return true; // MSAccess DB ID
+ if (preg_match("/grant\s*all/i", $string) === 1) return true;
+ if (preg_match("/into\s*dumpfile/i", $string) === 1) return true;
+ if (preg_match("/load\s*data\s*infile/i", $string) === 1) return true;
+ if (preg_match("/into\s*outfile/i", $string) === 1) return true;
+ if (preg_match("/load_file/i", $string) === 1) return true;
+ if (preg_match("/delete\s*from/i", $string) === 1) return true;
+ if (preg_match("/group_concat/i", $string) === 1) return true;
+ if (preg_match("/order by/i", $string) === 1) return true;
+ if (preg_match("/case when/i", $string) === 1) return true;
+ if (preg_match("/extractvalue/i", $string) === 1) return true;
+ if (preg_match("/\/etc\/passwd/i", $string) === 1) return true;
+ if (preg_match("/\/var\/log/i", $string) === 1) return true;
+ if (preg_match("/binary_checksum\s*\(/i", $string) === 1) return true; // ID MSSQL DB Engine
+ if (preg_match("/user\s*\(\)/i", $string) === 1) return true; // Get current user
+ if (preg_match("/system_user[\s]+\(\)/i", $string) === 1) return true; // Get current user
+ if (preg_match("/mysql.user/i", $string) === 1) return true; // List Users
+ if (preg_match("/mysql.db/i", $string) === 1) return true; // List Databases
+ if (preg_match("/database\s*\(/i", $string) === 1) return true;
+ if (preg_match("/information_schema/i", $string) === 1) return true; // List Columns
+ if (preg_match("/table_schema/i", $string) === 1) return true;
+ if (preg_match("/table_name/i", $string) === 1) return true;
+ if (preg_match("/\.columns/i", $string) === 1) return true;
+ if (preg_match("/\.tables/i", $string) === 1) return true;
+
+ // https://www.w3schools.com/mysql/mysql_ref_functions.asp
+ $fns = [
+ // String FNs
+ 'ascii', 'char_length', 'character_length', 'concat', 'concat_ws',
+ 'field', 'find_in_set', 'format', 'insert', 'instr', 'lcase', 'left',
+ 'length', 'locate', 'lower', 'lpad', 'ltrim', 'mid', 'position',
+ 'repeat', 'replace', 'reverse', 'right', 'rpad', 'rtrim', 'space',
+ 'strcmp', 'substr', 'substring', 'substring_index', 'trim', 'ucase',
+ 'upper',
+ // Numeric FNs
+ 'abs','acos', 'asin', 'atan', 'atan2', 'avg', 'ceil', 'ceiling', 'cos',
+ 'cot', 'count', 'degrees', 'div', 'exp', 'floor', 'greatest', 'least',
+ 'ln', 'log', 'log10', 'log2', 'max', 'min', 'mod', 'pi', 'pow', 'power',
+ 'radians', 'rand', 'round', 'sign', 'sin', 'sqrt', 'sum', 'tan', 'truncate',
+ // ADV FNs
+ 'bin', 'binary', 'case', 'cast', 'coalesce', 'connection_id', 'conv',
+ 'convert', 'current_user', 'database', 'if', 'ifnull', 'isnull',
+ 'last_insert_id', 'nullif', 'session_user', 'system_user', 'user',
+ 'version',
+ // OP FNs
+ 'and', 'between', 'cast', 'char', 'count', 'div', 'in', 'is', 'is_not',
+ 'is_not_null', 'is_null', 'like', 'member_of', 'not', 'not_between',
+ 'not_in', 'not_like', 'not_regexp', 'or', 'regexp', 'sounds_like',
+ 'floor', 'md5', 'rand', 'rlike', 'row', 'xor',
+ // https://dev.mysql.com/doc/refman/8.0/en/string-functions.html
+ 'bit_length', 'let', 'export_set', 'from_base64', 'hex', 'load_file',
+ 'make_set', 'match', 'oct', 'octet_length', 'ord', 'quote', 'regexp',
+ 'regexp_instr', 'regexp_like', 'regexp_replace', 'regexp_substr',
+ 'select', 'soundex', 'to_base64', 'unhex', 'weight_string'
+ ];
+
+ foreach($fns as $fn_keyword) {
+ if (preg_match("/{$fn_keyword}\s*\(/i", $string) === 1) return true;
+ }
+ return false;
+ }
+
+ private static function found_sql_evil_symbols(string $string): bool {
+ if (preg_match("/\-/", $string) === 1) return true;
+ if (preg_match("/\&/", $string) === 1) return true;
+ if (preg_match("/\*/", $string) === 1) return true;
+ if (preg_match("/\^/", $string) === 1) return true;
+ if (preg_match("/\'\s*\'/", $string) === 1) return true;
+ if (preg_match("/\"\s*\"/", $string) === 1) return true;
+ if (preg_match("/\)\)/", $string) === 1) return true;
+ if (preg_match("/\//", $string) === 1) return true;
+ if (function_exists("str_contains")) {
+ if (str_contains($string, '\')') === true) return true;
+ if (str_contains($string, '\")') === true) return true;
+ if (str_contains($string, '\`)') === true) return true;
+ if (str_contains($string, '\\') === true) return true;
+ if (str_contains($string, '%00') === true) return true;
+ if (str_contains($string, '\' or 1=1-- -') === true) return true; // Normal SQL
+ if (str_contains($string, '\' || 1==1//') === true) return true; // Mongo SQL
+ if (str_contains($string, '\' || 1==1%00') === true) return true; // Mongo SQL
+ }
+ return false;
+ }
+
+ private static function found_sql_bad_symbols(string $string): bool {
+ $ltc = ltrim($string);
+ $ltc_len = strlen($ltc);
+ $left_most = ($ltc_len < 6) ? $ltc_len : 6;
+ $first_chars = substr($ltc, 0, $left_most);
+ if ($first_chars !== false) {
+ if (function_exists("str_contains")) {
+ if (str_contains($first_chars, 'or') === true) return true;
+ if (str_contains($first_chars, 'and') === true) return true;
+ }
+ if (self::found_sql_suspicious($first_chars) === true) return true;
+ if (self::found_sql_evil_symbols($first_chars) === true) return true;
+ }
+ if (self::found_sql_suspicious($string) === false) return false;
+
+ if (function_exists("str_contains")) {
+ if (str_contains($first_chars, '1') === true) return true;
+ if (str_contains($first_chars, '0') === true) return true;
+ if (str_contains($first_chars, '1337') === true) return true;
+ }
+ if (self::found_sql_evil_symbols($string) === true) return true;
+ return false;
+ }
+
+ public static function found_sql_injection_cmds(string $string): bool {
+ /*
+ * There are a number of ways to prevent Poison Null Byte injections
+ * within PHP. These include escaping the NULL byte with a backslash,
+ * however, the most recommended way to do so is to completely remove
+ * the byte by using code similar to the following:
+ */
+ $string = str_replace(chr(0), '', $string);
+ if (self::found_sql_time_based_attack($string) === true) return true;
+ if (self::found_sql_admin_attack($string) === true) return true;
+ if (self::found_sql_bad_symbols($string) === true) return true;
+ if (self::found_sql_statement($string) === true) return true;
+ if (self::found_bad_json($string) === true) return true;
+ if (self::found_sql_comment($string) === true &&
+ self::found_quotes_in($string) === true) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static function found_sql_keyword(string $string): bool {
+ $words = [
+'ACCESSIBLE','ACCOUNT','ACTION','ACTIVE','ADD','ADMIN','AFTER','AGAINST','AGGREGATE',
+'ALGORITHM','ALL','ALTER','ALWAYS','ANALYSE','ANALYZE','AND','ANY','ARRAY','AS',
+'ASC','ASCII','ASENSITIVE','AT','AUTOEXTEND_SIZE','AUTO_INCREMENT','AVG','AVG_ROW_LENGTH',
+'BACKUP','BEFORE','BEGIN','BETWEEN','BIGINT','BINARY','BINLOG','BIT','BLOB','BLOCK',
+'BOOL','BOOLEAN','BOTH','BTREE','BUCKETS','BY','BYTE','CACHE','CALL','CASCADE','CASCADED',
+'CASE','CATALOG_NAME','CHAIN','CHANGE','CHANGED','CHANNEL','CHAR','CHARACTER','CHARSET',
+'CHECK','CHECKSUM','CIPHER','CLASS_ORIGIN','CLIENT','CLONE','CLOSE','COALESCE','CODE',
+'COLLATE','COLLATION','COLUMN','COLUMNS','COLUMN_FORMAT','COLUMN_NAME','COMMENT','COMMIT',
+'COMMITTED','COMPACT','COMPLETION','COMPONENT','COMPRESSED','COMPRESSION','CONCURRENT',
+'CONDITION','CONNECTION','CONSISTENT','CONSTRAINT','CONSTRAINT_CATALOG','CONSTRAINT_NAME',
+'CONSTRAINT_SCHEMA','CONTAINS','CONTEXT','CONTINUE','CONVERT','CPU','CREATE','CROSS',
+'CUBE','CUME_DIST','CURRENT','CURRENT_DATE','CURRENT_TIME','CURRENT_TIMESTAMP','CURRENT_USER',
+'CURSOR','CURSOR_NAME','DATA','DATABASE','DATABASES','DATAFILE','DATE','DATETIME','DAY',
+'DAY_HOUR','DAY_MICROSECOND','DAY_MINUTE','DAY_SECOND','DEALLOCATE','DEC','DECIMAL',
+'DECLARE','DEFAULT','DEFAULT_AUTH','DEFINER','DEFINITION','DELAYED','DELAY_KEY_WRITE',
+'DELETE','DENSE_RANK','DESC','DESCRIBE','DESCRIPTION','DES_KEY_FILE','DETERMINISTIC',
+'DIAGNOSTICS','DIRECTORY','DISABLE','DISCARD','DISK','DISTINCT','DISTINCTROW','DIV',
+'DO','DOUBLE','DROP','DUAL','DUMPFILE','DUPLICATE','DYNAMIC','EACH','ELSE','ELSEIF',
+'EMPTY','ENABLE','ENCLOSED','ENCRYPTION','END','ENDS','ENFORCED','ENGINE','ENGINES',
+'ENUM','ERROR','ERRORS','ESCAPE','ESCAPED','EVENT','EVENTS','EVERY','EXCEPT',
+'EXCHANGE','EXCLUDE','EXECUTE','EXISTS','EXIT','EXPANSION','EXPIRE','EXPLAIN',
+'EXPORT','EXTENDED','EXTENT_SIZE','FAILED_LOGIN_ATTEMPTS','FALSE','FAST','FAULTS',
+'FETCH','FIELDS','FILE','FILE_BLOCK_SIZE','FILTER','FIRST','FIRST_VALUE','FIXED',
+'FLOAT','FLOAT4','FLOAT8','FLUSH','FOLLOWING','FOLLOWS','FOR','FORCE','FOREIGN',
+'FORMAT','FOUND','FROM','FULL','FULLTEXT','FUNCTION','GENERAL','GENERATED',
+'GEOMCOLLECTION','GEOMETRY','GEOMETRYCOLLECTION','GET','GET_FORMAT','GET_MASTER_PUBLIC_KEY',
+'GLOBAL','GRANT','GRANTS','GROUP','GROUPING','GROUPS','GROUP_REPLICATION','HANDLER',
+'HASH','HAVING','HELP','HIGH_PRIORITY','HISTOGRAM','HISTORY','HOST','HOSTS','HOUR',
+'HOUR_MICROSECOND','HOUR_MINUTE','HOUR_SECOND','IDENTIFIED','IF','IGNORE',
+'IGNORE_SERVER_IDS','IMPORT','IN','INACTIVE','INDEX','INDEXES','INFILE','INITIAL_SIZE',
+'INNER','INOUT','INSENSITIVE','INSERT','INSERT_METHOD','INSTALL','INSTANCE','INT','INT1',
+'INT2','INT3','INT4','INT8','INTEGER','INTERVAL','INTO','INVISIBLE','INVOKER','IO',
+'IO_AFTER_GTIDS','IO_BEFORE_GTIDS','IO_THREAD','IPC','IS','ISOLATION','ISSUER','ITERATE',
+'JOIN','JSON','JSON_TABLE','JSON_VALUE','KEY','KEYS','KEY_BLOCK_SIZE','KILL','LAG',
+'LANGUAGE','LAST','LAST_VALUE','LATERAL','LEAD','LEADING','LEAVE','LEAVES','LEFT',
+'LESS','LEVEL','LIKE','LIMIT','LINEAR','LINES','LINESTRING','LIST','LOAD','LOCAL',
+'LOCALTIME','LOCALTIMESTAMP','LOCK','LOCKED','LOCKS','LOGFILE','LOGS','LONG',
+'LONGBLOB','LONGTEXT','LOOP','LOW_PRIORITY','MASTER','MASTER_AUTO_POSITION',
+'MASTER_BIND','MASTER_COMPRESSION_ALGORITHMS','MASTER_CONNECT_RETRY','MASTER_DELAY',
+'MASTER_HEARTBEAT_PERIOD','MASTER_HOST','MASTER_LOG_FILE',
+'MASTER_LOG_POS','MASTER_PASSWORD','MASTER_PORT','MASTER_PUBLIC_KEY_PATH',
+'MASTER_RETRY_COUNT','MASTER_SERVER_ID','MASTER_SSL','MASTER_SSL_CA',
+'MASTER_SSL_CAPATH','MASTER_SSL_CERT','MASTER_SSL_CIPHER','MASTER_SSL_CRL',
+'MASTER_SSL_CRLPATH','MASTER_SSL_KEY','MASTER_SSL_VERIFY_SERVER_CERT',
+'MASTER_TLS_CIPHERSUITES','MASTER_TLS_VERSION','MASTER_USER',
+'MASTER_ZSTD_COMPRESSION_LEVEL','MATCH','MAXVALUE','MAX_CONNECTIONS_PER_HOUR',
+'MAX_QUERIES_PER_HOUR','MAX_ROWS','MAX_SIZE','MAX_UPDATES_PER_HOUR','MAX_USER_CONNECTIONS',
+'MEDIUM','MEDIUMBLOB','MEDIUMINT','MEDIUMTEXT','MEMBER','MEMORY','MERGE','MESSAGE_TEXT',
+'MICROSECOND','MIDDLEINT','MIGRATE','MINUTE','MINUTE_MICROSECOND','MINUTE_SECOND',
+'MIN_ROWS','MOD','MODE','MODIFIES','MODIFY','MONTH','MULTILINESTRING','MULTIPOINT',
+'MULTIPOLYGON','MUTEX','MYSQL_ERRNO','NAME','NAMES','NATIONAL','NATURAL','NCHAR',
+'NDB','NDBCLUSTER','NESTED','NETWORK_NAMESPACE','NEVER','NEW','NEXT','NO','NODEGROUP',
+'NONE','NOT','NOWAIT','NO_WAIT','NO_WRITE_TO_BINLOG','NTH_VALUE','NTILE','NULL','NULLS',
+'NUMBER','NUMERIC','NVARCHAR','OF','OFF','OFFSET','OJ','OLD','ON','ONE','ONLY','OPEN',
+'OPTIMIZE','OPTIMIZER_COSTS','OPTION','OPTIONAL','OPTIONALLY','OPTIONS','OR','ORDER',
+'ORDINALITY','ORGANIZATION','OTHERS','OUT','OUTER','OUTFILE','OVER','OWNER','PACK_KEYS',
+'PAGE','PARSER','PARTIAL','PARTITION','PARTITIONING','PARTITIONS','PASSWORD',
+'PASSWORD_LOCK_TIME','PATH','PERCENT_RANK','PERSIST','PERSIST_ONLY','PHASE','PLUGIN',
+'PLUGINS','PLUGIN_DIR','POINT','POLYGON','PORT','PRECEDES','PRECEDING','PRECISION',
+'PREPARE','PRESERVE','PREV','PRIMARY','PRIVILEGES','PRIVILEGE_CHECKS_USER','PROCEDURE',
+'PROCESS','PROCESSLIST','PROFILE','PROFILES','PROXY','PURGE','QUARTER','QUERY','QUICK',
+'RANDOM','RANGE','RANK','READ','READS','READ_ONLY','READ_WRITE','REAL','REBUILD',
+'RECOVER','RECURSIVE','REDOFILE','REDO_BUFFER_SIZE','REDUNDANT','REFERENCE','REFERENCES',
+'REGEXP','RELAY','RELAYLOG','RELAY_LOG_FILE','RELAY_LOG_POS','RELAY_THREAD','RELEASE',
+'RELOAD','REMOTE','REMOVE','RENAME','REORGANIZE','REPAIR','REPEAT','REPEATABLE','REPLACE',
+'REPLICATE_DO_DB','REPLICATE_DO_TABLE','REPLICATE_IGNORE_DB','REPLICATE_IGNORE_TABLE',
+'REPLICATE_REWRITE_DB','REPLICATE_WILD_DO_TABLE','REPLICATE_WILD_IGNORE_TABLE',
+'REPLICATION','REQUIRE','REQUIRE_ROW_FORMAT','RESET','RESIGNAL','RESOURCE','RESPECT',
+'RESTART','RESTORE','RESTRICT','RESUME','RETAIN','RETURN','RETURNED_SQLSTATE','RETURNING',
+'RETURNS','REUSE','REVERSE','REVOKE','RIGHT','RLIKE','ROLE','ROLLBACK','ROLLUP','ROTATE',
+'ROUTINE','ROW','ROWS','ROW_COUNT','ROW_FORMAT','ROW_NUMBER','RTREE','SAVEPOINT','SCHEDULE',
+'SCHEMA','SCHEMAS','SCHEMA_NAME','SECOND','SECONDARY','SECONDARY_ENGINE','SECONDARY_LOAD',
+'SECONDARY_UNLOAD','SECOND_MICROSECOND','SECURITY','SELECT','SENSITIVE','SEPARATOR','SERIAL',
+'SERIALIZABLE','SERVER','SESSION','SET','SHARE','SHOW','SHUTDOWN','SIGNAL','SIGNED','SIMPLE',
+'SKIP','SLAVE','SLOW','SMALLINT','SNAPSHOT','SOCKET','SOME','SONAME','SOUNDS','SOURCE',
+'SPATIAL','SPECIFIC','SQL','SQLEXCEPTION','SQLSTATE','SQLWARNING','SQL_AFTER_GTIDS',
+'SQL_AFTER_MTS_GAPS','SQL_BEFORE_GTIDS','SQL_BIG_RESULT','SQL_BUFFER_RESULT','SQL_CACHE',
+'SQL_CALC_FOUND_ROWS','SQL_NO_CACHE','SQL_SMALL_RESULT','SQL_THREAD','SQL_TSI_DAY',
+'SQL_TSI_HOUR','SQL_TSI_MINUTE','SQL_TSI_MONTH','SQL_TSI_QUARTER','SQL_TSI_SECOND',
+'SQL_TSI_WEEK','SQL_TSI_YEAR','SRID','SSL','STACKED','START','STARTING','STARTS',
+'STATS_AUTO_RECALC','STATS_PERSISTENT','STATS_SAMPLE_PAGES','STATUS','STOP','STORAGE',
+'STORED','STRAIGHT_JOIN','STREAM','STRING','SUBCLASS_ORIGIN','SUBJECT','SUBPARTITION',
+'SUBPARTITIONS','SUPER','SUSPEND','SWAPS','SWITCHES','SYSTEM','TABLE','TABLES','TABLESPACE',
+'TABLE_CHECKSUM','TABLE_NAME','TEMPORARY','TEMPTABLE','TERMINATED','TEXT','THAN','THEN',
+'THREAD_PRIORITY','TIES','TIME','TIMESTAMP','TIMESTAMPADD','TIMESTAMPDIFF','TINYBLOB',
+'TINYINT','TINYTEXT','TLS','TO','TRAILING','TRANSACTION','TRIGGER','TRIGGERS','TRUE',
+'TRUNCATE','TYPE','TYPES','UNBOUNDED','UNCOMMITTED','UNDEFINED','UNDO','UNDOFILE',
+'UNDO_BUFFER_SIZE','UNICODE','UNINSTALL','UNION','UNIQUE','UNKNOWN','UNLOCK','UNSIGNED',
+'UNTIL','UPDATE','UPGRADE','USAGE','USE','USER','USER_RESOURCES','USE_FRM','USING',
+'UTC_DATE','UTC_TIME','UTC_TIMESTAMP','VALIDATION','VALUE','VALUES','VARBINARY',
+'VARCHAR','VARCHARACTER','VARIABLES','VARYING','VCPU','VIEW','VIRTUAL','VISIBLE','WAIT',
+'WARNINGS','WEEK','WEIGHT_STRING','WHEN','WHERE','WHILE','WINDOW','WITH','WITHOUT',
+'WORK','WRAPPER','WRITE','X509','XA','XID','XML','XOR','YEAR','YEAR_MONTH','ZEROFILL'
+ ];
+ $parts = preg_split('/\s+/', $string);
+ foreach($parts as $part) {
+ $lc = mb_strtoupper($part);
+ if (in_array($lc, $words)) return true;
+ }
+ return false;
+ }
+
+ private static function try_to_clean_sql(string $string): string {
+ $bad_items = [
+ '.user', '.db','.columns', '.tables', 'load_file', 'table_',
+ '_schema', 'connection_id', 'binary_checksum', 'cpu_busy',
+ 'user_id', 'rownum', 'rawtohex', 'lnnvl', 'pg_client_encoding',
+ 'get_current_ts_config', 'quote_literal', 'current_database',
+ 'sqlite_version', 'last_insert_rowid', 'last_insert_rowid',
+ 'group_concat', 'system_user'
+
+ ];
+ return str_replace($bad_items, "", $string);
+ }
+
+ public static function get_safer_sql_text(string $string): array {
+ $string = str_replace(chr(0), '', $string); // Remove NULL Bytes
+ if (self::found_sql_injection_cmds($string)) {
+ /*
+ * At this Point: Never allow Quotes, @$*=()%`
+ * Limit allowed chars now, to safe ones!
+ */
+ $cleaner = self::try_to_clean_sql($string);
+ $safer = preg_replace('/[^a-zA-Z0-9.\s]/', "", $cleaner);
+
+ if (self::found_sql_keyword($safer)) {
+ return ["text"=>$safer, "status"=>SQL_SAFETY_FLAG::dangerious];
+ }
+ return ["text"=>$safer, "status"=>SQL_SAFETY_FLAG::filtered];
+ }
+ return ["text"=>$string, "status"=>SQL_SAFETY_FLAG::good];
+ }
+
+}
\ No newline at end of file
diff --git a/src/classes/security.php b/src/classes/security.php
index a8144ae..72acb8b 100644
--- a/src/classes/security.php
+++ b/src/classes/security.php
@@ -76,26 +76,33 @@ final class security {
return false;
}
+ private static function is_valid_hash_algo($algo): bool {
+ return (in_array($algo, password_algos()));
+ }
+
/*
* The password_hash() function not only uses a secure
* one-way hashing algorithm, but it automatically handles
* salt and prevents time based side-channel attacks.
*/
- public static function do_password_hash(string $password): bool | string {
+ public static function do_password_hash(#[\SensitiveParameter] string $password): bool | string {
$pwd_peppered = self::make_hash($password);
- $hash_algo = \main_tts\configure::get(
+ $hash_algo = bootstrap\configure::get(
"security",
"hash_algo"
- );
- if (! empty($hash_algo)) {
- return password_hash($pwd_peppered, $hash_algo);
+ ) ?? false;
+ if ($hash_algo === false) {
+ throw new \Exception("Security Hash Algo not set!");
+ }
+ if (! self::is_valid_hash_algo($hash_algo)) {
+ throw new \Exception("Invalid Security Hash Alogo set");
}
- return password_hash($pwd_peppered, self::find_default_hash_algo());
+ return password_hash($pwd_peppered, $hash_algo);
}
public static function do_password_verify(
- string $input_pwd, $db_password
+ #[\SensitiveParameter] string $input_pwd, #[\SensitiveParameter] $db_password
): bool {
$pwd_peppered = self::make_hash($input_pwd);
return password_verify($pwd_peppered, $db_password);
@@ -107,7 +114,7 @@ final class security {
* @param string $level (weak, low, high, max)
* @return string new Hashed
*/
- public static function make_hash(string $text): string {
+ public static function make_hash(#[\SensitiveParameter] string $text): string {
$level = bootstrap\configure::get('security', 'hash_level');
if (empty($level)) {
$level = "normal";
diff --git a/src/classes/services/paragon_crypto/crypto.php b/src/classes/services/paragon_crypto/crypto.php
index 9a2843d..be9705e 100644
--- a/src/classes/services/paragon_crypto/crypto.php
+++ b/src/classes/services/paragon_crypto/crypto.php
@@ -18,7 +18,7 @@ class crypto {
public function __construct(#[\SensitiveParameter] private string $key) {
- $this->rnd = new \tts\random_engine();
+ $this->rnd = new \CodeHydrater\random_engine();
}
/*
* Secret key encryption (or symmetric encryption as it’s also
@@ -167,7 +167,7 @@ class crypto {
}
public static function a_single_key_maker(): string {
- $rnd = new \tts\random_engine();
+ $rnd = new \CodeHydrater\random_engine();
return base64_encode($rnd->get_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES));
}
/*
@@ -213,26 +213,26 @@ class crypto {
/*
* Usage:
*
-$key = tts\services\paragon_crypto\crypto::a_single_key_maker();
-$enc = tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String...', $key, \tts\services\paragon_crypto\crypto::single_key);
+$key = CodeHydrater\services\paragon_crypto\crypto::a_single_key_maker();
+$enc = CodeHydrater\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String...', $key, \CodeHydrater\services\paragon_crypto\crypto::single_key);
echo $enc . "
";
-$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $key, \tts\services\paragon_crypto\crypto::single_key);
+$dec = \CodeHydrater\services\paragon_crypto\crypto::safe_decrypt($enc, $key, \CodeHydrater\services\paragon_crypto\crypto::single_key);
echo $dec . "
";;
// --------------------
-$key_pair_Alice = \tts\services\paragon_crypto\crypto::make_user_box_kp();
-$secret_Alice = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Alice);
-$public_Alice = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Alice);
+$key_pair_Alice = \CodeHydrater\services\paragon_crypto\crypto::make_user_box_kp();
+$secret_Alice = \CodeHydrater\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Alice);
+$public_Alice = \CodeHydrater\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Alice);
-$key_pair_Bob = \tts\services\paragon_crypto\crypto::make_user_box_kp();
-$secret_Bob = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Bob);
-$public_Bob = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Bob);
+$key_pair_Bob = \CodeHydrater\services\paragon_crypto\crypto::make_user_box_kp();
+$secret_Bob = \CodeHydrater\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Bob);
+$public_Bob = \CodeHydrater\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Bob);
-$kA = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Alice, $public_Bob);
-$enc = \tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String2...', $kA, \tts\services\paragon_crypto\crypto::multiple_keys);
+$kA = \CodeHydrater\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Alice, $public_Bob);
+$enc = \CodeHydrater\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String2...', $kA, \CodeHydrater\services\paragon_crypto\crypto::multiple_keys);
echo $enc . "
";
-$kB = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Bob, $public_Alice);
-$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $kB, \tts\services\paragon_crypto\crypto::multiple_keys);
+$kB = \CodeHydrater\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Bob, $public_Alice);
+$dec = \CodeHydrater\services\paragon_crypto\crypto::safe_decrypt($enc, $kB, \CodeHydrater\services\paragon_crypto\crypto::multiple_keys);
echo $dec;
*/
diff --git a/src/classes/services/paragon_crypto/password_storage.php b/src/classes/services/paragon_crypto/password_storage.php
index ee8a899..b68d474 100644
--- a/src/classes/services/paragon_crypto/password_storage.php
+++ b/src/classes/services/paragon_crypto/password_storage.php
@@ -16,7 +16,7 @@ class password_storage {
private $random_engine;
public function __construct() {
- $this->random_engine = new \tts\random_engine();
+ $this->random_engine = new \CodeHydrater\random_engine();
}
public function generate_a_key(): string {
@@ -120,7 +120,7 @@ class password_storage {
}
/*
-$c = new \tts\services\paragon_crypto\password_storage();
+$c = new \CodeHydrater\services\paragon_crypto\password_storage();
$k = $c->generate_a_key();
$h = $c->hash("HelpMe", $k);
var_dump( $c->verify("HelpMe", $h, $k) );
diff --git a/src/classes/services/paragon_crypto/sodium_storage.php b/src/classes/services/paragon_crypto/sodium_storage.php
index 5d8d391..ff77311 100644
--- a/src/classes/services/paragon_crypto/sodium_storage.php
+++ b/src/classes/services/paragon_crypto/sodium_storage.php
@@ -29,7 +29,7 @@ class sodium_storage {
* Sets the encryption key
*/
public function __construct(#[\SensitiveParameter] private string $key) {
- $this->random_engine = new \tts\random_engine();
+ $this->random_engine = new \CodeHydrater\random_engine();
}
public function encrypt(#[\SensitiveParameter] string $plain_text, string $item_name = ""): string {
@@ -113,7 +113,7 @@ class sodium_storage {
$secretkey = "78a5011b9997cd03a28a3412c66565b7c32715b35e055d7abfc228236308d3b2";
$plain_text = "Hello World!";
-$sc = new \tts\services\paragon_crypto\sodium_storage($secretkey);
+$sc = new \CodeHydrater\services\paragon_crypto\sodium_storage($secretkey);
$index = "sensitive";
$encoded = $sc->encode($index, $plain_text);
setcookie($index, $encoded);
diff --git a/src/classes/services/sessions/cookie_session_handler.php b/src/classes/services/sessions/cookie_session_handler.php
index 6049e2e..9f75bae 100644
--- a/src/classes/services/sessions/cookie_session_handler.php
+++ b/src/classes/services/sessions/cookie_session_handler.php
@@ -110,7 +110,7 @@ class cookie_session_handler implements \SessionHandlerInterface {
public function write($id, $data): bool {
if (headers_sent($file, $line)) {
- throw new \CodeHydrater\services\sessions\cookie_sessions_handler_exception("Error headers were already sent by $file on line # $line ");
+ throw new cookie_sessions_handler_exception("Error headers were already sent by $file on line # $line ");
}
$data = $this->write_helper($data);
/*
@@ -119,7 +119,7 @@ class cookie_session_handler implements \SessionHandlerInterface {
* as web browsers only support up to 4K of Cookie Data!
*/
if (strlen($data) > 4000) {
- throw new \tts\services\sessions\cookie_sessions_handler_exception("Session data too big (over 4KB)");
+ throw new cookie_sessions_handler_exception("Session data too big (over 4KB)");
}
$cookie_lifetime = (int) ini_get('session.cookie_lifetime');