Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core\local\guzzle;
  18  
  19  use core\files\curl_security_helper_base;
  20  use GuzzleHttp\Exception\RequestException;
  21  use GuzzleHttp\RedirectMiddleware;
  22  use Psr\Http\Message\RequestInterface;
  23  use Psr\Http\Message\ResponseInterface;
  24  use GuzzleHttp\Promise\PromiseInterface;
  25  
  26  /**
  27   * Class to check that each URL is valid in a redirect.
  28   *
  29   * @package   core
  30   * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
  31   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class redirect_middleware extends RedirectMiddleware {
  34      /** @var curl_security_helper_base The helper to in use */
  35      protected $securityhelper;
  36  
  37      /** @var array The settings or options from client */
  38      protected $settings;
  39  
  40      /**
  41       * Setup method for the redirect middleware.
  42       *
  43       * @param array $settings The settings of the request
  44       * @return callable
  45       */
  46      public static function setup(array $settings): callable {
  47          return static function (callable $handler) use ($settings): self {
  48              return new self($handler, $settings);
  49          };
  50      }
  51  
  52      /**
  53       * Redirect middleware constructor.
  54       *
  55       * @param callable(RequestInterface, array): PromiseInterface $next The next handler to invoke
  56       * @param array $settings The options from the client
  57       */
  58      public function __construct(callable $next, array $settings) {
  59          parent::__construct($next);
  60          $this->settings = $settings;
  61      }
  62  
  63      /**
  64       * Set the security according to settings.
  65       *
  66       * @param curl_security_helper_base $securityhelper
  67       * @return void
  68       */
  69      protected function set_security(curl_security_helper_base $securityhelper): void {
  70          $this->securityhelper = $securityhelper;
  71      }
  72  
  73      /**
  74       * Curl security setup.
  75       *
  76       * @param RequestInterface $request The interface of the request
  77       * @param array $options The options for the request
  78       * @return PromiseInterface
  79       */
  80      public function __invoke(RequestInterface $request, array $options): PromiseInterface {
  81          $settings = $this->settings;
  82          // Curl security setup. Allow injection of a security helper, but if not found, default to the core helper.
  83          if (isset($settings['securityhelper']) && $settings['securityhelper'] instanceof \core\files\curl_security_helper_base) {
  84              $this->set_security($settings['securityhelper']);
  85          } else {
  86              $this->set_security(new \core\files\curl_security_helper());
  87          }
  88  
  89          return parent::__invoke($request, $options);
  90      }
  91  
  92      public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response): RequestInterface {
  93          $settings = $this->settings;
  94  
  95          $request = parent::modifyRequest($request, $options, $response);
  96  
  97          if (!empty($settings['ignoresecurity'])) {
  98              return $request;
  99          }
 100  
 101          if ($this->securityhelper->url_is_blocked((string) $request->getUri())) {
 102              throw new RequestException(
 103                  $this->securityhelper->get_blocked_url_string(),
 104                  $request,
 105                  $response
 106              );
 107          }
 108          return $request;
 109      }
 110  }