Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
commit
6a9fe03ff2
@ -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
|
||||
|
||||
@ -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! */
|
||||
|
||||
|
||||
@ -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 won’t 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 :
|
||||
|
||||
31
doc/faq.rst
31
doc/faq.rst
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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++;
|
||||
|
||||
@ -344,6 +344,7 @@ final class Collation
|
||||
// Fall through to other unicode
|
||||
case 'ucs2':
|
||||
case 'utf8':
|
||||
case 'utf8mb3':
|
||||
case 'utf16':
|
||||
case 'utf16le':
|
||||
case 'utf16be':
|
||||
|
||||
@ -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.'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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']
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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->config->get('ShowGitRevision') ?? true</code>
|
||||
<code>$this->config->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->sessionID]['AllowArbitraryServer']</code>
|
||||
<MixedArrayAssignment occurrences="9">
|
||||
<code>$_SESSION[$this->sessionID]['AllowArbitraryServer']</code>
|
||||
<code>$_SESSION[$this->sessionID]['BZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['BZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['GZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['GZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['LoginCookieStore']</code>
|
||||
<code>$_SESSION[$this->sessionID]['LoginCookieStore']</code>
|
||||
<code>$_SESSION[$this->sessionID]['LoginCookieValidity']</code>
|
||||
<code>$_SESSION[$this->sessionID]['LoginCookieValidity']</code>
|
||||
<code>$_SESSION[$this->sessionID]['SaveDir']</code>
|
||||
<code>$_SESSION[$this->sessionID]['SaveDir']</code>
|
||||
<code>$_SESSION[$this->sessionID]['Servers']</code>
|
||||
<code>$_SESSION[$this->sessionID]['Servers']</code>
|
||||
<code>$_SESSION[$this->sessionID]['Servers']</code>
|
||||
<code>$_SESSION[$this->sessionID]['TempDir']</code>
|
||||
<code>$_SESSION[$this->sessionID]['TempDir']</code>
|
||||
<code>$_SESSION[$this->sessionID]['ZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['ZipDump']</code>
|
||||
<code>$_SESSION[$this->sessionID]['blowfish_secret']</code>
|
||||
</MixedArrayAssignment>
|
||||
<MixedArrayOffset occurrences="1">
|
||||
<code>$_SESSION[$this->sessionID]</code>
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
AllowThirdPartyFraming: bool|'sameorigin',
|
||||
ArbitraryServerRegexp: string,
|
||||
AvailableCharsets: string[],
|
||||
blowfish_secret: string,
|
||||
BrowseMarkerEnable: bool,
|
||||
BrowsePointerEnable: bool,
|
||||
BrowseMIME: bool,
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user