Merge branch 'QA_5_2'

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
Maurício Meneghini Fauth 2023-07-15 15:19:35 -03:00
commit eaad8d8a1c
No known key found for this signature in database
GPG Key ID: 6A16FD38AFC89CC8
16 changed files with 905 additions and 892 deletions

View File

@ -63,6 +63,8 @@ phpMyAdmin - ChangeLog
- issue #18454 Fix date field calendar display when changing NULL state
- issue #18481 Fix missing pagination when using SELECT DISTINCT
- issue #18325 Allow hex representations for integers in the search box validation
- issue #14411 Fixed double tap to edit on mobile devices
- issue Update documentation to reflect that Node >= 12 is required to compile the JS and CSS files
5.2.1 (2023-02-07)
- issue #17522 Fix case where the routes cache file is invalid

View File

@ -90,7 +90,7 @@ In order to install from Git, you'll need a few supporting applications:
* `Git <https://git-scm.com/downloads>`_ to download the source, or you can download the most recent source directly from `Github <https://codeload.github.com/phpmyadmin/phpmyadmin/zip/QA_5_2>`_
* `Composer <https://getcomposer.org/download/>`__
* `Node.js <https://nodejs.org/en/download/>`_ (version 10 or higher)
* `Node.js <https://nodejs.org/en/download/>`_ (version 12 or higher)
* `Yarn <https://classic.yarnpkg.com/en/docs/install>`_
You can clone current phpMyAdmin source from

View File

