Compare commits

...

33 Commits

Author SHA1 Message Date
Clemens Schwaighofer
4e78b21c67 phpstan fix for fegetcsv param $length 2025-01-17 09:59:39 +09:00
Clemens Schwaighofer
d7e6434808 New DeprecatedHelper namespace
For temporary wrapper functions for deprecated calls that need this

PHP 8.4 fputcsv/fgetcsv/str_getcsv encoding default change deprecated warning

Note this does not cover the SqlFileInfo class as this is not used in our code
2025-01-17 09:58:02 +09:00
Clemens Schwaighofer
443cc2751d Update Logging file name change unit tests 2025-01-17 09:33:05 +09:00
Clemens Schwaighofer
cf6500b55a Logging class change to "." for block separator
Blocks for info are now separated with "." and not "_" to make it visual more easy to see
2025-01-17 09:08:13 +09:00
Clemens Schwaighofer
09c2ec653f ACL Login set deprecated edit user id too
We need that for some old calls in old projects
2025-01-16 14:49:15 +09:00
Clemens Schwaighofer
fc105f9295 Add ACL Login lookup edit access id to edit access cuid 2025-01-16 14:36:11 +09:00
Clemens Schwaighofer
053ab69330 Add edit access cuuid to the unit detail list 2025-01-16 14:04:30 +09:00
Clemens Schwaighofer
fd079316f5 ACL Login: Add edit_access_id to unit detail block
This is needed for a lot of legacy data lookup
2025-01-16 13:55:17 +09:00
Clemens Schwaighofer
08664e9834 Update log writing for login info
Fix the deprecated message in the Admin/Backend one with a full sample
Update the admin_header include sample page with the corret writeLog call
2025-01-16 10:40:41 +09:00
Clemens Schwaighofer
e063162161 Remove not needed use parts and ignore noop new for phan check 2025-01-15 12:53:02 +09:00
Clemens Schwaighofer
7fbc449a5c PHPunit test call script update
Fix for default PHP set via getting version from default PHP.
Add a verbose option and remove the fixed verbose setting from the phpunit config
Update the options call to add a usage info block
2025-01-15 11:57:25 +09:00
Clemens Schwaighofer
72912c8c90 Bad password check for PHP earlier than 8.4 2025-01-06 13:52:28 +09:00
Clemens Schwaighofer
de2ed8be3d EditBase SmartyExtended class call update 2024-12-27 17:07:44 +09:00
Clemens Schwaighofer
9d65f5d7c1 phpunit script update, SmartyExtended allow load of plugins
- phpunit has better options set for testdox/php version
- SmartyExtended has logger class as option (argument 2) and options
- SmartyExtneded can via option set html escape and load of plugins
	- plugin array is set of
		- file: path to plugin file
		- type: what type this is
		- tag: tag name
		- callable: the callable for the tag name
	- will throw exceptions on plugin load
	- for all other things will set warning only and skip read
- fix the Smarty call with the logger option
- fix password test for PHP 8.4 password hash change

*IMPORTANT*
SmartyExtended($l10n, $logger, $cache_id, $compile_id)
The second argument is now the Logger class, this MUST be updated for all calls
2024-12-27 14:00:12 +09:00
Clemens Schwaighofer
fbe827e989 Update Smarty Extended for Smarty-extended v5 upgrade 2024-12-27 11:30:55 +09:00
Clemens Schwaighofer
c778a4eb81 Add phive back in for static tools like phpunit instead of using the composer package 2024-12-27 09:32:54 +09:00
Clemens Schwaighofer
ce1c72a0bc Bug fix for DB IO parameters in CASE calls 2024-12-24 12:43:30 +09:00
Clemens Schwaighofer
10319ef728 Fix throws type for AsymmetricAnonymousEncryption in the phpdoc part 2024-12-23 12:56:57 +09:00
Clemens Schwaighofer
8d0036eaac Fix phpdoc return types 2024-12-23 11:26:50 +09:00
Clemens Schwaighofer
d1e65c702e Allow Seession settings to be changed
eg set the auto write + others
or set/unset can be chagned for single sets
2024-12-20 18:48:00 +09:00
Clemens Schwaighofer
7248906da7 Allow chaining of key set functions for encryption 2024-12-20 15:13:22 +09:00
Clemens Schwaighofer
7f9a4dc04f Merge branch 'Feature-AsymmetricEncryption' into NewFeatures 2024-12-18 10:52:29 +09:00
Clemens Schwaighofer
10935214eb Fix Class file name for asymmetric anonymous encryption 2024-12-18 10:50:27 +09:00
Clemens Schwaighofer
41e116f7d4 phpstan checks for level 9 2024-12-18 10:11:47 +09:00
Clemens Schwaighofer
881c93c343 Asymmetric Anoymouse Encryption phpunit tests 2024-12-18 09:56:48 +09:00
Clemens Schwaighofer
185d044a0b Symmetric encryption key set tests 2024-12-17 18:23:10 +09:00
Clemens Schwaighofer
cc067cc202 Update symmetric encryption with compare/get key, empty key test, unset on end
All key and messages are set SensitiveParameter type
On end, unset the key parameter with sodium mem zero
Get/Compare key set methods
Additional check on empty key
Add missing sodium mem zero for inner function variable clean up
2024-12-17 15:18:06 +09:00
Clemens Schwaighofer
37e2e54b2a Add asymmetric anonymous encryption
Private/Public key encryption for anonymous messages (not receipient)
2024-12-17 15:16:48 +09:00
Clemens Schwaighofer
711b3bfe97 Remove E_STRICT from error reporting, it is deprecated 2024-12-13 18:45:27 +09:00
Clemens Schwaighofer
3bd21c75d8 Make the font-size for ACL Login template a bit smaller
1.5em was too large, 1.3em is better
2024-12-13 13:58:56 +09:00
Clemens Schwaighofer
4971f62490 ecuid name fix in test file 2024-12-13 11:42:45 +09:00
Clemens Schwaighofer
1cf4fdf31a Fix column named for edit_log to eu prefixed
as eucuid and eucuuid
2024-12-13 11:37:52 +09:00
Clemens Schwaighofer
d16b920966 Update arrayReturnMatchinKeyOnly description 2024-12-13 11:29:37 +09:00
86 changed files with 2187 additions and 270 deletions

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive"> <phive xmlns="https://phar.io/phive">
<phar name="phpunit" version="^9.6" installed="9.6.21" location="./tools/phpunit" copy="false"/> <phar name="phpunit" version="^10.3.5" installed="10.3.5" location="./tools/phpunit" copy="false"/>
<phar name="phpcbf" version="^3.7.2" installed="3.10.3" location="./tools/phpcbf" copy="false"/> <phar name="phpcbf" version="^3.7.2" installed="3.10.3" location="./tools/phpcbf" copy="false"/>
<phar name="phpcs" version="^3.7.2" installed="3.10.3" location="./tools/phpcs" copy="false"/> <phar name="phpcs" version="^3.10.3" installed="3.10.3" location="./tools/phpcs" copy="false"/>
<phar name="phpstan" version="^1.10.37" installed="1.12.4" location="./tools/phpstan" copy="false"/> <phar name="phpstan" version="^2.0" installed="2.0.4" location="./tools/phpstan" copy="false"/>
<phar name="phan" version="^5.4.2" installed="5.4.3" location="./tools/phan" copy="false"/> <phar name="phan" version="^5.4.3" installed="5.4.3" location="./tools/phan" copy="false"/>
<phar name="psalm" version="^5.15.0" installed="5.24.0" location="./tools/psalm" copy="false"/> <phar name="psalm" version="^5.15.0" installed="5.24.0" location="./tools/psalm" copy="false"/>
<phar name="phpdox" version="^0.12.0" installed="0.12.0" location="./tools/phpdox" copy="false"/> <phar name="phpdox" version="^0.12.0" installed="0.12.0" location="./tools/phpdox" copy="false"/>
<phar name="phpdocumentor" version="^3.4.2" installed="3.4.3" location="./tools/phpDocumentor" copy="false"/> <phar name="phpdocumentor" version="^3.4.2" installed="3.4.3" location="./tools/phpDocumentor" copy="false"/>

View File

@@ -1,5 +1,5 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/"; base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
# must be run in ${base} # must be run in ${base}
cd $base; cd $base || exit;
${base}tools/phan --progress-bar -C --analyze-twice; ${base}tools/phan --progress-bar -C --analyze-twice;
cd ~; cd ~ || exit;

View File

@@ -1,5 +1,5 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/"; base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
# must be run in ${base} # must be run in ${base}
cd $base; cd $base || exit;
${base}tools/phpstan; ${base}tools/phpstan;
cd ~; cd ~ || exit;

View File

@@ -1,49 +1,96 @@
#!/bin/env bash #!/bin/env bash
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/"; function error() {
if [ -t 1 ]; then echo "[MAK] ERROR: $*" >&2; fi; exit 0;
}
usage() {
cat <<EOF
Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-t] [-v] [-p VERSION]
Runs all the PHP unit tests.
If -p is not set, the default intalled PHP is used.
Available options:
-h, --help Print this help and exit
-t, --testdox Enable testdox output for phpunit
-v, --verbose Enable verbose output for PHPunit
-p, --php VERSION Chose PHP version in the form of "N.N", if not found will exit
EOF
exit
}
# set base variables
BASE_PATH="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
PHPUNIT_CONFIG="${BASE_PATH}phpunit.xml";
PHP_BIN_PATH=$(which php);
if [ -z "${PHP_BIN_PATH}" ]; then
echo "Cannot find php binary";
exit;
fi;
DEFAULT_PHP_VERSION=$(${PHP_BIN_PATH} -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;");
if [ -z "${DEFAULT_PHP_VERSION}" ]; then
echo "Cannot set default PHP version";
exit;
fi;
# -c phpunit.xml # -c phpunit.xml
# --testdox # --testdox
# call with "t" to give verbose testdox output # call with "-tt" to give verbose testdox output
# SUPPORTED: https://www.php.net/supported-versions.php # SUPPORTED: https://www.php.net/supported-versions.php
# call with php version number to force a certain php version # call with -p <php version number> to force a certain php version
opt_testdox=""; opt_testdox="";
if [ "${1}" = "t" ] || [ "${2}" = "t" ]; then opt_verbose="";
opt_testdox="--testdox"; php_version="";
fi; no_php_version=0;
php_bin=""; while [ -n "${1-}" ]; do
if [ -n "${1}" ]; then
case "${1}" in case "${1}" in
# "7.3") php_bin="/usr/bin/php7.3 "; ;; -t | --testdox)
# "7.4") php_bin="/usr/bin/php7.4 "; ;; opt_testdox="--testdox";
# "8.0") php_bin="/usr/bin/php8.0 "; ;; ;;
# "8.1") php_bin="/usr/bin/php8.1 "; ;; -v | --verbose)
"8.2") php_bin="/usr/bin/php8.2 "; ;; opt_verbose="--verbose";
"8.3") php_bin="/usr/bin/php8.4 "; ;; ;;
*) echo "Not support PHP: ${1}"; exit; ;; -p | --php)
esac; php_version="${2-}";
shift
;;
-h | --help)
usage
;;
# invalid option
-?*)
error "[!] Unknown option: '$1'."
;;
esac
shift;
done;
if [ -z "${php_version}" ]; then
php_version="${DEFAULT_PHP_VERSION}";
no_php_version=1;
fi; fi;
if [ -n "${2}" ] && [ -z "${php_bin}" ]; then php_bin="${PHP_BIN_PATH}${php_version}";
case "${2}" in echo "Use PHP Version: ${php_version}";
# "7.3") php_bin="/usr/bin/php7.3 "; ;;
# "7.4") php_bin="/usr/bin/php7.4 "; ;; if [ ! -f "${php_bin}" ]; then
# "8.0") php_bin="/usr/bin/php8.0 "; ;; echo "Set php ${php_bin} does not exist";
# "8.1") php_bin="/usr/bin/php8.1 "; ;; exit;
"8.2") php_bin="/usr/bin/php8.2 "; ;;
"8.3") php_bin="/usr/bin/php8.3 "; ;;
*) echo "Not support PHP: ${1}"; exit; ;;
esac;
fi; fi;
php_bin="${php_bin} ";
# Note 4dev/tests/bootstrap.php has to be set as bootstrap file in phpunit.xml # Note 4dev/tests/bootstrap.php has to be set as bootstrap file in phpunit.xml
phpunit_call="${php_bin}${base}vendor/bin/phpunit ${opt_testdox} -c ${base}phpunit.xml ${base}4dev/tests/"; phpunit_call="${php_bin}${BASE_PATH}vendor/bin/phpunit ${opt_testdox} ${opt_verbose} -c ${PHPUNIT_CONFIG} ${BASE_PATH}4dev/tests/";
${phpunit_call}; ${phpunit_call};
if [ ! -z "${php_bin}" ]; then echo -e "\nPHPUnit Config: ${PHPUNIT_CONFIG}";
echo "CALLED WITH PHP: ${php_bin}"$(${php_bin} --version); if [ "${no_php_version}" -eq 0 ]; then
echo "CALLED WITH PHP: ${php_bin}$(${php_bin} --version)";
else else
echo "Default PHP used: "$(php --version); echo "Default PHP used: $(php --version)";
fi; fi;
# __END__ # __END__

View File

