Merge remote-tracking branch 'security/QA_4_9-security' into QA_4_9

This commit is contained in:
Isaac Bennetch 2022-01-20 09:55:49 -05:00
commit f271cadd59
52 changed files with 994 additions and 282 deletions

View File

@ -65,7 +65,7 @@
"samyoul/u2f-php-server": "<1.1"
},
"suggest": {
"ext-openssl": "Cookie encryption",
"ext-openssl": "For encryption performance",
"ext-curl": "Updates checking",
"ext-opcache": "Better performance",
"ext-zlib": "For gz import and export",
@ -76,7 +76,8 @@
"tecnickcom/tcpdf": "For PDF support",
"pragmarx/google2fa": "For 2FA authentication",
"bacon/bacon-qr-code": "For 2FA authentication",
"samyoul/u2f-php-server": "For FIDO U2F authentication"
"samyoul/u2f-php-server": "For FIDO U2F authentication",
"paragonie/sodium_compat": "For modern encryption support"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.7",
@ -87,7 +88,9 @@
"pragmarx/google2fa": "^3.0",
"bacon/bacon-qr-code": "^1.0",
"samyoul/u2f-php-server": "^1.1",
"phpmyadmin/coding-standard": "^0.3"
"phpmyadmin/coding-standard": "^0.3",
"paragonie/random_compat": ">=2",
"paragonie/sodium_compat": "^1.17"
},
"extra": {
"branch-alias": {

View File

@ -148,6 +148,13 @@ $cfg['SaveDir'] = '';
*/
//$cfg['SendErrorReports'] = 'always';
/**
* 'URLQueryEncryption' defines whether phpMyAdmin will encrypt sensitive data from the URL query string.
* 'URLQueryEncryptionSecretKey' is a 32 bytes long secret key used to encrypt/decrypt the URL query string.
*/
//$cfg['URLQueryEncryption'] = true;
//$cfg['URLQueryEncryptionSecretKey'] = '';
/**
* You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.

View File

@ -1477,6 +1477,20 @@ Server connection settings
after logout (doesn't affect config authentication method). Should be
absolute including protocol.
.. config:option:: $cfg['Servers'][$i]['hide_connection_errors']
:type: boolean
:default: false
.. versionadded:: 4.9.8
Whether to show or hide detailed MySQL/MariaDB connection errors on the login page.
.. note::
This error message can contain the target database server hostname or IP address,
which may reveal information about your network to an attacker.
Generic settings
----------------
@ -1736,6 +1750,27 @@ Generic settings
Define whether phpMyAdmin will continue executing a multi-query
statement if one of the queries fails. Default is to abort execution.
.. config:option:: $cfg['URLQueryEncryption']
:type: boolean
:default: false
.. versionadded:: 4.9.8
Define whether phpMyAdmin will encrypt sensitive data (like database name
and table name) from the URL query string. Default is to not encrypt the URL
query string.
.. config:option:: $cfg['URLQueryEncryptionSecretKey']
:type: string
:default: ``''``
.. versionadded:: 4.9.8
A secret key used to encrypt/decrypt the URL query string.
Should be 32 bytes long.
Cookie authentication options
-----------------------------

View File

@ -158,7 +158,7 @@ function loadChildNodes (isNode, $expandElem, callback) {
}
var url = $('#pma_navigation').find('a.navigation_url').attr('href');
$.get(url, params, function (data) {
$.post(url, params, function (data) {
if (typeof data !== 'undefined' && data.success === true) {
$destination.find('div.list_container').remove(); // FIXME: Hack, there shouldn't be a list container there
if (isNode) {

View File

@ -193,7 +193,7 @@ class ServerBinlogController extends Controller
}
$html .= '<a href="server_binlog.php" data-post="'
. Url::getCommon($this_url_params, '') . '"';
. Url::getCommon($this_url_params, '', false) . '"';
if (Util::showIcons('TableNavigationLinksMode')) {
$html .= ' title="' . _pgettext('Previous page', 'Previous') . '">';
} else {
@ -215,7 +215,7 @@ class ServerBinlogController extends Controller
$tempTitle = __('Show Full Queries');
$tempImgMode = 'full';
}
$html .= '<a href="server_binlog.php" data-post="' . Url::getCommon($this_url_params, '')
$html .= '<a href="server_binlog.php" data-post="' . Url::getCommon($this_url_params, '', false)
. '" title="' . $tempTitle . '">'
. '<img src="' . $GLOBALS['pmaThemeImage'] . 's_' . $tempImgMode
. 'text.png" alt="' . $tempTitle . '" /></a>';
@ -226,7 +226,7 @@ class ServerBinlogController extends Controller
$this_url_params = $url_params;
$this_url_params['pos'] = $pos + $GLOBALS['cfg']['MaxRows'];
$html .= ' - <a href="server_binlog.php" data-post="'
. Url::getCommon($this_url_params, '')
. Url::getCommon($this_url_params, '', false)
. '"';
if (Util::showIcons('TableNavigationLinksMode')) {
$html .= ' title="' . _pgettext('Next page', 'Next') . '">';

View File

@ -1241,13 +1241,6 @@ class TableStructureController extends TableController
'DistinctValues' => Util::getIcon('b_browse', __('Distinct values')),
);
$edit_view_url = '';
if ($this->_tbl_is_view && ! $this->_db_is_system_schema) {
$edit_view_url = Url::getCommon(
array('db' => $this->db, 'table' => $this->table)
);
}
/**
* Displays Space usage and row statistics
*/
@ -1275,11 +1268,11 @@ class TableStructureController extends TableController
'tbl_is_view' => $this->_tbl_is_view,
'mime_map' => $mime_map,
'url_query' => $this->_url_query,
'url_params' => $url_params,
'titles' => $titles,
'tbl_storage_engine' => $this->_tbl_storage_engine,
'primary' => $primary_index,
'columns_with_unique_index' => $columns_with_unique_index,
'edit_view_url' => $edit_view_url,
'columns_list' => $columns_list,
'table_stats' => isset($tablestats) ? $tablestats : null,
'fields' => $fields,

View File

@ -1317,4 +1317,36 @@ class Core
$hmac = hash_hmac('sha256', $sqlQuery, $_SESSION[' HMAC_secret '] . $cfg['blowfish_secret']);
return hash_equals($hmac, $signature);
}
/**
* @return void
*/
public static function populateRequestWithEncryptedQueryParams()
{
if (
(! isset($_GET['eq']) || ! is_string($_GET['eq']))
&& (! isset($_POST['eq']) || ! is_string($_POST['eq']))
) {
unset($_GET['eq'], $_POST['eq'], $_REQUEST['eq']);
return;
}
$isFromPost = isset($_POST['eq']);
$decryptedQuery = Url::decryptQuery($isFromPost ? $_POST['eq'] : $_GET['eq']);
unset($_GET['eq'], $_POST['eq'], $_REQUEST['eq']);
if ($decryptedQuery === null) {
return;
}
$urlQueryParams = (array) json_decode($decryptedQuery);
foreach ($urlQueryParams as $urlQueryParamKey => $urlQueryParamValue) {
if ($isFromPost) {
$_POST[$urlQueryParamKey] = $urlQueryParamValue;
} else {
$_GET[$urlQueryParamKey] = $urlQueryParamValue;
}
$_REQUEST[$urlQueryParamKey] = $urlQueryParamValue;
}
}
}

View File

