Merge branch 'QA_5_2'

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
Maurício Meneghini Fauth 2022-09-29 00:45:10 -03:00
commit 6a9fe03ff2
No known key found for this signature in database
GPG Key ID: 6A16FD38AFC89CC8
19 changed files with 292 additions and 139 deletions

View File

@ -36,6 +36,8 @@ phpMyAdmin - ChangeLog
- issue Fix PHP warning on GIS visualization when there is only one GIS column
- issue #17728 Some select HTML tags will now have the correct UI style
- issue #17734 PHP deprecations will only be shown when in a development environment
- issue #17369 Fix server error when blowfish_secret is not exactly 32 bytes long
- issue #17736 Add utf8mb3 as an alias of utf8 on the charset description page
5.2.0 (2022-05-10)
- issue #16521 Upgrade Bootstrap to version 5

View File

@ -10,8 +10,8 @@
declare(strict_types=1);
/**
* This is needed for cookie based authentication to encrypt password in
* cookie. Needs to be 32 chars long.
* This is needed for cookie based authentication to encrypt the cookie.
* Needs to be a 32-bytes long string of random bytes. See FAQ 2.10.
*/
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

View File

@ -1888,6 +1888,8 @@ Generic settings
A secret key used to encrypt/decrypt the URL query string.
Should be 32 bytes long.
.. seealso:: :ref:`faq2_10`
Cookie authentication options
-----------------------------
@ -1896,13 +1898,33 @@ Cookie authentication options
:type: string
:default: ``''``
The "cookie" auth\_type uses AES algorithm to encrypt the password. If you
are using the "cookie" auth\_type, enter here a random passphrase of your
choice. It will be used internally by the AES algorithm: you wont be
prompted for this passphrase.
The "cookie" auth\_type uses the :term:`Sodium` extension to encrypt the cookies (see :term:`Cookie`). If you are
using the "cookie" auth\_type, enter here a generated string of random bytes to be used as an encryption key. It
will be used internally by the :term:`Sodium` extension: you won't be prompted for this encryption key.
The secret should be 32 characters long. Using shorter will lead to weaker security
of encrypted cookies, using longer will cause no harm.
Since a binary string is usually not printable, it can be converted into a hexadecimal representation (using a
function like `sodium_bin2hex <https://www.php.net/sodium_bin2hex>`_) and then used in the configuration file. For
example:
.. code-block:: php
// The string is a hexadecimal representation of a 32-bytes long string of random bytes.
$cfg['blowfish_secret'] = sodium_hex2bin('f16ce59f45714194371b48fe362072dc3b019da7861558cd4ad29e4d6fb13851');
Using a binary string is recommended. However, if all 32 bytes of the string are visible
characters, then a function like `sodium_bin2hex <https://www.php.net/sodium_bin2hex>`_ is not required. For
example:
.. code-block:: php
// A string of 32 characters.
$cfg['blowfish_secret'] = 'JOFw435365IScA&Q!cDugr!lSfuAz*OW';
.. warning::
The encryption key must be 32 bytes long. If it is longer than the length of bytes, only the first 32 bytes will
be used, and if it is shorter, a new temporary key will be automatically generated for you. However, this
temporary key will only last for the duration of the session.
.. note::
@ -1910,11 +1932,21 @@ Cookie authentication options
Blowfish algorithm was originally used to do the encryption.
.. versionchanged:: 3.1.0
Since version 3.1.0 phpMyAdmin can generate this on the fly, but it
makes a bit weaker security as this generated secret is stored in
session and furthermore it makes impossible to recall user name from
cookie.
.. versionchanged:: 5.2.0
Since version 5.2.0, phpMyAdmin uses the
`sodium\_crypto\_secretbox <https://www.php.net/sodium_crypto_secretbox>`_ and
`sodium\_crypto\_secretbox\_open <https://www.php.net/sodium_crypto_secretbox_open>`_ PHP functions to encrypt
and decrypt cookies, respectively.
.. seealso:: :ref:`faq2_10`
.. config:option:: $cfg['CookieSameSite']
:type: string
@ -3809,8 +3841,8 @@ following example shows two of them:
.. code-block:: php
<?php
$cfg['blowfish_secret'] = 'multiServerExample70518';
// any string of your choice
// The string is a hexadecimal representation of a 32-bytes long string of random bytes.
$cfg['blowfish_secret'] = sodium_hex2bin('f16ce59f45714194371b48fe362072dc3b019da7861558cd4ad29e4d6fb13851');
$i = 0;
$i++; // server 1 :

