Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 400 and 403] [Versions 401 and 403]

   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 quizaccess_seb\external;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  global $CFG;
  22  
  23  use core_external\external_api;
  24  use core_external\external_function_parameters;
  25  use core_external\external_single_structure;
  26  use core_external\external_value;
  27  use invalid_parameter_exception;
  28  use mod_quiz\quiz_settings;
  29  use quizaccess_seb\event\access_prevented;
  30  use quizaccess_seb\seb_access_manager;
  31  
  32  /**
  33   * Validate browser exam key and config key.
  34   *
  35   * @package    quizaccess_seb
  36   * @author     Andrew Madden <andrewmadden@catalyst-au.net>
  37   * @copyright  2021 Catalyst IT
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class validate_quiz_keys extends external_api {
  41  
  42      /**
  43       * External function parameters.
  44       *
  45       * @return external_function_parameters
  46       */
  47      public static function execute_parameters(): external_function_parameters {
  48          return new external_function_parameters([
  49             'cmid' => new external_value(PARAM_INT, 'Course module ID',
  50                  VALUE_REQUIRED, null, NULL_NOT_ALLOWED),
  51             'url' => new external_value(PARAM_URL, 'Page URL to check',
  52                  VALUE_REQUIRED, null, NULL_NOT_ALLOWED),
  53             'configkey' => new external_value(PARAM_ALPHANUMEXT, 'SEB config key',
  54                  VALUE_DEFAULT, null),
  55             'browserexamkey' => new external_value(PARAM_ALPHANUMEXT, 'SEB browser exam key',
  56                  VALUE_DEFAULT, null),
  57          ]);
  58      }
  59  
  60      /**
  61       * Validate a SEB config key or browser exam key.
  62       *
  63       * @param string $cmid Course module ID.
  64       * @param string $url URL of the page on which the SEB JS API generated the keys.
  65       * @param string|null $configkey A SEB config key hash. Includes URL in the hash.
  66       * @param string|null $browserexamkey A SEB browser exam key hash. Includes the URL in the hash.
  67       * @return array
  68       */
  69      public static function execute(string $cmid, string $url, ?string $configkey = null, ?string $browserexamkey = null): array {
  70          list(
  71                  'cmid' => $cmid,
  72                  'url' => $url,
  73                  'configkey' => $configkey,
  74                  'browserexamkey' => $browserexamkey
  75              ) = self::validate_parameters(self::execute_parameters(), [
  76              'cmid' => $cmid,
  77              'url' => $url,
  78              'configkey' => $configkey,
  79              'browserexamkey' => $browserexamkey,
  80          ]);
  81  
  82          self::validate_context(\context_module::instance($cmid));
  83  
  84          // At least one SEB key must be provided.
  85          if (empty($configkey) && empty($browserexamkey)) {
  86              throw new invalid_parameter_exception(get_string('error:ws:nokeyprovided', 'quizaccess_seb'));
  87          }
  88  
  89          // Check quiz exists corresponding to cmid.
  90          if (($quizid = self::get_quiz_id($cmid)) === 0) {
  91              throw new invalid_parameter_exception(get_string('error:ws:quiznotexists', 'quizaccess_seb', $cmid));
  92          }
  93  
  94          $result = ['configkey' => true, 'browserexamkey' => true];
  95  
  96          $accessmanager = new seb_access_manager(quiz_settings::create($quizid));
  97  
  98          // Check if there is a valid config key.
  99          if (!$accessmanager->validate_config_key($configkey, $url)) {
 100              access_prevented::create_strict($accessmanager, get_string('invalid_config_key', 'quizaccess_seb'),
 101                      $configkey, $browserexamkey)->trigger();
 102              $result['configkey'] = false;
 103          }
 104  
 105          // Check if there is a valid browser exam key.
 106          if (!$accessmanager->validate_browser_exam_key($browserexamkey, $url)) {
 107              access_prevented::create_strict($accessmanager, get_string('invalid_browser_key', 'quizaccess_seb'),
 108                      $configkey, $browserexamkey)->trigger();
 109              $result['browserexamkey'] = false;
 110          }
 111  
 112          if ($result['configkey'] && $result['browserexamkey']) {
 113              // Set the state of the access for this Moodle session.
 114              $accessmanager->set_session_access(true);
 115          }
 116  
 117          return $result;
 118      }
 119  
 120      /**
 121       * External function returns.
 122       *
 123       * @return external_single_structure
 124       */
 125      public static function execute_returns(): external_single_structure {
 126          return new external_single_structure([
 127              'configkey' => new external_value(PARAM_BOOL, 'Is a provided config key valid?',
 128                      VALUE_REQUIRED, 0, NULL_NOT_ALLOWED),
 129              'browserexamkey' => new external_value(PARAM_BOOL, 'Is a provided browser exam key valid?',
 130                  VALUE_REQUIRED, 0, NULL_NOT_ALLOWED)
 131          ]);
 132      }
 133  
 134      /**
 135       * Check if there is a valid quiz corresponding to a course module it.
 136       *
 137       * @param string $cmid Course module ID.
 138       * @return int Returns quiz id if cmid matches valid quiz, or 0 if there is no match.
 139       */
 140      private static function get_quiz_id(string $cmid): int {
 141          $quizid = 0;
 142  
 143          $coursemodule = get_coursemodule_from_id('quiz', $cmid);
 144          if (!empty($coursemodule)) {
 145              $quizid = $coursemodule->instance;
 146          }
 147  
 148          return $quizid;
 149      }
 150  }