@ -0,0 +1,155 @@
<?php
namespace PhpMyAdmin\Crypto;
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Random;
final class Crypto
{
/** @var bool */
private $hasRandomBytesSupport;
/** @var bool */
private $hasSodiumSupport;
/**
* @param bool $forceFallback Force the usage of the fallback functions.
*/
public function __construct($forceFallback = false)
{
$this->hasRandomBytesSupport = ! $forceFallback && is_callable('random_bytes');
$this->hasSodiumSupport = ! $forceFallback
&& $this->hasRandomBytesSupport
&& is_callable('sodium_crypto_secretbox')
&& is_callable('sodium_crypto_secretbox_open')
&& defined('SODIUM_CRYPTO_SECRETBOX_NONCEBYTES')
&& defined('SODIUM_CRYPTO_SECRETBOX_KEYBYTES');
}
/**
* @param string $plaintext
*
* @return string
*/
public function encrypt($plaintext)
{
if ($this->hasSodiumSupport) {
return $this->encryptWithSodium($plaintext);
}
return $this->encryptWithPhpseclib($plaintext);
}
/**
* @param string $ciphertext
*
* @return string
*/
public function decrypt($ciphertext)
{
if ($this->hasSodiumSupport) {
return $this->decryptWithSodium($ciphertext);
}
return $this->decryptWithPhpseclib($ciphertext);
}
/**
* @return string
*/
private function getEncryptionKey()
{
global $PMA_Config;
$keyLength = $this->hasSodiumSupport ? SODIUM_CRYPTO_SECRETBOX_KEYBYTES : 32;
$key = $PMA_Config->get('URLQueryEncryptionSecretKey');
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
return $key;
}
$key = isset($_SESSION['URLQueryEncryptionSecretKey']) ? $_SESSION['URLQueryEncryptionSecretKey'] : null;
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
return $key;
}
$key = $this->hasRandomBytesSupport ? random_bytes($keyLength) : Random::string($keyLength);
$_SESSION['URLQueryEncryptionSecretKey'] = $key;
return $key;
}
/**
* @param string $plaintext
*
* @return string
*/
private function encryptWithPhpseclib($plaintext)
{
$key = $this->getEncryptionKey();
$cipher = new AES(AES::MODE_CBC);
$iv = $this->hasRandomBytesSupport ? random_bytes(16) : Random::string(16);
$cipher->setIV($iv);
$cipher->setKey($key);
$ciphertext = $cipher->encrypt($plaintext);
$hmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
return $hmac . $iv . $ciphertext;
}
/**
* @param string $encrypted
*
* @return string|null
*/
private function decryptWithPhpseclib($encrypted)
{
$key = $this->getEncryptionKey();
$hmac = mb_substr($encrypted, 0, 32, '8bit');
$iv = mb_substr($encrypted, 32, 16, '8bit');
$ciphertext = mb_substr($encrypted, 48, null, '8bit');
$calculatedHmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
if (! hash_equals($hmac, $calculatedHmac)) {
return null;
}
$cipher = new AES(AES::MODE_CBC);
$cipher->setIV($iv);
$cipher->setKey($key);
return $cipher->decrypt($ciphertext);
}
/**
* @param string $plaintext
*
* @return string
*/
private function encryptWithSodium($plaintext)
{
$key = $this->getEncryptionKey();
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
return $nonce . $ciphertext;
}
/**
* @param string $encrypted
*
* @return string|null
*/
private function decryptWithSodium($encrypted)
{
$key = $this->getEncryptionKey();
$nonce = mb_substr($encrypted, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($encrypted, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
if ($decrypted === false) {
return null;
}
return $decrypted;
}
}

View File

@ -1563,17 +1563,22 @@ class DatabaseInterface
*/
public function initRelationParamsCache()
{
if (strlen($GLOBALS['db'])) {
$cfgRelation = $this->relation->getRelationsParam();
if (empty($cfgRelation['db'])) {
$this->relation->fixPmaTables($GLOBALS['db'], false);
}
}
$cfgRelation = $this->relation->getRelationsParam();
if (empty($cfgRelation['db']) && isset($GLOBALS['dblist'])) {
if ($GLOBALS['dblist']->databases->exists('phpmyadmin')) {
$this->relation->fixPmaTables('phpmyadmin', false);
}
$storageDbName = $GLOBALS['cfg']['Server']['pmadb'] ?? '';
// Use "phpmyadmin" as a default database name to check to keep the behavior consistent
$storageDbName = $storageDbName !== null
&& is_string($storageDbName)
&& $storageDbName !== '' ? $storageDbName : 'phpmyadmin';
// This will make users not having explicitly listed databases
// have config values filled by the default phpMyAdmin storage table name values
$this->relation->fixPmaTables($storageDbName, false);
// This global will be changed if fixPmaTables did find one valid table
$storageDbName = $GLOBALS['cfg']['Server']['pmadb'] ?? '';
// Empty means that until now no pmadb was found eligible
if (empty($storageDbName)) {
$this->relation->fixPmaTables($GLOBALS['db'], false);
}
}

View File

@ -149,16 +149,29 @@ class DbiMysqli implements DbiExtension
$host = $server['host'];
}
$return_value = mysqli_real_connect(
$link,
$host,
$user,
$password,
'',
$server['port'],
$server['socket'],
$client_flags
);
if ($server['hide_connection_errors']) {
$return_value = @mysqli_real_connect(
$link,
$host,
$user,
$password,
'',
$server['port'],
$server['socket'],
$client_flags
);
} else {
$return_value = mysqli_real_connect(
$link,
$host,
$user,
$password,
'',
$server['port'],
$server['socket'],
$client_flags
);
}
if ($return_value === false || is_null($return_value)) {
/*
@ -180,7 +193,20 @@ class DbiMysqli implements DbiExtension
);
$server['ssl'] = true;
return self::connect($user, $password, $server);
} elseif ($error_number === 1045 && $server['hide_connection_errors']) {
trigger_error(
sprintf(
__(
'Error 1045: Access denied for user. Additional error information'
. ' may be available, but is being hidden by the %s configuration directive.'
),
'[code][doc@cfg_Servers_hide_connection_errors]'
. '$cfg[\'Servers\'][$i][\'hide_connection_errors\'][/doc][/code]'
),
E_USER_ERROR
);
}
return false;
}

View File

@ -1736,9 +1736,8 @@ class Results
$tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
. $tmp_txt . '" title="' . $tmp_txt . '" />';
$tmp_url = 'sql.php' . Url::getCommon($url_params_full_text);
return Util::linkOrButton($tmp_url, $tmp_image);
return Util::linkOrButton('sql.php', $url_params_full_text, $tmp_image);
} // end of the '_getFullOrPartialTextButtonOrLink()' function
@ -1869,13 +1868,11 @@ class Results
'session_max_rows' => $session_max_rows,
'is_browse_distinct' => $this->__get('is_browse_distinct'),
);
$single_order_url = 'sql.php' . Url::getCommon($_single_url_params);
$multi_order_url = 'sql.php' . Url::getCommon($_multi_url_params);
// Displays the sorting URL
// enable sort order swapping for image
$order_link = $this->_getSortOrderLink(
$order_img, $fields_meta, $single_order_url, $multi_order_url
$order_img, $fields_meta, $_single_url_params, $_multi_url_params
);
$sorted_header_html .= $this->_getDraggableClassForSortableColumns(
@ -2143,10 +2140,10 @@ class Results
/**
* Get sort order link
*
* @param string $order_img the sort order image
* @param array $fields_meta set of field properties
* @param string $order_url the url for sort
* @param string $multi_order_url the url for sort
* @param string $order_img the sort order image
* @param array $fields_meta set of field properties
* @param array $order_url_params the url params for sort
* @param array $multi_order_url_params the url params for sort
*
* @return string the sort order link
*
@ -2155,7 +2152,7 @@ class Results
* @see _getTableHeaders()
*/
private function _getSortOrderLink(
$order_img, $fields_meta, $order_url, $multi_order_url
$order_img, $fields_meta, $order_url_params, $multi_order_url_params
) {
$order_link_params = array(
'class' => 'sortlink'
@ -2163,10 +2160,12 @@ class Results
$order_link_content = htmlspecialchars($fields_meta->name);
$inner_link_content = $order_link_content . $order_img
. '<input type="hidden" value="' . $multi_order_url . '" />';
. '<input type="hidden" value="sql.php'
. Url::getCommon($multi_order_url_params, '?', false)
. '" />';
return Util::linkOrButton(
$order_url, $inner_link_content, $order_link_params
'sql.php', $order_url_params, $inner_link_content, $order_link_params
);
} // end of the '_getSortOrderLink()' function
@ -2608,7 +2607,7 @@ class Results
// 1. Prepares the row
// In print view these variable needs to be initialized
$del_url = $del_str = $edit_anchor_class
$del_url = $del_str = $edit_anchor_class = $editCopyUrlParams = $delUrlParams
= $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
// 1.2 Defines the URLs for the modify/delete link(s)
@ -2643,7 +2642,7 @@ class Results
if ($displayParts['edit_lnk'] == self::UPDATE_ROW) {
list($edit_url, $copy_url, $edit_str, $copy_str,
$edit_anchor_class)
$edit_anchor_class, $editCopyUrlParams)
= $this->_getModifiedLinks(
$where_clause,
$clause_is_unique, $url_sql_query
@ -2652,7 +2651,7 @@ class Results
} // end if (1.2.1)
// 1.2.2 Delete/Kill link(s)
list($del_url, $del_str, $js_conf)
list($del_url, $del_str, $js_conf, $delUrlParams)
= $this->_getDeleteAndKillLinks(
$where_clause, $clause_is_unique,
$url_sql_query, $displayParts['del_lnk'],
@ -2668,7 +2667,7 @@ class Results
self::POSITION_LEFT, $del_url, $displayParts, $row_no,
$where_clause, $where_clause_html, $condition_array,
$edit_url, $copy_url, $edit_anchor_class,
$edit_str, $copy_str, $del_str, $js_conf
$edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
);
} elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
@ -2677,7 +2676,7 @@ class Results
self::POSITION_NONE, $del_url, $displayParts, $row_no,
$where_clause, $where_clause_html, $condition_array,
$edit_url, $copy_url, $edit_anchor_class,
$edit_str, $copy_str, $del_str, $js_conf
$edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
);
} // end if (1.3)
@ -2711,7 +2710,7 @@ class Results
self::POSITION_RIGHT, $del_url, $displayParts, $row_no,
$where_clause, $where_clause_html, $condition_array,
$edit_url, $copy_url, $edit_anchor_class,
$edit_str, $copy_str, $del_str, $js_conf
$edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
);
}
@ -3327,15 +3326,9 @@ class Results
'goto' => 'sql.php',
);
$edit_url = 'tbl_change.php'
. Url::getCommon(
$_url_params + array('default_action' => 'update')
);
$edit_url = 'tbl_change.php';
$copy_url = 'tbl_change.php'
. Url::getCommon(
$_url_params + array('default_action' => 'insert')
);
$copy_url = 'tbl_change.php';
$edit_str = $this->_getActionLinkContent(
'b_edit', __('Edit')
@ -3350,7 +3343,7 @@ class Results
$edit_anchor_class .= ' nonunique';
}
return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class, $_url_params);
} // end of the '_getModifiedLinks()' function
@ -3401,7 +3394,7 @@ class Results
'message_to_show' => __('The row has been deleted.'),
'goto' => $lnk_goto,
);
$del_url = 'sql.php' . Url::getCommon($_url_params);
$del_url = 'sql.php';
$js_conf = 'DELETE FROM ' . Sanitize::jsFormat($this->__get('table'))
. ' WHERE ' . Sanitize::jsFormat($where_clause, false)
@ -3428,16 +3421,16 @@ class Results
'goto' => $lnk_goto,
);
$del_url = 'sql.php' . Url::getCommon($_url_params);
$del_url = 'sql.php';
$js_conf = $kill;
$del_str = Util::getIcon(
'b_drop', __('Kill')
);
} else {
$del_url = $del_str = $js_conf = null;
$del_url = $del_str = $js_conf = $_url_params = null;
}
return array($del_url, $del_str, $js_conf);
return array($del_url, $del_str, $js_conf, $_url_params);
} // end of the '_getDeleteAndKillLinks()' function
@ -3505,6 +3498,8 @@ class Results
* @param string $copy_str the label for copy row
* @param string $del_str the label for delete row
* @param string $js_conf text for the JS confirmation
* @param array $editCopyUrlParams URL parameters
* @param array $delUrlParams URL parameters
*
* @return string html content
*
@ -3515,7 +3510,7 @@ class Results
private function _getPlacedLinks(
$dir, $del_url, array $displayParts, $row_no, $where_clause, $where_clause_html,
array $condition_array, $edit_url, $copy_url,
$edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
$edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
) {
if (! isset($js_conf)) {
@ -3526,7 +3521,7 @@ class Results
$dir, $del_url, $displayParts,
$row_no, $where_clause, $where_clause_html, $condition_array,
$edit_url, $copy_url, $edit_anchor_class,
$edit_str, $copy_str, $del_str, $js_conf
$edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
);
} // end of the '_getPlacedLinks()' function
@ -4804,8 +4799,8 @@ class Results
/**
* Generates HTML to display the Create view in span tag
*
* @param array $analyzed_sql_results analyzed sql results
* @param string $url_query String with URL Parameters
* @param array $analyzed_sql_results analyzed sql results
* @param array $url_query URL Parameters
*
* @return string
*
@ -4813,14 +4808,15 @@ class Results
*
* @see _getResultsOperations()
*/
private function _getLinkForCreateView(array $analyzed_sql_results, $url_query)
private function _getLinkForCreateView(array $analyzed_sql_results, $urlParams)
{
$results_operations_html = '';
if (empty($analyzed_sql_results['procedure'])) {
$results_operations_html .= '<span>'
. Util::linkOrButton(
'view_create.php' . $url_query,
'view_create.php',
$urlParams,
Util::getIcon(
'b_view_add', __('Create view'), true
),
@ -4867,6 +4863,7 @@ class Results
{
$html = Util::linkOrButton(
'#',
null,
Util::getIcon(
'b_insrow', __('Copy to clipboard'), true
),
@ -4887,6 +4884,7 @@ class Results
{
$html = Util::linkOrButton(
'#',
null,
Util::getIcon(
'b_print', __('Print'), true
),
@ -4927,7 +4925,6 @@ class Results
'printview' => '1',
'sql_query' => $this->__get('sql_query'),
);
$url_query = Url::getCommon($_url_params);
if (!$header_shown) {
$results_operations_html .= $header;
@ -4937,7 +4934,7 @@ class Results
// show only view and not other options
if ($only_view) {
$results_operations_html .= $this->_getLinkForCreateView(
$analyzed_sql_results, $url_query
$analyzed_sql_results, $_url_params
);
if ($header_shown) {
@ -4992,7 +4989,8 @@ class Results
}
$results_operations_html .= Util::linkOrButton(
'tbl_export.php' . Url::getCommon($_url_params),
'tbl_export.php',
$_url_params,
Util::getIcon(
'b_tblexport', __('Export'), true
)
@ -5001,7 +4999,8 @@ class Results
// prepare chart
$results_operations_html .= Util::linkOrButton(
'tbl_chart.php' . Url::getCommon($_url_params),
'tbl_chart.php',
$_url_params,
Util::getIcon(
'b_chart', __('Display chart'), true
)
@ -5021,8 +5020,8 @@ class Results
if ($geometry_found) {
$results_operations_html
.= Util::linkOrButton(
'tbl_gis_visualization.php'
. Url::getCommon($_url_params),
'tbl_gis_visualization.php',
$_url_params,
Util::getIcon(
'b_globe',
__('Visualize GIS data'),
@ -5047,7 +5046,7 @@ class Results
}
$results_operations_html .= $this->_getLinkForCreateView(
$analyzed_sql_results, $url_query
$analyzed_sql_results, $_url_params
);
if ($header_shown) {
@ -5367,7 +5366,7 @@ class Results
$tag_params['class'] = 'ajax';
}
$result .= Util::linkOrButton(
'sql.php' . Url::getCommon($_url_params),
'sql.php', $_url_params,
$displayedData, $tag_params
);
}
@ -5443,6 +5442,7 @@ class Results
* Prepares an Edit link
*
* @param string $edit_url edit url
* @param array $urlParams URL parameters
* @param string $class css classes for td element
* @param string $edit_str text for the edit link
* @param string $where_clause where clause
@ -5455,7 +5455,7 @@ class Results
* @see _getTableBody(), _getCheckboxAndLinks()
*/
private function _getEditLink(
$edit_url, $class, $edit_str, $where_clause, $where_clause_html
$edit_url, $urlParams, $class, $edit_str, $where_clause, $where_clause_html
) {
$ret = '';
@ -5463,7 +5463,7 @@ class Results
$ret .= '<td class="' . $class . ' center print_ignore" '
. ' ><span class="nowrap">'
. Util::linkOrButton($edit_url, $edit_str);
. Util::linkOrButton($edit_url, $urlParams, $edit_str);
/*
* Where clause for selecting this row uniquely is provided as
* a hidden input. Used by jQuery scripts for handling grid editing
@ -5484,6 +5484,7 @@ class Results
* Prepares an Copy link
*
* @param string $copy_url copy url
* @param array $urlParams URL parameters
* @param string $copy_str text for the copy link
* @param string $where_clause where clause
* @param string $where_clause_html url encoded where clause
@ -5496,7 +5497,7 @@ class Results
* @see _getTableBody(), _getCheckboxAndLinks()
*/
private function _getCopyLink(
$copy_url, $copy_str, $where_clause, $where_clause_html, $class
$copy_url, $urlParams, $copy_str, $where_clause, $where_clause_html, $class
) {
$ret = '';
@ -5508,7 +5509,7 @@ class Results
}
$ret .= 'center print_ignore" ' . ' ><span class="nowrap">'
. Util::linkOrButton($copy_url, $copy_str);
. Util::linkOrButton($copy_url, $urlParams, $copy_str);
/*
* Where clause for selecting this row uniquely is provided as
@ -5529,10 +5530,11 @@ class Results
/**
* Prepares a Delete link
*
* @param string $del_url delete url
* @param string $del_str text for the delete link
* @param string $js_conf text for the JS confirmation
* @param string $class css classes for the td element
* @param string $del_url delete url
* @param array $delUrlParams URL parameters
* @param string $del_str text for the delete link
* @param string $js_conf text for the JS confirmation
* @param string $class css classes for the td element
*
* @return string the generated HTML
*
@ -5540,7 +5542,7 @@ class Results
*
* @see _getTableBody(), _getCheckboxAndLinks()
*/
private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
private function _getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, $class)
{
$ret = '';
@ -5556,6 +5558,7 @@ class Results
$ret .= 'center print_ignore" ' . ' >'
. Util::linkOrButton(
$del_url,
$delUrlParams,
$del_str,
array('class' => 'delete_row requireConfirm' . $ajax)
)
@ -5586,6 +5589,8 @@ class Results
* @param string $copy_str text for the copy link
* @param string $del_str text for the delete link
* @param string $js_conf text for the JS confirmation
* @param array $editCopyUrlParams URL parameters
* @param array $delUrlParams URL parameters
*
* @return string the generated HTML
*
@ -5596,49 +5601,51 @@ class Results
private function _getCheckboxAndLinks(
$position, $del_url, array $displayParts, $row_no, $where_clause,
$where_clause_html, array $condition_array,
$edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
$edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
) {
$ret = '';
$editUrlParams = $editCopyUrlParams + array('default_action' => 'update');
$copyUrlParams = $editCopyUrlParams + array('default_action' => 'insert');
if ($position == self::POSITION_LEFT) {
$ret .= $this->_getCheckboxForMultiRowSubmissions(
$del_url, $displayParts, $row_no, $where_clause_html,
$del_url . Url::getCommon($delUrlParams), $displayParts, $row_no, $where_clause_html,
$condition_array, '_left', ''
);
$ret .= $this->_getEditLink(
$edit_url, $class, $edit_str, $where_clause, $where_clause_html
$edit_url, $editUrlParams, $class, $edit_str, $where_clause, $where_clause_html
);
$ret .= $this->_getCopyLink(
$copy_url, $copy_str, $where_clause, $where_clause_html, ''
$copy_url, $copyUrlParams, $copy_str, $where_clause, $where_clause_html, ''
);
$ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
$ret .= $this->_getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, '');
} elseif ($position == self::POSITION_RIGHT) {
$ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
$ret .= $this->_getDeleteLink($del_url, $delUrlParams, $del_str, $js_conf, '');
$ret .= $this->_getCopyLink(
$copy_url, $copy_str, $where_clause, $where_clause_html, ''
$copy_url, $copyUrlParams, $copy_str, $where_clause, $where_clause_html, ''
);
$ret .= $this->_getEditLink(
$edit_url, $class, $edit_str, $where_clause, $where_clause_html
$edit_url, $editUrlParams, $class, $edit_str, $where_clause, $where_clause_html
);
$ret .= $this->_getCheckboxForMultiRowSubmissions(
$del_url, $displayParts, $row_no, $where_clause_html,
$del_url . Url::getCommon($delUrlParams), $displayParts, $row_no, $where_clause_html,
$condition_array, '_right', ''
);
} else { // $position == self::POSITION_NONE
$ret .= $this->_getCheckboxForMultiRowSubmissions(
$del_url, $displayParts, $row_no, $where_clause_html,
$del_url . Url::getCommon($delUrlParams), $displayParts, $row_no, $where_clause_html,
$condition_array, '_left', ''
);
}

View File

@ -197,6 +197,7 @@ class ErrorReport
unset($queryArray["table"]);
unset($queryArray["token"]);
unset($queryArray["server"]);
unset($queryArray["eq"]);
$query = http_build_query($queryArray);
} else {
$query = '';

View File

@ -479,14 +479,14 @@ class Export
*/
$back_button = '<p id="export_back_button">[ <a href="';
if ($export_type == 'server') {
$back_button .= 'server_export.php" data-post="' . Url::getCommon([], '');
$back_button .= 'server_export.php" data-post="' . Url::getCommon([], '', false);
} elseif ($export_type == 'database') {
$back_button .= 'db_export.php" data-post="' . Url::getCommon(array('db' => $db), '');
$back_button .= 'db_export.php" data-post="' . Url::getCommon(array('db' => $db), '', false);
} else {
$back_button .= 'tbl_export.php" data-post="' . Url::getCommon(
array(
'db' => $db, 'table' => $table
), ''
), '', false
);
}

View File

@ -741,7 +741,7 @@ class Index
$r .= '" ' . $row_span . '>'
. ' <a class="';
$r .= 'ajax';
$r .= '" href="tbl_indexes.php" data-post="' . Url::getCommon($this_params, '')
$r .= '" href="tbl_indexes.php" data-post="' . Url::getCommon($this_params, '', false)
. '">' . Util::getIcon('b_edit', __('Edit')) . '</a>'
. '</td>' . "\n";
$this_params = $GLOBALS['url_params'];
@ -766,7 +766,8 @@ class Index
$r .= '<input type="hidden" class="drop_primary_key_index_msg"'
. ' value="' . $js_msg . '" />';
$r .= Util::linkOrButton(
'sql.php' . Url::getCommon($this_params),
'sql.php',
$this_params,
Util::getIcon('b_drop', __('Drop')),
array('class' => 'drop_primary_key_index_anchor ajax')
);

View File

@ -280,12 +280,12 @@ class InsertEdit
if (! $is_show) {
return ' : <a href="tbl_change.php" data-post="'
. Url::getCommon($this_url_params, '') . '">'
. Url::getCommon($this_url_params, '', false) . '">'
. $this->showTypeOrFunctionLabel($which)
. '</a>';
}
return '<th><a href="tbl_change.php" data-post="'
. Url::getCommon($this_url_params, '')
. Url::getCommon($this_url_params, '', false)
. '" title="' . __('Hide') . '">'
. $this->showTypeOrFunctionLabel($which)
. '</a></th>';
@ -857,7 +857,7 @@ class InsertEdit
'rownumber' => $rownumber,
'data' => $data
),
''
'', false
) . '">'
. str_replace("'", "\'", $titles['Browse']) . '</a>';
return $html_output;
@ -1704,6 +1704,7 @@ class InsertEdit
return '<span class="open_gis_editor">'
. Util::linkOrButton(
'#',
null,
$edit_str,
array(),
'_blank'

View File

@ -231,7 +231,7 @@ class Navigation
$html .= '<tr>';
$html .= '<td>' . htmlspecialchars($hiddenItem) . '</td>';
$html .= '<td style="width:80px"><a href="navigation.php" data-post="'
. Url::getCommon($params, '') . '"'
. Url::getCommon($params, '', false) . '"'
. ' class="unhideNavItem ajax">'
. Util::getIcon('show', __('Show'))
. '</a></td>';

View File

@ -102,13 +102,13 @@ class NavigationTree
$this->_pos = $this->_getNavigationDbPos();
}
// Get the active node
if (isset($_REQUEST['aPath'])) {
$this->_aPath[0] = $this->_parsePath($_REQUEST['aPath']);
$this->_pos2_name[0] = $_REQUEST['pos2_name'];
$this->_pos2_value[0] = $_REQUEST['pos2_value'];
if (isset($_REQUEST['pos3_name'])) {
$this->_pos3_name[0] = $_REQUEST['pos3_name'];
$this->_pos3_value[0] = $_REQUEST['pos3_value'];
if (isset($_POST['aPath'])) {
$this->_aPath[0] = $this->_parsePath($_POST['aPath']);
$this->_pos2_name[0] = $_POST['pos2_name'];
$this->_pos2_value[0] = $_POST['pos2_value'];
if (isset($_POST['pos3_name'])) {
$this->_pos3_name[0] = $_POST['pos3_name'];
$this->_pos3_value[0] = $_POST['pos3_value'];
}
} else {
if (isset($_POST['n0_aPath'])) {
@ -129,8 +129,8 @@ class NavigationTree
}
}
}
if (isset($_REQUEST['vPath'])) {
$this->_vPath[0] = $this->_parsePath($_REQUEST['vPath']);
if (isset($_POST['vPath'])) {
$this->_vPath[0] = $this->_parsePath($_POST['vPath']);
} else {
if (isset($_POST['n0_vPath'])) {
$count = 0;
@ -142,11 +142,11 @@ class NavigationTree
}
}
}
if (isset($_REQUEST['searchClause'])) {
$this->_searchClause = $_REQUEST['searchClause'];
if (isset($_POST['searchClause'])) {
$this->_searchClause = $_POST['searchClause'];
}
if (isset($_REQUEST['searchClause2'])) {
$this->_searchClause2 = $_REQUEST['searchClause2'];
if (isset($_POST['searchClause2'])) {
$this->_searchClause2 = $_POST['searchClause2'];
}
// Initialise the tree by creating a root node
$node = NodeFactory::getInstance('NodeDatabaseContainer', 'root');
@ -1156,7 +1156,7 @@ class NavigationTree
}
foreach ($icons as $key => $icon) {
$link = vsprintf($iconLinks[$key], $args);
$link = $this->encryptQueryParams(vsprintf($iconLinks[$key], $args));
if ($linkClass != '') {
$retval .= "<a class='$linkClass' href='$link'>";
$retval .= "{$icon}</a>";
@ -1174,7 +1174,7 @@ class NavigationTree
foreach ($node->parents(true) as $parent) {;
$args[] = urlencode($parent->real_name);
}
$link = vsprintf($node->links['text'], $args);
$link = $this->encryptQueryParams(vsprintf($node->links['text'], $args));
$title = isset($node->links['title']) ? $node->links['title'] : '';
if ($node->type == Node::CONTAINER) {
$retval .= "&nbsp;<a class='hover_show_full' href='$link'>";
@ -1557,4 +1557,23 @@ class NavigationTree
return $retval;
}
/**
* @param string $link
*
* @return string
*/
private function encryptQueryParams($link)
{
global $PMA_Config;
if (! $PMA_Config->get('URLQueryEncryption')) {
return $link;
}
$url = parse_url($link);
parse_str(htmlspecialchars_decode($url['query']), $query);
return $url['path'] . '?' . htmlspecialchars(Url::buildHttpQuery($query));
}
}

View File

@ -678,7 +678,7 @@ class NodeDatabase extends Node
);
$ret = '<span class="dbItemControls">'
. '<a href="navigation.php" data-post="'
. Url::getCommon($params, '') . '"'
. Url::getCommon($params, '', false) . '"'
. ' class="showUnhide ajax">'
. Util::getImage(
'show',

View File

@ -49,7 +49,7 @@ abstract class NodeDatabaseChild extends Node
$ret = '<span class="navItemControls">'
. '<a href="navigation.php" data-post="'
. Url::getCommon($params, '') . '"'
. Url::getCommon($params, '', false) . '"'
. ' class="hideNavItem ajax">'
. Util::getImage('hide', __('Hide'))
. '</a></span>';

View File

@ -1507,7 +1507,8 @@ class Operations
{
return '<li>'
. Util::linkOrButton(
'sql.php' . Url::getCommon(array_merge($url_params, $params)),
'sql.php',
array_merge($url_params, $params),
$action_message,
['class' => 'maintain_action ajax']
)
@ -1567,7 +1568,8 @@ class Operations
public function getDeleteDataOrTablelink(array $url_params, $syntax, $link, $htmlId)
{
return '<li>' . Util::linkOrButton(
'sql.php' . Url::getCommon($url_params),
'sql.php',
$url_params,
$link,
array('id' => $htmlId, 'class' => 'ajax')
)

View File

@ -73,7 +73,7 @@ class ReplicationGui
$_url_params['repl_clear_scr'] = true;
$html .= ' <li><a href="server_replication.php" data-post="';
$html .= Url::getCommon($_url_params, '')
$html .= Url::getCommon($_url_params, '', false)
. '" id="master_addslaveuser_href">';
$html .= __('Add slave replication user') . '</a></li>';
}
@ -188,7 +188,7 @@ class ReplicationGui
}
$_url_params['sr_slave_control_parm'] = 'IO_THREAD';
$slave_control_io_link = Url::getCommon($_url_params, '');
$slave_control_io_link = Url::getCommon($_url_params, '', false);
if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') {
$_url_params['sr_slave_action'] = 'start';
@ -197,7 +197,7 @@ class ReplicationGui
}
$_url_params['sr_slave_control_parm'] = 'SQL_THREAD';
$slave_control_sql_link = Url::getCommon($_url_params, '');
$slave_control_sql_link = Url::getCommon($_url_params, '', false);
if ($server_slave_replication[0]['Slave_IO_Running'] == 'No'
|| $server_slave_replication[0]['Slave_SQL_Running'] == 'No'
@ -208,15 +208,15 @@ class ReplicationGui
}
$_url_params['sr_slave_control_parm'] = null;
$slave_control_full_link = Url::getCommon($_url_params, '');
$slave_control_full_link = Url::getCommon($_url_params, '', false);
$_url_params['sr_slave_action'] = 'reset';
$slave_control_reset_link = Url::getCommon($_url_params, '');
$slave_control_reset_link = Url::getCommon($_url_params, '', false);
$_url_params = $GLOBALS['url_params'];
$_url_params['sr_take_action'] = true;
$_url_params['sr_slave_skip_error'] = true;
$slave_skip_error_link = Url::getCommon($_url_params, '');
$slave_skip_error_link = Url::getCommon($_url_params, '', false);
if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') {
$html .= Message::error(
@ -233,7 +233,7 @@ class ReplicationGui
$_url_params['sl_configure'] = true;
$_url_params['repl_clear_scr'] = true;
$reconfiguremaster_link = Url::getCommon($_url_params, '');
$reconfiguremaster_link = Url::getCommon($_url_params, '', false);
$html .= __(
'Server is configured as slave in a replication process. Would you ' .
@ -293,7 +293,7 @@ class ReplicationGui
'This server is not configured as slave in a replication process. '
. 'Would you like to %sconfigure%s it?'
),
'<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '') . '">',
'<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '', false) . '">',
'</a>'
);
}
@ -355,7 +355,7 @@ class ReplicationGui
'This server is not configured as master in a replication process. '
. 'Would you like to %sconfigure%s it?'
),
'<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '') . '">',
'<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '', false) . '">',
'</a>'
);
$html .= '</fieldset>';

View File

@ -191,7 +191,7 @@ class RteList
*/
public static function getRoutineRow(array $routine, $rowclass = '')
{
global $url_query, $db, $titles;
global $url_query, $url_params, $db, $titles;
$sql_drop = sprintf(
'DROP %s IF EXISTS %s',
@ -316,7 +316,11 @@ class RteList
$retval .= " </td>\n";
$retval .= " <td>\n";
$retval .= Util::linkOrButton(
'sql.php' . $url_query . '&amp;sql_query=' . urlencode($sql_drop) . '&amp;goto=db_routines.php' . urlencode("?db={$db}"),
'sql.php',
array_merge(
$url_params,
['sql_query' => $sql_drop, 'goto' => 'db_routines.php' . Url::getCommon(['db' => $db])]
),
$titles['Drop'],
['class' => 'ajax drop_anchor']
);
@ -343,7 +347,7 @@ class RteList
*/
public static function getTriggerRow(array $trigger, $rowclass = '')
{
global $url_query, $db, $table, $titles;
global $url_query, $url_params, $db, $table, $titles;
$retval = " <tr class='$rowclass'>\n";
$retval .= " <td>\n";
@ -360,8 +364,8 @@ class RteList
$retval .= " </td>\n";
if (empty($table)) {
$retval .= " <td>\n";
$retval .= "<a href='db_triggers.php{$url_query}"
. "&amp;table=" . urlencode($trigger['table']) . "'>"
$retval .= "<a href='db_triggers.php"
. Url::getCommon(array_merge($url_params, ['table' => $trigger['table']])) . "'>"
. htmlspecialchars($trigger['table']) . "</a>";
$retval .= " </td>\n";
}
@ -390,7 +394,11 @@ class RteList
$retval .= " <td>\n";
if (Util::currentUserHasPrivilege('TRIGGER', $db)) {
$retval .= Util::linkOrButton(
'sql.php' . $url_query . '&amp;sql_query=' . urlencode($trigger['drop']) . '&amp;goto=db_triggers.php' . urlencode("?db={$db}"),
'sql.php',
array_merge(
$url_params,
['sql_query' => $trigger['drop'], 'goto' => 'db_triggers.php' . Url::getCommon(['db' => $db])]
),
$titles['Drop'],
['class' => 'ajax drop_anchor']
);
@ -419,7 +427,7 @@ class RteList
*/
public static function getEventRow(array $event, $rowclass = '')
{
global $url_query, $db, $titles;
global $url_query, $url_params, $db, $titles;
$sql_drop = sprintf(
'DROP EVENT IF EXISTS %s',
@ -468,7 +476,11 @@ class RteList
$retval .= " <td>\n";
if (Util::currentUserHasPrivilege('EVENT', $db)) {
$retval .= Util::linkOrButton(
'sql.php' . $url_query . '&amp;sql_query=' . urlencode($sql_drop) . '&amp;goto=db_events.php' . urlencode("?db={$db}"),
'sql.php',
array_merge(
$url_params,
['sql_query' => $sql_drop, 'goto' => 'db_events.php' . Url::getCommon(['db' => $db])]
),
$titles['Drop'],
['class' => 'ajax drop_anchor']
);

View File

@ -2844,7 +2844,7 @@ class Privileges
$html .= ' href="server_privileges.php';
if ($linktype == 'revoke') {
$html .= '" data-post="' . Url::getCommon($params, '');
$html .= '" data-post="' . Url::getCommon($params, '', false);
} else {
$html .= Url::getCommon($params);
}

View File

@ -141,7 +141,7 @@ class Processes
}
$retval .= '<th>';
$columnUrl = Url::getCommon($column);
$columnUrl = Url::getCommon($column, '', false);
$retval .= '<a href="server_status_processes.php" data-post="' . $columnUrl . '" class="sortlink">';
$retval .= $column['column_name'];
@ -179,7 +179,7 @@ class Processes
if (isset($_POST['sort_order'])) {
$url_params['sort_order'] = $_POST['sort_order'];
}
$retval .= '<a href="server_status_processes.php" data-post="' . Url::getCommon($url_params, '') . '" >';
$retval .= '<a href="server_status_processes.php" data-post="' . Url::getCommon($url_params, '', false) . '" >';
if ($show_full_sql) {
$retval .= Util::getImage('s_partialtext',
__('Truncate Shown Queries'), ['class' => 'icon_fulltext']);
@ -275,7 +275,7 @@ class Processes
$retval = '<tr>';
$retval .= '<td><a class="ajax kill_process" href="server_status_processes.php"'
. ' data-post="' . Url::getCommon(['kill' => $process['Id']], '') . '">'
. ' data-post="' . Url::getCommon(['kill' => $process['Id']], '', false) . '">'
. __('Kill') . '</a></td>';
$retval .= '<td class="value">' . $process['Id'] . '</td>';
$retval .= '<td>' . htmlspecialchars($process['User']) . '</td>';

View File

@ -115,7 +115,7 @@ class UserGroups
array(
'viewUsers' => 1, 'userGroup' => $groupName
),
''
'', false
)
. '">'
. Util::getIcon('b_usrlist', __('View users'))
@ -126,7 +126,7 @@ class UserGroups
array(
'editUserGroup' => 1, 'userGroup' => $groupName
),
''
'', false
)
. '">'
. Util::getIcon('b_edit', __('Edit')) . '</a>';
@ -137,7 +137,7 @@ class UserGroups
array(
'deleteUserGroup' => 1, 'userGroup' => $groupName
),
''
'', false
)
. '">'
. Util::getIcon('b_drop', __('Delete')) . '</a>';

View File

@ -227,7 +227,7 @@ class Sql
. htmlspecialchars($_POST['curr_value'])
. '</span>'
. '<a href="browse_foreigners.php" data-post="'
. Url::getCommon($_url_params, '') . '"'
. Url::getCommon($_url_params, '', false) . '"'
. 'class="ajax browse_foreign" ' . '>'
. __('Browse foreign values')
. '</a>';

View File

@ -199,20 +199,20 @@ class Tracking
$html .= Url::getCommon($url_params + [
'version' => $version['version'],
'submit_delete_version' => true,
], '');
], '', false);
$html .= '">' . $delete . '</a></td>';
$html .= '<td><a href="tbl_tracking.php" data-post="';
$html .= Url::getCommon($url_params + [
'report' => 'true',
'version' => $version['version'],
], '');
], '', false);
$html .= '">' . $report . '</a>';
$html .= '&nbsp;&nbsp;';
$html .= '<a href="tbl_tracking.php" data-post="';
$html .= Url::getCommon($url_params + [
'snapshot' => 'true',
'version' => $version['version'],
], '');
], '', false);
$html .= '">' . $structure . '</a>';
$html .= '</td>';
$html .= '</tr>';

View File

@ -7,6 +7,8 @@
*/
namespace PhpMyAdmin;
use PhpMyAdmin\Crypto\Crypto;
/**
* Static methods for URL/hidden inputs generating
*
@ -159,14 +161,15 @@ class Url
*
* @param mixed $params optional, Contains an associative array with url params
* @param string $divider optional character to use instead of '?'
* @param bool $encrypt whether to encrypt URL params
*
* @return string string with URL parameters
* @access public
*/
public static function getCommon($params = array(), $divider = '?')
public static function getCommon($params = array(), $divider = '?', $encrypt = true)
{
return htmlspecialchars(
Url::getCommonRaw($params, $divider)
Url::getCommonRaw($params, $divider, $encrypt)
);
}
@ -195,15 +198,15 @@ class Url
*
* @param mixed $params optional, Contains an associative array with url params
* @param string $divider optional character to use instead of '?'
* @param bool $encrypt whether to encrypt URL params
*
* @return string string with URL parameters
* @access public
*/
public static function getCommonRaw($params = array(), $divider = '?')
public static function getCommonRaw($params = array(), $divider = '?', $encrypt = true)
{
/** @var Config $PMA_Config */
global $PMA_Config;
$separator = Url::getArgSeparator();
// avoid overwriting when creating navi panel links to servers
if (isset($GLOBALS['server'])
@ -218,7 +221,7 @@ class Url
$params['lang'] = $GLOBALS['lang'];
}
$query = http_build_query($params, null, $separator);
$query = self::buildHttpQuery($params, $encrypt);
if ($divider != '?' || strlen($query) > 0) {
return $divider . $query;
@ -227,6 +230,81 @@ class Url
return '';
}
/**
* @param array<string, mixed> $params
* @param bool $encrypt whether to encrypt URL params
*
* @return string
*/
public static function buildHttpQuery($params, $encrypt = true)
{
global $PMA_Config;
$separator = self::getArgSeparator();
if (! $encrypt || ! $PMA_Config->get('URLQueryEncryption')) {
return http_build_query($params, null, $separator);
}
$data = $params;
$keys = [
'db',
'table',
'field',
'sql_query',
'sql_signature',
'where_clause',
'goto',
'back',
'message_to_show',
'username',
'hostname',
'dbname',
'tablename',
'checkprivsdb',
'checkprivstable',
];
$paramsToEncrypt = [];
foreach ($params as $paramKey => $paramValue) {
if (! in_array($paramKey, $keys)) {
continue;
}
$paramsToEncrypt[$paramKey] = $paramValue;
unset($data[$paramKey]);
}
if ($paramsToEncrypt !== []) {
$data['eq'] = self::encryptQuery(json_encode($paramsToEncrypt));
}
return http_build_query($data, null, $separator);
}
/**
* @param string $query
*
* @return string
*/
public static function encryptQuery($query)
{
$crypto = new Crypto();
return strtr(base64_encode($crypto->encrypt($query)), '+/', '-_');
}
/**
* @param string $query
*
* @return string|null
*/
public static function decryptQuery($query)
{
$crypto = new Crypto();
return $crypto->decrypt(base64_decode(strtr($query, '-_', '+/')));
}
/**
* Returns url separator
*

View File

@ -1039,7 +1039,8 @@ class Util
$explain_params['sql_query'] = 'EXPLAIN ' . $sql_query;
$explain_link = ' [&nbsp;'
. self::linkOrButton(
'import.php' . Url::getCommon($explain_params),
'import.php',
$explain_params,
__('Explain SQL')
) . '&nbsp;]';
} elseif (preg_match(
@ -1050,7 +1051,8 @@ class Util
= mb_substr($sql_query, 8);
$explain_link = ' [&nbsp;'
. self::linkOrButton(
'import.php' . Url::getCommon($explain_params),
'import.php',
$explain_params,
__('Skip Explain SQL')
) . ']';
$url = 'https://mariadb.org/explain_analyzer/analyze/'
@ -1059,6 +1061,7 @@ class Util
$explain_link .= ' ['
. self::linkOrButton(
htmlspecialchars('url.php?url=' . urlencode($url)),
null,
sprintf(__('Analyze Explain at %s'), 'mariadb.org'),
array(),
'_blank'
@ -1074,9 +1077,8 @@ class Util
if (! empty($cfg['SQLQuery']['Edit'])
&& empty($GLOBALS['show_as_php'])
) {
$edit_link .= Url::getCommon($url_params);
$edit_link = ' [&nbsp;'
. self::linkOrButton($edit_link, __('Edit'))
. self::linkOrButton($edit_link, $url_params, __('Edit'))
. '&nbsp;]';
} else {
$edit_link = '';
@ -1089,14 +1091,16 @@ class Util
if (! empty($GLOBALS['show_as_php'])) {
$php_link = ' [&nbsp;'
. self::linkOrButton(
'import.php' . Url::getCommon($url_params),
'import.php',
$url_params,
__('Without PHP code')
)
. '&nbsp;]';
$php_link .= ' [&nbsp;'
. self::linkOrButton(
'import.php' . Url::getCommon($url_params),
'import.php',
$url_params,
__('Submit query')
)
. '&nbsp;]';
@ -1105,7 +1109,8 @@ class Util
$php_params['show_as_php'] = 1;
$php_link = ' [&nbsp;'
. self::linkOrButton(
'import.php' . Url::getCommon($php_params),
'import.php',
$php_params,
__('Create PHP code')
)
. '&nbsp;]';
@ -1121,7 +1126,7 @@ class Util
) {
$refresh_link = 'import.php' . Url::getCommon($url_params);
$refresh_link = ' [&nbsp;'
. self::linkOrButton($refresh_link, __('Refresh')) . ']';
. self::linkOrButton('import.php', $url_params, __('Refresh')) . ']';
} else {
$refresh_link = '';
} //refresh
@ -1163,6 +1168,7 @@ class Util
$inline_edit_link = ' ['
. self::linkOrButton(
'#',
null,
_pgettext('Inline edit query', 'Edit inline'),
array('class' => 'inline_edit_sql')
)
@ -1707,17 +1713,22 @@ class Util
* - URL components are over Suhosin limits
* - There is SQL query in the parameters
*
* @param string $url the URL
* @param string $message the link message
* @param mixed $tag_params string: js confirmation; array: additional tag
* params (f.e. style="")
* @param string $target target
* @param string $urlPath the URL
* @param array|null $urlParams URL parameters
* @param string $message the link message
* @param mixed $tag_params string: js confirmation; array: additional tag params (f.e. style="")
* @param string $target target
*
* @return string the results to be echoed or saved in an array
*/
public static function linkOrButton(
$url, $message, $tag_params = array(), $target = ''
$urlPath, $urlParams, $message, $tag_params = array(), $target = ''
) {
$url = $urlPath;
if (is_array($urlParams)) {
$url = $urlPath . Url::getCommon($urlParams, '?', false);
}
$url_length = strlen($url);
if (! is_array($tag_params)) {
@ -1776,7 +1787,11 @@ class Util
) {
$url .= '?' . explode('&', $parts[1], 2)[0];
}
} else {
$url = $urlPath;
if (is_array($urlParams)) {
$url = $urlPath . Url::getCommon($urlParams);
}
}
foreach ($tag_params as $par_name => $par_value) {
@ -4737,9 +4752,7 @@ class Util
$urlParams['tbl_group'] = $_REQUEST['tbl_group'];
}
$url = 'db_structure.php' . Url::getCommon($urlParams);
return self::linkOrButton($url, $title . $orderImg, $orderLinkParams);
return self::linkOrButton('db_structure.php', $urlParams, $title . $orderImg, $orderLinkParams);
}
/**

View File

@ -132,6 +132,8 @@ if (! defined('PMA_NO_SESSION')) {
Session::setUp($GLOBALS['PMA_Config'], $GLOBALS['error_handler']);
}
Core::populateRequestWithEncryptedQueryParams();
/**
* init some variables LABEL_variables_init
*/

View File

@ -603,6 +603,13 @@ $cfg['Servers'][$i]['tracking_add_drop_table'] = true;
*/
$cfg['Servers'][$i]['tracking_add_drop_database'] = true;
/**
* Whether to show or hide detailed MySQL/MariaDB connection errors on the login page.
*
* @global bool $cfg['Servers'][$i]['hide_connection_errors']
*/
$cfg['Servers'][$i]['hide_connection_errors'] = false;
/**
* Default server (0 = no default server)
*
@ -817,6 +824,20 @@ $cfg['UseDbSearch'] = true;
*/
$cfg['IgnoreMultiSubmitErrors'] = false;
/**
* Define whether phpMyAdmin will encrypt sensitive data from the URL query string.
*
* @global bool $cfg['URLQueryEncryption']
*/
$cfg['URLQueryEncryption'] = false;
/**
* A secret key used to encrypt/decrypt the URL query string. Should be 32 bytes long.
*
* @global string $cfg['URLQueryEncryptionSecretKey']
*/
$cfg['URLQueryEncryptionSecretKey'] = '';
/**
* allow login to any user entered server in cookie based authentication
*

View File

@ -157,7 +157,7 @@ if ($cf->getServerCount() > 0) {
, __('Edit') , '</a>';
echo ' | ';
echo '<a class="delete-server" href="' . Url::getCommon(array('page' => 'servers', 'mode' => 'remove', 'id' => $id));
echo '" data-post="' . Url::getCommon(array('token' => $_SESSION[' PMA_token ']), '') . '">';
echo '" data-post="' . Url::getCommon(array('token' => $_SESSION[' PMA_token ']), '', false) . '">';
echo __('Delete') . '</a>';
echo '</small>';
echo '</td>';

View File

@ -50,7 +50,7 @@
'back': 'db_tracking.php',
'table': version.table_name,
'delete_tracking': true
}, '') }}">
}, '', false) }}">
{{ Util_getIcon('b_drop', 'Delete tracking'|trans) }}
</a>
</td>
@ -61,7 +61,7 @@
'goto': 'tbl_tracking.php',
'back': 'db_tracking.php',
'table': version.table_name
}, '') }}">
}, '', false) }}">
{{ Util_getIcon('b_versions', 'Versions'|trans) }}
</a>
<a href="tbl_tracking.php" data-post="
@ -72,7 +72,7 @@
'table': version.table_name,
'report': true,
'version': version.version
}, '') }}">
}, '', false) }}">
{{ Util_getIcon('b_report', 'Tracking report'|trans) }}
</a>
<a href="tbl_tracking.php" data-post="
@ -83,7 +83,7 @@
'table': version.table_name,
'snapshot': true,
'version': version.version
}, '') }}">
}, '', false) }}">
{{ Util_getIcon('b_props', 'Structure snapshot'|trans) }}
</a>
</td>

View File

@ -67,7 +67,7 @@
{{ Message_notice('Note: Enabling the database statistics here might cause heavy traffic between the web server and the MySQL server.'|trans) }}
<ul>
<li class="li_switch_dbstats">
<a href="server_databases.php" data-post="{{ Url_getCommon({'dbstats': '1'}, '') }}" title="{% trans 'Enable statistics' %}">
<a href="server_databases.php" data-post="{{ Url_getCommon({'dbstats': '1'}, '', false) }}" title="{% trans 'Enable statistics' %}">
<strong>{% trans 'Enable statistics' %}</strong>
</a>
</li>

View File

@ -26,9 +26,8 @@
{% if one_key['constraint'] is defined %}
<input type="hidden" class="drop_foreign_key_msg" value="
{{- js_msg }}" />
{% set drop_url = 'sql.php' ~ Url_getCommon(this_params) %}
{% set drop_str = Util_getIcon('b_drop', 'Drop'|trans) %}
{{ Util_linkOrButton(drop_url, drop_str, {'class': 'drop_foreign_key_anchor ajax'}) }}
{{ Util_linkOrButton('sql.php', this_params, drop_str, {'class': 'drop_foreign_key_anchor ajax'}) }}
{% endif %}
</td>
<td>

View File

@ -21,7 +21,7 @@
value="{{ criteria_values[column_index] }}"
{% endif %} />
<a class="ajax browse_foreign" href="browse_foreigners.php" data-post="
{{- Url_getCommon({'db': db, 'table': table}, '') -}}
{{- Url_getCommon({'db': db, 'table': table}, '', false) -}}
&amp;field={{ column_name|url_encode }}&amp;fieldkey=
{{- column_index }}&amp;fromsearch=1">
{{ titles['Browse']|replace({"'": "\\'"})|raw }}
@ -34,10 +34,9 @@
class="textfield"
id="field_{{ column_index }}" />
{% if in_fbs %}
{% set edit_url = 'gis_data_editor.php' ~ Url_getCommon() %}
{% set edit_str = Util_getIcon('b_edit', 'Edit/Insert'|trans) %}
<span class="open_search_gis_editor">
{{ Util_linkOrButton(edit_url, edit_str, [], '_blank') }}
{{ Util_linkOrButton('gis_data_editor.php', [], edit_str, [], '_blank') }}
</span>
{% endif %}
{% elseif column_type starts with 'enum'

View File

@ -134,7 +134,7 @@
{% if partitions is empty %}
<input type="submit" name="edit_partitioning" value="{% trans 'Partition table' %}" />
{% else %}
{{ Util_linkOrButton(remove_url, 'Remove partitioning'|trans, {
{{ Util_linkOrButton('sql.php', remove_url_params, 'Remove partitioning'|trans, {
'class': 'button ajax',
'id': 'remove_partitioning'
}) }}

View File

@ -133,9 +133,9 @@
{# Work on the table #}
<div id="structure-action-links">
{% if tbl_is_view and not db_is_system_schema %}
{% set edit_view_url = 'view_create.php' ~ edit_view_url %}
{{ Util_linkOrButton(
edit_view_url,
'view_create.php',
{'db': db, 'table': table},
Util_getIcon('b_edit', 'Edit view'|trans, true)
) }}
{% endif %}
@ -194,7 +194,6 @@
{{ Util_getDivForSliderEffect('partitions', 'Partitions'|trans) }}
{% set remove_sql = 'ALTER TABLE ' ~ Util_backquote(table) ~ ' REMOVE PARTITIONING' %}
{% set remove_url = 'sql.php' ~ url_query ~ '&sql_query=' ~ remove_sql|url_encode %}
{% include 'table/structure/display_partitions.twig' with {
'db': db,
@ -209,7 +208,7 @@
'sub_partition_expression': has_sub_partitions ? first_sub_partition.getExpression(),
'action_icons': action_icons,
'range_or_list': range_or_list,
'remove_url': remove_url
'remove_url_params': url_params|merge({'sql_query': remove_sql})
} only %}
{% else %}
{% include 'table/structure/display_partitions.twig' with {

View File

@ -26,6 +26,7 @@ class PageSettingsTest extends PmaTestCase
public function setUp()
{
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['server'] = 1;
$GLOBALS['db'] = 'db';
$GLOBALS['table'] = '';

View File

@ -34,6 +34,7 @@ class ServerDatabasesControllerTest extends PmaTestCase
//$GLOBALS
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['db'] = 'db';

View File

@ -11,6 +11,7 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\Core;
use PhpMyAdmin\Sanitize;
use PhpMyAdmin\Tests\PmaTestCase;
use PhpMyAdmin\Url;
use stdClass;
/**
@ -50,6 +51,7 @@ class CoreTest extends PmaTestCase
$GLOBALS['db'] = '';
$GLOBALS['table'] = '';
$GLOBALS['PMA_PHP_SELF'] = 'http://example.net/';
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
}
/**
@ -1226,4 +1228,61 @@ class CoreTest extends PmaTestCase
// Must work now, (good secret and blowfish_secret)
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* @return void
*/
public function testPopulateRequestWithEncryptedQueryParams()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryption', true);
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$_GET = ['pos' => '0', 'eq' => Url::encryptQuery('{"db":"test_db","table":"test_table"}')];
$_REQUEST = $_GET;
Core::populateRequestWithEncryptedQueryParams();
$expected = ['pos' => '0', 'db' => 'test_db', 'table' => 'test_table'];
$this->assertEquals($expected, $_GET);
$this->assertEquals($expected, $_REQUEST);
}
/**
* @return void
*
* @dataProvider providerForTestPopulateRequestWithEncryptedQueryParamsWithInvalidParam
*/
public function testPopulateRequestWithEncryptedQueryParamsWithInvalidParam($encrypted, $decrypted)
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryption', true);
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$_GET = $encrypted;
$_REQUEST = $encrypted;
Core::populateRequestWithEncryptedQueryParams();
$this->assertEquals($decrypted, $_GET);
$this->assertEquals($decrypted, $_REQUEST);
}
/**
* @return string[][][]
*/
public function providerForTestPopulateRequestWithEncryptedQueryParamsWithInvalidParam()
{
return [
[[], []],
[['eq' => []], []],
[['eq' => ''], []],
[['eq' => 'invalid'], []],
];
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace PhpMyAdmin\Tests\Crypto;
use PhpMyAdmin\Crypto\Crypto;
use PhpMyAdmin\Tests\PmaTestCase;
/**
* @covers \PhpMyAdmin\Crypto\Crypto
*/
class CryptoTest extends PmaTestCase
{
/**
* @return void
*/
public function testWithValidKeyFromConfig()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$cryptoWithSodium = new Crypto();
$encrypted = $cryptoWithSodium->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
$this->assertArrayNotHasKey('URLQueryEncryptionSecretKey', $_SESSION);
$cryptoWithPhpseclib = new Crypto(true);
$encrypted = $cryptoWithPhpseclib->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
$this->assertArrayNotHasKey('URLQueryEncryptionSecretKey', $_SESSION);
}
/**
* @return void
*/
public function testWithValidKeyFromSession()
{
global $PMA_Config;
$_SESSION = ['URLQueryEncryptionSecretKey' => str_repeat('a', 32)];
$PMA_Config->set('URLQueryEncryptionSecretKey', '');
$cryptoWithSodium = new Crypto();
$encrypted = $cryptoWithSodium->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
$cryptoWithPhpseclib = new Crypto(true);
$encrypted = $cryptoWithPhpseclib->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
}
/**
* @return void
*/
public function testWithNewSessionKey()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryptionSecretKey', '');
$cryptoWithSodium = new Crypto();
$encrypted = $cryptoWithSodium->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
$this->assertEquals(32, mb_strlen($_SESSION['URLQueryEncryptionSecretKey'], '8bit'));
$cryptoWithPhpseclib = new Crypto(true);
$encrypted = $cryptoWithPhpseclib->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
$this->assertArrayHasKey('URLQueryEncryptionSecretKey', $_SESSION);
$this->assertEquals(32, mb_strlen($_SESSION['URLQueryEncryptionSecretKey'], '8bit'));
}
/**
* @return void
*/
public function testDecryptWithInvalidKey()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$cryptoWithSodium = new Crypto();
$encrypted = $cryptoWithSodium->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithSodium->decrypt($encrypted));
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('b', 32));
$cryptoWithSodium = new Crypto();
$this->assertNull($cryptoWithSodium->decrypt($encrypted));
$cryptoWithPhpseclib = new Crypto(true);
$encrypted = $cryptoWithPhpseclib->encrypt('test');
$this->assertNotSame('test', $encrypted);
$this->assertSame('test', $cryptoWithPhpseclib->decrypt($encrypted));
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$cryptoWithPhpseclib = new Crypto(true);
$this->assertNull($cryptoWithPhpseclib->decrypt($encrypted));
}
}