View File

@ -867,6 +867,37 @@ If using PHP 5.4.0 or higher, you must set
starting from phpMyAdmin version 4.0.4, session-based upload progress has
been temporarily deactivated due to its problematic behavior.
.. _faq2_10:
2.10 How to generate a string of random bytes
---------------------------------------------
One way to generate a string of random bytes suitable for cryptographic use is using the
`random_bytes <https://www.php.net/random_bytes>`_ :term:`PHP` function. Since this function returns a binary string,
the returned value should be converted to printable format before being able to copy it.
For example, the :config:option:`$cfg['blowfish_secret']` configuration directive requires a 32-bytes long string. The
following command can be used to generate a hexadecimal representation of this string.
.. code-block:: sh
php -r 'echo bin2hex(random_bytes(32)) . PHP_EOL;'
The above example will output something similar to:
.. code-block:: sh
f16ce59f45714194371b48fe362072dc3b019da7861558cd4ad29e4d6fb13851
And then this hexadecimal value can be used in the configuration file.
.. code-block:: php
$cfg['blowfish_secret'] = sodium_hex2bin('f16ce59f45714194371b48fe362072dc3b019da7861558cd4ad29e4d6fb13851');
The `sodium_hex2bin <https://www.php.net/sodium_hex2bin>`_ is used here to convert the hexadecimal value back to the
binary format.
.. _faqlimitations:
Known limitations

View File

@ -335,6 +335,11 @@ From Wikipedia, the free encyclopedia
.. seealso:: <https://en.wikipedia.org/wiki/Server_(computing)>
Sodium
The Sodium PHP extension.
.. seealso:: `PHP manual for Sodium extension <https://www.php.net/manual/en/book.sodium.php>`_
Storage Engines
MySQL can use several different formats for storing data on disk, these
are called storage engines or table types. phpMyAdmin allows a user to

View File

@ -587,8 +587,8 @@ simple configuration may look like this:
.. code-block:: xml+php
<?php
// use here a value of your choice at least 32 chars long
$cfg['blowfish_secret'] = '1{dd0`<Q),5XP_:R9UK%%8\"EEcyH#{o';
// The string is a hexadecimal representation of a 32-bytes long string of random bytes.
$cfg['blowfish_secret'] = sodium_hex2bin('f16ce59f45714194371b48fe362072dc3b019da7861558cd4ad29e4d6fb13851');
$i=0;
$i++;

View File

@ -344,6 +344,7 @@ final class Collation
// Fall through to other unicode
case 'ucs2':
case 'utf8':
case 'utf8mb3':
case 'utf16':
case 'utf16le':
case 'utf16be':

View File

