diff --git a/app/services.php b/app/services.php index f68a3734e8..74cd4c07d1 100644 --- a/app/services.php +++ b/app/services.php @@ -158,7 +158,7 @@ return [ 'server_plugins' => ['class' => Plugins::class, 'arguments' => ['@dbi']], 'server_privileges' => [ 'class' => Privileges::class, - 'arguments' => ['@template', '@dbi', '@relation', '@relation_cleanup', '@server_plugins'], + 'arguments' => ['@template', '@dbi', '@relation', '@relation_cleanup', '@server_plugins', '@config'], ], 'server_privileges_account_locking' => [ 'class' => AccountLocking::class, diff --git a/app/services_controllers.php b/app/services_controllers.php index 874ac5a3b3..f0df786faf 100644 --- a/app/services_controllers.php +++ b/app/services_controllers.php @@ -700,6 +700,7 @@ return [ '$relation' => '@relation', '$dbi' => '@dbi', '$userPrivilegesFactory' => '@' . UserPrivilegesFactory::class, + '$config' => '@config', ], ], Server\ReplicationController::class => [ diff --git a/resources/js/src/modules/functions.ts b/resources/js/src/modules/functions.ts index e282ca87f6..fa116c6607 100644 --- a/resources/js/src/modules/functions.ts +++ b/resources/js/src/modules/functions.ts @@ -1974,6 +1974,10 @@ export function checkPassword ($theForm) { return true; } +export function shouldShowEmptyPasswordWarning (form): boolean { + return (form.find('#nopass_1').is(':checked') && form.data('allowNoPassword') === 0); +} + export function onloadChangePasswordEvents (): void { /* Handler for hostname type */ $(document).on('change', '#select_pred_hostname', function () { @@ -2067,25 +2071,35 @@ export function onloadChangePasswordEvents (): void { */ var thisValue = $(this).val(); - var $msgbox = ajaxShowMessage(window.Messages.strProcessingRequest); - $theForm.append(''); + var submitForm = function () { + var $msgbox = ajaxShowMessage(window.Messages.strProcessingRequest); + $theForm.append(''); - $.post($theForm.attr('action'), $theForm.serialize() + CommonParams.get('arg_separator') + 'change_pw=' + thisValue, function (data) { - if (typeof data === 'undefined' || data.success !== true) { - ajaxShowMessage(data.error, false); + $.post($theForm.attr('action'), $theForm.serialize() + CommonParams.get('arg_separator') + 'change_pw=' + thisValue, function (data) { + if (typeof data === 'undefined' || data.success !== true) { + ajaxShowMessage(data.error, false); - return; - } + return; + } - var $pageContent = $('#page_content'); - $pageContent.prepend(data.message); - highlightSql($pageContent); - $('#change_password_dialog').hide().remove(); - $('#edit_user_dialog').dialog('close').remove(); - ajaxRemoveMessage($msgbox); - }); // end $.post() + var $pageContent = $('#page_content'); + $pageContent.prepend(data.message); + highlightSql($pageContent); + $('#change_password_dialog').hide().remove(); + $('#edit_user_dialog').dialog('close').remove(); + ajaxRemoveMessage($msgbox); + }); // end $.post() - $('#changePasswordModal').modal('hide'); + $('#changePasswordModal').modal('hide'); + }; + + if (shouldShowEmptyPasswordWarning($theForm)) { + $(this).confirm(window.Messages.strPasswordEmptyWhenAllowNoPasswordIsEnabled, '', function () { + submitForm(); + }); + } else { + submitForm(); + } }); $.get($(this).attr('href'), { 'ajax_request': true }, function (data) { diff --git a/resources/js/src/server/privileges.ts b/resources/js/src/server/privileges.ts index 09ced013f8..9acfe92118 100644 --- a/resources/js/src/server/privileges.ts +++ b/resources/js/src/server/privileges.ts @@ -1,6 +1,13 @@ import $ from 'jquery'; import { AJAX } from '../modules/ajax.ts'; -import { checkPassword, checkPasswordStrength, checkboxesSel, displayPasswordGenerateButton, getSqlEditor } from '../modules/functions.ts'; +import { + checkPassword, + checkPasswordStrength, + checkboxesSel, + displayPasswordGenerateButton, + getSqlEditor, + shouldShowEmptyPasswordWarning +} from '../modules/functions.ts'; import { CommonParams } from '../modules/common.ts'; import { Navigation } from '../modules/navigation.ts'; import { ajaxRemoveMessage, ajaxShowMessage } from '../modules/ajax-message.ts'; @@ -475,6 +482,26 @@ const CheckAddUser = { } }; +const CheckEmptyPasswordWhenAllowNoPasswordIsEnabled = { + handleEvent: function () { + const theForm = this; + + if (shouldShowEmptyPasswordWarning($(theForm))) { + $(this).confirm(window.Messages.strPasswordEmptyWhenAllowNoPasswordIsEnabled, '', function () { + theForm.submit(); + + return true; + }); + + return false; + } else { + theForm.submit(); + + return true; + } + } +}; + const selectPasswordRadioWhenChangingPassword = () => { $('#nopass_0').prop('checked', true); }; @@ -561,4 +588,5 @@ AJAX.registerOnload('server/privileges.js', function () { $('#addUsersForm').on('submit', CheckAddUser.handleEvent); $('#copyUserForm').on('submit', CheckAddUser.handleEvent); + $('#change_password_form').on('submit', CheckEmptyPasswordWhenAllowNoPasswordIsEnabled.handleEvent); }); diff --git a/resources/templates/server/privileges/change_password.twig b/resources/templates/server/privileges/change_password.twig index 3e9dd5ac26..0ea362851b 100644 --- a/resources/templates/server/privileges/change_password.twig +++ b/resources/templates/server/privileges/change_password.twig @@ -1,5 +1,5 @@
+ {{- is_privileges ? url('/server/privileges') : url('/user-password') }}" name="chgPassword" class="{{ is_privileges ? 'submenu-item' }}" autocomplete="off" data-allow-no-password="{{ allow_no_password ? 1 : 0 }}"> {{ get_hidden_inputs() }} {% if is_privileges %} diff --git a/src/Controllers/JavaScriptMessagesController.php b/src/Controllers/JavaScriptMessagesController.php index 8ef1d2778d..0f8a1f65d6 100644 --- a/src/Controllers/JavaScriptMessagesController.php +++ b/src/Controllers/JavaScriptMessagesController.php @@ -143,6 +143,11 @@ final class JavaScriptMessagesController implements InvocableController 'strUserEmpty' => __('The user name is empty!'), 'strPasswordEmpty' => __('The password is empty!'), 'strPasswordNotSame' => __('The passwords aren\'t the same!'), + 'strPasswordEmptyWhenAllowNoPasswordIsEnabled' => __( + 'You are trying to set this account to log in with no password, but the configuration directive ' . + 'AllowNoPassword is false. If you proceed, the account will not be able to log in ' . + 'through phpMyAdmin.', + ), 'strRemovingSelectedUsers' => __('Removing Selected Users'), 'strClose' => __('Close'), 'strLock' => _pgettext('Lock the account.', 'Lock'), diff --git a/src/Controllers/Server/PrivilegesController.php b/src/Controllers/Server/PrivilegesController.php index db82039e20..9ddfcb3d22 100644 --- a/src/Controllers/Server/PrivilegesController.php +++ b/src/Controllers/Server/PrivilegesController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Controllers\Server; +use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Controllers\InvocableController; @@ -38,6 +39,7 @@ final class PrivilegesController implements InvocableController private readonly Relation $relation, private readonly DatabaseInterface $dbi, private readonly UserPrivilegesFactory $userPrivilegesFactory, + private readonly Config $config, ) { } @@ -62,6 +64,7 @@ final class PrivilegesController implements InvocableController $this->relation, $relationCleanup, new Plugins($this->dbi), + $this->config, ); $this->response->addHTML('
'); diff --git a/src/Server/Privileges.php b/src/Server/Privileges.php index 598bb9973b..e345fc0428 100644 --- a/src/Server/Privileges.php +++ b/src/Server/Privileges.php @@ -76,6 +76,7 @@ class Privileges public Relation $relation, private RelationCleanup $relationCleanup, private Plugins $plugins, + private readonly Config $config, ) { } @@ -3270,6 +3271,7 @@ class Privileges 'has_more_auth_plugins' => $hasMoreAuthPlugins, 'active_auth_plugins' => $activeAuthPlugins, 'orig_auth_plugin' => $origAuthPlugin, + 'allow_no_password' => $this->config->selectedServer['AllowNoPassword'], ]); } diff --git a/tests/unit/Controllers/Server/PrivilegesControllerTest.php b/tests/unit/Controllers/Server/PrivilegesControllerTest.php index eb53003d4b..e21ee1499b 100644 --- a/tests/unit/Controllers/Server/PrivilegesControllerTest.php +++ b/tests/unit/Controllers/Server/PrivilegesControllerTest.php @@ -75,6 +75,7 @@ class PrivilegesControllerTest extends AbstractTestCase new Relation($this->dbi), $this->dbi, new UserPrivilegesFactory($this->dbi), + new Config(), ))($request); $actual = $response->getHTMLResult(); diff --git a/tests/unit/Server/PrivilegesTest.php b/tests/unit/Server/PrivilegesTest.php index 04664decbe..10d4c7484f 100644 --- a/tests/unit/Server/PrivilegesTest.php +++ b/tests/unit/Server/PrivilegesTest.php @@ -1889,6 +1889,7 @@ class PrivilegesTest extends AbstractTestCase $relation, new RelationCleanup($this->dbi, $relation), new Plugins($this->dbi), + new Config(), ); $method = new ReflectionMethod(Privileges::class, 'getUserPrivileges'); @@ -1902,7 +1903,14 @@ class PrivilegesTest extends AbstractTestCase { $relation = new Relation($dbi); - return new Privileges(new Template(), $dbi, $relation, new RelationCleanup($dbi, $relation), new Plugins($dbi)); + return new Privileges( + new Template(), + $dbi, + $relation, + new RelationCleanup($dbi, $relation), + new Plugins($dbi), + new Config(), + ); } /** diff --git a/tests/unit/UserPasswordTest.php b/tests/unit/UserPasswordTest.php index 913ab7c7dd..2fb9dc957e 100644 --- a/tests/unit/UserPasswordTest.php +++ b/tests/unit/UserPasswordTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests; +use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Message; @@ -35,6 +36,7 @@ class UserPasswordTest extends AbstractTestCase $relation, new RelationCleanup($dbi, $relation), new Plugins($dbi), + new Config(), ); $this->object = new UserPassword( $serverPrivileges,