Disable browser back button module is designed to allow an administrator to disable browser back button on specific pages. In configuration form admin will enter list of url where admin want to disable browser back button.

Project link

https://www.drupal.org/project/disable_browser_back_button

Git instructions

git clone --branch 8.x-1.x https://git.drupalcode.org/project/disable_browser_back_button.git

PAReview checklist

https://pareview.sh/pareview/https-git.drupal.org-project-disable_browse...

Comments

Hardik_Patel_12 created an issue. See original summary.

apaderno’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: +PAreview: single application approval, +PAreview: security
/**
 * Implements hook_page_attachments().
 */
function disable_back_button_page_attachments(array &$attachments) {
  $attachments['#attached']['library'][] = 'disable_back_button/disable_back_button';
  $config = \Drupal::service('config.factory')->getEditable('disable_back_button_config.settings');
  if (!empty($config->get('no_back'))) {
    $no_back_array = explode(',', $config->get('no_back'));
    $attachments['#attached']['drupalSettings']['noback'] = $no_back_array;
  }
}
(function ($, Drupal) {
  'use strict';
  Drupal.behaviors.disable_back_button = {
    attach: function (context, settings) {
      // Array of url's where we have to disable browser back functionality.
      var noback = drupalSettings.noback;
      // Current path of page.
      var pathname = window.location.pathname;
      if (jQuery.inArray(pathname, noback) !== '-1') {
        window.history.pushState(null, '', window.location.href);
        window.onpopstate = function () {
          window.history.pushState(null, '', window.location.href);
        };
      }
    }
  };

}(jQuery, Drupal));

The value entered from users is not sanitized. Even though the setting page is accessible from users with the administer site configuration permission, the value they enter should still be sanitized.

kiamlaluno credited klausi.

apaderno’s picture

Hardik_Patel_12’s picture

Status: Needs work » Needs review

Thank you for the review, I've updated the repository.

apaderno’s picture

Status: Needs review » Needs work

HTML::escape() just converts special characters to HTML entities. It doesn't do anything to the URL protocol, which is the true issue.
Also, the code is escaping the value entered from users twice, once of which is when storing the values entered from users. (Sanitizing is done when outputting the value, not when storing it.)

      $output .= '<h3>' . t('Installation note') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Enable the module on <a href=":extend_link">extend menu</a>.', [':extend_link' => Url::fromRoute('system.modules_list')->toString()]) . '</dt>';
      $output .= '</dl>';

There is no need to add installation notes, since the users cannot see the output of disable_back_button_help() before installing the module, which means they are reading how to install the module after they installed it.

    $example_text = "<div>For example you want to disable browser back button on"
        . " below page<ul><li> <b>abc.com/xyz</b></li><li><b>abc.com/abc</b></li>"
        . "<li> <b>abc.com/efg</b></li></ul></div><div>Then enter <ul><li> <b>/xyz</b>"
        . "</li><li><b>/abc</b></li><li> <b>/efg</b></li></ul>"
        . "as comma seprated like <b>(/xyz,/abc,/efg)in  textarea</b></div>";
    // Markup for example.
    $form['example_text'] = [
      '#type' => 'markup',
      '#markup' => $example_text,
    ];