View File

@ -44,6 +44,7 @@ class ResultsTest extends PmaTestCase
$GLOBALS['PMA_PHP_SELF'] = 'index.php';
$this->object = new DisplayResults('as', '', '', '');
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['text_dir'] = 'ltr';
$_SESSION[' HMAC_secret '] = 'test';
@ -430,10 +431,16 @@ class ResultsTest extends PmaTestCase
{
return array(
array(
'tbl_change.php?db=Data&amp;table=customer&amp;where_clause=%60'
. 'customer%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query='
. 'SELECT+%2A+FROM+%60customer%60&amp;goto=sql.php&amp;default_'
. 'action=update',
'tbl_change.php',
[
'db' => 'Data',
'table' => 'customer',
'where_clause' => '`customer`.`id` = 1',
'clause_is_unique' => true,
'sql_query' => 'SELECT * FROM `customer`',
'goto' => 'sql.php',
'default_action' => 'update',
],
'klass edit_row_anchor',
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" alt='
. '"Edit" class="icon ic_b_edit" /> Edit</span>',
@ -444,7 +451,7 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=Data&amp;table=customer&amp;where_'
. 'clause=%60customer%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;'
. 'sql_query=SELECT+%2A+FROM+%60customer%60&amp;goto=sql.php&amp;'
. 'default_action=update"'
. 'default_action=update&amp;server=0&amp;lang=en"'
. '><span class="nowrap"><img src="themes/dot.gif" title="Edit" '
. 'alt="Edit" class="icon ic_b_edit" /> Edit</span></a>'
. '<input type="hidden" class="where_clause" value ="%60customer'
@ -468,7 +475,7 @@ class ResultsTest extends PmaTestCase
* @dataProvider dataProviderForGetEditLink
*/
public function testGetEditLink(
$edit_url, $class, $edit_str, $where_clause, $where_clause_html, $output
$edit_url, $urlParams, $class, $edit_str, $where_clause, $where_clause_html, $output
) {
$GLOBALS['cfg']['ActionLinksMode'] = 'both';
$GLOBALS['cfg']['LinkLengthLimit'] = 1000;
@ -478,7 +485,7 @@ class ResultsTest extends PmaTestCase
$this->_callPrivateFunction(
'_getEditLink',
array(
$edit_url, $class, $edit_str, $where_clause, $where_clause_html
$edit_url, $urlParams, $class, $edit_str, $where_clause, $where_clause_html
)
)
);
@ -493,10 +500,16 @@ class ResultsTest extends PmaTestCase
{
return array(
array(
'tbl_change.php?db=Data&amp;table=customer&amp;where_clause=%60cust'
. 'omer%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query='
. 'SELECT+%2A+FROM+%60customer%60&amp;goto=sql.php&amp;default_'
. 'action=insert',
'tbl_change.php',
[
'db' => 'Data',
'table' => 'customer',
'where_clause' => '`customer`.`id` = 1',
'clause_is_unique' => true,
'sql_query' => 'SELECT * FROM `customer`',
'goto' => 'sql.php',
'default_action' => 'insert',
],
'<span class="nowrap"><img src="themes/dot.gif" title="Copy" alt'
. '="Copy" class="icon ic_b_insrow" /> Copy</span>',
'`customer`.`id` = 1',
@ -507,7 +520,7 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=Data&amp;table=customer&amp;where_'
. 'clause=%60customer%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;'
. 'sql_query=SELECT+%2A+FROM+%60customer%60&amp;goto=sql.php&amp;'
. 'default_action=insert"'
. 'default_action=insert&amp;server=0&amp;lang=en"'
. '><span class="nowrap"><img src="themes/dot.gif" title="Copy" '
. 'alt="Copy" class="icon ic_b_insrow" /> Copy</span></a>'
. '<input type="hidden" class="where_clause" value="%60customer%60'
@ -531,7 +544,7 @@ class ResultsTest extends PmaTestCase
* @dataProvider dataProviderForGetCopyLink
*/
public function testGetCopyLink(
$copy_url, $copy_str, $where_clause, $where_clause_html, $class, $output
$copy_url, $urlParams, $copy_str, $where_clause, $where_clause_html, $class, $output
) {
$GLOBALS['cfg']['ActionLinksMode'] = 'both';
$GLOBALS['cfg']['LinkLengthLimit'] = 1000;
@ -541,7 +554,7 @@ class ResultsTest extends PmaTestCase
$this->_callPrivateFunction(
'_getCopyLink',
array(
$copy_url, $copy_str, $where_clause, $where_clause_html, $class
$copy_url, $urlParams, $copy_str, $where_clause, $where_clause_html, $class
)
)
);
@ -556,12 +569,14 @@ class ResultsTest extends PmaTestCase
{
return array(
array(
'sql.php?db=Data&amp;table=customer&amp;sql_query=DELETE+FROM+%60'
. 'Data%60.%60customer%60+WHERE+%60customer%60.%60id%60+%3D+1&amp;'
. 'message_to_show=The+row+has+been+deleted&amp;goto=sql.php%3Fdb'
. '%3DData%26table%3Dcustomer%26sql_query%3DSELECT%2B%252A%2BFROM'
. '%2B%2560customer%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen'
. '%2Bdeleted%26goto%3Dtbl_structure.php',
'sql.php',
[
'db' => 'Data',
'table' => 'customer',
'sql_query' => 'DELETE FROM `Data`.`customer` WHERE `customer`.`id` = 1',
'message_to_show' => 'The row has been deleted.',
'goto' => 'tbl_sql.php',
],
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
. 'alt="Delete" class="icon ic_b_drop" /> Delete</span>',
'DELETE FROM `Data`.`customer` WHERE `customer`.`id` = 1',
@ -569,10 +584,8 @@ class ResultsTest extends PmaTestCase
'<td class="klass center print_ignore" >'
. '<a href="sql.php" data-post="db=Data&amp;table=customer&amp;sql_query=DELETE'
. '+FROM+%60Data%60.%60customer%60+WHERE+%60customer%60.%60id%60+%3D'
. '+1&amp;message_to_show=The+row+has+been+deleted&amp;goto=sql.php'
. '%3Fdb%3DData%26table%3Dcustomer%26sql_query%3DSELECT%2B%252A%2B'
. 'FROM%2B%2560customer%2560%26message_to_show%3DThe%2Brow%2Bhas%2B'
. 'been%2Bdeleted%26goto%3Dtbl_structure.php" '
. '+1&amp;message_to_show=The+row+has+been+deleted.'
. '&amp;goto=tbl_sql.php&amp;server=0&amp;lang=en" '
. 'class="delete_row requireConfirm"><span class="nowrap"><img src="themes/dot.'
. 'gif" title="Delete" alt="Delete" class="icon ic_b_drop" /> '
. 'Delete</span></a>'
@ -596,7 +609,7 @@ class ResultsTest extends PmaTestCase
* @dataProvider dataProviderForGetDeleteLink
*/
public function testGetDeleteLink(
$del_url, $del_str, $js_conf, $class, $output
$del_url, $delUrlParams, $del_str, $js_conf, $class, $output
) {
$GLOBALS['cfg']['ActionLinksMode'] = 'both';
$GLOBALS['cfg']['LinkLengthLimit'] = 1000;
@ -606,7 +619,7 @@ class ResultsTest extends PmaTestCase
$this->_callPrivateFunction(
'_getDeleteLink',
array(
$del_url, $del_str, $js_conf, $class
$del_url, $delUrlParams, $del_str, $js_conf, $class
)
)
);
@ -622,12 +635,7 @@ class ResultsTest extends PmaTestCase
return array(
array(
DisplayResults::POSITION_LEFT,
'sql.php?db=data&amp;table=new&amp;sql_query=DELETE+FROM+%60data'
. '%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&amp;message_to_show='
. 'The+row+has+been+deleted&amp;goto=sql.php%3Fdb%3Ddata%26table%3D'
. 'new%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26'
. 'message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3D'
. 'tbl_structure.php',
'sql.php',
array(
'edit_lnk' => 'ur',
'del_lnk' => 'dr',
@ -643,12 +651,8 @@ class ResultsTest extends PmaTestCase
array(
'`new`.`id`' => '= 1',
),
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.'
. '%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+'
. 'FROM+%60new%60&amp;goto=sql.php&amp;default_action=update',
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.'
. '%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+'
. 'FROM+%60new%60&amp;goto=sql.php&amp;default_action=insert',
'tbl_change.php',
'tbl_change.php',
'edit_row_anchor',
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
. 'alt="Edit" class="icon ic_b_edit" /> Edit</span>',
@ -657,6 +661,21 @@ class ResultsTest extends PmaTestCase
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
. 'alt="Delete" class="icon ic_b_drop" /> Delete</span>',
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
[
'db' => 'data',
'table' => 'new',
'where_clause' => '`new`.`id` = 1',
'clause_is_unique' => true,
'sql_query' => 'SELECT * FROM `new`',
'goto' => 'sql.php',
],
[
'db' => 'data',
'table' => 'new',
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
'message_to_show' => 'The row has been deleted.',
'goto' => 'tbl_sql.php',
],
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_delete0_'
. 'left" name="rows_to_delete[0]" class="multi_checkbox checkall" '
. 'value="%60new%60.%60id%60+%3D+1" /><input type="hidden" class='
@ -666,7 +685,7 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=data&amp;table=new&amp;where_'
. 'clause=%60new%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;'
. 'sql_query=SELECT+%2A+FROM+%60new%60&amp;goto=sql.php&amp;default'
. '_action=update">'
. '_action=update&amp;server=0&amp;lang=en">'
. '<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
. 'alt="Edit" class="icon ic_b_edit" /> Edit</span></a>'
. '<input type="hidden" class="where_clause" value ="%60new%60.%60'
@ -675,17 +694,15 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=data&amp;table=new&amp;where_clause'
. '=%60new%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query='
. 'SELECT+%2A+FROM+%60new%60&amp;goto=sql.php&amp;default_action='
. 'insert"><span class'
. 'insert&amp;server=0&amp;lang=en"><span class'
. '="nowrap"><img src="themes/dot.gif" title="Copy" alt="Copy" '
. 'class="icon ic_b_insrow" /> Copy</span></a>'
. '<input type="hidden" class="where_clause" value="%60new%60.%60id'
. '%60+%3D+1" /></span></td><td class="center print_ignore" >'
. '<a href="sql.php" data-post="db=data&amp;table=new&amp;sql_query=DELETE+'
. 'FROM+%60data%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&amp;'
. 'message_to_show=The+row+has+been+deleted&amp;goto=sql.php%3F'
. 'db%3Ddata%26table%3Dnew%26sql_query%3DSELECT%2B%252A%2BFROM%2B'
. '%2560new%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2B'
. 'deleted%26goto%3Dtbl_structure.php" '
. 'message_to_show=The+row+has+been+deleted.'
. '&amp;goto=tbl_sql.php&amp;server=0&amp;lang=en" '
. 'class="delete_row requireConfirm"><span class="nowrap"><img src="themes/dot.'
. 'gif" title="Delete" alt="Delete" class="icon ic_b_drop" /> '
. 'Delete</span></a>'
@ -694,12 +711,7 @@ class ResultsTest extends PmaTestCase
),
array(
DisplayResults::POSITION_RIGHT,
'sql.php?db=data&amp;table=new&amp;sql_query=DELETE+FROM+%60data%60'
. '.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&amp;message_to_show='
. 'The+row+has+been+deleted&amp;goto=sql.php%3Fdb%3Ddata%26table%3D'
. 'new%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26message'
. '_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3Dtbl_'
. 'structure.php',
'sql.php',
array(
'edit_lnk' => 'ur',
'del_lnk' => 'dr',
@ -715,12 +727,8 @@ class ResultsTest extends PmaTestCase
array(
'`new`.`id`' => '= 1',
),
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.'
. '%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+'
. 'FROM+%60new%60&amp;goto=sql.php&amp;default_action=update',
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.'
. '%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+'
. 'FROM+%60new%60&amp;goto=sql.php&amp;default_action=insert',
'tbl_change.php',
'tbl_change.php',
'edit_row_anchor',
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
. 'alt="Edit" class="icon ic_b_edit" /> Edit</span>',
@ -729,13 +737,26 @@ class ResultsTest extends PmaTestCase
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
. 'alt="Delete" class="icon ic_b_drop" /> Delete</span>',
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
[
'db' => 'data',
'table' => 'new',
'where_clause' => '`new`.`id` = 1',
'clause_is_unique' => true,
'sql_query' => 'SELECT * FROM `new`',
'goto' => 'sql.php',
],
[
'db' => 'data',
'table' => 'new',
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
'message_to_show' => 'The row has been deleted.',
'goto' => 'tbl_sql.php',
],
'<td class="center print_ignore" >'
. '<a href="sql.php" data-post="db=data&amp;table=new&amp;sql_query=DELETE+'
. 'FROM+%60data%60.%60new%60+WHERE+%60new%60.%60id%60+%3D+1&amp;'
. 'message_to_show=The+row+has+been+deleted&amp;goto=sql.php%3Fdb'
. '%3Ddata%26table%3Dnew%26sql_query%3DSELECT%2B%252A%2BFROM%2B%25'
. '60new%2560%26message_to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted'
. '%26goto%3Dtbl_structure.php" class="delete'
. 'message_to_show=The+row+has+been+deleted.&amp;goto=tbl_sql.php'
. '&amp;server=0&amp;lang=en" class="delete'
. '_row requireConfirm"><span class="nowrap"><img src="themes/dot.gif" title='
. '"Delete" alt="Delete" class="icon ic_b_drop" /> Delete</span></a>'
. '<div class="hide">DELETE FROM `data`.`new` WHERE `new`.'
@ -743,7 +764,7 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=data&amp;table=new&amp;where_'
. 'clause=%60new%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_'
. 'query=SELECT+%2A+FROM+%60new%60&amp;goto=sql.php&amp;default_'
. 'action=insert"><span '
. 'action=insert&amp;server=0&amp;lang=en"><span '
. 'class="nowrap"><img src="themes/dot.gif" title="Copy" alt="Copy" '
. 'class="icon ic_b_insrow" /> Copy</span></a>'
. '<input type="hidden" class="where_clause" value="%60new%60.%60id'
@ -752,7 +773,7 @@ class ResultsTest extends PmaTestCase
. '<a href="tbl_change.php" data-post="db=data&amp;table=new&amp;where_clause'
. '=%60new%60.%60id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query='
. 'SELECT+%2A+FROM+%60new%60&amp;goto=sql.php&amp;default_action='
. 'update"><span class='
. 'update&amp;server=0&amp;lang=en"><span class='
. '"nowrap"><img src="themes/dot.gif" title="Edit" alt="Edit" class'
. '="icon ic_b_edit" /> Edit</span></a>'
. '<input type="hidden" class="where_clause" value ="%60new%60.%60'
@ -764,12 +785,7 @@ class ResultsTest extends PmaTestCase
),
array(
DisplayResults::POSITION_NONE,
'sql.php?db=data&amp;table=new&amp;sql_query=DELETE+FROM+%60data%60.'
. '%60new%60+WHERE+%60new%60.%60id%60+%3D+1&amp;message_to_show=The+'
. 'row+has+been+deleted&amp;goto=sql.php%3Fdb%3Ddata%26table%3Dnew'
. '%26sql_query%3DSELECT%2B%252A%2BFROM%2B%2560new%2560%26message_'
. 'to_show%3DThe%2Brow%2Bhas%2Bbeen%2Bdeleted%26goto%3Dtbl_structure'
. '.php',
'sql.php',
array(
'edit_lnk' => 'ur',
'del_lnk' => 'dr',
@ -785,12 +801,8 @@ class ResultsTest extends PmaTestCase
array(
'`new`.`id`' => '= 1',
),
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.%60'
. 'id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+FROM+'
. '%60new%60&amp;goto=sql.php&amp;default_action=update',
'tbl_change.php?db=data&amp;table=new&amp;where_clause=%60new%60.%60'
. 'id%60+%3D+1&amp;clause_is_unique=1&amp;sql_query=SELECT+%2A+FROM+'
. '%60new%60&amp;goto=sql.php&amp;default_action=insert',
'tbl_change.php',
'tbl_change.php',
'edit_row_anchor',
'<span class="nowrap"><img src="themes/dot.gif" title="Edit" '
. 'alt="Edit" class="icon ic_b_edit" /> Edit</span>',
@ -799,6 +811,21 @@ class ResultsTest extends PmaTestCase
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
. 'alt="Delete" class="icon ic_b_drop" /> Delete</span>',
'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
[
'db' => 'data',
'table' => 'new',
'where_clause' => '`new`.`id` = 1',
'clause_is_unique' => true,
'sql_query' => 'SELECT * FROM `new`',
'goto' => 'sql.php',
],
[
'db' => 'data',
'table' => 'new',
'sql_query' => 'DELETE FROM `data`.`new` WHERE `new`.`id` = 1',
'message_to_show' => 'The row has been deleted.',
'goto' => 'tbl_sql.php',
],
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_'
. 'delete0_left" name="rows_to_delete[0]" class="multi_checkbox '
. 'checkall" value="%60new%60.%60id%60+%3D+1" /><input type='
@ -835,7 +862,7 @@ class ResultsTest extends PmaTestCase
public function testGetCheckboxAndLinks(
$position, $del_url, $displayParts, $row_no, $where_clause,
$where_clause_html, $condition_array, $edit_url,
$copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf, $output
$copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams, $output
) {
$this->assertEquals(
$output,
@ -845,7 +872,7 @@ class ResultsTest extends PmaTestCase
$position, $del_url, $displayParts, $row_no, $where_clause,
$where_clause_html, $condition_array,
$edit_url, $copy_url, $class, $edit_str,
$copy_str, $del_str, $js_conf
$copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
)
)
);
@ -896,6 +923,8 @@ class ResultsTest extends PmaTestCase
'<span class="nowrap"><img src="themes/dot.gif" title="Delete" '
. 'alt="Delete" class="icon ic_b_drop" /> Delete</span>',
null,
[],
[],
'<td class="center print_ignore"><input type="checkbox" id="id_rows_to_'
. 'delete0_left" name="rows_to_delete[0]" class="multi_checkbox '
. 'checkall" value="%60new%60.%60id%60+%3D+1" /><input type='
@ -931,7 +960,7 @@ class ResultsTest extends PmaTestCase
public function testGetPlacedLinks(
$dir, $del_url, $displayParts, $row_no, $where_clause, $where_clause_html,
$condition_array, $edit_url, $copy_url,
$edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf, $output
$edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams, $output
) {
$this->assertEquals(
$output,
@ -941,7 +970,7 @@ class ResultsTest extends PmaTestCase
$dir, $del_url, $displayParts, $row_no, $where_clause,
$where_clause_html, $condition_array,
$edit_url, $copy_url, $edit_anchor_class,
$edit_str, $copy_str, $del_str, $js_conf
$edit_str, $copy_str, $del_str, $js_conf, $editCopyUrlParams, $delUrlParams
)
)
);

View File

@ -46,6 +46,7 @@ class FooterTest extends PmaTestCase
$GLOBALS['table'] = '';
$GLOBALS['text_dir'] = 'ltr';
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['cfg']['Server']['DisableIS'] = false;
$GLOBALS['cfg']['Server']['verbose'] = 'verbose host';

View File

@ -62,6 +62,7 @@ class InsertEditTest extends TestCase
$GLOBALS['cfg']['LoginCookieValidity'] = 1440;
$GLOBALS['cfg']['enable_drag_drop_import'] = true;
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$this->insertEdit = new InsertEdit($GLOBALS['dbi']);
}

View File

@ -11,6 +11,8 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\Navigation\NavigationTree;
use PhpMyAdmin\Tests\PmaTestCase;
use PhpMyAdmin\Theme;
use PhpMyAdmin\Url;
use ReflectionMethod;
/*
* we must set $GLOBALS['server'] here
@ -43,6 +45,7 @@ class NavigationTreeTest extends PmaTestCase
{
$GLOBALS['server'] = 1;
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['cfg']['Server']['host'] = 'localhost';
$GLOBALS['cfg']['Server']['user'] = 'root';
@ -100,4 +103,37 @@ class NavigationTreeTest extends PmaTestCase
$result = $this->object->renderDbSelect();
$this->assertContains('pma_navigation_select_database', $result);
}
/**
* @return void
*/
public function testEncryptQueryParams()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryption', false);
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$method = new ReflectionMethod($this->object, 'encryptQueryParams');
$method->setAccessible(true);
$link = 'tbl_structure.php?server=1&amp;db=test_db&amp;table=test_table&amp;pos=0';
$actual = $method->invoke($this->object, $link);
$this->assertEquals($link, $actual);
$PMA_Config->set('URLQueryEncryption', true);
$actual = $method->invoke($this->object, $link);
$this->assertStringStartsWith('tbl_structure.php?server=1&amp;pos=0&amp;eq=', $actual);
$url = parse_url($actual);
parse_str(htmlspecialchars_decode($url['query']), $query);
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $query['eq']);
$decrypted = Url::decryptQuery($query['eq']);
$this->assertJson($decrypted);
$this->assertSame('{"db":"test_db","table":"test_table"}', $decrypted);
}
}

View File

@ -37,6 +37,7 @@ class AuthenticationCookieTest extends PmaTestCase
function setUp()
{
$GLOBALS['PMA_Config'] = new Config();
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['server'] = 0;
$GLOBALS['text_dir'] = 'ltr';

View File

@ -28,6 +28,7 @@ class PmaTestCase extends TestCase
{
require 'libraries/config.default.php';
$GLOBALS['cfg'] = $cfg;
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
}
/**

View File

@ -196,7 +196,7 @@ class ProcessesTest extends TestCase
//validate 1: $kill_process
$kill_process = 'href="server_status_processes.php" data-post="'
. Url::getCommon(['kill' => $process['id']], '') . '"';
. Url::getCommon(['kill' => $process['id']], '', false) . '"';
$this->assertContains(
$kill_process,
$html

View File

@ -129,7 +129,7 @@ class UserGroupsTest extends TestCase
array(
'viewUsers'=>1, 'userGroup'=>htmlspecialchars('usergroup')
),
''
'', false
);
$this->assertContains(
$url_tag,
@ -141,7 +141,7 @@ class UserGroupsTest extends TestCase
'editUserGroup'=>1,
'userGroup'=>htmlspecialchars('usergroup')
),
''
'', false
);
$this->assertContains(
$url_tag,
@ -153,7 +153,7 @@ class UserGroupsTest extends TestCase
'deleteUserGroup'=> 1,
'userGroup'=>htmlspecialchars('usergroup')
),
""
"", false
);
$this->assertContains(
$url_tag,

View File

@ -27,6 +27,7 @@ class UrlTest extends TestCase
public function setUp()
{
unset($_COOKIE['pma_lang']);
$GLOBALS['PMA_Config']->set('URLQueryEncryption', false);
}
/**
@ -105,4 +106,61 @@ class UrlTest extends TestCase
$expected = '?server=x' . htmlentities($separator) . 'lang=en' ;
$this->assertEquals($expected, Url::getCommon());
}
/**
* @return void
*/
public function testBuildHttpQueryWithUrlQueryEncryptionDisabled()
{
global $PMA_Config;
$PMA_Config->set('URLQueryEncryption', false);
$params = ['db' => 'test_db', 'table' => 'test_table', 'pos' => 0];
$this->assertEquals('db=test_db&table=test_table&pos=0', Url::buildHttpQuery($params));
}
/**
* @return void
*/
public function testBuildHttpQueryWithUrlQueryEncryptionEnabled()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryption', true);
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$params = ['db' => 'test_db', 'table' => 'test_table', 'pos' => 0];
$query = Url::buildHttpQuery($params);
$this->assertStringStartsWith('pos=0&eq=', $query);
parse_str($query, $queryParams);
$this->assertCount(2, $queryParams);
$this->assertSame('0', $queryParams['pos']);
$this->assertTrue(is_string($queryParams['eq']));
$this->assertNotSame('', $queryParams['eq']);
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $queryParams['eq']);
$decrypted = Url::decryptQuery($queryParams['eq']);
$this->assertJson($decrypted);
$this->assertSame('{"db":"test_db","table":"test_table"}', $decrypted);
}
/**
* @return void
*/
public function testQueryEncryption()
{
global $PMA_Config;
$_SESSION = [];
$PMA_Config->set('URLQueryEncryption', true);
$PMA_Config->set('URLQueryEncryptionSecretKey', str_repeat('a', 32));
$query = '{"db":"test_db","table":"test_table"}';
$encrypted = Url::encryptQuery($query);
$this->assertNotSame($query, $encrypted);
$this->assertNotSame('', $encrypted);
$this->assertRegExp('/^[a-zA-Z0-9-_=]+$/', $encrypted);
$decrypted = Url::decryptQuery($encrypted);
$this->assertSame($query, $decrypted);
}
}

View File

@ -2107,22 +2107,22 @@ class UtilTest extends PmaTestCase
{
return [
[
['index.php', 'text'],
['index.php', null, 'text'],
1000,
'<a href="index.php" >text</a>'
],
[
['index.php?some=parameter', 'text'],
['index.php', ['some' => 'parameter'], 'text'],
20,
'<a href="index.php" data-post="some=parameter">text</a>',
'<a href="index.php" data-post="some=parameter&amp;lang=en">text</a>',
],
[
['index.php', 'text', [], 'target'],
['index.php', null, 'text', [], 'target'],
1000,
'<a href="index.php" target="target">text</a>',
],
[
['url.php?url=http://phpmyadmin.net/', 'text', [], '_blank'],
['url.php?url=http://phpmyadmin.net/', null, 'text', [], '_blank'],
1000,
'<a href="url.php?url=http://phpmyadmin.net/" target="_blank" rel="noopener noreferrer">text</a>',
],