From d7f3734d786e800ca371cc7edec99cfbc167a32e Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 27 Dec 2022 23:33:45 -0500 Subject: [PATCH] enc method names std --- documents/folders.txt | 3 +- src/bootstrap/common.php | 21 ---- src/bootstrap/site_helper.php | 9 +- src/classes/exceptions/DB_Exception.php | 2 +- src/classes/loadall.php | 8 +- src/classes/services/encryption.php | 10 +- .../services/paragon_crypto/crypto.php | 19 ++- .../paragon_crypto/sodium_storage.php | 4 +- src/classes/services/sessions.php | 116 ------------------ .../services/sessions/cookie_sessions.php | 57 ++++++++- .../services/sessions/file_sessions.php | 86 ++++++++++++- .../services/sessions/redis_sessions.php | 92 +++++++++++++- src/classes/session_management.php | 35 +++++- 13 files changed, 282 insertions(+), 180 deletions(-) delete mode 100644 src/classes/services/sessions.php diff --git a/documents/folders.txt b/documents/folders.txt index 4f8904d..d92ceaa 100644 --- a/documents/folders.txt +++ b/documents/folders.txt @@ -67,7 +67,6 @@ tts_framework/src │   │   │   ├── cookie_sessions.php │   │   │   ├── file_sessions.php │   │   │   └── redis_sessions.php -│   │   ├── sessions.php │   │   ├── simple_rest.php (demo REST API helper) │   │   └── twilio.php (Loads Twilio Vendor files into Name Space) │   ├── session_management.php (Starts PHP secure Sessions) @@ -89,4 +88,4 @@ tts_framework/src    ├── dev_error.php (When NOT Live, show Exceptions/Errors) └── prod_errors.php (when Live, this: Sorry, we had an error... Page is used) -~73 files +~72 files diff --git a/src/bootstrap/common.php b/src/bootstrap/common.php index 2cedb27..3a9f81d 100644 --- a/src/bootstrap/common.php +++ b/src/bootstrap/common.php @@ -15,27 +15,6 @@ final class common { protected function __construct() { } - - public static function has_user_right(string $right): bool { -// $session = \main_tts\registry::get('di')->get_service('session'); - $rights = (isset($_SESSION['users_rights'])) ? $_SESSION['users_rights'] : false; - if ($rights === false) { - return false; - } - $assoc = true; // Use Array format - $a_rights = json_decode($rights, $assoc); - if (in_array($right, $a_rights)) { - return true; - } else { - return false; - } - } - - public static function get_user_id(): int { - $session = \main_tts\registry::get('di')->get_service('session'); - $sid = (isset($_SESSION['user_id'])) ? $_SESSION['user_id'] : 0; - return intval($sid); - } public static function return_bool_as_int_bit(bool $b_data): int { return ($b_data) ? 1 : 0; // if true=1, else =0 diff --git a/src/bootstrap/site_helper.php b/src/bootstrap/site_helper.php index 4e8ac4c..2545f1b 100644 --- a/src/bootstrap/site_helper.php +++ b/src/bootstrap/site_helper.php @@ -17,6 +17,7 @@ final class site_helper { private static $PRJ; private static $REQUEST_URI; private static $REQUEST_METHOD; + private static $USE_SECURE = true; private static $TESTING; private static $queryParams; private static $DEFAULT_PROJECT; @@ -94,6 +95,10 @@ final class site_helper { public static function get_method(): string { return strtoupper(self::$REQUEST_METHOD); } + + public static function get_use_secure(): bool { + return self::$USE_SECURE; + } public static function get_testing() { return self::$TESTING; @@ -155,7 +160,9 @@ final class site_helper { public static function tts_site_url(): string { $server_port = \bs_tts\safer_io::get_clean_server_var('SERVER_PORT'); $secure_port_on = \bs_tts\safer_io::get_clean_server_var('HTTPS'); - $protocol = ($server_port == '443' || $secure_port_on == 'on') ? 'https://' : 'http://'; + $use_secure = ($server_port == '443' || $secure_port_on == 'on'); + self::$USE_SECURE = $use_secure; + $protocol = ($use_secure) ? 'https://' : 'http://'; define('TTS_PROTOCOL', $protocol); $domainName = \bs_tts\safer_io::get_clean_server_var('HTTP_HOST'); diff --git a/src/classes/exceptions/DB_Exception.php b/src/classes/exceptions/DB_Exception.php index fd295da..d016f0d 100644 --- a/src/classes/exceptions/DB_Exception.php +++ b/src/classes/exceptions/DB_Exception.php @@ -54,7 +54,7 @@ class DB_Exception extends \Exception { $message = self::$error_message; } $live = (\main_tts\is_live()); - if ($live === false || \bs_tts\common::has_user_right('debugger')) { + if ($live === false || \tts\session_management::has_user_right('debugger')) { $msg = ($debug == DEBUGGER::basic || (self::$debug === DEBUGGER::basic && $debug === DEBUGGER::static) diff --git a/src/classes/loadall.php b/src/classes/loadall.php index 6a8c1be..4b01d14 100644 --- a/src/classes/loadall.php +++ b/src/classes/loadall.php @@ -56,11 +56,11 @@ final class loadall { $file_content = ''; while (($line = fgets($f)) !== false) { - if ($lines == 0) { - fwrite($fl_handle, PHP_EOL . "/* Contents of : {$file} */" . PHP_EOL); - }else { - fwrite($fl_handle, $line); + $out = ($lines == 0) ? PHP_EOL . "/* Contents of : {$file} */" . PHP_EOL : $line; + if (str_contains($out, "declare(")) { + continue; } + fwrite($fl_handle, $out); $lines++; } diff --git a/src/classes/services/encryption.php b/src/classes/services/encryption.php index 6beab48..a4055d6 100644 --- a/src/classes/services/encryption.php +++ b/src/classes/services/encryption.php @@ -28,7 +28,7 @@ final class encryption { private $default_hash = 'sha256'; // should be sha256 or higher private $_iterations = self::iterations, $_length=self::length, $_raw=self::raw, $_key_bytes=self::key_bytes; - public function __construct() { + public function __construct(private string $key) { $this->random_engine = new \tts\random_engine(); } @@ -214,11 +214,11 @@ final class encryption { /** * OpenSSL Encrypt text with key - * @param string $key password * @param string $text data * @return string encoded text */ - public function encrypt(string $key, string $text, bool $validate = true): string { + public function encrypt(string $text, bool $validate = true): string { + $key = $this->key; $key = ($validate) ? $this->get_valid_key($key) : $key; $ivsize = openssl_cipher_iv_length($this->method); $iv = $this->random_engine->get_bytes($ivsize); // Requires PHP 7 @@ -247,11 +247,11 @@ final class encryption { /** * OpenSSL Decrypt data with key - * @param string $key password * @param string $data encoded text * @return string plain text */ - public function decrypt(string $key, string $data, bool $validate = true): false|string { + public function decrypt(string $data, bool $validate = true): false|string { + $key = $this->key; $key = ($validate) ? $this->get_valid_key($key) : $key; if (! $this->binary) { $text = (! $this->url_encode) ? base64_decode($data) : \tts\misc::base64url_decode($data); diff --git a/src/classes/services/paragon_crypto/crypto.php b/src/classes/services/paragon_crypto/crypto.php index dd468db..6f52109 100644 --- a/src/classes/services/paragon_crypto/crypto.php +++ b/src/classes/services/paragon_crypto/crypto.php @@ -14,6 +14,12 @@ class crypto { const single_key = true; const multiple_keys = false; + private $rnd; + + + public function __construct(private string $key) { + $this->rnd = new \tts\random_engine(); + } /* * Secret key encryption (or symmetric encryption as it’s also * known) uses a single key to both encrypt and decrypt data. @@ -39,13 +45,13 @@ class crypto { * compromised, so is any data encrypted by using it. */ - public static function safe_encrypt( + public function encrypt( string $message, - string $key, bool $key_usage = self::single_key ): string { - $rnd = new \tts\random_engine(); - $nonce = $rnd->get_bytes( + $key = $this->key; + + $nonce = $this->rnd->get_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); $fn = ($key_usage == self::single_key) ? "sodium_crypto_secretbox" : "sodium_crypto_box"; @@ -62,11 +68,12 @@ class crypto { return $cipher; } - public static function safe_decrypt( + public function decrypt( string $encrypted, - string $key, bool $key_usage = self::single_key ): string | false { + $key = $this->key; + $decoded = base64_decode($encrypted); if ($decoded === false) { throw new Exception('Unable to decode'); diff --git a/src/classes/services/paragon_crypto/sodium_storage.php b/src/classes/services/paragon_crypto/sodium_storage.php index 6b0cfa7..75672a2 100644 --- a/src/classes/services/paragon_crypto/sodium_storage.php +++ b/src/classes/services/paragon_crypto/sodium_storage.php @@ -32,7 +32,7 @@ class sodium_storage { $this->random_engine = new \tts\random_engine(); } - public function encode(string $item_name, string $plain_text): string { + public function encrypt(string $plain_text, string $item_name = ""): string { $nonce = $this->random_engine->get_bytes( SODIUM_CRYPTO_STREAM_NONCEBYTES ); @@ -53,7 +53,7 @@ class sodium_storage { return sodium_bin2hex($mac . $nonce . $salt . $cipher_text); } - public function decode(string $item_name, string $cypher_data): string { + public function decrypt(string $cypher_data, string $item_name = ""): string { $bin_data = sodium_hex2bin($cypher_data); $mac = mb_substr( diff --git a/src/classes/services/sessions.php b/src/classes/services/sessions.php deleted file mode 100644 index d623fd4..0000000 --- a/src/classes/services/sessions.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @copyright Copyright (c) 2022, Robert Strutts. - * @license https://mit-license.org/ - */ - -namespace tts\services; - -class sessions { - - public function __construct(string $type) { - if ($type !== "none") { - switch ($type) { - case 'db': - $handler = new db_sessions(); - break; - case 'memory': - $handler = new memory_sessions(); - break; - case 'file': - default : - $handler = new \tts\sessions\file_sessions(); - } - session_set_save_handler($handler, true); - } - \tts\session_management::make_session_started(); - } - - private function get_enc_data(string $data): string { - $security_level = \main_tts\configure::get('session', 'session_security_level'); - if ($security_level === false || empty($data)) { - return $data; - } else { - $enc_sess = \main_tts\registry::get('di')->get_service('encryption'); - $enc_sess->change_security_level($security_level); - $d = $enc_sess->decrypt($data, \main_tts\configure::get('session', 'key')); - unset($enc_sess); - return $d; - } - } - - private function save_enc_data(string $data): string { - $security_level = \main_tts\configure::get('session', 'session_security_level'); - if ($security_level !== false) { - $enc_sess = \main_tts\registry::get('di')->get_service('encryption'); - $enc_sess->change_security_level($security_level); - $data = $enc_sess->encrypt($data, px_configure::get('session', 'key')); - unset($enc_sess); - } - return $data; - } - - /** - * Fetch Session Variable - * @param type $var key for Session - * @return data from Session - */ - public function get_session_var(string $var, int $flags = FILTER_DEFAULT): string { - $svar = \main_tts\configure::get('session', 'session_variable') ?? false; - if ($svar === false) { - $svar = 'SES_'; - } - if (! filter_has_var(INPUT_SESSION, $svar . $var)) { - return ':null'; - } - $content = filter_input(INPUT_SESSION, $svar . $var, $flags); - if ($content === false) { - throw new \Exception('Session filter: Failed!'); - } - return ($content === ':null') ? ':null' : $this->get_enc_data($content); - } - - /** - * Set Session Variable - * @param type $var key - * @param type $content data - */ - public function set_session_var(string $var, string $content): void { - $svar = \main_tts\configure::get('session', 'session_variable') ?? false; - if ($svar === false) { - $svar = 'SES_'; - } - $_SESSION[$svar . $var] = (empty($content)) ? ':null' : $this->save_enc_data($content); - } - - /** - * Fetch integer from Session Variable - * @param type $var - * @return type - */ - public function get_int($var): int { - $content = $this->get_session_var($var); - return ($content == ':null') ? -1 : intval($content); - } - - /** - * Fetch Session ID - * @return Session ID - */ - public function get_id(): string { - return session_id(); - } - - /** - * Session Destroy - */ - public function destroy(): bool { - session_unset(); - return session_destroy(); - } - -} diff --git a/src/classes/services/sessions/cookie_sessions.php b/src/classes/services/sessions/cookie_sessions.php index 2a68ce6..5ee66d8 100644 --- a/src/classes/services/sessions/cookie_sessions.php +++ b/src/classes/services/sessions/cookie_sessions.php @@ -13,12 +13,13 @@ namespace tts\services\sessions; class cookie_sessions_handler_exception extends \Exception {} class cookie_sessions implements \SessionHandlerInterface { - private static int $zlib_compression_level = 4; + public static int $zlib_compression_level = 4; public static string $cookie_domain; public static string $cookie_name = 'SES'; public static string $cookie_path = '/'; public static bool $cookie_secure = true; public static bool $cookie_HTTP_only = true; + public static bool $use_compression = true; private $enc; public static function set_zlib_compression_level(int $level): void { @@ -26,24 +27,61 @@ class cookie_sessions implements \SessionHandlerInterface { $level : 4; } - public function __construct($enc) { - self::$cookie_domain = $_SERVER['SERVER_NAME'] ?? ''; + public function __construct($enc, array $options) { $this->enc = $enc; + + if (isset($options['compression_level'])) { + self::$zlib_compression_level = $options['compression_level']; + } + if (isset($options['cookie_domain'])) { + self::$cookie_domain = $options['cookie_domain']; + } else { + self::$cookie_domain = $_SERVER['SERVER_NAME'] ?? ''; + } + if (isset($options['cookie_name'])) { + self::$cookie_name = $options['cookie_name']; + } + if (isset($options['cookie_path'])) { + self::$cookie_path = $options['cookie_path']; + } + if (isset($options['cookie_secure'])) { + self::$cookie_secure = $options['cookie_secure']; + } else { + $use_secure = \bs_tts\site_helper::get_use_secure(); + if ($use_secure === false) { + self::$cookie_secure = false; + } + } + if (isset($options['cookie_HTTP_only'])) { + self::$cookie_HTTP_only = $options['cookie_HTTP_only']; + } + if (isset($options['use_compression'])) { + self::$use_compression = $options['use_compression']; + } } private function encrypt(string & $data): void { - $data = $this->enc->encode("sess", $data); + if ($this->enc === false) { + return; + } + $data = $this->enc->encrypt($data); } private function decrypt(string & $data): void { + if ($this->enc === false) { + return; + } try { - $data = $this->enc->decode("sess", $data); + $data = $this->enc->decrypt($data); } catch (\Exception $e) { $data = false; // Maybe it has no data to decode } } private function compress(string & $data): void { + if (self::$use_compression === false) { + return; + } $data = gzdeflate($data, self::$zlib_compression_level); if ($data === false) { throw new \tts\services\sessions\cookie_sessions_handler_exception('Failed to compress session data'); @@ -51,7 +89,14 @@ class cookie_sessions implements \SessionHandlerInterface { } private function decompress(string & $data): void { - $data = gzinflate($data); + if (self::$use_compression === false) { + return; + } + + $ret = gzinflate($data); + if ($ret !== false) { + $data = $ret; + } } public function open($save_path, $session_name):bool { diff --git a/src/classes/services/sessions/file_sessions.php b/src/classes/services/sessions/file_sessions.php index 8f7706b..5a23a56 100644 --- a/src/classes/services/sessions/file_sessions.php +++ b/src/classes/services/sessions/file_sessions.php @@ -10,10 +10,28 @@ declare(strict_types=1); namespace tts\services\sessions; -class file_sessions implements \tts\contracts\sessions_interface { - +class file_sessions implements \SessionHandlerInterface { + public static int $zlib_compression_level = 4; + public static bool $use_compression = true; + private $enc; private $save_path; + public function __construct($enc, array $options) { + $this->enc = $enc; + if (isset($options['compression_level'])) { + self::$zlib_compression_level = $options['compression_level']; + } + if (isset($options['use_compression'])) { + self::$use_compression = $options['use_compression']; + } + } + + public static function set_zlib_compression_level(int $level): void { + self::$zlib_compression_level = ($level >= 0 && $level <= 9) ? + $level : 4; + } + + private function filter_id(string $id): string { if (\bs_tts\requires::is_valid_file($id)) { return \bs_tts\requires::filter_file_name($id); @@ -21,30 +39,88 @@ class file_sessions implements \tts\contracts\sessions_interface { throw new \Exception('Bad ID for session!'); } + private function encrypt(string & $data): void { + if ($this->enc === false) { + return; + } + $data = $this->enc->encrypt($data); + } + + private function decrypt(string & $data): void { + if ($this->enc === false) { + return; + } + try { + $data = $this->enc->decrypt($data); + } catch (\Exception $e) { + $data = false; // Maybe it has no data to decode + } + } + + private function compress(string & $data): void { + if (self::$use_compression === false) { + return; + } + $data = gzdeflate($data, self::$zlib_compression_level); + if ($data === false) { + throw new \Exception('Failed to compress session data'); + } + } + + private function decompress(string & $data): void { + if (self::$use_compression === false) { + return; + } + $ret = gzinflate($data); + if ($ret !== false) { + $data = $ret; + } + } + public function open(string $save_path, string $session_name): bool { $safer_dir = \bs_tts\requires::safer_dir_exists($save_path); if ($safer_dir === false) { return false; } - + $this->save_path = $safer_dir; if (!is_dir($this->save_path)) { mkdir($this->save_path, 0777); } return true; } - + public function close(): bool { return true; } public function read(string $id): false|string { $safer_id = $this->filter_id($id); - return (string) @file_get_contents("{$this->save_path}/sess_{$safer_id}"); + $data = (string) @file_get_contents("{$this->save_path}/sess_{$safer_id}"); + if ($data === null) { + return ""; + } + + $data = base64_decode($data); + if ($data === false) { + return ""; + } + + $this->decrypt($data); + if ($data === false) { + return ""; + } + + $this->decompress($data); + return ($data !== false) ? $data : ''; } public function write(string $id, string $data): bool { $safer_id = $this->filter_id($id); + + $this->compress($data); + $this->encrypt($data); + $data = base64_encode($data); return file_put_contents("{$this->save_path}/sess_{$safer_id}", $data) === false ? false : true; } diff --git a/src/classes/services/sessions/redis_sessions.php b/src/classes/services/sessions/redis_sessions.php index 48e6f80..05978a6 100644 --- a/src/classes/services/sessions/redis_sessions.php +++ b/src/classes/services/sessions/redis_sessions.php @@ -10,14 +10,76 @@ declare(strict_types=1); namespace tts\services\sessions; -class redis_sessions implements \tts\contracts\sessions_interface { +class redis_sessions implements \SessionHandlerInterface { + public static int $zlib_compression_level = 4; + public static bool $use_compression = true; public $ttl = 1800; // 30 minutes default protected $db; protected $prefix; + private $enc; - public function __construct(PredisClient $db, $prefix = 'SESS:') { - $this->db = $db; + public function __construct($enc, array $options) { + $exists = \main_tts\registry::get('di')->exists('session_redis_servers'); + if ($exists) { + $db = \main_tts\registry::get('di')->get_service('session_redis_servers'); + } + if (! is_object($db)) { + throw new \Exception("Session service type not set"); + } + $this->db = $options['db'] ?? $db; + if (isset($options['prefix'])) { + $prefix = $options['prefix']; + } else { + $prefix = 'SESS:'; + } + $this->prefix = $prefix; + $this->enc = $enc; + if (isset($options['compression_level'])) { + self::$zlib_compression_level = $options['compression_level']; + } + if (isset($options['use_compression'])) { + self::$use_compression = $options['use_compression']; + } + + } + + private function encrypt(string & $data): void { + if ($this->enc === false) { + return; + } + $data = $this->enc->encrypt($data); + } + + private function decrypt(string & $data): void { + if ($this->enc === false) { + return; + } + try { + $data = $this->enc->decrypt($data); + } catch (\Exception $e) { + $data = false; // Maybe it has no data to decode + } + } + + private function compress(string & $data): void { + if (self::$use_compression === false) { + return; + } + $data = gzdeflate($data, self::$zlib_compression_level); + if ($data === false) { + throw new \Exception('Failed to compress session data'); + } + } + + private function decompress(string & $data): void { + if (self::$use_compression === false) { + return; + } + $ret = gzinflate($data); + if ($ret !== false) { + $data = $ret; + } } public function open($save_path, $session_name): bool{ @@ -32,12 +94,32 @@ class redis_sessions implements \tts\contracts\sessions_interface { public function read($id): false|string { $id = $this->prefix . $id; - $sessData = $this->db->get($id); + $data = $this->db->get($id); $this->db->expire($id, $this->ttl); - return $sessData; + + if ($data === null) { + return ""; + } + + $data = base64_decode($data); + if ($data === false) { + return ""; + } + + $this->decrypt($data); + if ($data === false) { + return ""; + } + + $this->decompress($data); + return ($data !== false) ? $data : ''; } public function write($id, $data): bool { + $this->compress($data); + $this->encrypt($data); + $data = base64_encode($data); + $id = $this->prefix . $id; $this->db->set($id, $data); $this->db->expire($id, $this->ttl); diff --git a/src/classes/session_management.php b/src/classes/session_management.php index f7d0eff..3e8d107 100644 --- a/src/classes/session_management.php +++ b/src/classes/session_management.php @@ -12,7 +12,34 @@ namespace tts; final class session_management { - public static function make_session_started(bool $force_secure = false) { + public static function start( + string $type = "", + array $options = [], + $enc = false + ): void { + if (empty($type)) { + $type = \main_tts\configure::get('sessions', 'type'); + } + if ($enc === false) { + $exists = \main_tts\registry::get('di')->exists('session_encryption'); + if ($exists) { + $enc = \main_tts\registry::get('di')->get_service('session_encryption'); + } + } + if ($type === "none" || $type === "php") { + self::make_session_started(); + return; + } + $handler = match($type) { + 'redis' => new \tts\services\sessions\redis_sessions($enc, $options), + 'files' => new \tts\services\sessions\file_sessions($enc, $options), + default => new \tts\services\sessions\cookie_sessions($enc, $options), + }; + session_set_save_handler($handler, true); + self::make_session_started(); + } + + private static function make_session_started(bool $force_secure = false) { if ((function_exists('session_status') && session_status() !== PHP_SESSION_ACTIVE) || !session_id()) { $name = \main_tts\configure::get('sessions', 'session_name'); if ($name !== null) { @@ -20,9 +47,7 @@ final class session_management { } if (! headers_sent()) { - $server_port = \bs_tts\safer_io::get_clean_server_var('SERVER_PORT'); - $secure_port_on = \bs_tts\safer_io::get_clean_server_var('HTTPS'); - $use_secure = ($server_port == '443' || $secure_port_on == 'on') ? 1 : 0; + $use_secure = (\bs_tts\site_helper::get_use_secure()) ? 1 : 0; $use_secure = ($force_secure) ? 1 : $use_secure; session_start([ 'cookie_lifetime' => 0, // until browser is closed @@ -39,7 +64,6 @@ final class session_management { } public static function has_user_right(string $right): bool { - $session = \main_tts\registry::get('di')->get_service('session'); $rights = (isset($_SESSION['users_rights'])) ? $_SESSION['users_rights'] : false; if ($rights === false) { return false; @@ -54,7 +78,6 @@ final class session_management { } public static function get_user_id(): int { - $session = \main_tts\registry::get('di')->get_service('session'); $sid = (isset($_SESSION['user_id'])) ? $_SESSION['user_id'] : 0; return intval($sid); }