Loading private_message.routing.yml +9 −1 Original line number Diff line number Diff line Loading @@ -82,13 +82,21 @@ private_message.private_message_thread_settings: _permission: 'administer private message module' private_message.members_widget_callback: path: '/private-message/autocomplete/members' path: '/private-message/autocomplete/members/{target_type}/{selection_handler}/{selection_settings_key}' defaults: _controller: '\Drupal\private_message\Controller\AjaxController::privateMessageMembersAutocomplete' requirements: _csrf_token: 'TRUE' _user_is_logged_in: 'TRUE' _permission: 'use private messaging system,access user profiles' options: parameters: target_type: type: string selection_handler: type: string selection_settings_key: type: string private_message.admin_config: path: '/admin/config/private-message' Loading src/Controller/AjaxController.php +23 −2 Original line number Diff line number Diff line Loading @@ -2,12 +2,14 @@ namespace Drupal\private_message\Controller; use Drupal\Component\Utility\Crypt; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Site\Settings; use Drupal\private_message\Ajax\PrivateMessageInboxUpdateCommand; use Drupal\private_message\Ajax\PrivateMessageInsertNewMessagesCommand; use Drupal\private_message\Ajax\PrivateMessageInboxInsertThreadsCommand; Loading @@ -20,6 +22,7 @@ use Drupal\private_message\Entity\PrivateMessageThread; use Drupal\private_message\Service\PrivateMessageServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Controller to handle Ajax requests. Loading Loading @@ -176,11 +179,29 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface { /** * {@inheritdoc} */ public function privateMessageMembersAutocomplete() { public function privateMessageMembersAutocomplete($target_type, $selection_handler, $selection_settings_key) { $response = new AjaxResponse(); // Selection settings are passed in as a hashed key of a serialized array // stored in the key/value store. $selection_settings = \Drupal::keyValue('entity_autocomplete')->get($selection_settings_key, FALSE); if ($selection_settings !== FALSE) { $selection_settings_hash = Crypt::hmacBase64(serialize($selection_settings) . $target_type . $selection_handler, Settings::getHashSalt()); if (!hash_equals($selection_settings_hash, $selection_settings_key)) { // Disallow access when the selection settings hash does not match the // passed-in key. throw new AccessDeniedHttpException('Invalid selection settings key.'); } } else { // Disallow access when the selection settings key is not found in the // key/value store. throw new AccessDeniedHttpException(); } $match_limit = isset($selection_settings['match_limit']) ? (int) $selection_settings['match_limit'] : self::AUTOCOMPLETE_COUNT; $username = $this->requestStack->getCurrentRequest()->get('username'); $accounts = $this->privateMessageService->getUsersFromString($username, self::AUTOCOMPLETE_COUNT); $accounts = $this->privateMessageService->getUsersFromString($username, $match_limit); $user_info = []; foreach ($accounts as $account) { if ($account->access('view', $this->currentUser) && $account->isActive()) { Loading src/Controller/AjaxControllerInterface.php +8 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,16 @@ interface AjaxControllerInterface { /** * Create AJAX response containing usernames for an autocomplete callback. * * @param $target_type * Target type of autocomplete. * @param $selection_handler * Selection handler of autocomplete. * @param $selection_settings_key * Key to the hashed settings. * * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response */ public function privateMessageMembersAutocomplete(); public function privateMessageMembersAutocomplete($target_type, $selection_handler, $selection_settings_key); } src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php +23 −2 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\private_message\Plugin\Field\FieldWidget; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\Config\ConfigFactoryInterface; Loading @@ -12,6 +13,7 @@ use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Site\Settings; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; Loading Loading @@ -166,7 +168,6 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget $form = parent::settingsForm($form, $form_state); // This setting has no bearing on this widget, so it is removed. unset($form['match_operator']); unset($form['match_limit']); $form['max_members'] = [ '#type' => 'number', Loading Loading @@ -211,7 +212,27 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget if (!$style_disabled) { $element['#attached']['library'][] = 'private_message/members_widget_style'; } $url = Url::fromRoute('private_message.members_widget_callback'); $target_type = $element['target_id']['#target_type']; $selection_handler = $element['target_id']['#selection_handler']; // Store the selection settings in the key/value store and pass a hashed key // in the route parameters. $selection_settings = $element['target_id']['#selection_settings'] ?? []; $data = serialize($selection_settings) . $target_type . $selection_handler; $selection_settings_key = Crypt::hmacBase64($data, Settings::getHashSalt()); $key_value_storage = \Drupal::keyValue('entity_autocomplete'); if (!$key_value_storage->has($selection_settings_key)) { $key_value_storage->set($selection_settings_key, $selection_settings); } $url = Url::fromRoute('private_message.members_widget_callback', [ 'target_type' => $target_type, 'selection_handler' => $selection_handler, 'selection_settings_key' => $selection_settings_key, ]); $token = $this->csrfTokenGenerator->get($url->getInternalPath()); $url->setOptions(['query' => ['token' => $token]]); Loading Loading
private_message.routing.yml +9 −1 Original line number Diff line number Diff line Loading @@ -82,13 +82,21 @@ private_message.private_message_thread_settings: _permission: 'administer private message module' private_message.members_widget_callback: path: '/private-message/autocomplete/members' path: '/private-message/autocomplete/members/{target_type}/{selection_handler}/{selection_settings_key}' defaults: _controller: '\Drupal\private_message\Controller\AjaxController::privateMessageMembersAutocomplete' requirements: _csrf_token: 'TRUE' _user_is_logged_in: 'TRUE' _permission: 'use private messaging system,access user profiles' options: parameters: target_type: type: string selection_handler: type: string selection_settings_key: type: string private_message.admin_config: path: '/admin/config/private-message' Loading
src/Controller/AjaxController.php +23 −2 Original line number Diff line number Diff line Loading @@ -2,12 +2,14 @@ namespace Drupal\private_message\Controller; use Drupal\Component\Utility\Crypt; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Site\Settings; use Drupal\private_message\Ajax\PrivateMessageInboxUpdateCommand; use Drupal\private_message\Ajax\PrivateMessageInsertNewMessagesCommand; use Drupal\private_message\Ajax\PrivateMessageInboxInsertThreadsCommand; Loading @@ -20,6 +22,7 @@ use Drupal\private_message\Entity\PrivateMessageThread; use Drupal\private_message\Service\PrivateMessageServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Controller to handle Ajax requests. Loading Loading @@ -176,11 +179,29 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface { /** * {@inheritdoc} */ public function privateMessageMembersAutocomplete() { public function privateMessageMembersAutocomplete($target_type, $selection_handler, $selection_settings_key) { $response = new AjaxResponse(); // Selection settings are passed in as a hashed key of a serialized array // stored in the key/value store. $selection_settings = \Drupal::keyValue('entity_autocomplete')->get($selection_settings_key, FALSE); if ($selection_settings !== FALSE) { $selection_settings_hash = Crypt::hmacBase64(serialize($selection_settings) . $target_type . $selection_handler, Settings::getHashSalt()); if (!hash_equals($selection_settings_hash, $selection_settings_key)) { // Disallow access when the selection settings hash does not match the // passed-in key. throw new AccessDeniedHttpException('Invalid selection settings key.'); } } else { // Disallow access when the selection settings key is not found in the // key/value store. throw new AccessDeniedHttpException(); } $match_limit = isset($selection_settings['match_limit']) ? (int) $selection_settings['match_limit'] : self::AUTOCOMPLETE_COUNT; $username = $this->requestStack->getCurrentRequest()->get('username'); $accounts = $this->privateMessageService->getUsersFromString($username, self::AUTOCOMPLETE_COUNT); $accounts = $this->privateMessageService->getUsersFromString($username, $match_limit); $user_info = []; foreach ($accounts as $account) { if ($account->access('view', $this->currentUser) && $account->isActive()) { Loading
src/Controller/AjaxControllerInterface.php +8 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,16 @@ interface AjaxControllerInterface { /** * Create AJAX response containing usernames for an autocomplete callback. * * @param $target_type * Target type of autocomplete. * @param $selection_handler * Selection handler of autocomplete. * @param $selection_settings_key * Key to the hashed settings. * * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response */ public function privateMessageMembersAutocomplete(); public function privateMessageMembersAutocomplete($target_type, $selection_handler, $selection_settings_key); }
src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php +23 −2 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\private_message\Plugin\Field\FieldWidget; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\Config\ConfigFactoryInterface; Loading @@ -12,6 +13,7 @@ use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Site\Settings; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; Loading Loading @@ -166,7 +168,6 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget $form = parent::settingsForm($form, $form_state); // This setting has no bearing on this widget, so it is removed. unset($form['match_operator']); unset($form['match_limit']); $form['max_members'] = [ '#type' => 'number', Loading Loading @@ -211,7 +212,27 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget if (!$style_disabled) { $element['#attached']['library'][] = 'private_message/members_widget_style'; } $url = Url::fromRoute('private_message.members_widget_callback'); $target_type = $element['target_id']['#target_type']; $selection_handler = $element['target_id']['#selection_handler']; // Store the selection settings in the key/value store and pass a hashed key // in the route parameters. $selection_settings = $element['target_id']['#selection_settings'] ?? []; $data = serialize($selection_settings) . $target_type . $selection_handler; $selection_settings_key = Crypt::hmacBase64($data, Settings::getHashSalt()); $key_value_storage = \Drupal::keyValue('entity_autocomplete'); if (!$key_value_storage->has($selection_settings_key)) { $key_value_storage->set($selection_settings_key, $selection_settings); } $url = Url::fromRoute('private_message.members_widget_callback', [ 'target_type' => $target_type, 'selection_handler' => $selection_handler, 'selection_settings_key' => $selection_settings_key, ]); $token = $this->csrfTokenGenerator->get($url->getInternalPath()); $url->setOptions(['query' => ['token' => $token]]); Loading