@@ -10,8 +10,8 @@ CREATE TABLE edit_log (
edit_log_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, edit_log_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
euid INT, -- this is a foreign key, but I don't nedd to reference to it euid INT, -- this is a foreign key, but I don't nedd to reference to it
FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL, FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL,
ecuid VARCHAR, eucuid VARCHAR,
ecuuid UUID, -- this is the one we want to use, full UUIDv4 from the edit user table eucuuid UUID, -- this is the one we want to use, full UUIDv4 from the edit user table
-- date_created equal, but can be overridden -- date_created equal, but can be overridden
event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
-- session ID if set -- session ID if set

View File

@@ -1531,6 +1531,12 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->loginGetEditAccessCuidFromUid($mock_settings['edit_access_uid']), $login_mock->loginGetEditAccessCuidFromUid($mock_settings['edit_access_uid']),
'Assert check access uid to cuid valid' 'Assert check access uid to cuid valid'
); );
// - loginGetEditAccessCuidFromId
$this->assertEquals(
$expected['check_access_cuid'],
$login_mock->loginGetEditAccessCuidFromUid($mock_settings['edit_access_id']),
'Assert check access id to cuid valid'
);
// Deprecated // Deprecated
// - loginCheckEditAccess // - loginCheckEditAccess
$this->assertEquals( $this->assertEquals(

View File

@@ -652,8 +652,8 @@ CREATE TABLE edit_log (
edit_log_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, edit_log_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
euid INT, -- this is a foreign key, but I don't nedd to reference to it euid INT, -- this is a foreign key, but I don't nedd to reference to it
FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL, FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL,
ecuid VARCHAR, eucuid VARCHAR,
ecuuid UUID, -- this is the one we want to use, full UUIDv4 from the edit user table eucuuid UUID, -- this is the one we want to use, full UUIDv4 from the edit user table
-- date_created equal, but can be overridden -- date_created equal, but can be overridden
event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
-- session ID if set -- session ID if set

View File

@@ -5196,6 +5196,27 @@ final class CoreLibsDBIOTest extends TestCase
SQL, SQL,
'count' => 1, 'count' => 1,
'convert' => false, 'convert' => false,
],
'update with case' => [
'query' => <<<SQL
UPDATE table_with_primary_key SET
row_int = $1::INT,
row_varchar = CASE WHEN row_int = 1 THEN $2 ELSE 'bar'::VARCHAR END
WHERE
row_varchar = $3
SQL,
'count' => 3,
'convert' => false,
],
'select with case' => [
'query' => <<<SQL
SELECT row_int
FROM table_with_primary_key
WHERE
row_varchar = CASE WHEN row_int = 1 THEN $1 ELSE $2 END
SQL,
'count' => 2,
'convert' => false,
] ]
]; ];
} }

View File

@@ -395,7 +395,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
} }
$per_run_id = $log->getLogUniqueId(); $per_run_id = $log->getLogUniqueId();
$this->assertMatchesRegularExpression( $this->assertMatchesRegularExpression(
"/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/", "/^\d{4}-\d{2}-\d{2}_\d{6}\.U_[a-z0-9]{8}$/",
$per_run_id, $per_run_id,
'assert per log run id 1st' 'assert per log run id 1st'
); );
@@ -403,7 +403,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
$log->setLogUniqueId(true); $log->setLogUniqueId(true);
$per_run_id_2nd = $log->getLogUniqueId(); $per_run_id_2nd = $log->getLogUniqueId();
$this->assertMatchesRegularExpression( $this->assertMatchesRegularExpression(
"/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/", "/^\d{4}-\d{2}-\d{2}_\d{6}\.U_[a-z0-9]{8}$/",
$per_run_id_2nd, $per_run_id_2nd,
'assert per log run id 2nd' 'assert per log run id 2nd'
); );
@@ -824,13 +824,13 @@ final class CoreLibsLoggingLoggingTest extends TestCase
$this->assertTrue($log_ok, 'assert ::log (debug) OK'); $this->assertTrue($log_ok, 'assert ::log (debug) OK');
$this->assertEquals( $this->assertEquals(
$log->getLogFile(), $log->getLogFile(),
$log->getLogFileId() . '_DEBUG.log' $log->getLogFileId() . '.DEBUG.log'
); );
$log_ok = $log->log(Level::Info, 'INFO', group_id: 'GROUP_ID', prefix: 'PREFIX:'); $log_ok = $log->log(Level::Info, 'INFO', group_id: 'GROUP_ID', prefix: 'PREFIX:');
$this->assertTrue($log_ok, 'assert ::log (info) OK'); $this->assertTrue($log_ok, 'assert ::log (info) OK');
$this->assertEquals( $this->assertEquals(
$log->getLogFile(), $log->getLogFile(),
$log->getLogFileId() . '_INFO.log' $log->getLogFileId() . '.INFO.log'
); );
} }

View File