@ -11,17 +11,17 @@ use PhpMyAdmin\Core;
use PhpMyAdmin\Sanitize;
use PhpMyAdmin\Setup\Index as SetupIndex;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use function __;
use function count;
use function function_exists;
use function htmlspecialchars;
use function implode;
use function ini_get;
use function preg_match;
use function is_string;
use function mb_strlen;
use function sodium_crypto_secretbox_keygen;
use function sprintf;
use function strlen;
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
/**
* Performs various compatibility, security and consistency checks on current config
@ -247,9 +247,12 @@ class ServerConfigChecks
$cookieAuthServer,
$blowfishSecretSet
): array {
if ($cookieAuthServer && $blowfishSecret === null) {
if (
$cookieAuthServer
&& (! is_string($blowfishSecret) || mb_strlen($blowfishSecret, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES)
) {
$blowfishSecretSet = true;
$this->cfg->set('blowfish_secret', Util::generateRandom(32));
$this->cfg->set('blowfish_secret', sodium_crypto_secretbox_keygen());
}
return [
@ -345,55 +348,21 @@ class ServerConfigChecks
): void {
// $cfg['blowfish_secret']
// it's required for 'cookie' authentication
if (! $cookieAuthUsed) {
return;
}
if ($blowfishSecretSet) {
// 'cookie' auth used, blowfish_secret was generated
SetupIndex::messagesSet(
'notice',
'blowfish_secret_created',
Descriptions::get('blowfish_secret'),
Sanitize::sanitizeMessage(__(
'You didn\'t have blowfish secret set and have enabled '
. '[kbd]cookie[/kbd] authentication, so a key was automatically '
. 'generated for you. It is used to encrypt cookies; you don\'t need to '
. 'remember it.'
))
);
return;
}
$blowfishWarnings = [];
// check length
if (strlen($blowfishSecret) < 32) {
// too short key
$blowfishWarnings[] = __('Key is too short, it should have at least 32 characters.');
}
// check used characters
$hasDigits = (bool) preg_match('/\d/', $blowfishSecret);
$hasChars = (bool) preg_match('/\S/', $blowfishSecret);
$hasNonword = (bool) preg_match('/\W/', $blowfishSecret);
if (! $hasDigits || ! $hasChars || ! $hasNonword) {
$blowfishWarnings[] = Sanitize::sanitizeMessage(
__(
'Key should contain letters, numbers [em]and[/em] special characters.'
)
);
}
if (empty($blowfishWarnings)) {
if (! $cookieAuthUsed || ! $blowfishSecretSet) {
return;
}
// 'cookie' auth used, blowfish_secret was generated
SetupIndex::messagesSet(
'error',
'blowfish_warnings' . count($blowfishWarnings),
'notice',
'blowfish_secret_created',
Descriptions::get('blowfish_secret'),
implode('<br>', $blowfishWarnings)
Sanitize::sanitizeMessage(__(
'You didn\'t have blowfish secret set and have enabled '
. '[kbd]cookie[/kbd] authentication, so a key was automatically '
. 'generated for you. It is used to encrypt cookies; you don\'t need to '
. 'remember it.'
))
);
}

View File

@ -118,10 +118,9 @@ final class Settings
public $AllowThirdPartyFraming;
/**
* The 'cookie' auth_type uses AES algorithm to encrypt the password. If
* at least one server configuration uses 'cookie' auth_type, enter here a
* pass phrase that will be used by AES. The maximum length seems to be 46
* characters.
* The 'cookie' auth_type uses the Sodium extension to encrypt the cookies. If at least one server configuration
* uses 'cookie' auth_type, enter here a generated string of random bytes to be used as an encryption key. The
* encryption key must be 32 bytes long.
*
* @var string
*/

View File