There is no need to give URLs examples before the form field to enter them, when they can be given in the description of that form field.
Also, a markup element is going to filter out the HTML markup, with the effect that not all the HTML tags are rendered. (See Render API, the part about the #markup property.)

function disable_back_button_uninstall() {

  // Uninstall configuration.
  \Drupal::configFactory()->getEditable('disable_back_button_config.settings')->delete();

}

None of the Drupal core modules delete their own settings when uninstalled. That is because Drupal core code automatically delete the settings that can be removed.

disable_back_button.config_form:
  path: '/admin/config/browser/noback/settings'
  defaults:
    _form: '\Drupal\disable_back_button\Form\DisableBackConfigForm'
    _title_callback: '\Drupal\disable_back_button\Form\DisableBackConfigForm::pageTitle'
  requirements:
    _permission: 'administer site configuration'
  options:
    _admin_route: TRUE

There is no need to use a title callback for a literal string used as title. _title is used also for forms, as in the following route example taken from Drupal core.

user.admin_permissions:
  path: '/admin/people/permissions'
  defaults:
    _form: '\Drupal\user\Form\UserPermissionsForm'
    _title: 'Permissions'
  requirements:
    _permission: 'administer permissions'
(function ($, Drupal) {
  'use strict';
  Drupal.behaviors.disable_back_button = {
    attach: function (context, settings) {
      // Array of url's where we have to disable browser back functionality.
      var noback = drupalSettings.noback;
      // Current path of page.
      var pathname = window.location.pathname;
      if (jQuery.inArray(pathname, noback) !== '-1') {
        window.history.pushState(null, '', window.location.href);
        window.onpopstate = function () {
          window.history.pushState(null, '', window.location.href);
        };
      }
    }
  };
}(jQuery, Drupal));

Inside the anonymous function, jQuery is not defined. Rather, it gets $. There is no need to use when JavaScript arrays have <code>indexOf().

name: Disable Back Button
description: Disable Back Button On Specific Pages.
type: module
core: 8.x
package: Back Button
configure: disable_back_button.config_form

There is no need to use a custom package that is used just for a module. package is not mandatory.

As minor issue, some of the strings shown to users contain grammar mistakes or misspellings.

  • Disable Back Button module is disabling browser back button on specific pages depends on user configured urls.(The Disable Back Button module disables the browser back button on user-configured URLs.
  • To add url, simply visit that configuration page at Configure (To add a URL, visit the configuration page)
  • Enter comma seprated page url where you want to disable browser back functionality (Enter a list of comma-separated URLs where the browser back functionality should be disabled)
apaderno’s picture

Issue tags: -PAreview: security

Actually, there is probably no need for the users to enter URLs, as they aren't supposed to disable the Back button for other sites. Plus, window.location.pathname doesn't return a URL but a path.

Hardik_Patel_12’s picture

Status: Needs work » Needs review

@kiamlaluno , thank-you so much for your review and suggestions , I've updated the repository.

apaderno’s picture

Status: Needs review » Needs work
  if (!empty($config->get('no_back'))) {
    $no_back_array = explode(',', $config->get('no_back'));
    $attachments['#attached']['drupalSettings']['noback'] = Html::escape(UrlHelper::stripDangerousProtocols($no_back_array));
  }

UrlHelper::stripDangerousProtocols() expects a string, not an array. Calling that method is also not necessary, since the module is asking users to enter a path starting with a slash.

    $url_list = explode(',', trim($form_state->getValue('url_list')));
    foreach ($url_list as $url) {
      $trim_url = trim($url);
      if ($trim_url[0] !== '/') {
        $form_state->setErrorByName('url_list', $this->t("@url path needs to start with a slash.", ['@url' => $trim_url]));
      }
    }

The first call to trim() is not necessary, as it's called for each item of the array.

(function ($, Drupal) {
  'use strict';
  Drupal.behaviors.disable_back_button = {
    attach: function (context, settings) {
      // Array of url's where we have to disable browser back functionality.
      var noback = drupalSettings.noback;
      // Current path of page.
      var pathname = window.location.pathname;
      if ( (noback.indexOf(pathname)) !== '-1') {
        window.history.pushState(null, '', window.location.href);
        window.onpopstate = function () {
          window.history.pushState(null, '', window.location.href);
        };
      }
    }
  };

}(jQuery, Drupal));

If jQuery is not used, it's not necessary to pass it as argument of the anonymous function, nor add it to the parameters list.

Hardik_Patel_12’s picture

Status: Needs work » Needs review

I've updated the repository, and for

(function ($, Drupal) {
'use strict';
Drupal.behaviors.disable_back_button = {
attach: function (context, settings) {
// Array of url's where we have to disable browser back functionality.
var noback = drupalSettings.noback;
// Current path of page.
var pathname = window.location.pathname;
if ( (noback.indexOf(pathname)) !== '-1') {
window.history.pushState(null, '', window.location.href);
window.onpopstate = function () {
window.history.pushState(null, '', window.location.href);
};
}
}
};

}(jQuery, Drupal));

If jQuery is not used, it's not necessary to pass it as argument of the anonymous function, nor add it to the parameters list.

i have seen various core js files also and they also unused but still there and i have cheked this link also "https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview".

batkor’s picture

Hi, Thank for this module.
Add dependencies for library

js:
    js/disable_back_button.js: {}
  dependencies:
    - core/drupal
    - core/drupalSettings

Remove jQuery and add drupalSettings

(function (Drupal, drupalSettings) {
...
}(Drupal, drupalSettings));

Correct get settings

var noback = settings.noback || drupalSettings.noback;
batkor’s picture

Status: Needs review » Needs work

NitPick
Call immutable config.
https://git.drupalcode.org/project/disable_browser_back_button/blob/8.x-...
Use get

$config = \Drupal::service('config.factory')->get('disable_back_button.settings');

See method comment https://git.drupalcode.org/project/drupal/blob/8.8.x/core/lib/Drupal/Cor...

batkor’s picture

i have seen various core js files also and they also unused but still there and i have cheked this link also

can not be.
This

(Function (Drupal) {

} ())

 automatically call anonymous function with parameter

Hardik_Patel_12’s picture

Status: Needs work » Needs review

@batkor thankyou so much for review , I've updated the repository.

klausi’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for you contribution!

Looks good to me, did not see any security issues.

apaderno’s picture

Assigned: Unassigned » apaderno
Status: Reviewed & tested by the community » Fixed

Thank you for your contribution! I am going to update the project to opt it into security coverage.

These are some recommended readings to help with excellent maintainership:

You can find more contributors chatting on the IRC #drupal-contribute channel. So, come hang out and stay involved.
Thank you, also, for your patience with the review process.
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

I thank all the dedicated reviewers as well.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.