@ -2153,8 +2153,8 @@ const makeGrid = function (t, enableResize = undefined, enableReorder = undefine
}
});
$(g.t).find('td.data.click2')
.on('click', function (e) {
$(g.t)
.on('click', 'td.data.click2', function (e) {
var $cell = $(this);
// In the case of relational link, We want single click on the link
// to goto the link and double click to start grid-editing.
@ -2188,7 +2188,7 @@ const makeGrid = function (t, enableResize = undefined, enableReorder = undefine
}
}
})
.on('dblclick', function (e) {
.on('dblclick', 'td.data.click2', function (e) {
if ($(e.target).is('.grid_edit a')) {
e.preventDefault();
} else {

View File

@ -1499,8 +1499,9 @@ var ConsoleDebug = {
);
if (url) {
var decodedUrl = new URLSearchParams(url.split('?')[1]);
$('#debug_console').find('.debug>.welcome').append(
$('<span class="script_name">').text(url.split('?')[0])
$('<span class="script_name">').text(decodedUrl.has('route') ? decodedUrl.get('route') : url)
);
}

View File

@ -3153,14 +3153,23 @@ function onloadRecentFavoriteTables (): void {
return;
}
var favoriteTables = '';
if (isStorageSupported('localStorage')
&& typeof window.localStorage.favoriteTables !== 'undefined'
&& window.localStorage.favoriteTables !== 'undefined') {
favoriteTables = window.localStorage.favoriteTables;
if (favoriteTables === 'undefined') {
// Do not send an invalid value
return;
}
}
$.ajax({
url: $('#sync_favorite_tables').attr('href'),
cache: false,
type: 'POST',
data: {
'favoriteTables': (isStorageSupported('localStorage') && typeof window.localStorage.favoriteTables !== 'undefined')
? window.localStorage.favoriteTables
: '',
'favoriteTables': favoriteTables,
'server': CommonParams.get('server'),
'no_debug': true
},

View File

@ -186,8 +186,25 @@ function verifyAfterSearchFieldChange (index, searchFormId) {
}
});
// validator method for IN(...), NOT IN(...)
// BETWEEN and NOT BETWEEN
// See all possible syntaxes in tests of https://regexr.com/7h1eq
jQuery.validator.addMethod('validationFunctionForMultipleInt', function (value) {
return value.match(/^(((0x[0-9a-f]+)|([+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)(e[+-]?[0-9]+)?))(,|$))+$/i) !== null;
},
window.Messages.strEnterValidNumber
);
validateMultipleIntField($thisInput, true);
} else {
// validator method for INTs
// See all possible syntaxes in tests of https://regexr.com/7h1ci
jQuery.validator.addMethod('validationFunctionForInt', function (value) {
return value.match(/^(0x[0-9a-f]+$)|([+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)(e[+-]?[0-9]+)?)$/i) !== null;
},
window.Messages.strEnterValidNumber
);
$(searchFormId).validate({
// update errors as we write
onkeyup: function (element) {

View File

@ -10,7 +10,6 @@ use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\InternalRelations;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\SqlParser\Parser;
use PhpMyAdmin\SqlParser\Statements\CreateStatement;
use PhpMyAdmin\SqlParser\Utils\Table as TableUtils;
@ -1622,32 +1621,13 @@ class Relation
}
$GLOBALS['cfg']['Server']['pmadb'] = $db;
//NOTE: I am unsure why we do that, as it defeats the purpose of the session cache
// Unset the cache
unset($_SESSION['relation'][$GLOBALS['server']]);
unset(self::$cache[$GLOBALS['server']]);
$relationParameters = $this->getRelationParameters();
if (
$relationParameters->recentlyUsedTablesFeature === null
&& $relationParameters->favoriteTablesFeature === null
) {
return;
}
// Since configuration storage is updated, we need to
// re-initialize the favorite and recent tables stored in the
// session from the current configuration storage.
if ($relationParameters->favoriteTablesFeature !== null) {
$favTables = RecentFavoriteTable::getInstance('favorite');
$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] = $favTables->getFromDb();
}
if ($relationParameters->recentlyUsedTablesFeature !== null) {
$recentTables = RecentFavoriteTable::getInstance('recent');
$_SESSION['tmpval']['recentTables'][$GLOBALS['server']] = $recentTables->getFromDb();
}
// Reload navi panel to update the recent/favorite lists.
$GLOBALS['reload'] = true;
// Fill back the cache
$this->getRelationParameters();
}
/**

View File

@ -44,7 +44,7 @@ final class FavoriteTableController extends AbstractController
$GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database');
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
if (! $this->hasDatabase() || ! $this->response->isAjax()) {
if (! $this->response->isAjax()) {
return;
}
@ -72,6 +72,10 @@ final class FavoriteTableController extends AbstractController
return;
}
if (! $this->hasDatabase()) {
return;
}
$changes = true;
$favoriteTable = $parameters['favorite_table'] ?? '';
$alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
@ -166,10 +170,8 @@ final class FavoriteTableController extends AbstractController
*/
private function checkFavoriteTable(string $currentTable): bool
{
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
RecentFavoriteTable::getInstance('favorite');
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
foreach ($favoriteTables as $value) {
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
foreach ($recentFavoriteTables->getTables() as $value) {
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
return true;
}

View File

@ -591,10 +591,8 @@ class StructureController extends AbstractController
*/
protected function checkFavoriteTable(string $currentTable): bool
{
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
RecentFavoriteTable::getInstance('favorite');
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
foreach ($favoriteTables as $value) {
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
foreach ($recentFavoriteTables->getTables() as $value) {
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
return true;
}

View File

@ -439,7 +439,7 @@ class Header
/**
* Re-enable possible disabled XSS filters.
*
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
* @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection
*/
$headers['X-XSS-Protection'] = '1; mode=block';
@ -447,21 +447,21 @@ class Header
* "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing
* a response away from the declared content-type.
*
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
* @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options
*/
$headers['X-Content-Type-Options'] = 'nosniff';
/**
* Adobe cross-domain-policies.
*
* @see https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
* @see https://www.sentrium.co.uk/labs/application-security-101-http-headers
*/
$headers['X-Permitted-Cross-Domain-Policies'] = 'none';
/**
* Robots meta tag.
*
* @see https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
* @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
*/
$headers['X-Robots-Tag'] = 'noindex, nofollow';

View File

@ -59,12 +59,15 @@ class RecentFavoriteTable
* Creates a new instance of RecentFavoriteTable
*
* @param string $type the table type
* @phpstan-param 'favorite'|'recent' $type
*/
private function __construct(public Template $template, string $type)
{
$this->relation = new Relation($GLOBALS['dbi']);
$this->tableType = $type;
$serverId = $GLOBALS['server'];
// Code search hint: recentTables
// Code search hint: favoriteTables
if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId])) {
$_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId] = $this->getPmaTable()
? $this->getFromDb()

View File

@ -1147,12 +1147,12 @@ parameters:
-
message: "#^Cannot access offset 'db' on mixed\\.$#"
count: 1
count: 2
path: libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Cannot access offset 'table' on mixed\\.$#"
count: 1
count: 2
path: libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
-
@ -1255,6 +1255,16 @@ parameters:
count: 1
path: libraries/classes/Controllers/Database/StructureController.php
-
message: "#^Cannot access offset 'db' on mixed\\.$#"
count: 1
path: libraries/classes/Controllers/Database/StructureController.php
-
message: "#^Cannot access offset 'table' on mixed\\.$#"
count: 1
path: libraries/classes/Controllers/Database/StructureController.php
-
message: "#^Parameter \\#1 \\$connection of method PhpMyAdmin\\\\Replication\\\\ReplicationInfo\\:\\:load\\(\\) expects string\\|null, mixed given\\.$#"
count: 1

View File

@ -718,10 +718,6 @@
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$_SESSION['sql_history'][]]]></code>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables']]]></code>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
<code><![CDATA[$_SESSION['tmpval']['recentTables']]]></code>
<code><![CDATA[$_SESSION['tmpval']['recentTables'][$GLOBALS['server']]]]></code>
</MixedArrayAssignment>
<MixedArrayOffset>
<code>$foreign[$field]</code>
@ -1404,7 +1400,6 @@
<code><![CDATA[$value['table']]]></code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['table']]]></code>
@ -1418,7 +1413,6 @@
<MixedAssignment>
<code><![CDATA[$GLOBALS['errorUrl']]]></code>
<code>$favoriteTables</code>
<code>$favoriteTables</code>
<code>$value</code>
<code>$value</code>
</MixedAssignment>
@ -1545,7 +1539,6 @@
<code>$updateTimeAll</code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
<code><![CDATA[$currentTable['Check_time']]]></code>
<code><![CDATA[$currentTable['Collation']]]></code>
<code><![CDATA[$currentTable['Create_time']]]></code>
@ -1577,7 +1570,6 @@
<code>$createTimeAll</code>
<code>$currentTable</code>
<code>$dbTable</code>
<code>$favoriteTables</code>
<code>$overheadSize</code>
<code>$searchDb</code>
<code>$searchDoDBInDB</code>
@ -13387,8 +13379,6 @@
<code>$sumSize</code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables']]]></code>
<code><![CDATA[$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]]]></code>
<code><![CDATA[$currentTable['ENGINE']]]></code>
<code><![CDATA[$currentTable['ENGINE']]]></code>
<code><![CDATA[$currentTable['ENGINE']]]></code>

View File

@ -1912,15 +1912,6 @@ class RelationTest extends AbstractTestCase
$dummyDbi->addResult('SELECT NULL FROM `pma__favorite_custom` LIMIT 0', [], ['NULL']);
$dummyDbi->addResult(
'SELECT `tables` FROM `PMA-storage`.`pma__favorite_custom` WHERE `username` = \'\'',
[],
);
$dummyDbi->addResult(
'SELECT `tables` FROM `PMA-storage`.`pma__favorite_custom` WHERE `username` = \'\'',
[],
);
$_SESSION['relation'] = [];
$_SESSION['tmpval'] = [];
(new ReflectionClass(Relation::class))->getProperty('cache')->setValue([]);

View File

@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\Database\StructureController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Replication\Replication;
use PhpMyAdmin\Table;
use PhpMyAdmin\Template;
@ -249,6 +250,26 @@ class StructureControllerTest extends AbstractTestCase
$class = new ReflectionClass(StructureController::class);
$method = $class->getMethod('checkFavoriteTable');
$dbiDummy = $this->createDbiDummy();
$dbi = $this->createDatabaseInterface($dbiDummy);
$GLOBALS['db'] = 'sakila';
$GLOBALS['dbi'] = $dbi;
$dbiDummy->removeDefaultResults();
$dbiDummy->addResult(
'SHOW COLUMNS FROM `sakila`.`country`',
[
['country_id', 'smallint(5) unsigned', 'NO', 'PRI', null, 'auto_increment'],
],
['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'],
);
$dbiDummy->addResult(
'SHOW INDEXES FROM `sakila`.`country`',
[],
['Table', 'Non_unique', 'Key_name', 'Column_name'],
);
$controller = new StructureController(
$this->response,
$this->template,
@ -259,14 +280,23 @@ class StructureControllerTest extends AbstractTestCase
$this->createStub(PageSettings::class),
);
$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] = [['db' => 'db', 'table' => 'table']];
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
$this->assertSame([], $recentFavoriteTables->getTables());
$recentFavoriteTables->remove('sakila', 'country');
$recentFavoriteTables->add('sakila', 'country');
$this->assertSame([
[
'db' => 'sakila',
'table' => 'country',
],
], $recentFavoriteTables->getTables());
$this->assertFalse(
$method->invokeArgs($controller, ['']),
);
$this->assertTrue(
$method->invokeArgs($controller, ['table']),
$method->invokeArgs($controller, ['country']),
);
}

1626
yarn.lock

File diff suppressed because it is too large Load Diff