@ -318,19 +318,23 @@ class HomeController extends AbstractController
* Check if user does not have defined blowfish secret and it is being used.
*/
if (! empty($_SESSION['encryption_key'])) {
if (empty($GLOBALS['cfg']['blowfish_secret'])) {
$encryptionKeyLength = mb_strlen($GLOBALS['cfg']['blowfish_secret'], '8bit');
if ($encryptionKeyLength < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
$this->errors[] = [
'message' => __(
'The configuration file now needs a secret passphrase (blowfish_secret).'
'The configuration file needs a valid key for cookie encryption.'
. ' A temporary key was automatically generated for you.'
. ' Please refer to the [doc@cfg_blowfish_secret]documentation[/doc].'
),
'severity' => 'warning',
];
} elseif (mb_strlen($GLOBALS['cfg']['blowfish_secret'], '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
} elseif ($encryptionKeyLength > SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
$this->errors[] = [
'message' => sprintf(
__(
'The secret passphrase in configuration (blowfish_secret) is not the correct length.'
. ' It should be %d bytes long.'
'The cookie encryption key in the configuration file is longer than necessary.'
. ' It should only be %d bytes long.'
. ' Please refer to the [doc@cfg_blowfish_secret]documentation[/doc].'
),
SODIUM_CRYPTO_SECRETBOX_KEYBYTES
),

View File

@ -592,11 +592,21 @@ class AuthenticationCookie extends AuthenticationPlugin
*/
private function getEncryptionSecret(): string
{
/** @var mixed $key */
$key = $GLOBALS['cfg']['blowfish_secret'] ?? null;
if (is_string($key) && mb_strlen($key, '8bit') === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
if (! is_string($key)) {
return $this->getSessionEncryptionSecret();
}
$length = mb_strlen($key, '8bit');
if ($length === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
return $key;
}
if ($length > SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
return mb_substr($key, 0, SODIUM_CRYPTO_SECRETBOX_KEYBYTES, '8bit');
}
return $this->getSessionEncryptionSecret();
}
@ -605,6 +615,7 @@ class AuthenticationCookie extends AuthenticationPlugin
*/
private function getSessionEncryptionSecret(): string
{
/** @var mixed $key */
$key = $_SESSION['encryption_key'] ?? null;
if (is_string($key) && mb_strlen($key, '8bit') === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
return $key;

View File

@ -15,12 +15,18 @@ use function count;
use function gmdate;
use function implode;
use function is_array;
use function is_string;
use function mb_strlen;
use function preg_replace;
use function sodium_bin2hex;
use function sodium_crypto_secretbox_keygen;
use function sprintf;
use function str_contains;
use function strtr;
use function var_export;
use const DATE_RFC1123;
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
/**
* Config file generation class
@ -92,6 +98,12 @@ class ConfigGenerator
*/
private static function getVarExport($var_name, $var_value, string $eol)
{
if ($var_name === 'blowfish_secret') {
$secret = self::getBlowfishSecretKey($var_value);
return sprintf('$cfg[\'blowfish_secret\'] = \sodium_hex2bin(\'%s\');%s', sodium_bin2hex($secret), $eol);
}
if (! is_array($var_value) || empty($var_value)) {
return "\$cfg['" . $var_name . "'] = "
. var_export($var_value, true) . ';' . $eol;
@ -197,4 +209,18 @@ class ConfigGenerator
return $ret;
}
/**
* @param mixed $key
*
* @psalm-return non-empty-string
*/
private static function getBlowfishSecretKey($key): string
{
if (is_string($key) && mb_strlen($key, '8bit') === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
return $key;
}
return sodium_crypto_secretbox_keygen();
}
}

View File

@ -100,10 +100,9 @@ $cfg['TranslationWarningThreshold'] = 80;
$cfg['AllowThirdPartyFraming'] = false;
/**
* The 'cookie' auth_type uses AES algorithm to encrypt the password. If
* at least one server configuration uses 'cookie' auth_type, enter here a
* pass phrase that will be used by AES. The maximum length seems to be 46
* characters.
* The 'cookie' auth_type uses the Sodium extension to encrypt the cookies. If at least one server configuration
* uses 'cookie' auth_type, enter here a generated string of random bytes to be used as an encryption key. The
* encryption key must be 32 bytes long.
*
* @global string $cfg['blowfish_secret']
*/

View File

@ -7145,6 +7145,11 @@ parameters:
count: 1
path: libraries/classes/Setup/ConfigGenerator.php
-
message: "#^Method PhpMyAdmin\\\\Setup\\\\ConfigGenerator\\:\\:getBlowfishSecretKey\\(\\) should return non\\-empty\\-string but returns string\\.$#"
count: 2
path: libraries/classes/Setup/ConfigGenerator.php
-
message: "#^Method PhpMyAdmin\\\\Setup\\\\ConfigGenerator\\:\\:getServerPart\\(\\) has parameter \\$servers with no value type specified in iterable type array\\.$#"
count: 1

View File

@ -2151,8 +2151,7 @@
<code>$GLOBALS['cfg']['TranslationWarningThreshold']</code>
<code>$GLOBALS['language_stats']</code>
</InvalidArrayOffset>
<MixedArgument occurrences="3">
<code>$GLOBALS['cfg']['blowfish_secret']</code>
<MixedArgument occurrences="2">
<code>$this-&gt;config-&gt;get('ShowGitRevision') ?? true</code>
<code>$this-&gt;config-&gt;get('TempDir')</code>
</MixedArgument>
@ -4331,10 +4330,6 @@
</MixedAssignment>
</file>
<file src="libraries/classes/Core.php">
<InvalidArrayOffset occurrences="2">
<code>$GLOBALS['cfg']['blowfish_secret']</code>
<code>$GLOBALS['cfg']['blowfish_secret']</code>
</InvalidArrayOffset>
<InvalidOperand occurrences="1">
<code>$matches[1]</code>
</InvalidOperand>
@ -9061,13 +9056,11 @@
<MixedArrayOffset occurrences="1">
<code>$_SESSION['browser_access_time'][$key]</code>
</MixedArrayOffset>
<MixedAssignment occurrences="12">
<MixedAssignment occurrences="10">
<code>$GLOBALS['pma_auth_server']</code>
<code>$captchaSiteVerifyURL</code>
<code>$captchaSiteVerifyURL</code>
<code>$key</code>
<code>$key</code>
<code>$key</code>
<code>$password</code>
<code>$serverCookie</code>
<code>$serverCookie</code>
@ -12516,6 +12509,10 @@
</UnusedFunctionCall>
</file>
<file src="libraries/classes/Setup/ConfigGenerator.php">
<LessSpecificReturnStatement occurrences="2">
<code>$key</code>
<code>sodium_crypto_secretbox_keygen()</code>
</LessSpecificReturnStatement>
<MixedArgument occurrences="1">
<code>$conf['Servers']</code>
</MixedArgument>
@ -12533,6 +12530,9 @@
<code>$v</code>
<code>$v</code>
</MixedAssignment>
<MoreSpecificReturnType occurrences="1">
<code>non-empty-string</code>
</MoreSpecificReturnType>
<PossiblyNullOperand occurrences="1">
<code>self::getServerPart($cf, $eol, $conf['Servers'])</code>
</PossiblyNullOperand>
@ -14172,40 +14172,24 @@
</MixedArrayAccess>
</file>
<file src="test/classes/Config/ServerConfigChecksTest.php">
<MixedArgument occurrences="5">
<code>$_SESSION['messages']</code>
<MixedArgument occurrences="2">
<code>$_SESSION['messages']['error']</code>
<code>$_SESSION['messages']['error']</code>
<code>$_SESSION['messages']['notice']</code>
<code>$_SESSION['messages']['notice']</code>
</MixedArgument>
<MixedArrayAccess occurrences="4">
<MixedArrayAccess occurrences="2">
<code>$_SESSION['messages']['error']</code>
<code>$_SESSION['messages']['error']</code>
<code>$_SESSION['messages']['notice']</code>
<code>$_SESSION['messages']['notice']</code>
</MixedArrayAccess>
<MixedArrayAssignment occurrences="20">
<code>$_SESSION[$this-&gt;sessionID]['AllowArbitraryServer']</code>
<MixedArrayAssignment occurrences="9">
<code>$_SESSION[$this-&gt;sessionID]['AllowArbitraryServer']</code>
<code>$_SESSION[$this-&gt;sessionID]['BZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['BZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['GZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['GZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['LoginCookieStore']</code>
<code>$_SESSION[$this-&gt;sessionID]['LoginCookieStore']</code>
<code>$_SESSION[$this-&gt;sessionID]['LoginCookieValidity']</code>
<code>$_SESSION[$this-&gt;sessionID]['LoginCookieValidity']</code>
<code>$_SESSION[$this-&gt;sessionID]['SaveDir']</code>
<code>$_SESSION[$this-&gt;sessionID]['SaveDir']</code>
<code>$_SESSION[$this-&gt;sessionID]['Servers']</code>
<code>$_SESSION[$this-&gt;sessionID]['Servers']</code>
<code>$_SESSION[$this-&gt;sessionID]['Servers']</code>
<code>$_SESSION[$this-&gt;sessionID]['TempDir']</code>
<code>$_SESSION[$this-&gt;sessionID]['TempDir']</code>
<code>$_SESSION[$this-&gt;sessionID]['ZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['ZipDump']</code>
<code>$_SESSION[$this-&gt;sessionID]['blowfish_secret']</code>
</MixedArrayAssignment>
<MixedArrayOffset occurrences="1">
<code>$_SESSION[$this-&gt;sessionID]</code>

View File

@ -42,6 +42,7 @@
AllowThirdPartyFraming: bool|'sameorigin',
ArbitraryServerRegexp: string,
AvailableCharsets: string[],
blowfish_secret: string,
BrowseMarkerEnable: bool,
BrowsePointerEnable: bool,
BrowseMIME: bool,

View File

@ -262,7 +262,7 @@ restore_vendor_folder() {
echo 'No backup to restore'
exit 1;
fi
rm -rf ./vendor
rm -r ./vendor
mv "${TEMP_FOLDER}/vendor" ./vendor
rmdir "${TEMP_FOLDER}"
}
@ -284,7 +284,7 @@ delete_phpunit_sandbox() {
echo 'No phpunit sandbox to delete'
exit 1;
fi
rm -rf "${TEMP_PHPUNIT_FOLDER}"
rm -r "${TEMP_PHPUNIT_FOLDER}"
}
security_checkup() {
@ -425,16 +425,16 @@ fi
echo "* Removing unneeded files"
# Remove developer information
rm -rf .github CODE_OF_CONDUCT.md DCO
rm -r .github CODE_OF_CONDUCT.md DCO
# Testsuite setup
rm -f .scrutinizer.yml .weblate codecov.yml
rm .scrutinizer.yml .weblate codecov.yml
# Remove Doctum config file
rm -f test/doctum-config.php
rm test/doctum-config.php
# Remove readme for github
rm -f README.rst
rm README.rst
if [ -f ./scripts/console ]; then
# Update the vendors to have the dev vendors
@ -468,15 +468,18 @@ do
PACKAGES_VERSIONS="$PACKAGES_VERSIONS $PACKAGES:$PKG_VERSION"
done
echo "Installing composer packages '$PACKAGES_VERSIONS'"
echo "* Installing composer packages '$PACKAGES_VERSIONS'"
composer require --no-interaction --optimize-autoloader --update-no-dev $PACKAGES_VERSIONS
echo "* Running a security checkup"
security_checkup
echo "* Cleaning up vendor folders"
mv composer.json.backup composer.json
cleanup_composer_vendors
echo "* Running a security checkup"
security_checkup
if [ $do_tag -eq 1 ] ; then
echo "* Commiting composer.lock"
@ -491,8 +494,8 @@ fi
# Remove git metadata
rm .git
find . -name .gitignore -print0 | xargs -0 -r rm -f
find . -name .gitattributes -print0 | xargs -0 -r rm -f
find . -name .gitignore -print0 | xargs -0 -r rm
find . -name .gitattributes -print0 | xargs -0 -r rm
if [ $do_test -eq 1 ] ; then
# Move the folder out and install dev vendors
@ -505,7 +508,7 @@ if [ $do_test -eq 1 ] ; then
test_ret=$?
if [ $do_ci -eq 1 ] ; then
cd ../..
rm -rf $workdir
rm -r $workdir
git worktree prune
if [ "$branch" = "ci" ] ; then
git branch -D ci
@ -520,7 +523,7 @@ if [ $do_test -eq 1 ] ; then
# Generate an normal autoload (this is just a security, because normally the vendor folder will be restored)
composer dump-autoload
# Remove libs installed for testing
rm -rf build
rm -r build
delete_phpunit_sandbox
restore_vendor_folder
fi
@ -531,6 +534,7 @@ cd ..
# Prepare all kits
for kit in $KITS ; do
echo "* Building kit: $kit"
# Copy all files
name=phpMyAdmin-$version-$kit
cp -r phpMyAdmin-$version $name
@ -543,27 +547,27 @@ for kit in $KITS ; do
if [ $kit != source ] ; then
echo "* Removing source files"
# Testsuite
rm -rf test/
rm -r test/
# Template test files
rm -r templates/test/
rm phpunit.xml.* build.xml
rm -f .editorconfig .browserslistrc .eslintignore .jshintrc .eslintrc.json .stylelintrc.json psalm.xml psalm-baseline.xml phpstan.neon.dist phpstan-baseline.neon phpcs.xml.dist jest.config.js infection.json.dist
# Gettext po files
rm -rf po/
rm .editorconfig .browserslistrc .eslintignore .jshintrc .eslintrc.json .stylelintrc.json psalm.xml psalm-baseline.xml phpstan.neon.dist phpstan-baseline.neon phpcs.xml.dist jest.config.js infection.json.dist
# Gettext po files (if they where not removed by ./scripts/lang-cleanup.sh)
rm -rf po
# Documentation source code
mv doc/html htmldoc
rm -rf doc
rm -r doc
mkdir doc
mv htmldoc doc/html
rm doc/html/.buildinfo doc/html/objects.inv
rm -rf node_modules
rm -r node_modules
# Remove bin files for non source version
# https://github.com/phpmyadmin/phpmyadmin/issues/16033
rm -rf vendor/bin
rm -r vendor/bin
fi
# Remove developer scripts
rm -rf scripts
rm -r scripts
# Remove possible tmp folder
rm -rf tmp
@ -604,11 +608,11 @@ for kit in $KITS ; do
# Cleanup
rm -f $name.tar
# Remove directory with current dist set
rm -rf $name
rm -r $name
done
# Cleanup
rm -rf phpMyAdmin-${version}
rm -r phpMyAdmin-${version}
git worktree prune
# Signing of files with default GPG key
@ -657,7 +661,7 @@ if [ $do_tag -eq 1 ] ; then
git rm --force composer.lock
git commit -s -m "Removing composer.lock"
cd ../..
rm -rf $workdir
rm -r $workdir
git worktree prune
fi

View File

@ -11,6 +11,10 @@ use ReflectionException;
use ReflectionProperty;
use function array_keys;
use function mb_strlen;
use function str_repeat;
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
/**
* @covers \PhpMyAdmin\Config\ServerConfigChecks
@ -100,8 +104,10 @@ class ServerConfigChecksTest extends AbstractTestCase
);
}
public function testBlowfishCreate(): void
public function testBlowfish(): void
{
$_SESSION[$this->sessionID] = [];
$_SESSION[$this->sessionID]['blowfish_secret'] = null;
$_SESSION[$this->sessionID]['Servers'] = [
'1' => [
'host' => 'localhost',
@ -110,7 +116,6 @@ class ServerConfigChecksTest extends AbstractTestCase
'AllowRoot' => false,
],
];
$_SESSION[$this->sessionID]['AllowArbitraryServer'] = false;
$_SESSION[$this->sessionID]['LoginCookieValidity'] = -1;
$_SESSION[$this->sessionID]['LoginCookieStore'] = 0;
@ -123,28 +128,73 @@ class ServerConfigChecksTest extends AbstractTestCase
$configChecker = new ServerConfigChecks($GLOBALS['ConfigFile']);
$configChecker->performConfigChecks();
$this->assertEquals(
['blowfish_secret_created'],
array_keys($_SESSION['messages']['notice'])
);
$this->assertArrayNotHasKey('error', $_SESSION['messages']);
/**
* @var mixed $secret
* @psalm-suppress TypeDoesNotContainType
*/
$secret = $_SESSION[$this->sessionID]['blowfish_secret'] ?? '';
$this->assertIsString($secret);
$this->assertSame(SODIUM_CRYPTO_SECRETBOX_KEYBYTES, mb_strlen($secret, '8bit'));
$messages = $_SESSION['messages'] ?? null;
$this->assertIsArray($messages);
$this->assertArrayHasKey('notice', $messages);
$this->assertIsArray($messages['notice']);
$this->assertArrayHasKey('blowfish_secret_created', $messages['notice']);
$this->assertArrayNotHasKey('error', $messages);
}
public function testBlowfish(): void
public function testBlowfishWithInvalidSecret(): void
{
$_SESSION[$this->sessionID]['blowfish_secret'] = 'sec';
$_SESSION[$this->sessionID] = [];
$_SESSION[$this->sessionID]['blowfish_secret'] = str_repeat('a', SODIUM_CRYPTO_SECRETBOX_KEYBYTES + 1);
$_SESSION[$this->sessionID]['Servers'] = [
'1' => [
'host' => 'localhost',
'ssl' => true,
'auth_type' => 'cookie',
'AllowRoot' => false,
],
];
$configChecker = new ServerConfigChecks($GLOBALS['ConfigFile']);
$configChecker->performConfigChecks();
$this->assertArrayHasKey('blowfish_warnings2', $_SESSION['messages']['error']);
/**
* @var mixed $secret
* @psalm-suppress TypeDoesNotContainType
*/
$secret = $_SESSION[$this->sessionID]['blowfish_secret'] ?? '';
$this->assertIsString($secret);
$this->assertSame(SODIUM_CRYPTO_SECRETBOX_KEYBYTES, mb_strlen($secret, '8bit'));
$messages = $_SESSION['messages'] ?? null;
$this->assertIsArray($messages);
$this->assertArrayHasKey('notice', $messages);
$this->assertIsArray($messages['notice']);
$this->assertArrayHasKey('blowfish_secret_created', $messages['notice']);
$this->assertArrayNotHasKey('error', $messages);
}
public function testBlowfishWithValidSecret(): void
{
$_SESSION[$this->sessionID] = [];
$_SESSION[$this->sessionID]['blowfish_secret'] = str_repeat('a', SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$_SESSION[$this->sessionID]['Servers'] = ['1' => ['host' => 'localhost', 'auth_type' => 'cookie']];
$configChecker = new ServerConfigChecks($GLOBALS['ConfigFile']);
$configChecker->performConfigChecks();
/**
* @var mixed $secret
* @psalm-suppress TypeDoesNotContainType
*/
$secret = $_SESSION[$this->sessionID]['blowfish_secret'] ?? '';
$this->assertIsString($secret);
$this->assertSame(SODIUM_CRYPTO_SECRETBOX_KEYBYTES, mb_strlen($secret, '8bit'));
$messages = $_SESSION['messages'] ?? null;
$this->assertIsArray($messages);
$this->assertArrayHasKey('notice', $messages);
$this->assertIsArray($messages['notice']);
$this->assertArrayNotHasKey('blowfish_secret_created', $messages['notice']);
$this->assertArrayNotHasKey('error', $messages);
}
}

View File

@ -10,6 +10,13 @@ use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Version;
use ReflectionClass;
use function explode;
use function hex2bin;
use function mb_strlen;
use function str_repeat;
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
/**
* @covers \PhpMyAdmin\Setup\ConfigGenerator
*/
@ -115,6 +122,29 @@ class ConfigGeneratorTest extends AbstractTestCase
);
}
public function testGetVarExportForBlowfishSecret(): void
{
$reflection = new ReflectionClass(ConfigGenerator::class);
$method = $reflection->getMethod('getVarExport');
$method->setAccessible(true);
$this->assertEquals(
'$cfg[\'blowfish_secret\'] = \sodium_hex2bin(\''
. '6161616161616161616161616161616161616161616161616161616161616161\');' . "\n",
$method->invoke(null, 'blowfish_secret', str_repeat('a', SODIUM_CRYPTO_SECRETBOX_KEYBYTES), "\n")
);
/** @var string $actual */
$actual = $method->invoke(null, 'blowfish_secret', 'invalid secret', "\n");
$this->assertStringStartsWith('$cfg[\'blowfish_secret\'] = \sodium_hex2bin(\'', $actual);
$this->assertStringEndsWith('\');' . "\n", $actual);
$pieces = explode('\'', $actual);
$this->assertCount(5, $pieces);
$binaryString = hex2bin($pieces[3]);
$this->assertIsString($binaryString);
$this->assertSame(SODIUM_CRYPTO_SECRETBOX_KEYBYTES, mb_strlen($binaryString, '8bit'));
}
/**
* Test for ConfigGenerator::isZeroBasedArray
*/