@@ -0,0 +1,838 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Security\CreateKey;
use CoreLibs\Security\AsymmetricAnonymousEncryption;
/**
* Test class for Security\AsymmetricAnonymousEncryption and Security\CreateKey
* @coversDefaultClass \CoreLibs\Security\AsymmetricAnonymousEncryption
* @testdox \CoreLibs\Security\AsymmetricAnonymousEncryption method tests
*/
final class CoreLibsSecurityAsymmetricAnonymousEncryptionTest extends TestCase
{
// MARK: key set and compare
/**
* Undocumented function
*
* @covers ::getKeyPair
* @covers ::compareKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if init class set key pair matches to created key pair and public key
*
* @return void
*/
public function testKeyPairInitGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption($key_pair);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'set key pair not equal to original key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'automatic set public key not equal to original public key'
);
$this->assertEquals(
$key_pair,
$crypt->getKeyPair(),
'set key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'automatic set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @covers ::getKeyPair
* @covers ::compareKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if init class set key pair and public key matches to created key pair and public key
*
* @return void
*/
public function testKeyPairPublicKeyInitGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption($key_pair, $public_key);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'set key pair not equal to original key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'set public key not equal to original public key'
);
$this->assertEquals(
$key_pair,
$crypt->getKeyPair(),
'set key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @covers ::getKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if init class set public key matches to created public key
*
* @return void
*/
public function testPublicKeyInitGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption(public_key:$public_key);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'set public key not equal to original public key'
);
$this->assertEquals(
null,
$crypt->getKeyPair(),
'unset set key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @covers ::setKeyPair
* @covers ::getKeyPair
* @covers ::compareKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if set key pair after class init matches to created key pair and public key
*
* @return void
*/
public function testKeyPairSetGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption();
$crypt->setKeyPair($key_pair);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'post class init set key pair not equal to original key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'post class init automatic set public key not equal to original public key'
);
$this->assertEquals(
$key_pair,
$crypt->getKeyPair(),
'post class init set key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'post class init automatic set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @covers ::setKeyPair
* @covers ::setPublicKey
* @covers ::getKeyPair
* @covers ::compareKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if set key pair after class init matches to created key pair and public key
*
* @return void
*/
public function testKeyPairPublicKeySetGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption();
$crypt->setKeyPair($key_pair);
$crypt->setPublicKey($public_key);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'post class init set key pair not equal to original key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'post class init set public key not equal to original public key'
);
$this->assertEquals(
$key_pair,
$crypt->getKeyPair(),
'post class init set key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'post class init set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @covers ::setPublicKey
* @covers ::getKeyPair
* @covers ::compareKeyPair
* @covers ::getPublicKey
* @covers ::comparePublicKey
* @testdox Check if set key pair after class init matches to created key pair and public key
*
* @return void
*/
public function testPublicKeySetGetCompare(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption();
$crypt->setPublicKey($public_key);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'post class init set public key not equal to original public key'
);
$this->assertEquals(
null,
$crypt->getKeyPair(),
'post class init unset key pair returned not equal to original key pair'
);
$this->assertEquals(
$public_key,
$crypt->getPublicKey(),
'post class init set public key returned not equal to original public key'
);
}
/**
* Undocumented function
*
* @testdox Check different key pair and public key set
*
* @return void
*/
public function testDifferentSetKeyPairPublicKey()
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$key_pair_2 = CreateKey::createKeyPair();
$public_key_2 = CreateKey::getPublicKey($key_pair_2);
$crypt = new AsymmetricAnonymousEncryption($key_pair, $public_key_2);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'key pair set matches key pair created'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key_2),
'alternate public key set matches alternate public key created'
);
$this->assertFalse(
$crypt->comparePublicKey($public_key),
'alternate public key set does not match key pair public key'
);
}
/**
* Undocumented function
*
* @testdox Check if new set privat key does not overwrite set public key
*
* @return void
*/
public function testUpdateKeyPairNotUpdatePublicKey(): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$crypt = new AsymmetricAnonymousEncryption($key_pair);
$this->assertTrue(
$crypt->compareKeyPair($key_pair),
'set key pair not equal to original key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'set public key not equal to original public key'
);
$key_pair_2 = CreateKey::createKeyPair();
$public_key_2 = CreateKey::getPublicKey($key_pair_2);
$crypt->setKeyPair($key_pair_2);
$this->assertTrue(
$crypt->compareKeyPair($key_pair_2),
'new set key pair not equal to original new key pair'
);
$this->assertTrue(
$crypt->comparePublicKey($public_key),
'original set public key not equal to original public key'
);
$this->assertFalse(
$crypt->comparePublicKey($public_key_2),
'new public key equal to original public key'
);
}
// MARK: empty encrytped string
/**
* Undocumented function
*
* @covers ::decryptKey
* @covers ::decrypt
* @testdox Test empty encrypted string to decrypt
*
* @return void
*/
public function testEmptyDecryptionString(): void
{
$this->expectExceptionMessage('Encrypted string cannot be empty');
AsymmetricAnonymousEncryption::decryptKey('', CreateKey::generateRandomKey());
}
// MARK: encrypt/decrypt
/**
* Undocumented function
*
* @return array
*/
public function providerEncryptDecryptSuccess(): array
{
return [
'valid string' => [
'input' => 'I am a secret',
'expected' => 'I am a secret',
],
];
}
/**
* test encrypt/decrypt produce correct output
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt $input must be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testEncryptDecryptSuccess(string $input, string $expected): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
// test class
$crypt = new AsymmetricAnonymousEncryption($key_pair);
$encrypted = $crypt->encrypt($input);
$decrypted = $crypt->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class call',
);
$crypt = new AsymmetricAnonymousEncryption($key_pair, $public_key);
$encrypted = $crypt->encrypt($input);
$decrypted = $crypt->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class call botjh set',
);
}
/**
* test encrypt/decrypt produce correct output
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt indirect $input must be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testEncryptDecryptSuccessIndirect(string $input, string $expected): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
// test indirect
$encrypted = AsymmetricAnonymousEncryption::getInstance(public_key:$public_key)->encrypt($input);
$decrypted = AsymmetricAnonymousEncryption::getInstance($key_pair)->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class Instance call',
);
}
/**
* test encrypt/decrypt produce correct output
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt indirect with public key $input must be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testEncryptDecryptSuccessIndirectPublicKey(string $input, string $expected): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
// test indirect
$encrypted = AsymmetricAnonymousEncryption::getInstance(public_key:$public_key)->encrypt($input);
$decrypted = AsymmetricAnonymousEncryption::getInstance($key_pair)->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class Instance call public key',
);
}
/**
* test encrypt/decrypt produce correct output
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt static $input must be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testEncryptDecryptSuccessStatic(string $input, string $expected): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
// test static
$encrypted = AsymmetricAnonymousEncryption::encryptKey($input, $public_key);
$decrypted = AsymmetricAnonymousEncryption::decryptKey($encrypted, $key_pair);
$this->assertEquals(
$expected,
$decrypted,
'Static call',
);
}
// MARK: invalid decrypt key
/**
* Undocumented function
*
* @return array
*/
public function providerEncryptFailed(): array
{
return [
'wrong decryption key' => [
'input' => 'I am a secret',
'excpetion_message' => 'Invalid key pair'
],
];
}
/**
* Test decryption with wrong key
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptFailed
* @testdox decrypt with wrong key $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testEncryptFailed(string $input, string $exception_message): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$wrong_key_pair = CreateKey::createKeyPair();
// wrong key in class call
$crypt = new AsymmetricAnonymousEncryption(public_key:$public_key);
$encrypted = $crypt->encrypt($input);
$this->expectExceptionMessage($exception_message);
$crypt->setKeyPair($wrong_key_pair);
$crypt->decrypt($encrypted);
}
/**
* Test decryption with wrong key
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptFailed
* @testdox decrypt indirect with wrong key $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testEncryptFailedIndirect(string $input, string $exception_message): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$wrong_key_pair = CreateKey::createKeyPair();
// class instance
$encrypted = AsymmetricAnonymousEncryption::getInstance(public_key:$public_key)->encrypt($input);
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::getInstance($wrong_key_pair)->decrypt($encrypted);
}
/**
* Test decryption with wrong key
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptFailed
* @testdox decrypt static with wrong key $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testEncryptFailedStatic(string $input, string $exception_message): void
{
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$wrong_key_pair = CreateKey::createKeyPair();
// class static
$encrypted = AsymmetricAnonymousEncryption::encryptKey($input, $public_key);
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::decryptKey($encrypted, $wrong_key_pair);
}
// MARK: invalid key pair
/**
* Undocumented function
*
* @return array
*/
public function providerWrongKeyPair(): array
{
return [
'not hex key pair' => [
'key_pair' => 'not_a_hex_key_pair',
'exception_message' => 'Invalid hex key pair'
],
'too short hex key pair' => [
'key_pair' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
'excpetion_message' => 'Key pair is not the correct size (must be '
],
'empty key pair' => [
'key_pair' => '',
'excpetion_message' => 'Key pair cannot be empty'
]
];
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongKeyPair
* @testdox wrong key pair $key_pair throws $exception_message [$_dataName]
*
* @param string $key_pair
* @param string $exception_message
* @return void
*/
public function testWrongKeyPair(string $key_pair, string $exception_message): void
{
$enc_key_pair = CreateKey::createKeyPair();
// class
$this->expectExceptionMessage($exception_message);
$crypt = new AsymmetricAnonymousEncryption($key_pair);
$this->expectExceptionMessage($exception_message);
$crypt->encrypt('test');
$crypt->setKeyPair($enc_key_pair);
$encrypted = $crypt->encrypt('test');
$this->expectExceptionMessage($exception_message);
$crypt->setKeyPair($key_pair);
$crypt->decrypt($encrypted);
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongKeyPair
* @testdox wrong key pair indirect $key_pair throws $exception_message [$_dataName]
*
* @param string $key_pair
* @param string $exception_message
* @return void
*/
public function testWrongKeyPairIndirect(string $key_pair, string $exception_message): void
{
$enc_key_pair = CreateKey::createKeyPair();
// set valid encryption
$encrypted = AsymmetricAnonymousEncryption::getInstance($enc_key_pair)->encrypt('test');
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::getInstance($key_pair)->decrypt($encrypted);
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongKeyPair
* @testdox wrong key pair static $key_pair throws $exception_message [$_dataName]
*
* @param string $key_pair
* @param string $exception_message
* @return void
*/
public function testWrongKeyPairStatic(string $key_pair, string $exception_message): void
{
$enc_key_pair = CreateKey::createKeyPair();
// set valid encryption
$encrypted = AsymmetricAnonymousEncryption::encryptKey('test', CreateKey::getPublicKey($enc_key_pair));
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::decryptKey($encrypted, $key_pair);
}
// MARK: invalid public key
/**
* Undocumented function
*
* @return array
*/
public function providerWrongPublicKey(): array
{
return [
'not hex public key' => [
'public_key' => 'not_a_hex_public_key',
'exception_message' => 'Invalid hex public key'
],
'too short hex public key' => [
'public_key' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
'excpetion_message' => 'Public key is not the correct size (must be '
],
'empty public key' => [
'public_key' => '',
'excpetion_message' => 'Public key cannot be empty'
]
];
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongPublicKey
* @testdox wrong public key $public_key throws $exception_message [$_dataName]
*
* @param string $public_key
* @param string $exception_message
* @return void
*/
public function testWrongPublicKey(string $public_key, string $exception_message): void
{
$enc_key_pair = CreateKey::createKeyPair();
// $enc_public_key = CreateKey::getPublicKey($enc_key_pair);
// class
$this->expectExceptionMessage($exception_message);
$crypt = new AsymmetricAnonymousEncryption(public_key:$public_key);
$this->expectExceptionMessage($exception_message);
$crypt->decrypt('test');
$crypt->setKeyPair($enc_key_pair);
$encrypted = $crypt->encrypt('test');
$this->expectExceptionMessage($exception_message);
$crypt->setPublicKey($public_key);
$crypt->decrypt($encrypted);
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongPublicKey
* @testdox wrong public key indirect $key throws $exception_message [$_dataName]
*
* @param string $key
* @param string $exception_message
* @return void
*/
public function testWrongPublicKeyIndirect(string $key, string $exception_message): void
{
$enc_key = CreateKey::createKeyPair();
// class instance
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::getInstance(public_key:$key)->encrypt('test');
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = AsymmetricAnonymousEncryption::getInstance($enc_key)->encrypt('test');
// $this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::getInstance($key)->decrypt($encrypted);
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongPublicKey
* @testdox wrong public key static $key throws $exception_message [$_dataName]
*
* @param string $key
* @param string $exception_message
* @return void
*/
public function testWrongPublicKeyStatic(string $key, string $exception_message): void
{
$enc_key = CreateKey::createKeyPair();
// class static
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::encryptKey('test', $key);
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = AsymmetricAnonymousEncryption::encryptKey('test', $enc_key);
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::decryptKey($encrypted, $key);
}
// MARK: wrong cipher text
/**
* Undocumented function
*
* @return array
*/
public function providerWrongCiphertext(): array
{
return [
'invalid cipher text' => [
'input' => 'short',
'exception_message' => 'base642bin failed: '
],
'cannot decrypt' => [
// phpcs:disable Generic.Files.LineLength
'input' => 'Um8tBGiVfFAOg2YoUgA5fTqK1wXPB1S7uxhPNE1lqDxgntkEhYJDOmjXa0DMpBlYHjab6sC4mgzwZSzGCUnXDAgsHckwYwfAzs/r',
// phpcs:enable Generic.Files.LineLength
'exception_message' => 'Invalid key pair'
],
'invalid text' => [
'input' => 'U29tZSB0ZXh0IGhlcmU=',
'exception_message' => 'Invalid key pair'
]
];
}
/**
* Undocumented function
*
* @covers ::decrypt
* @dataProvider providerWrongCiphertext
* @testdox too short ciphertext $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testWrongCiphertext(string $input, string $exception_message): void
{
$key = CreateKey::createKeyPair();
// class
$crypt = new AsymmetricAnonymousEncryption($key);
$this->expectExceptionMessage($exception_message);
$crypt->decrypt($input);
}
/**
* Undocumented function
*
* @covers ::decryptKey
* @dataProvider providerWrongCiphertext
* @testdox too short ciphertext indirect $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testWrongCiphertextIndirect(string $input, string $exception_message): void
{
$key = CreateKey::createKeyPair();
// class instance
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::getInstance($key)->decrypt($input);
// class static
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::decryptKey($input, $key);
}
/**
* Undocumented function
*
* @covers ::decryptKey
* @dataProvider providerWrongCiphertext
* @testdox too short ciphertext static $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testWrongCiphertextStatic(string $input, string $exception_message): void
{
$key = CreateKey::createKeyPair();
// class static
$this->expectExceptionMessage($exception_message);
AsymmetricAnonymousEncryption::decryptKey($input, $key);
}
}
// __END__

View File

@@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase;
*/ */
final class CoreLibsSecurityPasswordTest extends TestCase final class CoreLibsSecurityPasswordTest extends TestCase
{ {
/**
* Undocumented function
*
* @return array
*/
public function passwordProvider(): array public function passwordProvider(): array
{ {
return [ return [
@@ -21,6 +26,11 @@ final class CoreLibsSecurityPasswordTest extends TestCase
]; ];
} }
/**
* Note: we need different hash types for PHP versions
*
* @return array
*/
public function passwordRehashProvider(): array public function passwordRehashProvider(): array
{ {
return [ return [
@@ -63,6 +73,10 @@ final class CoreLibsSecurityPasswordTest extends TestCase
*/ */
public function testPasswordRehashCheck(string $input, bool $expected): void public function testPasswordRehashCheck(string $input, bool $expected): void
{ {
// in PHP 8.4 the length is $12
if (PHP_VERSION_ID > 80400) {
$input = str_replace('$2y$10$', '$2y$12$', $input);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Security\Password::passwordRehashCheck($input) \CoreLibs\Security\Password::passwordRehashCheck($input)

View File

@@ -15,6 +15,77 @@ use CoreLibs\Security\SymmetricEncryption;
*/ */
final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
{ {
// MARK: key set compare
/**
* Undocumented function
*
* @covers ::compareKey
* @covers ::getKey
* @testdox Check if init class set key matches to created key
*
* @return void
*/
public function testKeyInitGetCompare(): void
{
$key = CreateKey::generateRandomKey();
$crypt = new SymmetricEncryption($key);
$this->assertTrue(
$crypt->compareKey($key),
'set key not equal to original key'
);
$this->assertEquals(
$key,
$crypt->getKey(),
'set key returned not equal to original key'
);
}
/**
* Undocumented function
*
* @covers ::setKey
* @covers ::compareKey
* @covers ::getKey
* @testdox Check if set key after class init matches to created key
*
* @return void
*/
public function testKeySetGetCompare(): void
{
$key = CreateKey::generateRandomKey();
$crypt = new SymmetricEncryption();
$crypt->setKey($key);
$this->assertTrue(
$crypt->compareKey($key),
'set key not equal to original key'
);
$this->assertEquals(
$key,
$crypt->getKey(),
'set key returned not equal to original key'
);
}
// MARK: empty encrypted string
/**
* Undocumented function
*
* @covers ::decryptKey
* @covers ::decrypt
* @testdox Test empty encrypted string to decrypt
*
* @return void
*/
public function testEmptyDecryptionString(): void
{
$this->expectExceptionMessage('Encrypted string cannot be empty');
SymmetricEncryption::decryptKey('', CreateKey::generateRandomKey());
}
// MARK: encrypt/decrypt compare
/** /**
* Undocumented function * Undocumented function
* *
@@ -88,8 +159,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
* test encrypt/decrypt produce correct output * test encrypt/decrypt produce correct output
* *
* @covers ::generateRandomKey * @covers ::generateRandomKey
* @covers ::encrypt * @covers ::encryptKey
* @covers ::decrypt * @covers ::decryptKey
* @dataProvider providerEncryptDecryptSuccess * @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt static $input must be $expected [$_dataName] * @testdox encrypt/decrypt static $input must be $expected [$_dataName]
* *
@@ -111,6 +182,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
); );
} }
// MARK: invalid key
/** /**
* Undocumented function * Undocumented function
* *
@@ -180,8 +253,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
* Test decryption with wrong key * Test decryption with wrong key
* *
* @covers ::generateRandomKey * @covers ::generateRandomKey
* @covers ::encrypt * @covers ::encryptKey
* @covers ::decrypt * @covers ::decryptKey
* @dataProvider providerEncryptFailed * @dataProvider providerEncryptFailed
* @testdox decrypt static with wrong key $input throws $exception_message [$_dataName] * @testdox decrypt static with wrong key $input throws $exception_message [$_dataName]
* *
@@ -200,6 +273,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
SymmetricEncryption::decryptKey($encrypted, $wrong_key); SymmetricEncryption::decryptKey($encrypted, $wrong_key);
} }
// MARK: wrong key
/** /**
* Undocumented function * Undocumented function
* *
@@ -216,6 +291,10 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
'key' => '1cabd5cba9e042f12522f4ff2de5c31d233b', 'key' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
'excpetion_message' => 'Key is not the correct size (must be ' 'excpetion_message' => 'Key is not the correct size (must be '
], ],
'empty key' => [
'key' => '',
'excpetion_message' => 'Key cannot be empty'
]
]; ];
} }
@@ -236,6 +315,7 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
$enc_key = CreateKey::generateRandomKey(); $enc_key = CreateKey::generateRandomKey();
// class // class
$this->expectExceptionMessage($exception_message);
$crypt = new SymmetricEncryption($key); $crypt = new SymmetricEncryption($key);
$this->expectExceptionMessage($exception_message); $this->expectExceptionMessage($exception_message);
$crypt->encrypt('test'); $crypt->encrypt('test');
@@ -244,22 +324,6 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
$this->expectExceptionMessage($exception_message); $this->expectExceptionMessage($exception_message);
$crypt->setKey($key); $crypt->setKey($key);
$crypt->decrypt($encrypted); $crypt->decrypt($encrypted);
// class instance
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($key)->encrypt('test');
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = SymmetricEncryption::getInstance($enc_key)->encrypt('test');
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($key)->decrypt($encrypted);
// class static
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::encryptKey('test', $key);
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = SymmetricEncryption::encryptKey('test', $enc_key);
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::decryptKey($encrypted, $key);
} }
/** /**
@@ -290,8 +354,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
/** /**
* test invalid key provided to decrypt or encrypt * test invalid key provided to decrypt or encrypt
* *
* @covers ::encrypt * @covers ::encryptKey
* @covers ::decrypt * @covers ::decryptKey
* @dataProvider providerWrongKey * @dataProvider providerWrongKey
* @testdox wrong key static $key throws $exception_message [$_dataName] * @testdox wrong key static $key throws $exception_message [$_dataName]
* *
@@ -312,6 +376,8 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
SymmetricEncryption::decryptKey($encrypted, $key); SymmetricEncryption::decryptKey($encrypted, $key);
} }
// MARK: wrong input
/** /**
* Undocumented function * Undocumented function
* *
@@ -358,7 +424,7 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
/** /**
* Undocumented function * Undocumented function
* *
* @covers ::decrypt * @covers ::decryptKey
* @dataProvider providerWrongCiphertext * @dataProvider providerWrongCiphertext
* @testdox too short ciphertext indirect $input throws $exception_message [$_dataName] * @testdox too short ciphertext indirect $input throws $exception_message [$_dataName]
* *
@@ -382,7 +448,7 @@ final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
/** /**
* Undocumented function * Undocumented function
* *
* @covers ::decrypt * @covers ::decryptKey
* @dataProvider providerWrongCiphertext * @dataProvider providerWrongCiphertext
* @testdox too short ciphertext static $input throws $exception_message [$_dataName] * @testdox too short ciphertext static $input throws $exception_message [$_dataName]
* *

View File

@@ -1,7 +1,7 @@
-- 20241203: update edit tables -- 20241203: update edit tables
ALTER TABLE edit_generic ADD cuuid UUID DEFAULT gen_random_uuid(); ALTER TABLE edit_generic ADD cuuid UUID DEFAULT gen_random_uuid();
ALTER TABLE edit_log ADD ecuid VARCHAR; ALTER TABLE edit_log ADD eucuid VARCHAR;
ALTER TABLE edit_log ADD ecuuid VARCHAR; ALTER TABLE edit_log ADD eucuuid VARCHAR;
ALTER TABLE edit_log ADD action_sub_id VARCHAR; ALTER TABLE edit_log ADD action_sub_id VARCHAR;
ALTER TABLE edit_log ADD http_data JSONB; ALTER TABLE edit_log ADD http_data JSONB;
ALTER TABLE edit_log ADD ip_address JSONB; ALTER TABLE edit_log ADD ip_address JSONB;
@@ -32,3 +32,5 @@ BEGIN
END; END;
$$ $$
LANGUAGE 'plpgsql'; LANGUAGE 'plpgsql';
-- END --

View File

@@ -9,7 +9,7 @@ parameters:
#friendly: #friendly:
# lineBefore: 3 # lineBefore: 3
# lineAfter: 3 # lineAfter: 3
level: 8 # max is now 9 level: 8 # max is now 10
# strictRules: # strictRules:
# allRules: false # allRules: false
checkMissingCallableSignature: true checkMissingCallableSignature: true

View File

@@ -1,7 +1,7 @@
<phpunit <phpunit
cacheResultFile="/tmp/phpunit-corelibs.result.cache" cacheResultFile="/tmp/phpunit-corelibs.result.cache"
colors="true" colors="true"
verbose="true" verbose="false"
convertDeprecationsToExceptions="true" convertDeprecationsToExceptions="true"
bootstrap="4dev/tests/bootstrap.php" bootstrap="4dev/tests/bootstrap.php"
> >

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
// basic class test file // basic class test file

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -273,8 +273,8 @@ $query_insert = <<<SQL
INSERT INTO INSERT INTO
test_foo test_foo
( (
test, some_bool, string_a, number_a, number_a_numeric, test, some_bool, string_a, number_a, numeric_a,
some_time, some_timestamp, json_string some_internval, some_timestamp, json_string
) VALUES ( ) VALUES (
$1, $2, $3, $4, $5, $1, $2, $3, $4, $5,
$6, $7, $8 $6, $7, $8
@@ -283,8 +283,8 @@ RETURNING test
SQL; SQL;
$query_select = <<<SQL $query_select = <<<SQL
SELECT SELECT
test, some_bool, string_a, number_a, number_a_numeric, test, some_bool, string_a, number_a, numeric_a,
some_time, some_time, some_timestamp, json_string some_time, some_internval, some_timestamp, json_string
FROM FROM
test_foo test_foo
WHERE WHERE
@@ -554,7 +554,7 @@ print "<b>PREPARE QUERIES</b><br>";
// READ PREPARE // READ PREPARE
$q_prep = <<<SQL $q_prep = <<<SQL
SELECT test_foo_id, test, some_bool, string_a, number_a, SELECT test_foo_id, test, some_bool, string_a, number_a,
number_a_numeric, some_time numeric_a, some_time
FROM test_foo FROM test_foo
WHERE test = $1 WHERE test = $1
ORDER BY test_foo_id DESC LIMIT 5 ORDER BY test_foo_id DESC LIMIT 5
@@ -582,7 +582,7 @@ if ($db->dbPrepare('sel_test_foo', $q_prep) === false) {
// sel test with ANY () type // sel test with ANY () type
$q_prep = "SELECT test_foo_id, test, some_bool, string_a, number_a, " $q_prep = "SELECT test_foo_id, test, some_bool, string_a, number_a, "
. "number_a_numeric, some_time " . "numeric_a, some_time "
. "FROM test_foo " . "FROM test_foo "
. "WHERE test = ANY($1) " . "WHERE test = ANY($1) "
. "ORDER BY test_foo_id DESC LIMIT 5"; . "ORDER BY test_foo_id DESC LIMIT 5";
@@ -618,7 +618,7 @@ $test_bar = $db->dbEscapeLiteral('SOMETHING DIFFERENT');
$q = <<<SQL $q = <<<SQL
SELECT test_foo_id, test, some_bool, string_a, number_a, SELECT test_foo_id, test, some_bool, string_a, number_a,
-- comment -- comment
number_a_numeric, some_time numeric_a, some_time
FROM test_foo FROM test_foo
WHERE test = $test_bar WHERE test = $test_bar
ORDER BY test_foo_id DESC LIMIT 5 ORDER BY test_foo_id DESC LIMIT 5
@@ -631,7 +631,7 @@ print "DB RETURN PARAMS<br>";
$q = <<<SQL $q = <<<SQL
SELECT test_foo_id, test, some_bool, string_a, number_a, SELECT test_foo_id, test, some_bool, string_a, number_a,
-- comment -- comment
number_a_numeric, some_time numeric_a, some_time
FROM test_foo FROM test_foo
WHERE test = $1 WHERE test = $1
ORDER BY test_foo_id DESC LIMIT 5 ORDER BY test_foo_id DESC LIMIT 5
@@ -646,7 +646,7 @@ echo "<hr>";
print "DB RETURN PARAMS LIKE<br>"; print "DB RETURN PARAMS LIKE<br>";
$q = <<<SQL $q = <<<SQL
SELECT SELECT
test_foo_id, test, some_bool, string_a, number_a, number_a_numeric test_foo_id, test, some_bool, string_a, number_a, numeric_a
FROM test_foo FROM test_foo
WHERE string_a LIKE $1; WHERE string_a LIKE $1;
SQL; SQL;
@@ -660,7 +660,7 @@ echo "<hr>";
print "DB RETURN PARAMS ANY<br>"; print "DB RETURN PARAMS ANY<br>";
$q = <<<SQL $q = <<<SQL
SELECT SELECT
test_foo_id, test, some_bool, string_a, number_a, number_a_numeric test_foo_id, test, some_bool, string_a, number_a, numeric_a
FROM test_foo FROM test_foo
WHERE string_a = ANY($1); WHERE string_a = ANY($1);
SQL; SQL;

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -174,6 +174,26 @@ while (is_array($res = $db->dbReturnParams($query, [$query_value]))) {
echo "<hr>"; echo "<hr>";
echo "<b>CASE part</b><br>";
$query = <<<SQL
UPDATE
test_foo
SET
some_timestamp = NOW(),
-- if not 1 set, else keep at one
smallint_a = (CASE
WHEN smallint_a <> 1 THEN $1
ELSE 1::INT
END)::INT
WHERE
string_a = $2
SQL;
echo "QUERY: <pre>" . $query . "</pre>";
$res = $db->dbExecParams($query, [1, 'foobar']);
print "ERROR: " . $db->dbGetLastError(true) . "<br>";
echo "<hr>";
// test connectors: = , <> () for query detection // test connectors: = , <> () for query detection
// convert placeholder tests // convert placeholder tests
@@ -237,7 +257,7 @@ SQL,
SQL, SQL,
'params' => [1, 2, 3, 4, 5, 6], 'params' => [1, 2, 3, 4, 5, 6],
'direction' => 'pg' 'direction' => 'pg'
] ],
]; ];
$db->dbSetConvertPlaceholder(true); $db->dbSetConvertPlaceholder(true);

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
// turn on all error reporting // turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -57,6 +57,43 @@ if (($dbh = $db->dbGetDbh()) instanceof \PgSql\Connection) {
print "<b>TRUNCATE test_foo</b><br>"; print "<b>TRUNCATE test_foo</b><br>";
$db->dbExec("TRUNCATE test_foo"); $db->dbExec("TRUNCATE test_foo");
/*
BELOW IS THE FULL TABLE WITH ALL PostgreSQL Types
=> \d test_foo
Table "public.test_foo"
Column | Type | Nullable | Default
------------------+-----------------------------+----------+-----------------------------------------------
test | character varying | |
some_bool | boolean | |
string_a | character varying | |
number_a | integer | |
numeric_a | numeric | |
some_internval | interval | |
test_foo_id | integer | not null | generated always as identity
json_string | jsonb | |
some_timestamp | timestamp without time zone | |
some_binary | bytea | |
null_var | character varying | |
smallint_a | smallint | |
number_real | real | |
number_double | double precision | |
number_serial | integer | not null | nextval('test_foo_number_serial_seq'::regclass)
array_char_1 | character varying[] | |
array_char_2 | character varying[] | |
array_int_1 | integer[] | |
array_int_2 | integer[] | |
composite_item | inventory_item | |
array_composite | inventory_item[] | |
numeric_3 | numeric(3,0) | |
identity_always | bigint | not null | generated always as identity
identitiy_default | bigint | not null | generated by default as identity
uuid_var | uuid | | gen_random_uuid()
some_date | date | |
some_time | time without time zone | |
bigint_a | bigint | |
default_uuid | uuid | | gen_random_uuid()
*/
/* $q = <<<SQL /* $q = <<<SQL
INSERT INTO test_foo (test, array_composite) VALUES ('C', '{"(a,1,1.5)","(b,2,2.5)"}') INSERT INTO test_foo (test, array_composite) VALUES ('C', '{"(a,1,1.5)","(b,2,2.5)"}')
SQL; SQL;
@@ -90,7 +127,7 @@ $query_params = [
$query_insert = <<<SQL $query_insert = <<<SQL
INSERT INTO test_foo ( INSERT INTO test_foo (
test, some_bool, string_a, number_a, number_a_numeric, smallint_a, test, some_bool, string_a, number_a, numeric_a, smallint_a,
some_time, some_timestamp, json_string, null_var, some_time, some_timestamp, json_string, null_var,
array_char_1, array_int_1, array_char_1, array_int_1,
array_composite, array_composite,
@@ -106,7 +143,7 @@ INSERT INTO test_foo (
) )
RETURNING RETURNING
test_foo_id, test_foo_id,
test, some_bool, string_a, number_a, number_a_numeric, smallint_a, test, some_bool, string_a, number_a, numeric_a, smallint_a,
some_time, some_timestamp, json_string, null_var, some_time, some_timestamp, json_string, null_var,
array_char_1, array_int_1, array_char_1, array_int_1,
array_composite, array_composite,
@@ -127,8 +164,8 @@ echo "<hr>";
$query_select = <<<SQL $query_select = <<<SQL
SELECT SELECT
test_foo_id, test_foo_id,
test, some_bool, string_a, number_a, number_a_numeric, smallint_a, test, some_bool, string_a, number_a, numeric_a, smallint_a,
number_real, number_double, number_numeric_3, number_serial, number_real, number_double, numeric_3, number_serial,
some_time, some_timestamp, json_string, null_var, some_time, some_timestamp, json_string, null_var,
array_char_1, array_char_2, array_int_1, array_int_2, array_composite, array_char_1, array_char_2, array_int_1, array_int_2, array_composite,
composite_item, (composite_item).*, composite_item, (composite_item).*,

View File

@@ -12,7 +12,7 @@ $PRINT_ALL = false;
$ECHO_ALL = true; $ECHO_ALL = true;
$DB_DEBUG = true; $DB_DEBUG = true;
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -0,0 +1,62 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start();
// basic class test file
define('USE_DATABASE', false);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest-phpv';
ob_end_flush();
$log = new CoreLibs\Logging\Logging([
'log_folder' => BASE . LOG,
'log_file_id' => $LOG_FILE_ID,
'log_per_date' => true,
]);
$_phpv = new CoreLibs\Check\PhpVersion();
$phpv_class = 'CoreLibs\Check\PhpVersion';
$PAGE_NAME = 'TEST CLASS: PHP VERSION';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title></head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
// fputcsv
print "<h3>\CoreLibs\DeprecatedHelper\Deprecated84::fputcsv()</h3>";
$test_csv = BASE . TMP . 'DeprecatedHelper.test.csv';
print "File: $test_csv<br>";
$fp = fopen($test_csv, "w");
if (!is_resource($fp)) {
die("Cannot open file: $test_csv");
}
\CoreLibs\DeprecatedHelper\Deprecated84::fputcsv($fp, ["A", "B", "C"]);
fclose($fp);
$fp = fopen($test_csv, "r");
if (!is_resource($fp)) {
die("Cannot open file: $test_csv");
}
while ($entry = \CoreLibs\DeprecatedHelper\Deprecated84::fgetcsv($fp)) {
print "fgetcsv: <pre>" . print_r($entry, true) . "</pre>";
}
fclose($fp);
$out = \CoreLibs\DeprecatedHelper\Deprecated84::str_getcsv("A,B,C");
print "str_getcsv: <pre>" . print_r($out, true) . "</pre>";
print "</body></html>";
// __END__

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -18,6 +18,7 @@ require 'config.php';
$LOG_FILE_ID = 'classTest-encryption'; $LOG_FILE_ID = 'classTest-encryption';
ob_end_flush(); ob_end_flush();
use CoreLibs\Security\AsymmetricAnonymousEncryption;
use CoreLibs\Security\SymmetricEncryption; use CoreLibs\Security\SymmetricEncryption;
use CoreLibs\Security\CreateKey; use CoreLibs\Security\CreateKey;
@@ -36,6 +37,8 @@ print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>'; print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>'; print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "<h2>Symmetric Encryption</h2>";
$key = CreateKey::generateRandomKey(); $key = CreateKey::generateRandomKey();
print "Secret Key: " . $key . "<br>"; print "Secret Key: " . $key . "<br>";
@@ -105,6 +108,49 @@ try {
// $encrypted = $se->encrypt($string); // $encrypted = $se->encrypt($string);
// $decrypted = $se->decrypt($encrypted); // $decrypted = $se->decrypt($encrypted);
echo "<hr>";
print "<h2>Asymmetric Encryption</h2>";
$key_pair = CreateKey::createKeyPair();
$public_key = CreateKey::getPublicKey($key_pair);
$string = "I am some asymmetric secret";
print "Message: " . $string . "<br>";
$encrypted = sodium_crypto_box_seal($string, CreateKey::hex2bin($public_key));
$message = sodium_bin2base64($encrypted, SODIUM_BASE64_VARIANT_ORIGINAL);
print "Encrypted PL: " . $message . "<br>";
$result = sodium_base642bin($message, SODIUM_BASE64_VARIANT_ORIGINAL);
$decrypted = sodium_crypto_box_seal_open($result, CreateKey::hex2bin($key_pair));
print "Decrypted PL: " . $decrypted . "<br>";
$encrypted = AsymmetricAnonymousEncryption::encryptKey($string, $public_key);
print "Encrypted ST: " . $encrypted . "<br>";
$decrypted = AsymmetricAnonymousEncryption::decryptKey($encrypted, $key_pair);
print "Decrypted ST: " . $decrypted . "<br>";
$aa_crypt = new AsymmetricAnonymousEncryption($key_pair, $public_key);
$encrypted = $aa_crypt->encrypt($string);
print "Encrypted: " . $encrypted . "<br>";
$decrypted = $aa_crypt->decrypt($encrypted);
print "Decrypted: " . $decrypted . "<br>";
print "Base64 encode: " . base64_encode('Some text here') . "<Br>";
/// this has to fail
$crypt = new AsymmetricAnonymousEncryption();
$crypt->setPublicKey(CreateKey::getPublicKey(CreateKey::createKeyPair()));
print "Public Key: " . $crypt->getPublicKey() . "<br>";
try {
$crypt->setPublicKey(CreateKey::createKeyPair());
} catch (RangeException $e) {
print "Invalid range: <pre>$e</pre>";
}
try {
$crypt->setKeyPair(CreateKey::getPublicKey(CreateKey::createKeyPair()));
} catch (RangeException $e) {
print "Invalid range: <pre>$e</pre>";
}
print "</body></html>"; print "</body></html>";
// __END__ // __END__

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -29,15 +29,17 @@ $table_arrays = [];
$table_arrays[\CoreLibs\Get\System::getPageName(1)] = [ $table_arrays[\CoreLibs\Get\System::getPageName(1)] = [
// form fields mtaching up with db fields // form fields mtaching up with db fields
'table_array' => [ 'table_array' => [
'foo',
'bar'
], ],
// laod query // laod query
'load_query' => '', 'load_query' => 'SELECT uuid_nr, foo, bar FROM test',
// database table to load from // database table to load from
'table_name' => '', 'table_name' => 'test',
// for load dro pdown, format output // for load dro pdown, format output
'show_fields' => [ 'show_fields' => [
[ [
'name' => 'name' 'name' => 'foo'
], ],
[ [
'name' => 'enabled', 'name' => 'enabled',

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -37,6 +37,8 @@ print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>'; print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>'; print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "PHP Version: " . PHP_VERSION . "<br>";
$password = 'something1234'; $password = 'something1234';
$enc_password = $_password->passwordSet($password); $enc_password = $_password->passwordSet($password);
print "PASSWORD: $password: " . $enc_password . "<br>"; print "PASSWORD: $password: " . $enc_password . "<br>";
@@ -51,6 +53,20 @@ print "PASSWORD REHASH: " . (string)$password_class::passwordRehashCheck($enc_pa
// direct static // direct static
print "S::PASSWORD VERFIY: " . (string)PwdChk::passwordVerify($password, $enc_password) . "<br>"; print "S::PASSWORD VERFIY: " . (string)PwdChk::passwordVerify($password, $enc_password) . "<br>";
if (PHP_VERSION_ID < 80400) {
$rehash_test = '$2y$10$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W';
$rehash_test_throw = '$2y$12$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W';
} else {
$rehash_test = '$2y$12$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W';
$rehash_test_throw = '$2y$10$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W';
}
if (PwdChk::passwordRehashCheck($rehash_test)) {
print "Bad password [BAD]<br>";
}
if (PwdChk::passwordRehashCheck($rehash_test_throw)) {
print "Bad password [OK]<br>";
}
print "</body></html>"; print "</body></html>";
// __END__ // __END__

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -141,6 +141,7 @@ $test_files = [
'class_test.error_msg.php' => 'Class Test: ERROR MSG', 'class_test.error_msg.php' => 'Class Test: ERROR MSG',
'class_test.url-requests.curl.php' => 'Class Test: URL REQUESTS: CURL', 'class_test.url-requests.curl.php' => 'Class Test: URL REQUESTS: CURL',
'subfolder/class_test.config.direct.php' => 'Class Test: CONFIG DIRECT SUB', 'subfolder/class_test.config.direct.php' => 'Class Test: CONFIG DIRECT SUB',
'class_test.deprecated.helper.php' => 'Class Test: DEPRECATED HELPERS',
]; ];
asort($test_files); asort($test_files);

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -28,8 +28,6 @@ $log = new CoreLibs\Logging\Logging([
$_phpv = new CoreLibs\Check\PhpVersion(); $_phpv = new CoreLibs\Check\PhpVersion();
$phpv_class = 'CoreLibs\Check\PhpVersion'; $phpv_class = 'CoreLibs\Check\PhpVersion';
// define a list of from to color sets for conversion test
$PAGE_NAME = 'TEST CLASS: PHP VERSION'; $PAGE_NAME = 'TEST CLASS: PHP VERSION';
print "<!DOCTYPE html>"; print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title></head>"; print "<html><head><title>" . $PAGE_NAME . "</title></head>";

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
/** /**
* Undocumented function * Undocumented function

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
/** /**
* Undocumented function * Undocumented function

View File

@@ -4,9 +4,11 @@
* @phan-file-suppress PhanTypeSuspiciousStringExpression * @phan-file-suppress PhanTypeSuspiciousStringExpression
*/ */
// FIXME: Smarty Class must be updated for PHP 8.4
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();
@@ -33,6 +35,7 @@ $l10n = new \CoreLibs\Language\L10n(
); );
$smarty = new CoreLibs\Template\SmartyExtend( $smarty = new CoreLibs\Template\SmartyExtend(
$l10n, $l10n,
$log,
CACHE_ID, CACHE_ID,
COMPILE_ID, COMPILE_ID,
); );
@@ -45,6 +48,7 @@ $adm = new CoreLibs\Admin\Backend(
); );
$adm->DATA['adm_set'] = 'SET from admin class'; $adm->DATA['adm_set'] = 'SET from admin class';
$PAGE_NAME = 'TEST CLASS: SMARTY'; $PAGE_NAME = 'TEST CLASS: SMARTY';
print "<!DOCTYPE html>"; print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title></head>"; print "<html><head><title>" . $PAGE_NAME . "</title></head>";

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -6,7 +6,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -4,7 +4,7 @@
declare(strict_types=1); declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start(); ob_start();

View File

@@ -21,7 +21,7 @@
} }
}, },
"require": { "require": {
"egrajp/smarty-extended": "^4.3", "egrajp/smarty-extended": "^5.4",
"php": ">=8.1", "php": ">=8.1",
"gullevek/dotenv": "^2.0", "gullevek/dotenv": "^2.0",
"psr/log": "^2.0 || ^3.0" "psr/log": "^2.0 || ^3.0"

View File

@@ -91,7 +91,7 @@ $l10n = new \CoreLibs\Language\L10n(
); );
// create smarty object // create smarty object
$smarty = new \CoreLibs\Template\SmartyExtend($l10n, CACHE_ID, COMPILE_ID); $smarty = new \CoreLibs\Template\SmartyExtend($l10n, $log, CACHE_ID, COMPILE_ID);
// create new Backend class with db and loger attached // create new Backend class with db and loger attached
$cms = new \CoreLibs\Admin\Backend($db, $log, $session, $l10n, DEFAULT_ACL_LEVEL); $cms = new \CoreLibs\Admin\Backend($db, $log, $session, $l10n, DEFAULT_ACL_LEVEL);
// the menu show flag (what menu to show) // the menu show flag (what menu to show)
@@ -116,7 +116,7 @@ $data = [
// log action // log action
// no log if login // no log if login
if (!$login->loginActionRun()) { if (!$login->loginActionRun()) {
$login->writeLog('Submit', $data, $cms->adbGetActionSet(), 'BINARY'); $login->writeLog('Submit', $data, action_set:$cms->adbGetActionSet(), write_type:'BINARY');
} }
//------------------------------ logging end //------------------------------ logging end

View File

@@ -79,7 +79,7 @@ class Login
private ?int $edit_user_id; private ?int $edit_user_id;
/** @var ?string the user cuid (note will be super seeded with uuid v4 later) */ /** @var ?string the user cuid (note will be super seeded with uuid v4 later) */
private ?string $edit_user_cuid; private ?string $edit_user_cuid;
/** @var ?string UUIDv4, will superseed the ecuid and replace euid as login id */ /** @var ?string UUIDv4, will superseed the eucuid and replace euid as login id */
private ?string $edit_user_cuuid; private ?string $edit_user_cuuid;
/** @var string _GET/_POST loginUserId parameter for non password login */ /** @var string _GET/_POST loginUserId parameter for non password login */
private string $login_user_id = ''; private string $login_user_id = '';
@@ -1418,6 +1418,7 @@ class Login
'additional_acl' => Json::jsonConvertToArray($res['additional_acl']), 'additional_acl' => Json::jsonConvertToArray($res['additional_acl']),
'data' => $ea_data 'data' => $ea_data
]; ];
// LEGACY LOOKUP
$unit_access_eaid[$res['edit_access_id']] = [ $unit_access_eaid[$res['edit_access_id']] = [
'cuid' => $res['cuid'], 'cuid' => $res['cuid'],
]; ];
@@ -1477,6 +1478,8 @@ class Login
// username (login), group name // username (login), group name
$this->acl['user_name'] = $_SESSION['LOGIN_USER_NAME']; $this->acl['user_name'] = $_SESSION['LOGIN_USER_NAME'];
$this->acl['group_name'] = $_SESSION['LOGIN_GROUP_NAME']; $this->acl['group_name'] = $_SESSION['LOGIN_GROUP_NAME'];
// DEPRECATED
$this->acl['euid'] = $_SESSION['LOGIN_EUID'];
// edit user cuid // edit user cuid
$this->acl['eucuid'] = $_SESSION['LOGIN_EUCUID']; $this->acl['eucuid'] = $_SESSION['LOGIN_EUCUID'];
$this->acl['eucuuid'] = $_SESSION['LOGIN_EUCUUID']; $this->acl['eucuuid'] = $_SESSION['LOGIN_EUCUUID'];
@@ -1552,8 +1555,10 @@ class Login
$this->acl['unit_legacy'][$unit['id']] = $this->acl['unit'][$ea_cuid]; $this->acl['unit_legacy'][$unit['id']] = $this->acl['unit'][$ea_cuid];
// detail name/level set // detail name/level set
$this->acl['unit_detail'][$ea_cuid] = [ $this->acl['unit_detail'][$ea_cuid] = [
'id' => $unit['id'],
'name' => $unit['name'], 'name' => $unit['name'],
'uid' => $unit['uid'], 'uid' => $unit['uid'],
'cuuid' => $unit['cuuid'],
'level' => $this->default_acl_list[$this->acl['unit'][$ea_cuid]]['name'] ?? -1, 'level' => $this->default_acl_list[$this->acl['unit'][$ea_cuid]]['name'] ?? -1,
'default' => $unit['default'], 'default' => $unit['default'],
'data' => $unit['data'], 'data' => $unit['data'],
@@ -2138,10 +2143,10 @@ body {
text-align: right; text-align: right;
} }
input.login-input-text { input.login-input-text {
font-size: 1.5em; font-size: 1.3em;
} }
button.login-button { button.login-button {
font-size: 1.5em; font-size: 1.3em;
} }
.login-visible { .login-visible {
visibility: visible; visibility: visible;
@@ -2371,7 +2376,7 @@ HTML;
} }
$q = <<<SQL $q = <<<SQL
INSERT INTO {DB_SCHEMA}.edit_log ( INSERT INTO {DB_SCHEMA}.edit_log (
username, euid, ecuid, ecuuid, event_date, event, error, data, data_binary, page, username, euid, eucuid, eucuuid, event_date, event, error, data, data_binary, page,
ip, ip_address, user_agent, referer, script_name, query_string, request_scheme, server_name, ip, ip_address, user_agent, referer, script_name, query_string, request_scheme, server_name,
http_host, http_data, session_id, http_host, http_data, session_id,
action_data action_data
@@ -2727,7 +2732,7 @@ HTML;
return $this->session->get('LOGIN_PAGES'); return $this->session->get('LOGIN_PAGES');
} }
// MARK: logged in uid(pk)/cuid/ecuuid // MARK: logged in uid(pk)/eucuid/eucuuid
/** /**
* Get the current set EUID (edit user id) * Get the current set EUID (edit user id)
@@ -2938,7 +2943,7 @@ HTML;
if (empty($this->edit_user_cuuid)) { if (empty($this->edit_user_cuuid)) {
return $this->permission_okay; return $this->permission_okay;
} }
// euid must match ecuid and ecuuid // euid must match eucuid and eucuuid
// bail for previous wrong page match, eg if method is called twice // bail for previous wrong page match, eg if method is called twice
if ($this->login_error == 103) { if ($this->login_error == 103) {
return $this->permission_okay; return $this->permission_okay;
@@ -3277,6 +3282,20 @@ HTML;
return (int)$_SESSION['LOGIN_UNIT_CUID'][$uid]; return (int)$_SESSION['LOGIN_UNIT_CUID'][$uid];
} }
/**
* Legacy lookup for edit access id to cuid
*
* @param int $id edit access id PK
* @return string|false edit access cuid or false if not found
*/
public function loginGetEditAccessCuidFromId(int $id): string|false
{
if (!isset($_SESSION['LOGIN_UNIT_ACL_LEVEL'][$id])) {
return false;
}
return (string)$_SESSION['LOGIN_UNIT_ACL_LEVEL'][$id]['cuid'];
}
/** /**
* Check if admin flag is set * Check if admin flag is set
* *

View File

@@ -289,7 +289,7 @@ class Backend
* JSON, STRING/SERIEAL, BINARY/BZIP or ZLIB * JSON, STRING/SERIEAL, BINARY/BZIP or ZLIB
* @param string|null $db_schema [default=null] override target schema * @param string|null $db_schema [default=null] override target schema
* @return void * @return void
* @deprecated Use $login->writeLog() and set action_set from ->adbGetActionSet() * @deprecated Use $login->writeLog($event, $data, action_set:$cms->adbGetActionSet(), write_type:$write_type)
*/ */
public function adbEditLog( public function adbEditLog(
string $event = '', string $event = '',
@@ -358,7 +358,7 @@ class Backend
} }
$q = <<<SQL $q = <<<SQL
INSERT INTO {DB_SCHEMA}.edit_log ( INSERT INTO {DB_SCHEMA}.edit_log (
username, euid, ecuid, ecuuid, event_date, event, error, data, data_binary, page, username, euid, eucuid, eucuuid, event_date, event, error, data, data_binary, page,
ip, user_agent, referer, script_name, query_string, server_name, http_host, ip, user_agent, referer, script_name, query_string, server_name, http_host,
http_accept, http_accept_charset, http_accept_encoding, session_id, http_accept, http_accept_charset, http_accept_encoding, session_id,
action, action_id, action_sub_id, action_yes, action_flag, action_menu, action_loaded, action, action_id, action_sub_id, action_yes, action_flag, action_menu, action_loaded,

View File

@@ -14,9 +14,6 @@ declare(strict_types=1);
namespace CoreLibs\Admin; namespace CoreLibs\Admin;
use Exception;
use SmartyException;
class EditBase class EditBase
{ {
/** @var array<mixed> */ /** @var array<mixed> */
@@ -63,6 +60,7 @@ class EditBase
// smarty template engine (extended Translation version) // smarty template engine (extended Translation version)
$this->smarty = new \CoreLibs\Template\SmartyExtend( $this->smarty = new \CoreLibs\Template\SmartyExtend(
$l10n, $l10n,
$log,
$options['cache_id'] ?? '', $options['cache_id'] ?? '',
$options['compile_id'] ?? '', $options['compile_id'] ?? '',
); );
@@ -538,8 +536,7 @@ class EditBase
* builds the smarty content and runs smarty display output * builds the smarty content and runs smarty display output
* *
* @return void * @return void
* @throws Exception * @throws \Smarty\Exception
* @throws SmartyException
*/ */
public function editBaseRun( public function editBaseRun(
?string $template_dir = null, ?string $template_dir = null,

View File

@@ -527,7 +527,9 @@ class ArrayHandler
} }
/** /**
* From the array with key -> anything values return only the matching entries from key list * From the array with key -> mixed values,
* return only the entries where the key matches the key given in the key list parameter
*
* key list is a list[string] * key list is a list[string]
* if key list is empty, return array as is * if key list is empty, return array as is
* *

View File

@@ -363,11 +363,12 @@ class Session
* set the auto write close flag * set the auto write close flag
* *
* @param bool $flag * @param bool $flag
* @return void * @return Session
*/ */
public function setAutoWriteClose(bool $flag): void public function setAutoWriteClose(bool $flag): Session
{ {
$this->auto_write_close = $flag; $this->auto_write_close = $flag;
return $this;
} }
/** /**
@@ -513,14 +514,15 @@ class Session
* *
* @param string $name array name in _SESSION * @param string $name array name in _SESSION
* @param mixed $value value to set (can be anything) * @param mixed $value value to set (can be anything)
* @return void * @return Session
*/ */
public function set(string $name, mixed $value): void public function set(string $name, mixed $value): Session
{ {
$this->checkValidSessionEntryKey($name); $this->checkValidSessionEntryKey($name);
$this->restartSession(); $this->restartSession();
$_SESSION[$name] = $value; $_SESSION[$name] = $value;
$this->closeSessionCall(); $this->closeSessionCall();
return $this;
} }
/** /**
@@ -577,16 +579,17 @@ class Session
* unset one _SESSION entry 'name' if exists * unset one _SESSION entry 'name' if exists
* *
* @param string $name _SESSION key name to remove * @param string $name _SESSION key name to remove
* @return void * @return Session
*/ */
public function unset(string $name): void public function unset(string $name): Session
{ {
if (!isset($_SESSION[$name])) { if (!isset($_SESSION[$name])) {
return; return $this;
} }
$this->restartSession(); $this->restartSession();
unset($_SESSION[$name]); unset($_SESSION[$name]);
$this->closeSessionCall(); $this->closeSessionCall();
return $this;
} }
/** /**

View File

@@ -26,7 +26,9 @@ class ConvertPlaceholder
. '&&|' // array overlap . '&&|' // array overlap
. '\-\|\-|' // range overlap for array . '\-\|\-|' // range overlap for array
. '[^-]-{1}|' // single -, used in JSON too . '[^-]-{1}|' // single -, used in JSON too
. '->|->>|#>|#>>|@>|<@|@@|@\?|\?{1}|\?\||\?&|#-'; //JSON searches, Array searchs, etc . '->|->>|#>|#>>|@>|<@|@@|@\?|\?{1}|\?\||\?&|#-|' // JSON searches, Array searchs, etc
. 'THEN|ELSE' // command parts (CASE)
;
/** @var string the main regex including the pattern query split */ /** @var string the main regex including the pattern query split */
private const PATTERN_ELEMENT = '(?:\'.*?\')?\s*(?:' . self::PATTERN_QUERY_SPLIT . ')\s*'; private const PATTERN_ELEMENT = '(?:\'.*?\')?\s*(?:' . self::PATTERN_QUERY_SPLIT . ')\s*';
/** @var string comment regex /** @var string comment regex

View File

@@ -0,0 +1,95 @@
<?php
/**
* AUTHOR: Clemens Schwaighofer
* CREATED: 2025/1/17
* DESCRIPTION:
* Deprecated helper for fputcsv
*/
declare(strict_types=1);
namespace CoreLibs\DeprecatedHelper;
use InvalidArgumentException;
class Deprecated84
{
/**
* This is a wrapper for fputcsv to fix deprecated warning for $escape parameter
* See: https://www.php.net/manual/en/function.fputcsv.php
* escape parameter deprecation and recommend to set to "" for compatible with PHP 9.0
*
* @param mixed $stream
* @param array<mixed> $fields
* @param string $separator
* @param string $enclosure
* @param string $escape
* @param string $eol
* @return int|false
* @throws InvalidArgumentException
*/
public static function fputcsv(
mixed $stream,
array $fields,
string $separator = ",",
string $enclosure = '"',
string $escape = '', // set to empty for future compatible
string $eol = PHP_EOL
): int | false {
if (!is_resource($stream)) {
throw new \InvalidArgumentException("fputcsv stream parameter must be a resrouce");
}
return fputcsv($stream, $fields, $separator, $enclosure, $escape, $eol);
}
/**
* This is a wrapper for fgetcsv to fix deprecated warning for $escape parameter
* See: https://www.php.net/manual/en/function.fgetcsv.php
* escape parameter deprecation and recommend to set to "" for compatible with PHP 9.0
*
* @param mixed $stream
* @param null|int<0,max> $length
* @param string $separator
* @param string $enclosure
* @param string $escape
* @return array<mixed>|false
* @throws InvalidArgumentException
*/
public static function fgetcsv(
mixed $stream,
?int $length = null,
string $separator = ',',
string $enclosure = '"',
string $escape = '' // set to empty for future compatible
): array | false {
if (!is_resource($stream)) {
throw new \InvalidArgumentException("fgetcsv stream parameter must be a resrouce");
}
return fgetcsv($stream, $length, $separator, $enclosure, $escape);
}
/**
* This is a wrapper for str_getcsv to fix deprecated warning for $escape parameter
* See: https://www.php.net/manual/en/function.str-getcsv.php
* escape parameter deprecation and recommend to set to "" for compatible with PHP 9.0
*
* @param string $string
* @param string $separator
* @param string $enclosure
* @param string $escape
* @return array<mixed>
*/
// phpcs:disable PSR1.Methods.CamelCapsMethodName
public static function str_getcsv(
string $string,
string $separator = ",",
string $enclosure = '"',
string $escape = '' // set to empty for future compatible
): array {
return str_getcsv($string, $separator, $enclosure, $escape);
}
// phpcs:enable PSR1.Methods.CamelCapsMethodName
}
// __END__

View File

@@ -30,6 +30,10 @@ class Logging
{ {
/** @var int minimum size for a max file size, so we don't set 1 byte, 10kb */ /** @var int minimum size for a max file size, so we don't set 1 byte, 10kb */
public const MIN_LOG_MAX_FILESIZE = 10 * 1024; public const MIN_LOG_MAX_FILESIZE = 10 * 1024;
/** @var string log file extension, not changeable */
private const LOG_FILE_NAME_EXT = "log";
/** @var string log file block separator, not changeable */
private const LOG_FILE_BLOCK_SEPARATOR = '.';
// NOTE: the second party array{} hs some errors // NOTE: the second party array{} hs some errors
/** @var array<string,array<string,string|bool|Level>>|array{string:array{type:string,type_info?:string,mandatory:true,alias?:string,default:string|bool|Level,deprecated:bool,use?:string}} */ /** @var array<string,array<string,string|bool|Level>>|array{string:array{type:string,type_info?:string,mandatory:true,alias?:string,default:string|bool|Level,deprecated:bool,use?:string}} */
@@ -104,8 +108,6 @@ class Logging
private string $log_folder = ''; private string $log_folder = '';
/** @var string a alphanumeric name that has to be set as global definition */ /** @var string a alphanumeric name that has to be set as global definition */
private string $log_file_id = ''; private string $log_file_id = '';
/** @var string log file name extension */
private string $log_file_name_ext = 'log';
/** @var string log file name with folder, for actual writing */ /** @var string log file name with folder, for actual writing */
private string $log_file_name = ''; private string $log_file_name = '';
/** @var int set in bytes */ /** @var int set in bytes */
@@ -431,7 +433,7 @@ class Logging
private function buildLogFileName(Level $level, string $group_id = ''): string private function buildLogFileName(Level $level, string $group_id = ''): string
{ {
// init base file path // init base file path
$fn = $this->log_print_file . '.' . $this->log_file_name_ext; $fn = $this->log_print_file . '.' . self::LOG_FILE_NAME_EXT;
// log ID prefix settings, if not valid, replace with empty // log ID prefix settings, if not valid, replace with empty
if (!empty($this->log_file_id)) { if (!empty($this->log_file_id)) {
$rpl_string = $this->log_file_id; $rpl_string = $this->log_file_id;
@@ -440,14 +442,15 @@ class Logging
} }
$fn = str_replace('{LOGID}', $rpl_string, $fn); // log id (like a log file prefix) $fn = str_replace('{LOGID}', $rpl_string, $fn); // log id (like a log file prefix)
$rpl_string = !$this->getLogFlag(Flag::per_level) ? '' : $rpl_string = $this->getLogFlag(Flag::per_level) ?
'_' . $level->getName(); self::LOG_FILE_BLOCK_SEPARATOR . $level->getName() :
'';
$fn = str_replace('{LEVEL}', $rpl_string, $fn); // create output filename $fn = str_replace('{LEVEL}', $rpl_string, $fn); // create output filename
// write per level // write per level
$rpl_string = !$this->getLogFlag(Flag::per_group) ? '' : $rpl_string = $this->getLogFlag(Flag::per_group) ?
// normalize level, replace all non alphanumeric characters with - // normalize level, replace all non alphanumeric characters with -
'_' . ( self::LOG_FILE_BLOCK_SEPARATOR . (
// if return is only - then set error string // if return is only - then set error string
preg_match( preg_match(
"/^-+$/", "/^-+$/",
@@ -455,25 +458,29 @@ class Logging
) ? ) ?
'INVALID-LEVEL-STRING' : 'INVALID-LEVEL-STRING' :
$level_string $level_string
); ) :
'';
$fn = str_replace('{GROUP}', $rpl_string, $fn); // create output filename $fn = str_replace('{GROUP}', $rpl_string, $fn); // create output filename
// set per class, but don't use get_class as we will only get self // set per class, but don't use get_class as we will only get self
$rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_' $rpl_string = $this->getLogFlag(Flag::per_class) ?
// set sub class settings // set sub class settings
. str_replace('\\', '-', Support::getCallerTopLevelClass()); self::LOG_FILE_BLOCK_SEPARATOR . str_replace('\\', '-', Support::getCallerTopLevelClass()) :
'';
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file // if request to write to one file
$rpl_string = !$this->getLogFlag(Flag::per_page) ? $rpl_string = $this->getLogFlag(Flag::per_page) ?
'' : self::LOG_FILE_BLOCK_SEPARATOR . System::getPageName(System::NO_EXTENSION) :
'_' . System::getPageName(System::NO_EXTENSION); '';
$fn = str_replace('{PAGENAME}', $rpl_string, $fn); // create output filename $fn = str_replace('{PAGENAME}', $rpl_string, $fn); // create output filename
// if run id, we auto add ymd, so we ignore the log file date // if run id, we auto add ymd, so we ignore the log file date
if ($this->getLogFlag(Flag::per_run)) { if ($this->getLogFlag(Flag::per_run)) {
$rpl_string = '_' . $this->getLogUniqueId(); // add 8 char unique string // add 8 char unique string and date block with time
$rpl_string = self::LOG_FILE_BLOCK_SEPARATOR . $this->getLogUniqueId();
} elseif ($this->getLogFlag(Flag::per_date)) { } elseif ($this->getLogFlag(Flag::per_date)) {
$rpl_string = '_' . $this->getLogDate(); // add date to file // add date to file
$rpl_string = self::LOG_FILE_BLOCK_SEPARATOR . $this->getLogDate();
} else { } else {
$rpl_string = ''; $rpl_string = '';
} }
@@ -739,7 +746,10 @@ class Logging
{ {
if (empty($this->log_file_unique_id) || $override == true) { if (empty($this->log_file_unique_id) || $override == true) {
$this->log_file_unique_id = $this->log_file_unique_id =
date('Y-m-d_His') . '_U_' date('Y-m-d_His')
. self::LOG_FILE_BLOCK_SEPARATOR
. 'U_'
// this doesn't have to be unique for everything, just for this logging purpose
. substr(hash( . substr(hash(
'sha1', 'sha1',
random_bytes(63) random_bytes(63)

View File

@@ -0,0 +1,408 @@
<?php
/**
* very simple asymmetric encryption
* Better use:
* https://paragonie.com/project/halite
* https://github.com/paragonie/halite
*
* current code is just to encrypt and decrypt
*
* must use a valid encryption key created with
* Secruty\CreateKey class
*/
declare(strict_types=1);
namespace CoreLibs\Security;
use CoreLibs\Security\CreateKey;
use SodiumException;
class AsymmetricAnonymousEncryption
{
/** @var AsymmetricAnonymousEncryption self instance */
private static AsymmetricAnonymousEncryption $instance;
/** @var ?string key pair which holds secret and public key, needed for encryption */
private ?string $key_pair = null;
/** @var ?string public key, needed for decryption
* if not set but key_pair set, this will be extracted from key pair */
private ?string $public_key = null;
/**
* init class
* if key not passed, key must be set with createKey
*
* @param string|null $key_pair
* @param string|null $public_key
*/
public function __construct(
#[\SensitiveParameter]
string|null $key_pair = null,
string|null $public_key = null
) {
if ($public_key !== null) {
$this->setPublicKey($public_key);
}
if ($key_pair !== null) {
$this->setKeyPair($key_pair);
if (empty($public_key)) {
$public_key = CreateKey::getPublicKey($key_pair);
$this->setPublicKey($public_key);
}
}
}
/**
* Returns the singleton self object.
* For function wrapper use
*
* @param string|null $key_pair
* @param string|null $public_key
* @return AsymmetricAnonymousEncryption object
*/
public static function getInstance(
#[\SensitiveParameter]
string|null $key_pair = null,
string|null $public_key = null
): self {
// new if no instsance or key is different
if (
empty(self::$instance) ||
self::$instance->key_pair != $key_pair ||
self::$instance->public_key != $public_key
) {
self::$instance = new self($key_pair, $public_key);
}
return self::$instance;
}
/**
* clean up
*/
public function __destruct()
{
if (empty($this->key_pair)) {
return;
}
try {
// would set it to null, but we we do not want to make key null
sodium_memzero($this->key_pair);
return;
} catch (SodiumException) {
// empty catch
}
if (is_null($this->key_pair)) {
return;
}
$zero = str_repeat("\0", mb_strlen($this->key_pair, '8bit'));
$this->key_pair = $this->key_pair ^ (
$zero ^ $this->key_pair
);
unset($zero);
unset($this->key_pair); /** @phan-suppress-current-line PhanTypeObjectUnsetDeclaredProperty */
}
/* ************************************************************************
* MARK: PRIVATE
* *************************************************************************/
/**
* Create the internal key pair in binary
*
* @param ?string $key_pair
* @return string
* @throws \UnexpectedValueException key pair empty
* @throws \UnexpectedValueException invalid hex key pair
* @throws \RangeException key pair not correct size
*/
private function createKeyPair(
#[\SensitiveParameter]
?string $key_pair
): string {
if (empty($key_pair)) {
throw new \UnexpectedValueException('Key pair cannot be empty');
}
try {
$key_pair = CreateKey::hex2bin($key_pair);
} catch (SodiumException $e) {
sodium_memzero($key_pair);
throw new \UnexpectedValueException('Invalid hex key pair: ' . $e->getMessage());
}
if (mb_strlen($key_pair, '8bit') !== SODIUM_CRYPTO_BOX_KEYPAIRBYTES) {
sodium_memzero($key_pair);
throw new \RangeException(
'Key pair is not the correct size (must be '
. SODIUM_CRYPTO_BOX_KEYPAIRBYTES . ' bytes long).'
);
}
return $key_pair;
}
/**
* create the internal public key in binary
*
* @param ?string $public_key
* @return string
* @throws \UnexpectedValueException public key empty
* @throws \UnexpectedValueException invalid hex key
* @throws \RangeException invalid key length
*/
private function createPublicKey(?string $public_key): string
{
if (empty($public_key)) {
throw new \UnexpectedValueException('Public key cannot be empty');
}
try {
$public_key = CreateKey::hex2bin($public_key);
} catch (SodiumException $e) {
sodium_memzero($public_key);
throw new \UnexpectedValueException('Invalid hex public key: ' . $e->getMessage());
}
if (mb_strlen($public_key, '8bit') !== SODIUM_CRYPTO_BOX_PUBLICKEYBYTES) {
sodium_memzero($public_key);
throw new \RangeException(
'Public key is not the correct size (must be '
. SODIUM_CRYPTO_BOX_PUBLICKEYBYTES . ' bytes long).'
);
}
return $public_key;
}
/**
* encrypt a message asymmetric with a bpulic key
*
* @param string $message
* @param ?string $public_key
* @return string
* @throws \UnexpectedValueException create encryption failed
* @throws \UnexpectedValueException convert to base64 failed
*/
private function asymmetricEncryption(
#[\SensitiveParameter]
string $message,
?string $public_key
): string {
$public_key = $this->createPublicKey($public_key);
try {
$encrypted = sodium_crypto_box_seal($message, $public_key);
} catch (SodiumException $e) {
sodium_memzero($message);
throw new \UnexpectedValueException("Create encrypted message failed: " . $e->getMessage());
}
sodium_memzero($message);
try {
$result = sodium_bin2base64($encrypted, SODIUM_BASE64_VARIANT_ORIGINAL);
} catch (SodiumException $e) {
sodium_memzero($encrypted);
throw new \UnexpectedValueException("bin2base64 failed: " . $e->getMessage());
}
sodium_memzero($encrypted);
return $result;
}
/**
* decrypt a message that is asymmetric encrypted with a key pair
*
* @param string $message
* @param ?string $key_pair
* @return string
* @throws \UnexpectedValueException message string empty
* @throws \UnexpectedValueException base64 decoding failed
* @throws \UnexpectedValueException decryption failed
* @throws \UnexpectedValueException could not decrypt message
*/
private function asymmetricDecryption(
#[\SensitiveParameter]
string $message,
#[\SensitiveParameter]
?string $key_pair
): string {
if (empty($message)) {
throw new \UnexpectedValueException('Encrypted string cannot be empty');
}
$key_pair = $this->createKeyPair($key_pair);
try {
$result = sodium_base642bin($message, SODIUM_BASE64_VARIANT_ORIGINAL);
} catch (SodiumException $e) {
sodium_memzero($message);
sodium_memzero($key_pair);
throw new \UnexpectedValueException("base642bin failed: " . $e->getMessage());
}
sodium_memzero($message);
$plaintext = false;
try {
$plaintext = sodium_crypto_box_seal_open($result, $key_pair);
} catch (SodiumException $e) {
sodium_memzero($message);
sodium_memzero($key_pair);
sodium_memzero($result);
throw new \UnexpectedValueException("Decrypting message failed: " . $e->getMessage());
}
sodium_memzero($key_pair);
sodium_memzero($result);
if (!is_string($plaintext)) {
throw new \UnexpectedValueException('Invalid key pair');
}
return $plaintext;
}
/* ************************************************************************
* MARK: PUBLIC
* *************************************************************************/
/**
* sets the private key for encryption
*
* @param string $key_pair Key pair in hex
* @return AsymmetricAnonymousEncryption
* @throws \UnexpectedValueException key pair empty
*/
public function setKeyPair(
#[\SensitiveParameter]
string $key_pair
): AsymmetricAnonymousEncryption {
if (empty($key_pair)) {
throw new \UnexpectedValueException('Key pair cannot be empty');
}
// check if valid;
$this->createKeyPair($key_pair);
// set new key pair
$this->key_pair = $key_pair;
sodium_memzero($key_pair);
// set public key if not set
if (empty($this->public_key)) {
$this->public_key = CreateKey::getPublicKey($this->key_pair);
// check if valid
$this->createPublicKey($this->public_key);
}
return $this;
}
/**
* check if set key pair matches given one
*
* @param string $key_pair
* @return bool
*/
public function compareKeyPair(
#[\SensitiveParameter]
string $key_pair
): bool {
return $this->key_pair === $key_pair;
}
/**
* get the current set key pair, null if not set
*
* @return string|null
*/
public function getKeyPair(): ?string
{
return $this->key_pair;
}
/**
* sets the public key for decryption
* if only key pair exists Security\Create::getPublicKey() can be used to
* extract the public key from the key pair
*
* @param string $public_key Public Key in hex
* @return AsymmetricAnonymousEncryption
* @throws \UnexpectedValueException public key empty
*/
public function setPublicKey(string $public_key): AsymmetricAnonymousEncryption
{
if (empty($public_key)) {
throw new \UnexpectedValueException('Public key cannot be empty');
}
// check if valid
$this->createPublicKey($public_key);
$this->public_key = $public_key;
sodium_memzero($public_key);
return $this;
}
/**
* check if the set public key matches the given one
*
* @param string $public_key
* @return bool
*/
public function comparePublicKey(string $public_key): bool
{
return $this->public_key === $public_key;
}
/**
* get the current set public key, null if not set
*
* @return string|null
*/
public function getPublicKey(): ?string
{
return $this->public_key;
}
/**
* Encrypt a message with a public key
* static version
*
* @param string $message Message to encrypt
* @param string $public_key Public key in hex to encrypt message with
* @return string Encrypted message as hex string
*/
public static function encryptKey(
#[\SensitiveParameter]
string $message,
string $public_key
): string {
return self::getInstance()->asymmetricEncryption($message, $public_key);
}
/**
* Encrypt a message
*
* @param string $message Message to ecnrypt
* @return string Encrypted message as hex string
*/
public function encrypt(
#[\SensitiveParameter]
string $message
): string {
return $this->asymmetricEncryption($message, $this->public_key);
}
/**
* decrypt a message with a key pair
* static version
*
* @param string $message Message to decrypt in hex
* @param string $key_pair Key pair in hex to decrypt the message with
* @return string Decrypted message
*/
public static function decryptKey(
#[\SensitiveParameter]
string $message,
#[\SensitiveParameter]
string $key_pair
): string {
return self::getInstance()->asymmetricDecryption($message, $key_pair);
}
/**
* decrypt a message
*
* @param string $message Message to decrypt in hex
* @return string Decrypted message
*/
public function decrypt(
#[\SensitiveParameter]
string $message
): string {
return $this->asymmetricDecryption($message, $this->key_pair);
}
}
// __END__

View File

@@ -35,14 +35,39 @@ class CreateKey
return random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); return random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
} }
/**
* creates a sodium cyptobox keypair as hex string
*
* @return string hex string for the keypair
*/
public static function createKeyPair(): string
{
return self::bin2hex(sodium_crypto_box_keypair());
}
/**
* extracts the public key and returns it as hex string from the hex keypari
*
* @param string $hex_keypair hex encoded keypair
* @return string hex encoded public key
*/
public static function getPublicKey(
#[\SensitiveParameter]
string $hex_keypair
): string {
return self::bin2hex(sodium_crypto_box_publickey(self::hex2bin($hex_keypair)));
}
/** /**
* convert binary key to hex string * convert binary key to hex string
* *
* @param string $hex_key Convert binary key string to hex * @param string $hex_key Convert binary key string to hex
* @return string * @return string
*/ */
public static function bin2hex(string $hex_key): string public static function bin2hex(
{ #[\SensitiveParameter]
string $hex_key
): string {
return sodium_bin2hex($hex_key); return sodium_bin2hex($hex_key);
} }
@@ -52,8 +77,10 @@ class CreateKey
* @param string $string_key Convery hex key string to binary * @param string $string_key Convery hex key string to binary
* @return string * @return string
*/ */
public static function hex2bin(string $string_key): string public static function hex2bin(
{ #[\SensitiveParameter]
string $string_key
): string {
return sodium_hex2bin($string_key); return sodium_hex2bin($string_key);
} }
} }

View File

@@ -16,8 +16,10 @@ class Password
* @param string $password password * @param string $password password
* @return string hashed password * @return string hashed password
*/ */
public static function passwordSet(string $password): string public static function passwordSet(
{ #[\SensitiveParameter]
string $password
): string {
// always use the PHP default for the password // always use the PHP default for the password
// password options ca be set in the password init, // password options ca be set in the password init,
// but should be kept as default // but should be kept as default
@@ -31,8 +33,11 @@ class Password
* @param string $hash password hash * @param string $hash password hash
* @return bool true or false * @return bool true or false
*/ */
public static function passwordVerify(string $password, string $hash): bool public static function passwordVerify(
{ #[\SensitiveParameter]
string $password,
string $hash
): bool {
if (password_verify($password, $hash)) { if (password_verify($password, $hash)) {
return true; return true;
} else { } else {

View File

@@ -24,19 +24,19 @@ class SymmetricEncryption
/** @var SymmetricEncryption self instance */ /** @var SymmetricEncryption self instance */
private static SymmetricEncryption $instance; private static SymmetricEncryption $instance;
/** @var string bin hex key */ /** @var ?string bin hex key */
private string $key = ''; private ?string $key = null;
/** /**
* init class * init class
* if key not passed, key must be set with createKey * if key not passed, key must be set with createKey
* *
* @param string|null|null $key * @param string|null $key encryption key
*/ */
public function __construct( public function __construct(
string|null $key = null ?string $key = null
) { ) {
if ($key != null) { if ($key !== null) {
$this->setKey($key); $this->setKey($key);
} }
} }
@@ -45,9 +45,10 @@ class SymmetricEncryption
* Returns the singleton self object. * Returns the singleton self object.
* For function wrapper use * For function wrapper use
* *
* @param string|null $key encryption key
* @return SymmetricEncryption object * @return SymmetricEncryption object
*/ */
public static function getInstance(string|null $key = null): self public static function getInstance(?string $key = null): self
{ {
// new if no instsance or key is different // new if no instsance or key is different
if ( if (
@@ -59,6 +60,34 @@ class SymmetricEncryption
return self::$instance; return self::$instance;
} }
/**
* clean up
*
* @return void
*/
public function __deconstruct()
{
if (empty($this->key)) {
return;
}
try {
// would set it to null, but we we do not want to make key null
sodium_memzero($this->key);
return;
} catch (SodiumException) {
// empty catch
}
if (is_null($this->key)) {
return;
}
$zero = str_repeat("\0", mb_strlen($this->key, '8bit'));
$this->key = $this->key ^ (
$zero ^ $this->key
);
unset($zero);
unset($this->key); /** @phan-suppress-current-line PhanTypeObjectUnsetDeclaredProperty */
}
/* ************************************************************************ /* ************************************************************************
* MARK: PRIVATE * MARK: PRIVATE
* *************************************************************************/ * *************************************************************************/
@@ -66,11 +95,19 @@ class SymmetricEncryption
/** /**
* create key and check validity * create key and check validity
* *
* @param string $key The key from which the binary key will be created * @param ?string $key The key from which the binary key will be created
* @return string Binary key string * @return string Binary key string
* @throws \UnexpectedValueException empty key
* @throws \UnexpectedValueException invalid hex key
* @throws \RangeException invalid length
*/ */
private function createKey(string $key): string private function createKey(
{ #[\SensitiveParameter]
?string $key
): string {
if (empty($key)) {
throw new \UnexpectedValueException('Key cannot be empty');
}
try { try {
$key = CreateKey::hex2bin($key); $key = CreateKey::hex2bin($key);
} catch (SodiumException $e) { } catch (SodiumException $e) {
@@ -91,36 +128,42 @@ class SymmetricEncryption
* @param string $encrypted Text to decrypt * @param string $encrypted Text to decrypt
* @param ?string $key Mandatory encryption key, will throw exception if empty * @param ?string $key Mandatory encryption key, will throw exception if empty
* @return string Plain text * @return string Plain text
* @throws \RangeException * @throws \UnexpectedValueException key cannot be empty
* @throws \UnexpectedValueException * @throws \UnexpectedValueException decipher message failed
* @throws \UnexpectedValueException * @throws \UnexpectedValueException invalid key
*/ */
private function decryptData(string $encrypted, ?string $key): string private function decryptData(
{ #[\SensitiveParameter]
if (empty($key)) { string $encrypted,
throw new \UnexpectedValueException('Key not set'); #[\SensitiveParameter]
?string $key
): string {
if (empty($encrypted)) {
throw new \UnexpectedValueException('Encrypted string cannot be empty');
} }
$key = $this->createKey($key); $key = $this->createKey($key);
$decoded = base64_decode($encrypted); $decoded = base64_decode($encrypted);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); $ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plain = false; $plaintext = false;
try { try {
$plain = sodium_crypto_secretbox_open( $plaintext = sodium_crypto_secretbox_open(
$ciphertext, $ciphertext,
$nonce, $nonce,
$key $key
); );
} catch (SodiumException $e) { } catch (SodiumException $e) {
sodium_memzero($ciphertext);
sodium_memzero($key);
throw new \UnexpectedValueException('Decipher message failed: ' . $e->getMessage()); throw new \UnexpectedValueException('Decipher message failed: ' . $e->getMessage());
} }
if (!is_string($plain)) {
throw new \UnexpectedValueException('Invalid Key');
}
sodium_memzero($ciphertext); sodium_memzero($ciphertext);
sodium_memzero($key); sodium_memzero($key);
return $plain; if (!is_string($plaintext)) {
throw new \UnexpectedValueException('Invalid Key');
}
return $plaintext;
} }
/** /**
@@ -128,15 +171,15 @@ class SymmetricEncryption
* *
* @param string $message Message to encrypt * @param string $message Message to encrypt
* @param ?string $key Mandatory encryption key, will throw exception if empty * @param ?string $key Mandatory encryption key, will throw exception if empty
* @return string * @return string Ciphered text
* @throws \Exception * @throws \UnexpectedValueException create message failed
* @throws \RangeException
*/ */
private function encryptData(string $message, ?string $key): string private function encryptData(
{ #[\SensitiveParameter]
if ($key === null) { string $message,
throw new \UnexpectedValueException('Key not set'); #[\SensitiveParameter]
} ?string $key
): string {
$key = $this->createKey($key); $key = $this->createKey($key);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
try { try {
@@ -149,6 +192,8 @@ class SymmetricEncryption
) )
); );
} catch (SodiumException $e) { } catch (SodiumException $e) {
sodium_memzero($message);
sodium_memzero($key);
throw new \UnexpectedValueException("Create encrypted message failed: " . $e->getMessage()); throw new \UnexpectedValueException("Create encrypted message failed: " . $e->getMessage());
} }
sodium_memzero($message); sodium_memzero($message);
@@ -160,19 +205,49 @@ class SymmetricEncryption
* MARK: PUBLIC * MARK: PUBLIC
* *************************************************************************/ * *************************************************************************/
/** /**
* set a new key for encryption * set a new key for encryption
* *
* @param string $key * @param string $key
* @return void * @return SymmetricEncryption
* @throws \UnexpectedValueException key cannot be empty
*/ */
public function setKey(string $key) public function setKey(
{ #[\SensitiveParameter]
string $key
): SymmetricEncryption {
if (empty($key)) { if (empty($key)) {
throw new \UnexpectedValueException('Key cannot be empty'); throw new \UnexpectedValueException('Key cannot be empty');
} }
// check that this is a valid key
$this->createKey($key);
// set key
$this->key = $key; $this->key = $key;
sodium_memzero($key);
return $this;
}
/**
* Checks if set key is equal to parameter key
*
* @param string $key
* @return bool
*/
public function compareKey(
#[\SensitiveParameter]
string $key
): bool {
return $key === $this->key;
}
/**
* returns the current set key, null if not set
*
* @return ?string
*/
public function getKey(): ?string
{
return $this->key;
} }
/** /**
@@ -182,13 +257,13 @@ class SymmetricEncryption
* @param string $encrypted Message encrypted with safeEncrypt() * @param string $encrypted Message encrypted with safeEncrypt()
* @param string $key Encryption key (as hex string) * @param string $key Encryption key (as hex string)
* @return string * @return string
* @throws \Exception
* @throws \RangeException
* @throws \UnexpectedValueException
* @throws \UnexpectedValueException
*/ */
public static function decryptKey(string $encrypted, string $key): string public static function decryptKey(
{ #[\SensitiveParameter]
string $encrypted,
#[\SensitiveParameter]
string $key
): string {
return self::getInstance()->decryptData($encrypted, $key); return self::getInstance()->decryptData($encrypted, $key);
} }
@@ -197,12 +272,11 @@ class SymmetricEncryption
* *
* @param string $encrypted Message encrypted with safeEncrypt() * @param string $encrypted Message encrypted with safeEncrypt()
* @return string * @return string
* @throws \RangeException
* @throws \UnexpectedValueException
* @throws \UnexpectedValueException
*/ */
public function decrypt(string $encrypted): string public function decrypt(
{ #[\SensitiveParameter]
string $encrypted
): string {
return $this->decryptData($encrypted, $this->key); return $this->decryptData($encrypted, $this->key);
} }
@@ -213,11 +287,13 @@ class SymmetricEncryption
* @param string $message Message to encrypt * @param string $message Message to encrypt
* @param string $key Encryption key (as hex string) * @param string $key Encryption key (as hex string)
* @return string * @return string
* @throws \Exception
* @throws \RangeException
*/ */
public static function encryptKey(string $message, string $key): string public static function encryptKey(
{ #[\SensitiveParameter]
string $message,
#[\SensitiveParameter]
string $key
): string {
return self::getInstance()->encryptData($message, $key); return self::getInstance()->encryptData($message, $key);
} }
@@ -226,11 +302,11 @@ class SymmetricEncryption
* *
* @param string $message Message to encrypt * @param string $message Message to encrypt
* @return string * @return string
* @throws \Exception
* @throws \RangeException
*/ */
public function encrypt(string $message): string public function encrypt(
{ #[\SensitiveParameter]
string $message
): string {
return $this->encryptData($message, $this->key); return $this->encryptData($message, $this->key);
} }
} }

View File

@@ -19,12 +19,13 @@ declare(strict_types=1);
namespace CoreLibs\Template; namespace CoreLibs\Template;
// leading slash if this is in lib\Smarty class SmartyExtend extends \Smarty\Smarty
class SmartyExtend extends \Smarty
{ {
// internal translation engine // internal translation engine
/** @var \CoreLibs\Language\L10n */ /** @var \CoreLibs\Language\L10n language class */
public \CoreLibs\Language\L10n $l10n; public \CoreLibs\Language\L10n $l10n;
/** @var \CoreLibs\Logging\Logging $log logging class */
public \CoreLibs\Logging\Logging $log;
// lang & encoding // lang & encoding
/** @var string */ /** @var string */
@@ -157,14 +158,18 @@ class SmartyExtend extends \Smarty
* calls L10 for pass on internaly in smarty * calls L10 for pass on internaly in smarty
* also registers the getvar caller plugin * also registers the getvar caller plugin
* *
* @param \CoreLibs\Language\L10n $l10n l10n language class * @param \CoreLibs\Language\L10n $l10n l10n language class
* @param string|null $cache_id * @param \CoreLibs\Logging\Logging $log Logger class
* @param string|null $compile_id * @param string|null $cache_id [default=null]
* @param string|null $compile_id [default=null]
* @param array<string,mixed> $options [default=[]]
*/ */
public function __construct( public function __construct(
\CoreLibs\Language\L10n $l10n, \CoreLibs\Language\L10n $l10n,
\CoreLibs\Logging\Logging $log,
?string $cache_id = null, ?string $cache_id = null,
?string $compile_id = null ?string $compile_id = null,
array $options = []
) { ) {
// trigger deprecation // trigger deprecation
if ( if (
@@ -177,14 +182,33 @@ class SmartyExtend extends \Smarty
E_USER_DEPRECATED E_USER_DEPRECATED
); );
} }
// set variables (to be deprecated) // set variables from global constants (deprecated)
$cache_id = $cache_id ?? if ($cache_id === null && defined('CACHE_ID')) {
(defined('CACHE_ID') ? CACHE_ID : ''); trigger_error(
$compile_id = $compile_id ?? 'SmartyExtended: No cache_id set and CACHE_ID constant set, this is deprecated',
(defined('COMPILE_ID') ? COMPILE_ID : ''); E_USER_DEPRECATED
);
$cache_id = CACHE_ID;
}
if ($compile_id === null && defined('COMPILE_ID')) {
trigger_error(
'SmartyExtended: No compile_id set and COMPILE_ID constant set, this is deprecated',
E_USER_DEPRECATED
);
$compile_id = COMPILE_ID;
}
if (empty($cache_id)) {
throw new \BadMethodCallException('cache_id parameter is not set');
}
if (empty($compile_id)) {
throw new \BadMethodCallException('compile_id parameter is not set');
}
// call basic smarty // call basic smarty
// or Smarty::__construct();
parent::__construct(); parent::__construct();
$this->log = $log;
// init lang // init lang
$this->l10n = $l10n; $this->l10n = $l10n;
// parse and read, legacy stuff // parse and read, legacy stuff
@@ -194,7 +218,6 @@ class SmartyExtend extends \Smarty
$this->lang_short = $locale['lang_short']; $this->lang_short = $locale['lang_short'];
$this->domain = $locale['domain']; $this->domain = $locale['domain'];
$this->lang_dir = $locale['path']; $this->lang_dir = $locale['path'];
// opt load functions so we can use legacy init for smarty run perhaps // opt load functions so we can use legacy init for smarty run perhaps
\CoreLibs\Language\L10n::loadFunctions(); \CoreLibs\Language\L10n::loadFunctions();
_setlocale(LC_MESSAGES, $locale['locale']); _setlocale(LC_MESSAGES, $locale['locale']);
@@ -203,7 +226,6 @@ class SmartyExtend extends \Smarty
_bind_textdomain_codeset($this->domain, $this->encoding); _bind_textdomain_codeset($this->domain, $this->encoding);
// register smarty variable // register smarty variable
// $this->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'getvar', [&$this, 'getTemplateVars']);
$this->registerPlugin(self::PLUGIN_MODIFIER, 'getvar', [&$this, 'getTemplateVars']); $this->registerPlugin(self::PLUGIN_MODIFIER, 'getvar', [&$this, 'getTemplateVars']);
$this->page_name = \CoreLibs\Get\System::getPageName(); $this->page_name = \CoreLibs\Get\System::getPageName();
@@ -211,6 +233,77 @@ class SmartyExtend extends \Smarty
// set internal settings // set internal settings
$this->CACHE_ID = $cache_id; $this->CACHE_ID = $cache_id;
$this->COMPILE_ID = $compile_id; $this->COMPILE_ID = $compile_id;
// set options
$this->setOptions($options);
}
/**
* set options
*
* @param array<string,mixed> $options
* @return void
*/
private function setOptions(array $options): void
{
// set escape html if option is set
if (!empty($options['escape_html'])) {
$this->setEscapeHtml(true);
}
// load plugins
// plugin array:
// 'file': string, path to plugin content to load
// 'type': a valid smarty type see Smarty PLUGIN_ constants for correct names
// 'tag': the smarty tag
// 'callback': the function to call in 'file'
if (!empty($options['plugins'])) {
foreach ($options['plugins'] as $plugin) {
// file is readable
if (
empty($plugin['file']) ||
!is_file($plugin['file']) ||
!is_readable($plugin['file'])
) {
$this->log->warning('SmartyExtended plugin load failed, file not accessable', [
'plugin' => $plugin,
]);
continue;
}
// tag is alphanumeric
if (!preg_match("/^\w+$/", $plugin['tag'] ?? '')) {
$this->log->warning('SmartyExtended plugin load failed, invalid tag', [
'plugin' => $plugin,
]);
continue;
}
// callback is alphanumeric
if (!preg_match("/^\w+$/", $plugin['callback'] ?? '')) {
$this->log->warning('SmartyExtended plugin load failed, invalid callback', [
'plugin' => $plugin,
]);
continue;
}
try {
/** @phan-suppress-next-line PhanNoopNew */
new \ReflectionClassConstant($this, $plugin['type']);
} catch (\ReflectionException $e) {
$this->log->error('SmartyExtended plugin load failed, type is not valid', [
'message' => $e->getMessage(),
'plugin' => $plugin,
]);
continue;
}
try {
require $plugin['file'];
$this->registerPlugin($plugin['type'], $plugin['tag'], $plugin['callback']);
} catch (\Smarty\Exception $e) {
$this->log->error('SmartyExtended plugin load failed with exception', [
'message' => $e->getMessage(),
'plugin' => $plugin,
]);
continue;
}
}
}
} }
/** /**

View File

@@ -46,19 +46,19 @@ class qqUploadedFileXhr implements qqUploadedFile // phpcs:ignore Squiz.Classes.
*/ */
public function getName(): string public function getName(): string
{ {
return $_GET['qqfile'] ?? ''; return !empty($_GET['qqfile']) && is_string($_GET['qqfile']) ? $_GET['qqfile'] : '';
} }
/** /**
* Get file size from _SERVERa array, throws an error if not possible * Get file size from _SERVERa array, throws an error if not possible
* *
* @return int * @return int size of the file
* *
* @throws \Exception * @throws \Exception
*/ */
public function getSize(): int public function getSize(): int
{ {
if (isset($_SERVER['CONTENT_LENGTH'])) { if (isset($_SERVER['CONTENT_LENGTH']) && is_numeric($_SERVER['CONTENT_LENGTH'])) {
return (int)$_SERVER['CONTENT_LENGTH']; return (int)$_SERVER['CONTENT_LENGTH'];
} else { } else {
throw new \Exception('Getting content length is not supported.'); throw new \Exception('Getting content length is not supported.');