Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c010673705 | |||
| b16ff4c613 | |||
| e9c791c164 | |||
| c7ec1300b7 | |||
| 064710324e | |||
| e0356dcadf | |||
| 62a5992e3a | |||
| 6bb957fcb3 | |||
| 0c1f060759 | |||
| aad46ec80a | |||
| f5e9f0610d | |||
| 14a5250cd7 | |||
| 6e6edef57d | |||
| d3810db965 | |||
| 187a012284 | |||
| b3d2662fd2 | |||
| 1189aecae9 |
@@ -1 +1 @@
|
|||||||
8.1.2
|
8.4.0
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ fi;
|
|||||||
# read in the .env.deploy file and we must have
|
# read in the .env.deploy file and we must have
|
||||||
# GITLAB_USER
|
# GITLAB_USER
|
||||||
# GITLAB_TOKEN
|
# GITLAB_TOKEN
|
||||||
|
# GITLAB_URL
|
||||||
|
# GITEA_USER
|
||||||
# GITEA_DEPLOY_TOKEN
|
# GITEA_DEPLOY_TOKEN
|
||||||
|
# GITEA_URL_DL
|
||||||
|
# GITEA_URL_PUSH
|
||||||
if [ ! -f "${BASE_FOLDER}.env.deploy" ]; then
|
if [ ! -f "${BASE_FOLDER}.env.deploy" ]; then
|
||||||
echo "Deploy enviroment file .env.deploy is missing";
|
echo "Deploy enviroment file .env.deploy is missing";
|
||||||
exit;
|
exit;
|
||||||
@@ -33,26 +37,27 @@ set +o allexport;
|
|||||||
|
|
||||||
echo "[START]";
|
echo "[START]";
|
||||||
# gitea
|
# gitea
|
||||||
if [ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
|
if [ ! -z "${GITEA_URL_DL}" ] && [ ! -z "${GITEA_URL_PUSH}" ] &&
|
||||||
|
[ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
|
||||||
curl -LJO \
|
curl -LJO \
|
||||||
--output-dir "${BASE_FOLDER}" \
|
--output-dir "${BASE_FOLDER}" \
|
||||||
https://git.egplusww.jp/Composer/CoreLibs-Composer-All/archive/v${VERSION}.zip;
|
${GITEA_URL_DL}/v${VERSION}.zip;
|
||||||
curl --user ${GITEA_USER}:${GITEA_TOKEN} \
|
curl --user ${GITEA_USER}:${GITEA_TOKEN} \
|
||||||
--upload-file "${BASE_FOLDER}/CoreLibs-Composer-All-v${VERSION}.zip" \
|
--upload-file "${BASE_FOLDER}/CoreLibs-Composer-All-v${VERSION}.zip" \
|
||||||
https://git.egplusww.jp/api/packages/Composer/composer?version=${VERSION};
|
${GITEA_URL_PUSH}?version=${VERSION};
|
||||||
echo "${VERSION}" > "${file_last_published}";
|
echo "${VERSION}" > "${file_last_published}";
|
||||||
else
|
else
|
||||||
echo "Missing either GITEA_USER or GITEA_TOKEN environment variable";
|
echo "Missing either GITEA_USER or GITEA_TOKEN environment variable";
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
# gitlab
|
# gitlab
|
||||||
if [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
|
if [ ! -z "${GITLAB_URL}" ] && [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
|
||||||
curl --data tag=v${VERSION} \
|
curl --data tag=v${VERSION} \
|
||||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||||
"https://gitlab-na.factory.tools/api/v4/projects/950/packages/composer";
|
"${GITLAB_URL}";
|
||||||
curl --data branch=master \
|
curl --data branch=master \
|
||||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||||
"https://gitlab-na.factory.tools/api/v4/projects/950/packages/composer";
|
"${GITLAB_URL}";
|
||||||
echo "${VERSION}" > "${file_last_published}";
|
echo "${VERSION}" > "${file_last_published}";
|
||||||
else
|
else
|
||||||
echo "Missing GITLAB_DEPLOY_TOKEN environment variable";
|
echo "Missing GITLAB_DEPLOY_TOKEN environment variable";
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace CoreLibs\ACL;
|
namespace CoreLibs\ACL;
|
||||||
|
|
||||||
use CoreLibs\Check\Password;
|
use CoreLibs\Security\Password;
|
||||||
|
use CoreLibs\Convert\Json;
|
||||||
|
|
||||||
class Login
|
class Login
|
||||||
{
|
{
|
||||||
@@ -753,7 +754,10 @@ class Login
|
|||||||
// we have to get the themes in here too
|
// we have to get the themes in here too
|
||||||
$q = "SELECT eu.edit_user_id, eu.username, eu.password, "
|
$q = "SELECT eu.edit_user_id, eu.username, eu.password, "
|
||||||
. "eu.edit_group_id, "
|
. "eu.edit_group_id, "
|
||||||
. "eg.name AS edit_group_name, admin, "
|
. "eg.name AS edit_group_name, eu.admin, "
|
||||||
|
// additinal acl lists
|
||||||
|
. "eu.additional_acl AS user_additional_acl, "
|
||||||
|
. "eg.additional_acl AS group_additional_acl, "
|
||||||
// login error + locked
|
// login error + locked
|
||||||
. "eu.login_error_count, eu.login_error_date_last, "
|
. "eu.login_error_count, eu.login_error_date_last, "
|
||||||
. "eu.login_error_date_first, eu.strict, eu.locked, "
|
. "eu.login_error_date_first, eu.strict, eu.locked, "
|
||||||
@@ -901,8 +905,10 @@ class Login
|
|||||||
$_SESSION['GROUP_NAME'] = $res['edit_group_name'];
|
$_SESSION['GROUP_NAME'] = $res['edit_group_name'];
|
||||||
$_SESSION['USER_ACL_LEVEL'] = $res['user_level'];
|
$_SESSION['USER_ACL_LEVEL'] = $res['user_level'];
|
||||||
$_SESSION['USER_ACL_TYPE'] = $res['user_type'];
|
$_SESSION['USER_ACL_TYPE'] = $res['user_type'];
|
||||||
|
$_SESSION['USER_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['user_additional_acl']);
|
||||||
$_SESSION['GROUP_ACL_LEVEL'] = $res['group_level'];
|
$_SESSION['GROUP_ACL_LEVEL'] = $res['group_level'];
|
||||||
$_SESSION['GROUP_ACL_TYPE'] = $res['group_type'];
|
$_SESSION['GROUP_ACL_TYPE'] = $res['group_type'];
|
||||||
|
$_SESSION['GROUP_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['group_additional_acl']);
|
||||||
// deprecated TEMPLATE setting
|
// deprecated TEMPLATE setting
|
||||||
$_SESSION['TEMPLATE'] = $res['template'] ? $res['template'] : '';
|
$_SESSION['TEMPLATE'] = $res['template'] ? $res['template'] : '';
|
||||||
$_SESSION['HEADER_COLOR'] = !empty($res['second_header_color']) ?
|
$_SESSION['HEADER_COLOR'] = !empty($res['second_header_color']) ?
|
||||||
@@ -1021,7 +1027,8 @@ class Login
|
|||||||
$_SESSION['PAGES'] = $pages;
|
$_SESSION['PAGES'] = $pages;
|
||||||
$_SESSION['PAGES_ACL_LEVEL'] = $pages_acl;
|
$_SESSION['PAGES_ACL_LEVEL'] = $pages_acl;
|
||||||
// load the edit_access user rights
|
// load the edit_access user rights
|
||||||
$q = "SELECT ea.edit_access_id, level, type, ea.name, ea.color, ea.uid, edit_default "
|
$q = "SELECT ea.edit_access_id, level, type, ea.name, "
|
||||||
|
. "ea.color, ea.uid, edit_default, ea.additional_acl "
|
||||||
. "FROM edit_access_user eau, edit_access_right ear, edit_access ea "
|
. "FROM edit_access_user eau, edit_access_right ear, edit_access ea "
|
||||||
. "WHERE eau.edit_access_id = ea.edit_access_id "
|
. "WHERE eau.edit_access_id = ea.edit_access_id "
|
||||||
. "AND eau.edit_access_right_id = ear.edit_access_right_id "
|
. "AND eau.edit_access_right_id = ear.edit_access_right_id "
|
||||||
@@ -1048,6 +1055,7 @@ class Login
|
|||||||
'uid' => $res['uid'],
|
'uid' => $res['uid'],
|
||||||
'color' => $res['color'],
|
'color' => $res['color'],
|
||||||
'default' => $res['edit_default'],
|
'default' => $res['edit_default'],
|
||||||
|
'additional_acl' => Json::jsonConvertToArray($res['additional_acl']),
|
||||||
'data' => $ea_data
|
'data' => $ea_data
|
||||||
];
|
];
|
||||||
// set the default unit
|
// set the default unit
|
||||||
@@ -1122,6 +1130,11 @@ class Login
|
|||||||
// username (login), group name
|
// username (login), group name
|
||||||
$this->acl['user_name'] = $_SESSION['USER_NAME'];
|
$this->acl['user_name'] = $_SESSION['USER_NAME'];
|
||||||
$this->acl['group_name'] = $_SESSION['GROUP_NAME'];
|
$this->acl['group_name'] = $_SESSION['GROUP_NAME'];
|
||||||
|
// set additional acl
|
||||||
|
$this->acl['additional_acl'] = [
|
||||||
|
'user' => $_SESSION['USER_ADDITIONAL_ACL'],
|
||||||
|
'group' => $_SESSION['GROUP_ADDITIONAL_ACL'],
|
||||||
|
];
|
||||||
// we start with the default acl
|
// we start with the default acl
|
||||||
$this->acl['base'] = $this->default_acl_level;
|
$this->acl['base'] = $this->default_acl_level;
|
||||||
|
|
||||||
@@ -1184,7 +1197,8 @@ class Login
|
|||||||
'uid' => $unit['uid'],
|
'uid' => $unit['uid'],
|
||||||
'level' => $this->default_acl_list[$this->acl['unit'][$ea_id]]['name'] ?? -1,
|
'level' => $this->default_acl_list[$this->acl['unit'][$ea_id]]['name'] ?? -1,
|
||||||
'default' => $unit['default'],
|
'default' => $unit['default'],
|
||||||
'data' => $unit['data']
|
'data' => $unit['data'],
|
||||||
|
'additional_acl' => $unit['additional_acl']
|
||||||
];
|
];
|
||||||
// set default
|
// set default
|
||||||
if (!empty($unit['default'])) {
|
if (!empty($unit['default'])) {
|
||||||
@@ -1594,7 +1608,7 @@ class Login
|
|||||||
// TODO: submit or JS to set target page as ajax call
|
// TODO: submit or JS to set target page as ajax call
|
||||||
// NOTE: for the HTML block I ignore line lengths
|
// NOTE: for the HTML block I ignore line lengths
|
||||||
// phpcs:disable
|
// phpcs:disable
|
||||||
$this->login_template['password_change'] = <<<EOM
|
$this->login_template['password_change'] = <<<HTML
|
||||||
<div id="pw_change_div" class="hidden" style="position: absolute; top: 30px; left: 50px; width: 400px; height: 220px; background-color: white; border: 1px solid black; padding: 25px;">
|
<div id="pw_change_div" class="hidden" style="position: absolute; top: 30px; left: 50px; width: 400px; height: 220px; background-color: white; border: 1px solid black; padding: 25px;">
|
||||||
<table>
|
<table>
|
||||||
<tr><td class="norm" align="center" colspan="2"><h3>{TITLE_PASSWORD_CHANGE}</h3></td></tr>
|
<tr><td class="norm" align="center" colspan="2"><h3>{TITLE_PASSWORD_CHANGE}</h3></td></tr>
|
||||||
@@ -1612,7 +1626,7 @@ class Login
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{PASSWORD_CHANGE_SHOW}
|
{PASSWORD_CHANGE_SHOW}
|
||||||
EOM;
|
HTML;
|
||||||
// phpcs:enable
|
// phpcs:enable
|
||||||
}
|
}
|
||||||
if ($this->password_forgot) {
|
if ($this->password_forgot) {
|
||||||
@@ -1636,7 +1650,7 @@ EOM;
|
|||||||
// now check templates
|
// now check templates
|
||||||
// TODO: submit or JS to set target page as ajax call
|
// TODO: submit or JS to set target page as ajax call
|
||||||
if (!$this->login_template['template']) {
|
if (!$this->login_template['template']) {
|
||||||
$this->login_template['template'] = <<<EOM
|
$this->login_template['template'] = <<<HTML
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{LANGUAGE}">
|
<html lang="{LANGUAGE}">
|
||||||
<head>
|
<head>
|
||||||
@@ -1698,7 +1712,7 @@ h3 { font-size: 18px; }
|
|||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
EOM;
|
HTML;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1164,7 +1164,7 @@ class Basic
|
|||||||
public function passwordSet(string $password): string
|
public function passwordSet(string $password): string
|
||||||
{
|
{
|
||||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordSet()', E_USER_DEPRECATED);
|
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordSet()', E_USER_DEPRECATED);
|
||||||
return \CoreLibs\Check\Password::passwordSet($password);
|
return \CoreLibs\Security\Password::passwordSet($password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1177,7 +1177,7 @@ class Basic
|
|||||||
public function passwordVerify(string $password, string $hash): bool
|
public function passwordVerify(string $password, string $hash): bool
|
||||||
{
|
{
|
||||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordVerify()', E_USER_DEPRECATED);
|
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordVerify()', E_USER_DEPRECATED);
|
||||||
return \CoreLibs\Check\Password::passwordVerify($password, $hash);
|
return \CoreLibs\Security\Password::passwordVerify($password, $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1189,7 @@ class Basic
|
|||||||
public function passwordRehashCheck(string $hash): bool
|
public function passwordRehashCheck(string $hash): bool
|
||||||
{
|
{
|
||||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordRehashCheck()', E_USER_DEPRECATED);
|
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordRehashCheck()', E_USER_DEPRECATED);
|
||||||
return \CoreLibs\Check\Password::passwordRehashCheck($hash);
|
return \CoreLibs\Security\Password::passwordRehashCheck($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** BETTER PASSWORD OPTIONS END ***
|
// *** BETTER PASSWORD OPTIONS END ***
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* NOTE: this is deprecated and all moved \CoreLibs\Security\Password
|
||||||
|
*
|
||||||
* core password set, check and rehash check wrapper functions
|
* core password set, check and rehash check wrapper functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -8,6 +10,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace CoreLibs\Check;
|
namespace CoreLibs\Check;
|
||||||
|
|
||||||
|
use CoreLibs\Security\Password as PasswordNew;
|
||||||
|
|
||||||
class Password
|
class Password
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -15,13 +19,16 @@ class Password
|
|||||||
*
|
*
|
||||||
* @param string $password password
|
* @param string $password password
|
||||||
* @return string hashed password
|
* @return string hashed password
|
||||||
|
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordSet
|
||||||
*/
|
*/
|
||||||
public static function passwordSet(string $password): string
|
public static function passwordSet(string $password): string
|
||||||
{
|
{
|
||||||
// always use the PHP default for the password
|
trigger_error(
|
||||||
// password options ca be set in the password init,
|
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||||
// but should be kept as default
|
. '\CoreLibs\Security\Password::passwordSet',
|
||||||
return password_hash($password, PASSWORD_DEFAULT);
|
E_USER_DEPRECATED
|
||||||
|
);
|
||||||
|
return PasswordNew::passwordSet($password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,14 +37,16 @@ class Password
|
|||||||
* @param string $password password
|
* @param string $password password
|
||||||
* @param string $hash password hash
|
* @param string $hash password hash
|
||||||
* @return bool true or false
|
* @return bool true or false
|
||||||
|
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordVerify
|
||||||
*/
|
*/
|
||||||
public static function passwordVerify(string $password, string $hash): bool
|
public static function passwordVerify(string $password, string $hash): bool
|
||||||
{
|
{
|
||||||
if (password_verify($password, $hash)) {
|
trigger_error(
|
||||||
return true;
|
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||||
} else {
|
. '\CoreLibs\Security\Password::passwordVerify',
|
||||||
return false;
|
E_USER_DEPRECATED
|
||||||
}
|
);
|
||||||
|
return PasswordNew::passwordVerify($password, $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,14 +54,16 @@ class Password
|
|||||||
*
|
*
|
||||||
* @param string $hash password hash
|
* @param string $hash password hash
|
||||||
* @return bool true or false
|
* @return bool true or false
|
||||||
|
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordRehashCheck
|
||||||
*/
|
*/
|
||||||
public static function passwordRehashCheck(string $hash): bool
|
public static function passwordRehashCheck(string $hash): bool
|
||||||
{
|
{
|
||||||
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
|
trigger_error(
|
||||||
return true;
|
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||||
} else {
|
. '\CoreLibs\Security\Password::passwordRehashCheck',
|
||||||
return false;
|
E_USER_DEPRECATED
|
||||||
}
|
);
|
||||||
|
return PasswordNew::passwordRehashCheck($hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,65 @@ class ArrayHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* search for one or many keys in array and return matching values
|
||||||
|
* If flat is set to true, return flat array with found values only
|
||||||
|
* If prefix is turned on each found group will be prefixed with the
|
||||||
|
* search key
|
||||||
|
*
|
||||||
|
* @param array<mixed> $array array to search in
|
||||||
|
* @param array<mixed> $needles keys to find in array
|
||||||
|
* @param bool $flat [false] Turn on flat output
|
||||||
|
* @param bool $prefix [false] Prefix found with needle key
|
||||||
|
* @return array<mixed> Found values
|
||||||
|
*/
|
||||||
|
public static function arraySearchKey(
|
||||||
|
array $array,
|
||||||
|
array $needles,
|
||||||
|
bool $flat = false,
|
||||||
|
bool $prefix = false
|
||||||
|
): array {
|
||||||
|
$iterator = new \RecursiveArrayIterator($array);
|
||||||
|
$recursive = new \RecursiveIteratorIterator(
|
||||||
|
$iterator,
|
||||||
|
\RecursiveIteratorIterator::SELF_FIRST
|
||||||
|
);
|
||||||
|
$hit_list = [];
|
||||||
|
if ($prefix === true) {
|
||||||
|
$hit_list = array_fill_keys($needles, []);
|
||||||
|
}
|
||||||
|
$key_path = [];
|
||||||
|
$prev_depth = 0;
|
||||||
|
foreach ($recursive as $key => $value) {
|
||||||
|
if ($prev_depth > $recursive->getDepth()) {
|
||||||
|
// remove all trailing to ne depth
|
||||||
|
$diff = $prev_depth - $recursive->getDepth();
|
||||||
|
array_splice($key_path, -$diff, $diff);
|
||||||
|
}
|
||||||
|
$prev_depth = $recursive->getDepth();
|
||||||
|
if ($flat === false) {
|
||||||
|
$key_path[$recursive->getDepth()] = $key;
|
||||||
|
}
|
||||||
|
if (in_array($key, $needles, true)) {
|
||||||
|
ksort($key_path);
|
||||||
|
if ($flat === true) {
|
||||||
|
$hit = $value;
|
||||||
|
} else {
|
||||||
|
$hit = [
|
||||||
|
'value' => $value,
|
||||||
|
'path' => $key_path
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ($prefix === true) {
|
||||||
|
$hit_list[$key][] = $hit;
|
||||||
|
} else {
|
||||||
|
$hit_list[] = $hit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $hit_list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* correctly recursive merges as an array as array_merge_recursive
|
* correctly recursive merges as an array as array_merge_recursive
|
||||||
* just glues things together
|
* just glues things together
|
||||||
|
|||||||
127
src/DB/IO.php
127
src/DB/IO.php
@@ -279,8 +279,20 @@ class IO
|
|||||||
public const NO_CACHE = 3;
|
public const NO_CACHE = 3;
|
||||||
/** @var string default hash type */
|
/** @var string default hash type */
|
||||||
public const ERROR_HASH_TYPE = 'adler32';
|
public const ERROR_HASH_TYPE = 'adler32';
|
||||||
|
/**
|
||||||
|
* @var string regex for params: only stand alone $number allowed
|
||||||
|
* never allowed to start with '
|
||||||
|
* must be after space/tab, =, (
|
||||||
|
*/
|
||||||
|
public const REGEX_PARAMS = '/[^\'][\s(=](\$[0-9]{1,})/';
|
||||||
/** @var string regex to get returning with matches at position 1 */
|
/** @var string regex to get returning with matches at position 1 */
|
||||||
public const REGEX_RETURNING = '/\s+returning\s+(.+\s*(?:.+\s*)+);?$/i';
|
public const REGEX_RETURNING = '/\s+returning\s+(.+\s*(?:.+\s*)+);?$/i';
|
||||||
|
// REGEX_SELECT
|
||||||
|
// REGEX_UPDATE
|
||||||
|
// REGEX INSERT
|
||||||
|
// REGEX_INSERT_UPDATE_DELETE
|
||||||
|
// REGEX_FROM_TABLE
|
||||||
|
// REGEX_INSERT_UPDATE_DELETE_TABLE
|
||||||
|
|
||||||
// recommend to set private/protected and only allow setting via method
|
// recommend to set private/protected and only allow setting via method
|
||||||
// can bet set from outside
|
// can bet set from outside
|
||||||
@@ -723,7 +735,10 @@ class IO
|
|||||||
*/
|
*/
|
||||||
private function __dbErrorPreprocessor(\PgSql\Result|false $cursor = false): array
|
private function __dbErrorPreprocessor(\PgSql\Result|false $cursor = false): array
|
||||||
{
|
{
|
||||||
$pg_error_string = '';
|
$db_prefix = '';
|
||||||
|
$db_error_string = '';
|
||||||
|
$db_prefix_last = '';
|
||||||
|
$db_error_string_last = '';
|
||||||
// 1 = self/__dbErrorPreprocessor, 2 = __dbError, __dbWarning,
|
// 1 = self/__dbErrorPreprocessor, 2 = __dbError, __dbWarning,
|
||||||
// 3+ == actual source
|
// 3+ == actual source
|
||||||
// loop until we get a null, build where called chain
|
// loop until we get a null, build where called chain
|
||||||
@@ -737,16 +752,31 @@ class IO
|
|||||||
if ($where_called === null) {
|
if ($where_called === null) {
|
||||||
$where_called = '[Unknown Method]';
|
$where_called = '[Unknown Method]';
|
||||||
}
|
}
|
||||||
|
[$db_prefix_last, $db_error_string_last] = $this->db_functions->__dbPrintLastError();
|
||||||
if ($cursor !== false) {
|
if ($cursor !== false) {
|
||||||
$pg_error_string = $this->db_functions->__dbPrintError($cursor);
|
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError($cursor);
|
||||||
}
|
}
|
||||||
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) {
|
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) {
|
||||||
$pg_error_string = $this->db_functions->__dbPrintError();
|
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError();
|
||||||
}
|
}
|
||||||
if ($pg_error_string) {
|
// prefix the master if not the same
|
||||||
$this->__dbDebug('db', $pg_error_string, 'DB_ERROR', $where_called);
|
if (
|
||||||
|
!empty($db_error_string_last) &&
|
||||||
|
trim($db_error_string) != trim($db_error_string_last)
|
||||||
|
) {
|
||||||
|
$db_error_string =
|
||||||
|
$db_prefix_last . ' ' . $db_error_string_last . ';'
|
||||||
|
. $db_prefix . ' ' . $db_error_string;
|
||||||
|
} elseif (!empty($db_error_string)) {
|
||||||
|
$db_error_string = $db_prefix . ' ' . $db_error_string;
|
||||||
}
|
}
|
||||||
return [$where_called, $pg_error_string];
|
if ($db_error_string) {
|
||||||
|
$this->__dbDebug('db', $db_error_string, 'DB_ERROR', $where_called);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
$where_called,
|
||||||
|
$db_error_string
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -890,11 +920,14 @@ class IO
|
|||||||
// because the placeholders start with $ and at 1,
|
// because the placeholders start with $ and at 1,
|
||||||
// we need to increase each key and prefix it with a $ char
|
// we need to increase each key and prefix it with a $ char
|
||||||
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
|
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
|
||||||
$keys[$i] = '$' . ($keys[$i] + 1);
|
// note: if I use $ here, the str_replace will
|
||||||
|
// replace it again. eg $11 '$1'1would be replaced with $1 again
|
||||||
// prefix data set with parameter pos
|
// prefix data set with parameter pos
|
||||||
$data[$i] = $keys[$i] . ':' . ($data[$i] === null ?
|
$data[$i] = '#' . ($keys[$i] + 1) . ':' . ($data[$i] === null ?
|
||||||
'"NULL"' : (string)$data[$i]
|
'"NULL"' : (string)$data[$i]
|
||||||
);
|
);
|
||||||
|
// search part
|
||||||
|
$keys[$i] = '$' . ($keys[$i] + 1);
|
||||||
}
|
}
|
||||||
// simply replace the $1, $2, ... with the actual data and return it
|
// simply replace the $1, $2, ... with the actual data and return it
|
||||||
return str_replace(
|
return str_replace(
|
||||||
@@ -1017,7 +1050,7 @@ class IO
|
|||||||
{
|
{
|
||||||
// search for $1, $2, in the query and push it into the control array
|
// search for $1, $2, in the query and push it into the control array
|
||||||
// skip counts for same eg $1, $1, $2 = 2 and not 3
|
// skip counts for same eg $1, $1, $2 = 2 and not 3
|
||||||
preg_match_all('/(\$[0-9]{1,})/', $query, $match);
|
preg_match_all(self::REGEX_PARAMS, $query, $match);
|
||||||
$placeholder_count = count(array_unique($match[1]));
|
$placeholder_count = count(array_unique($match[1]));
|
||||||
if ($params_count != $placeholder_count) {
|
if ($params_count != $placeholder_count) {
|
||||||
$this->__dbError(
|
$this->__dbError(
|
||||||
@@ -1134,7 +1167,7 @@ class IO
|
|||||||
$this->params
|
$this->params
|
||||||
),
|
),
|
||||||
'__dbPrepareExec',
|
'__dbPrepareExec',
|
||||||
($this->params === [] ? 'Q' : 'Qp'),
|
($this->params === [] ? 'Q' : 'Qp')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// import protection, hash needed
|
// import protection, hash needed
|
||||||
@@ -1154,7 +1187,15 @@ class IO
|
|||||||
$this->query_called[$query_hash] > $this->MAX_QUERY_CALL
|
$this->query_called[$query_hash] > $this->MAX_QUERY_CALL
|
||||||
) {
|
) {
|
||||||
$this->__dbError(30, false, $this->query);
|
$this->__dbError(30, false, $this->query);
|
||||||
$this->__dbDebug('db', $this->query, 'dbExec', 'Q[nc]');
|
$this->__dbDebug(
|
||||||
|
'db',
|
||||||
|
$this->__dbDebugPrepare(
|
||||||
|
$this->query,
|
||||||
|
$this->params
|
||||||
|
),
|
||||||
|
'dbExec',
|
||||||
|
($this->params === [] ? 'Q[nc]' : 'Qp[nc]')
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->query_called[$query_hash] ++;
|
$this->query_called[$query_hash] ++;
|
||||||
@@ -1933,6 +1974,18 @@ class IO
|
|||||||
// check if params count matches
|
// check if params count matches
|
||||||
// checks if the params count given matches the expected count
|
// checks if the params count given matches the expected count
|
||||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
||||||
|
// in case we got an error print out query
|
||||||
|
if ($this->db_debug) {
|
||||||
|
$this->__dbDebug(
|
||||||
|
'db',
|
||||||
|
$this->__dbDebugPrepare(
|
||||||
|
$this->query,
|
||||||
|
$this->params
|
||||||
|
),
|
||||||
|
'dbReturn',
|
||||||
|
($this->params === [] ? 'Q[e]' : 'Qp[e]')
|
||||||
|
);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// set first call to false
|
// set first call to false
|
||||||
@@ -1956,7 +2009,15 @@ class IO
|
|||||||
$this->cursor_ext[$query_hash]['log'][] = 'No cursor';
|
$this->cursor_ext[$query_hash]['log'][] = 'No cursor';
|
||||||
// for DEBUG, print out each query executed
|
// for DEBUG, print out each query executed
|
||||||
if ($this->db_debug) {
|
if ($this->db_debug) {
|
||||||
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
|
$this->__dbDebug(
|
||||||
|
'db',
|
||||||
|
$this->__dbDebugPrepare(
|
||||||
|
$this->cursor_ext[$query_hash]['query'],
|
||||||
|
$this->cursor_ext[$query_hash]['params']
|
||||||
|
),
|
||||||
|
'dbReturn',
|
||||||
|
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q' : 'Qp'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// if no DB Handler try to reconnect
|
// if no DB Handler try to reconnect
|
||||||
if (!$this->dbh) {
|
if (!$this->dbh) {
|
||||||
@@ -1985,7 +2046,15 @@ class IO
|
|||||||
// if still no cursor ...
|
// if still no cursor ...
|
||||||
if (!$this->cursor_ext[$query_hash]['cursor']) {
|
if (!$this->cursor_ext[$query_hash]['cursor']) {
|
||||||
if ($this->db_debug) {
|
if ($this->db_debug) {
|
||||||
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
|
$this->__dbDebug(
|
||||||
|
'db',
|
||||||
|
$this->__dbDebugPrepare(
|
||||||
|
$this->cursor_ext[$query_hash]['query'],
|
||||||
|
$this->cursor_ext[$query_hash]['params']
|
||||||
|
),
|
||||||
|
'dbReturn',
|
||||||
|
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q[e]' : 'Qp[e]'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// internal error handling
|
// internal error handling
|
||||||
$this->__dbError(13, $this->cursor_ext[$query_hash]['cursor']);
|
$this->__dbError(13, $this->cursor_ext[$query_hash]['cursor']);
|
||||||
@@ -2288,10 +2357,6 @@ class IO
|
|||||||
$this->__dbError(17, false, $query);
|
$this->__dbError(17, false, $query);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// checks if the params count given matches the expected count
|
|
||||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$cursor = $this->dbExecParams($query, $params);
|
$cursor = $this->dbExecParams($query, $params);
|
||||||
if ($cursor === false) {
|
if ($cursor === false) {
|
||||||
return false;
|
return false;
|
||||||
@@ -2336,10 +2401,6 @@ class IO
|
|||||||
$this->__dbError(17, false, $query);
|
$this->__dbError(17, false, $query);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// checks if the params count given matches the expected count
|
|
||||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$cursor = $this->dbExecParams($query, $params);
|
$cursor = $this->dbExecParams($query, $params);
|
||||||
if ($cursor === false) {
|
if ($cursor === false) {
|
||||||
return false;
|
return false;
|
||||||
@@ -2588,7 +2649,7 @@ class IO
|
|||||||
$match = [];
|
$match = [];
|
||||||
// search for $1, $2, in the query and push it into the control array
|
// search for $1, $2, in the query and push it into the control array
|
||||||
// skip counts for same eg $1, $1, $2 = 2 and not 3
|
// skip counts for same eg $1, $1, $2 = 2 and not 3
|
||||||
preg_match_all('/(\$[0-9]{1,})/', $query, $match);
|
preg_match_all(self::REGEX_PARAMS, $query, $match);
|
||||||
$this->prepare_cursor[$stm_name]['count'] = count(array_unique($match[1]));
|
$this->prepare_cursor[$stm_name]['count'] = count(array_unique($match[1]));
|
||||||
$this->prepare_cursor[$stm_name]['query'] = $query;
|
$this->prepare_cursor[$stm_name]['query'] = $query;
|
||||||
$result = $this->db_functions->__dbPrepare($stm_name, $query);
|
$result = $this->db_functions->__dbPrepare($stm_name, $query);
|
||||||
@@ -2649,6 +2710,17 @@ class IO
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($this->db_debug) {
|
||||||
|
$this->__dbDebug(
|
||||||
|
'db',
|
||||||
|
$this->__dbDebugPrepare(
|
||||||
|
$this->prepare_cursor[$stm_name]['query'],
|
||||||
|
$data
|
||||||
|
),
|
||||||
|
'dbExecPrep',
|
||||||
|
'Qpe'
|
||||||
|
);
|
||||||
|
}
|
||||||
// if the count does not match
|
// if the count does not match
|
||||||
if ($this->prepare_cursor[$stm_name]['count'] != count($data)) {
|
if ($this->prepare_cursor[$stm_name]['count'] != count($data)) {
|
||||||
$this->__dbError(
|
$this->__dbError(
|
||||||
@@ -2661,17 +2733,6 @@ class IO
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($this->db_debug) {
|
|
||||||
$this->__dbDebug(
|
|
||||||
'db',
|
|
||||||
$this->__dbDebugPrepare(
|
|
||||||
$this->prepare_cursor[$stm_name]['query'],
|
|
||||||
$data
|
|
||||||
),
|
|
||||||
'dbExecPrep',
|
|
||||||
'Qp'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$result = $this->db_functions->__dbExecute($stm_name, $data);
|
$result = $this->db_functions->__dbExecute($stm_name, $data);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
$this->log->debug('ExecuteData', 'ERROR in STM[' . $stm_name . '|'
|
$this->log->debug('ExecuteData', 'ERROR in STM[' . $stm_name . '|'
|
||||||
|
|||||||
@@ -209,10 +209,17 @@ interface SqlFunctions
|
|||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Undocumented function
|
||||||
*
|
*
|
||||||
* @param \PgSql\Result|false $cursor
|
* @return array{0:string,1:string}
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): string;
|
public function __dbPrintLastError(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @param \PgSql\Result|false $cursor
|
||||||
|
* @return array{0:string,1:string}
|
||||||
|
*/
|
||||||
|
public function __dbPrintError(\PgSql\Result|false $cursor = false): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Undocumented function
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class PgSQL implements Interface\SqlFunctions
|
|||||||
/** @var string */
|
/** @var string */
|
||||||
private $last_error_query;
|
private $last_error_query;
|
||||||
/** @var \PgSql\Connection|false */
|
/** @var \PgSql\Connection|false */
|
||||||
private $dbh;
|
private $dbh = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* queries last error query and returns true or false if error was set
|
* queries last error query and returns true or false if error was set
|
||||||
@@ -532,18 +532,37 @@ class PgSQL implements Interface\SqlFunctions
|
|||||||
return $this->dbh;
|
return $this->dbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns last error for active cursor
|
||||||
|
*
|
||||||
|
* @return array{0:string,1:string} prefix, error string
|
||||||
|
*/
|
||||||
|
public function __dbPrintLastError(): array
|
||||||
|
{
|
||||||
|
if (is_bool($this->dbh)) {
|
||||||
|
return ['', ''];
|
||||||
|
}
|
||||||
|
if (!empty($error_message = pg_last_error($this->dbh))) {
|
||||||
|
return [
|
||||||
|
'-PostgreSQL-Error-Last-',
|
||||||
|
$error_message
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return ['', ''];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads the last error for this cursor and returns
|
* reads the last error for this cursor and returns
|
||||||
* html formatted string with error name
|
* html formatted string with error name
|
||||||
*
|
*
|
||||||
* @param \PgSql\Result|false $cursor cursor
|
* @param \PgSql\Result|false $cursor cursor
|
||||||
* or null
|
* or null
|
||||||
* @return string error string
|
* @return array{0:string,1:string} prefix, error string
|
||||||
*/
|
*/
|
||||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): string
|
public function __dbPrintError(\PgSql\Result|false $cursor = false): array
|
||||||
{
|
{
|
||||||
if (is_bool($this->dbh)) {
|
if (is_bool($this->dbh)) {
|
||||||
return '';
|
return ['', ''];
|
||||||
}
|
}
|
||||||
// run the query again for the error result here
|
// run the query again for the error result here
|
||||||
if ((is_bool($cursor)) && $this->last_error_query) {
|
if ((is_bool($cursor)) && $this->last_error_query) {
|
||||||
@@ -552,10 +571,12 @@ class PgSQL implements Interface\SqlFunctions
|
|||||||
$cursor = pg_get_result($this->dbh);
|
$cursor = pg_get_result($this->dbh);
|
||||||
}
|
}
|
||||||
if ($cursor && $error_str = pg_result_error($cursor)) {
|
if ($cursor && $error_str = pg_result_error($cursor)) {
|
||||||
return '-PostgreSQL-Error- '
|
return [
|
||||||
. $error_str;
|
'-PostgreSQL-Error-',
|
||||||
|
$error_str
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return ['', ''];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1954,7 +1954,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
|
|||||||
if ($this->table_array[$key]['value']) {
|
if ($this->table_array[$key]['value']) {
|
||||||
// use the better new passwordSet instead of crypt based
|
// use the better new passwordSet instead of crypt based
|
||||||
$this->table_array[$key]['value'] =
|
$this->table_array[$key]['value'] =
|
||||||
\CoreLibs\Check\Password::passwordSet($this->table_array[$key]['value']);
|
\CoreLibs\Security\Password::passwordSet($this->table_array[$key]['value']);
|
||||||
$this->table_array[$key]['HIDDEN_value'] = $this->table_array[$key]['value'];
|
$this->table_array[$key]['HIDDEN_value'] = $this->table_array[$key]['value'];
|
||||||
} else {
|
} else {
|
||||||
// $this->table_array[$key]['HIDDEN_value'] =
|
// $this->table_array[$key]['HIDDEN_value'] =
|
||||||
|
|||||||
61
src/Security/CreateKey.php
Normal file
61
src/Security/CreateKey.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* very simple symmetric encryption
|
||||||
|
* better use: https://paragonie.com/project/halite
|
||||||
|
*
|
||||||
|
* this is for creating secret keys for
|
||||||
|
* Security\SymmetricEncryption
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CoreLibs\Security;
|
||||||
|
|
||||||
|
class CreateKey
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a random key that is a hex string
|
||||||
|
*
|
||||||
|
* @return string Hex string key for encrypting
|
||||||
|
*/
|
||||||
|
public static function generateRandomKey(): string
|
||||||
|
{
|
||||||
|
return self::bin2hex(self::randomKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a random string as binary to encrypt data
|
||||||
|
* to store it in clear text in some .env file use bin2hex
|
||||||
|
*
|
||||||
|
* @return string Binary string for encryption
|
||||||
|
*/
|
||||||
|
public static function randomKey(): string
|
||||||
|
{
|
||||||
|
return random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert binary key to hex string
|
||||||
|
*
|
||||||
|
* @param string $hex_key Convert binary key string to hex
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function bin2hex(string $hex_key): string
|
||||||
|
{
|
||||||
|
return sodium_bin2hex($hex_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert hex string to binary key
|
||||||
|
*
|
||||||
|
* @param string $string_key Convery hex key string to binary
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function hex2bin(string $string_key): string
|
||||||
|
{
|
||||||
|
return sodium_hex2bin($string_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __END__
|
||||||
59
src/Security/Password.php
Normal file
59
src/Security/Password.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* core password set, check and rehash check wrapper functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CoreLibs\Security;
|
||||||
|
|
||||||
|
class Password
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* creates the password hash
|
||||||
|
*
|
||||||
|
* @param string $password password
|
||||||
|
* @return string hashed password
|
||||||
|
*/
|
||||||
|
public static function passwordSet(string $password): string
|
||||||
|
{
|
||||||
|
// always use the PHP default for the password
|
||||||
|
// password options ca be set in the password init,
|
||||||
|
// but should be kept as default
|
||||||
|
return password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the entered password matches the hash
|
||||||
|
*
|
||||||
|
* @param string $password password
|
||||||
|
* @param string $hash password hash
|
||||||
|
* @return bool true or false
|
||||||
|
*/
|
||||||
|
public static function passwordVerify(string $password, string $hash): bool
|
||||||
|
{
|
||||||
|
if (password_verify($password, $hash)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the password needs to be rehashed
|
||||||
|
*
|
||||||
|
* @param string $hash password hash
|
||||||
|
* @return bool true or false
|
||||||
|
*/
|
||||||
|
public static function passwordRehashCheck(string $hash): bool
|
||||||
|
{
|
||||||
|
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __END__
|
||||||
96
src/Security/SymmetricEncryption.php
Normal file
96
src/Security/SymmetricEncryption.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* very simple symmetric encryption
|
||||||
|
* Better use: https://paragonie.com/project/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 SymmetricEncryption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Encrypt a message
|
||||||
|
*
|
||||||
|
* @param string $message Message to encrypt
|
||||||
|
* @param string $key Encryption key (as hex string)
|
||||||
|
* @return string
|
||||||
|
* @throws \RangeException
|
||||||
|
*/
|
||||||
|
public static function encrypt(string $message, string $key): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$key = CreateKey::hex2bin($key);
|
||||||
|
} catch (SodiumException $e) {
|
||||||
|
throw new \Exception('Invalid hex key');
|
||||||
|
}
|
||||||
|
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
|
||||||
|
throw new \RangeException(
|
||||||
|
'Key is not the correct size (must be '
|
||||||
|
. 'SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long).'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||||
|
|
||||||
|
$cipher = base64_encode(
|
||||||
|
$nonce
|
||||||
|
. sodium_crypto_secretbox(
|
||||||
|
$message,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sodium_memzero($message);
|
||||||
|
sodium_memzero($key);
|
||||||
|
return $cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt a message
|
||||||
|
*
|
||||||
|
* @param string $encrypted Message encrypted with safeEncrypt()
|
||||||
|
* @param string $key Encryption key (as hex string)
|
||||||
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function decrypt(string $encrypted, string $key): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$key = CreateKey::hex2bin($key);
|
||||||
|
} catch (SodiumException $e) {
|
||||||
|
throw new \Exception('Invalid hex key');
|
||||||
|
}
|
||||||
|
$decoded = base64_decode($encrypted);
|
||||||
|
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||||
|
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||||
|
|
||||||
|
$plain = false;
|
||||||
|
try {
|
||||||
|
$plain = sodium_crypto_secretbox_open(
|
||||||
|
$ciphertext,
|
||||||
|
$nonce,
|
||||||
|
$key
|
||||||
|
);
|
||||||
|
} catch (SodiumException $e) {
|
||||||
|
throw new \Exception('Invalid ciphertext (too short)');
|
||||||
|
}
|
||||||
|
if (!is_string($plain)) {
|
||||||
|
throw new \Exception('Invalid Key');
|
||||||
|
}
|
||||||
|
sodium_memzero($ciphertext);
|
||||||
|
sodium_memzero($key);
|
||||||
|
return $plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __END__
|
||||||
@@ -267,6 +267,8 @@ final class CoreLibsACLLoginTest extends TestCase
|
|||||||
'GROUP_ACL_LEVEL' => -1,
|
'GROUP_ACL_LEVEL' => -1,
|
||||||
'PAGES_ACL_LEVEL' => [],
|
'PAGES_ACL_LEVEL' => [],
|
||||||
'USER_ACL_LEVEL' => -1,
|
'USER_ACL_LEVEL' => -1,
|
||||||
|
'USER_ADDITIONAL_ACL' => [],
|
||||||
|
'GROUP_ADDITIONAL_ACL' => [],
|
||||||
'UNIT_UID' => [
|
'UNIT_UID' => [
|
||||||
'AdminAccess' => 1,
|
'AdminAccess' => 1,
|
||||||
],
|
],
|
||||||
@@ -280,6 +282,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
|||||||
'data' => [
|
'data' => [
|
||||||
'test' => 'value',
|
'test' => 'value',
|
||||||
],
|
],
|
||||||
|
'additional_acl' => []
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
// 'UNIT_DEFAULT' => '',
|
// 'UNIT_DEFAULT' => '',
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
|||||||
4,
|
4,
|
||||||
'b',
|
'b',
|
||||||
'c' => 'test',
|
'c' => 'test',
|
||||||
|
'single' => 'single',
|
||||||
'same' => 'same',
|
'same' => 'same',
|
||||||
'deep' => [
|
'deep' => [
|
||||||
'sub' => [
|
'sub' => [
|
||||||
@@ -288,6 +289,188 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function arraySearchKeyProvider(): array
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
0: search in array
|
||||||
|
1: search keys
|
||||||
|
2: flat flag
|
||||||
|
3: prefix flag
|
||||||
|
4: expected array
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
// single
|
||||||
|
'find single, standard' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single'],
|
||||||
|
2 => null,
|
||||||
|
3 => null,
|
||||||
|
4 => [
|
||||||
|
0 => [
|
||||||
|
'value' => 'single',
|
||||||
|
'path' => ['single'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'find single, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single'],
|
||||||
|
2 => null,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'single' => [
|
||||||
|
0 => [
|
||||||
|
'value' => 'single',
|
||||||
|
'path' => ['single'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'find single, flat' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single'],
|
||||||
|
2 => true,
|
||||||
|
3 => null,
|
||||||
|
4 => [
|
||||||
|
'single',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'find single, flat, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single'],
|
||||||
|
2 => true,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'single' => [
|
||||||
|
'single',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// not found
|
||||||
|
'not found, standard' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['NOT FOUND'],
|
||||||
|
2 => null,
|
||||||
|
3 => null,
|
||||||
|
4 => [],
|
||||||
|
],
|
||||||
|
'not found, standard, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['NOT FOUND'],
|
||||||
|
2 => null,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'NOT FOUND' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'not found, flat' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['NOT FOUND'],
|
||||||
|
2 => true,
|
||||||
|
3 => null,
|
||||||
|
4 => [],
|
||||||
|
],
|
||||||
|
'not found, flat, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['NOT FOUND'],
|
||||||
|
2 => true,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'NOT FOUND' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// multi
|
||||||
|
'multiple found, standard' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['same'],
|
||||||
|
2 => null,
|
||||||
|
3 => null,
|
||||||
|
4 => [
|
||||||
|
[
|
||||||
|
'value' => 'same',
|
||||||
|
'path' => ['a', 'same', ],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'value' => 'same',
|
||||||
|
'path' => ['same', ],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'value' => 'same',
|
||||||
|
'path' => ['deep', 'sub', 'same', ],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'multiple found, flat' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['same'],
|
||||||
|
2 => true,
|
||||||
|
3 => null,
|
||||||
|
4 => ['same', 'same', 'same', ],
|
||||||
|
],
|
||||||
|
// search with multiple
|
||||||
|
'search multiple, standard' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single', 'nested'],
|
||||||
|
2 => null,
|
||||||
|
3 => null,
|
||||||
|
4 => [
|
||||||
|
[
|
||||||
|
'value' => 'single',
|
||||||
|
'path' => ['single'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'value' => 'bar',
|
||||||
|
'path' => ['deep', 'sub', 'nested', ],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'search multiple, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single', 'nested'],
|
||||||
|
2 => null,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'single' => [
|
||||||
|
[
|
||||||
|
'value' => 'single',
|
||||||
|
'path' => ['single'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'nested' => [
|
||||||
|
[
|
||||||
|
'value' => 'bar',
|
||||||
|
'path' => ['deep', 'sub', 'nested', ],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'search multiple, flat' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single', 'nested'],
|
||||||
|
2 => true,
|
||||||
|
3 => null,
|
||||||
|
4 => [
|
||||||
|
'single', 'bar',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'search multiple, flat, prefix' => [
|
||||||
|
0 => self::$array,
|
||||||
|
1 => ['single', 'nested'],
|
||||||
|
2 => true,
|
||||||
|
3 => true,
|
||||||
|
4 => [
|
||||||
|
'single' => ['single', ],
|
||||||
|
'nested' => ['bar', ],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provides array listing for the merge test
|
* provides array listing for the merge test
|
||||||
*
|
*
|
||||||
@@ -691,6 +874,44 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @covers::arraySearchKey
|
||||||
|
* @dataProvider arraySearchKeyProvider
|
||||||
|
* @testdox arraySearchKey Search array with keys and flat: $flat, prefix: $prefix [$_dataName]
|
||||||
|
*
|
||||||
|
* @param array $input
|
||||||
|
* @param array $needles
|
||||||
|
* @param bool|null $flat
|
||||||
|
* @param bool|null $prefix
|
||||||
|
* @param array $expected
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testArraySearchKey(
|
||||||
|
array $input,
|
||||||
|
array $needles,
|
||||||
|
?bool $flat,
|
||||||
|
?bool $prefix,
|
||||||
|
array $expected
|
||||||
|
): void {
|
||||||
|
if ($flat === null && $prefix === null) {
|
||||||
|
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles);
|
||||||
|
} elseif ($flat === null) {
|
||||||
|
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, prefix: $prefix);
|
||||||
|
} elseif ($prefix === null) {
|
||||||
|
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, flat: $flat);
|
||||||
|
} else {
|
||||||
|
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, $flat, $prefix);
|
||||||
|
}
|
||||||
|
// print "E: " . print_r($expected, true) . "\n";
|
||||||
|
// print "R: " . print_r($result, true) . "\n";
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
$result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Undocumented function
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
$db->dbExec("DROP TABLE test_meta");
|
$db->dbExec("DROP TABLE test_meta");
|
||||||
}
|
}
|
||||||
// uid is for internal reference tests
|
// uid is for internal reference tests
|
||||||
$base_table = <<<EOM
|
$base_table = <<<SQL
|
||||||
uid VARCHAR,
|
uid VARCHAR,
|
||||||
row_int INT,
|
row_int INT,
|
||||||
row_numeric NUMERIC,
|
row_numeric NUMERIC,
|
||||||
@@ -172,36 +172,36 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
row_array_varchar VARCHAR ARRAY
|
row_array_varchar VARCHAR ARRAY
|
||||||
)
|
)
|
||||||
WITHOUT OIDS
|
WITHOUT OIDS
|
||||||
EOM;
|
SQL;
|
||||||
// create the tables
|
// create the tables
|
||||||
$db->dbExec(
|
$db->dbExec(
|
||||||
// primary key name is table + '_id'
|
// primary key name is table + '_id'
|
||||||
<<<EOM
|
<<<SQL
|
||||||
CREATE TABLE table_with_primary_key (
|
CREATE TABLE table_with_primary_key (
|
||||||
table_with_primary_key_id SERIAL PRIMARY KEY,
|
table_with_primary_key_id SERIAL PRIMARY KEY,
|
||||||
$base_table
|
$base_table
|
||||||
EOM
|
SQL
|
||||||
/* "CREATE TABLE table_with_primary_key ("
|
/* "CREATE TABLE table_with_primary_key ("
|
||||||
// primary key name is table + '_id'
|
// primary key name is table + '_id'
|
||||||
. "table_with_primary_key_id SERIAL PRIMARY KEY, "
|
. "table_with_primary_key_id SERIAL PRIMARY KEY, "
|
||||||
. $base_table */
|
. $base_table */
|
||||||
);
|
);
|
||||||
$db->dbExec(
|
$db->dbExec(
|
||||||
<<<EOM
|
<<<SQL
|
||||||
CREATE TABLE table_without_primary_key (
|
CREATE TABLE table_without_primary_key (
|
||||||
$base_table
|
$base_table
|
||||||
EOM
|
SQL
|
||||||
/* "CREATE TABLE table_without_primary_key ("
|
/* "CREATE TABLE table_without_primary_key ("
|
||||||
. $base_table */
|
. $base_table */
|
||||||
);
|
);
|
||||||
// create simple table for meta test
|
// create simple table for meta test
|
||||||
$db->dbExec(
|
$db->dbExec(
|
||||||
<<<EOM
|
<<<SQL
|
||||||
CREATE TABLE test_meta (
|
CREATE TABLE test_meta (
|
||||||
row_1 VARCHAR,
|
row_1 VARCHAR,
|
||||||
row_2 INT
|
row_2 INT
|
||||||
) WITHOUT OIDS
|
) WITHOUT OIDS
|
||||||
EOM
|
SQL
|
||||||
/* "CREATE TABLE test_meta ("
|
/* "CREATE TABLE test_meta ("
|
||||||
. "row_1 VARCHAR, "
|
. "row_1 VARCHAR, "
|
||||||
. "row_2 INT"
|
. "row_2 INT"
|
||||||
@@ -1342,10 +1342,10 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
'has default' => false,
|
'has default' => false,
|
||||||
'array dims' => 0,
|
'array dims' => 0,
|
||||||
'is enum' => false,
|
'is enum' => false,
|
||||||
'is base' => 1,
|
'is base' => true,
|
||||||
'is composite' => false,
|
'is composite' => false,
|
||||||
'is pesudo' => false,
|
|
||||||
'description' => '',
|
'description' => '',
|
||||||
|
'is pseudo' => false
|
||||||
],
|
],
|
||||||
'row_2' => [
|
'row_2' => [
|
||||||
'num' => 2,
|
'num' => 2,
|
||||||
@@ -1355,10 +1355,10 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
'has default' => false,
|
'has default' => false,
|
||||||
'array dims' => 0,
|
'array dims' => 0,
|
||||||
'is enum' => false,
|
'is enum' => false,
|
||||||
'is base' => 1,
|
'is base' => true,
|
||||||
'is composite' => false,
|
'is composite' => false,
|
||||||
'is pesudo' => false,
|
|
||||||
'description' => '',
|
'description' => '',
|
||||||
|
'is pseudo' => false
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -1374,10 +1374,10 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
'has default' => false,
|
'has default' => false,
|
||||||
'array dims' => 0,
|
'array dims' => 0,
|
||||||
'is enum' => false,
|
'is enum' => false,
|
||||||
'is base' => 1,
|
'is base' => true,
|
||||||
'is composite' => false,
|
'is composite' => false,
|
||||||
'is pesudo' => false,
|
|
||||||
'description' => '',
|
'description' => '',
|
||||||
|
'is pseudo' => false
|
||||||
],
|
],
|
||||||
'row_2' => [
|
'row_2' => [
|
||||||
'num' => 2,
|
'num' => 2,
|
||||||
@@ -1387,10 +1387,10 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
'has default' => false,
|
'has default' => false,
|
||||||
'array dims' => 0,
|
'array dims' => 0,
|
||||||
'is enum' => false,
|
'is enum' => false,
|
||||||
'is base' => 1,
|
'is base' => true,
|
||||||
'is composite' => false,
|
'is composite' => false,
|
||||||
'is pesudo' => false,
|
|
||||||
'description' => '',
|
'description' => '',
|
||||||
|
'is pseudo' => false
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -4425,16 +4425,16 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
// same but as EOM
|
// same but as heredoc
|
||||||
'single insert (PK), EOM string' => [
|
'single insert (PK), heredoc string' => [
|
||||||
<<<EOM
|
<<<SQL
|
||||||
INSERT INTO table_with_primary_key (
|
INSERT INTO table_with_primary_key (
|
||||||
row_varchar, row_varchar_literal, row_int, row_date
|
row_varchar, row_varchar_literal, row_int, row_date
|
||||||
) VALUES (
|
) VALUES (
|
||||||
'Text', 'Other', 123, '2022-03-01'
|
'Text', 'Other', 123, '2022-03-01'
|
||||||
)
|
)
|
||||||
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
||||||
EOM,
|
SQL,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
@@ -4529,16 +4529,16 @@ final class CoreLibsDBIOTest extends TestCase
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
// same as above but as EOM string
|
// same as above but as heredoc string
|
||||||
'single insert (No PK), EOM string' => [
|
'single insert (No PK), heredoc string' => [
|
||||||
<<<EOM
|
<<<SQL
|
||||||
INSERT INTO table_without_primary_key (
|
INSERT INTO table_without_primary_key (
|
||||||
row_varchar, row_varchar_literal, row_int, row_date
|
row_varchar, row_varchar_literal, row_int, row_date
|
||||||
) VALUES (
|
) VALUES (
|
||||||
'Text', 'Other', 123, '2022-03-01'
|
'Text', 'Other', 123, '2022-03-01'
|
||||||
)
|
)
|
||||||
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
||||||
EOM,
|
SQL,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ namespace tests;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for Check\Password
|
* Test class for Security\Password
|
||||||
* @coversDefaultClass \CoreLibs\Check\Password
|
* @coversDefaultClass \CoreLibs\Security\Password
|
||||||
* @testdox \CoreLibs\Check\Password method tests
|
* @testdox \CoreLibs\Security\Password method tests
|
||||||
*/
|
*/
|
||||||
final class CoreLibsCheckPasswordTest extends TestCase
|
final class CoreLibsSecurityPasswordTest extends TestCase
|
||||||
{
|
{
|
||||||
public function passwordProvider(): array
|
public function passwordProvider(): array
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
$expected,
|
$expected,
|
||||||
\CoreLibs\Check\Password::passwordVerify($input, \CoreLibs\Check\Password::passwordSet($input_hash))
|
\CoreLibs\Security\Password::passwordVerify($input, \CoreLibs\Security\Password::passwordSet($input_hash))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
$expected,
|
$expected,
|
||||||
\CoreLibs\Check\Password::passwordRehashCheck($input)
|
\CoreLibs\Security\Password::passwordRehashCheck($input)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
172
test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php
Normal file
172
test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use CoreLibs\Security\CreateKey;
|
||||||
|
use CoreLibs\Security\SymmetricEncryption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for Security\SymmetricEncryption and Security\CreateKey
|
||||||
|
* @coversDefaultClass \CoreLibs\Security\SymmetricEncryption
|
||||||
|
* @testdox \CoreLibs\Security\SymmetricEncryption method tests
|
||||||
|
*/
|
||||||
|
final class CoreLibsSecuritySymmetricEncryption extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 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 = CreateKey::generateRandomKey();
|
||||||
|
$encrypted = SymmetricEncryption::encrypt($input, $key);
|
||||||
|
$decrypted = SymmetricEncryption::decrypt($encrypted, $key);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
$decrypted
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function providerEncryptFailed(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'wrong decryption key' => [
|
||||||
|
'input' => 'I am a secret',
|
||||||
|
'excpetion_message' => 'Invalid Key'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = CreateKey::generateRandomKey();
|
||||||
|
$encrypted = SymmetricEncryption::encrypt($input, $key);
|
||||||
|
$wrong_key = CreateKey::generateRandomKey();
|
||||||
|
$this->expectExceptionMessage($exception_message);
|
||||||
|
SymmetricEncryption::decrypt($encrypted, $wrong_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function providerWrongKey(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'not hex key' => [
|
||||||
|
'key' => 'not_a_hex_key',
|
||||||
|
'exception_message' => 'Invalid hex key'
|
||||||
|
],
|
||||||
|
'too short hex key' => [
|
||||||
|
'key' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
|
||||||
|
'excpetion_message' => 'Key is not the correct size (must be '
|
||||||
|
. 'SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long).'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test invalid key provided to decrypt or encrypt
|
||||||
|
*
|
||||||
|
* @covers ::encrypt
|
||||||
|
* @covers ::decrypt
|
||||||
|
* @dataProvider providerWrongKey
|
||||||
|
* @testdox wrong key $key throws $exception_message [$_dataName]
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param string $exception_message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testWrongKey(string $key, string $exception_message): void
|
||||||
|
{
|
||||||
|
$this->expectExceptionMessage($exception_message);
|
||||||
|
SymmetricEncryption::encrypt('test', $key);
|
||||||
|
// we must encrypt valid thing first so we can fail with the wrong kjey
|
||||||
|
$enc_key = CreateKey::generateRandomKey();
|
||||||
|
$encrypted = SymmetricEncryption::encrypt('test', $enc_key);
|
||||||
|
$this->expectExceptionMessage($exception_message);
|
||||||
|
SymmetricEncryption::decrypt($encrypted, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function providerWrongCiphertext(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'too short ciphertext' => [
|
||||||
|
'input' => 'short',
|
||||||
|
'exception_message' => 'Invalid ciphertext (too short)'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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::generateRandomKey();
|
||||||
|
$this->expectExceptionMessage($exception_message);
|
||||||
|
SymmetricEncryption::decrypt($input, $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __END__
|
||||||
Reference in New Issue
Block a user