Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [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 /** 18 * This is the external API for this tool. 19 * 20 * @package tool_mobile 21 * @copyright 2016 Juan Leyva 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace tool_mobile; 26 27 defined('MOODLE_INTERNAL') || die(); 28 require_once("$CFG->dirroot/webservice/lib.php"); 29 30 use core_external\external_api; 31 use core_external\external_files; 32 use core_external\external_function_parameters; 33 use core_external\external_multiple_structure; 34 use core_external\external_single_structure; 35 use core_external\external_settings; 36 use core_external\external_value; 37 use core_external\external_warnings; 38 use context_system; 39 use moodle_exception; 40 use moodle_url; 41 use core_user; 42 use coding_exception; 43 44 /** 45 * This is the external API for this tool. 46 * 47 * @copyright 2016 Juan Leyva 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class external extends external_api { 51 52 /** 53 * Returns description of get_plugins_supporting_mobile() parameters. 54 * 55 * @return external_function_parameters 56 * @since Moodle 3.1 57 */ 58 public static function get_plugins_supporting_mobile_parameters() { 59 return new external_function_parameters(array()); 60 } 61 62 /** 63 * Returns a list of Moodle plugins supporting the mobile app. 64 * 65 * @return array an array of warnings and objects containing the plugin information 66 * @since Moodle 3.1 67 */ 68 public static function get_plugins_supporting_mobile() { 69 return array( 70 'plugins' => api::get_plugins_supporting_mobile(), 71 'warnings' => array(), 72 ); 73 } 74 75 /** 76 * Returns description of get_plugins_supporting_mobile() result value. 77 * 78 * @return \core_external\external_description 79 * @since Moodle 3.1 80 */ 81 public static function get_plugins_supporting_mobile_returns() { 82 return new external_single_structure( 83 array( 84 'plugins' => new external_multiple_structure( 85 new external_single_structure( 86 array( 87 'component' => new external_value(PARAM_COMPONENT, 'The plugin component name.'), 88 'version' => new external_value(PARAM_NOTAGS, 'The plugin version number.'), 89 'addon' => new external_value(PARAM_COMPONENT, 'The Mobile addon (package) name.'), 90 'dependencies' => new external_multiple_structure( 91 new external_value(PARAM_COMPONENT, 'Mobile addon name.'), 92 'The list of Mobile addons this addon depends on.' 93 ), 94 'fileurl' => new external_value(PARAM_URL, 'The addon package url for download 95 or empty if it doesn\'t exist.'), 96 'filehash' => new external_value(PARAM_RAW, 'The addon package hash or empty if it doesn\'t exist.'), 97 'filesize' => new external_value(PARAM_INT, 'The addon package size or empty if it doesn\'t exist.'), 98 'handlers' => new external_value(PARAM_RAW, 'Handlers definition (JSON)', VALUE_OPTIONAL), 99 'lang' => new external_value(PARAM_RAW, 'Language strings used by the handlers (JSON)', VALUE_OPTIONAL), 100 ) 101 ) 102 ), 103 'warnings' => new external_warnings(), 104 ) 105 ); 106 } 107 108 /** 109 * Returns description of get_public_config() parameters. 110 * 111 * @return external_function_parameters 112 * @since Moodle 3.2 113 */ 114 public static function get_public_config_parameters() { 115 return new external_function_parameters(array()); 116 } 117 118 /** 119 * Returns a list of the site public settings, those not requiring authentication. 120 * 121 * @return array with the settings and warnings 122 * @since Moodle 3.2 123 */ 124 public static function get_public_config() { 125 $result = api::get_public_config(); 126 $result['warnings'] = array(); 127 return $result; 128 } 129 130 /** 131 * Returns description of get_public_config() result value. 132 * 133 * @return \core_external\external_description 134 * @since Moodle 3.2 135 */ 136 public static function get_public_config_returns() { 137 return new external_single_structure( 138 array( 139 'wwwroot' => new external_value(PARAM_RAW, 'Site URL.'), 140 'httpswwwroot' => new external_value(PARAM_RAW, 'Site https URL (if httpslogin is enabled).'), 141 'sitename' => new external_value(PARAM_RAW, 'Site name.'), 142 'guestlogin' => new external_value(PARAM_INT, 'Whether guest login is enabled.'), 143 'rememberusername' => new external_value(PARAM_INT, 'Values: 0 for No, 1 for Yes, 2 for optional.'), 144 'authloginviaemail' => new external_value(PARAM_INT, 'Whether log in via email is enabled.'), 145 'registerauth' => new external_value(PARAM_PLUGIN, 'Authentication method for user registration.'), 146 'forgottenpasswordurl' => new external_value(PARAM_URL, 'Forgotten password URL.'), 147 'authinstructions' => new external_value(PARAM_RAW, 'Authentication instructions.'), 148 'authnoneenabled' => new external_value(PARAM_INT, 'Whether auth none is enabled.'), 149 'enablewebservices' => new external_value(PARAM_INT, 'Whether Web Services are enabled.'), 150 'enablemobilewebservice' => new external_value(PARAM_INT, 'Whether the Mobile service is enabled.'), 151 'maintenanceenabled' => new external_value(PARAM_INT, 'Whether site maintenance is enabled.'), 152 'maintenancemessage' => new external_value(PARAM_RAW, 'Maintenance message.'), 153 'logourl' => new external_value(PARAM_URL, 'The site logo URL', VALUE_OPTIONAL), 154 'compactlogourl' => new external_value(PARAM_URL, 'The site compact logo URL', VALUE_OPTIONAL), 155 'typeoflogin' => new external_value(PARAM_INT, 'The type of login. 1 for app, 2 for browser, 3 for embedded.'), 156 'launchurl' => new external_value(PARAM_URL, 'SSO login launch URL.', VALUE_OPTIONAL), 157 'mobilecssurl' => new external_value(PARAM_URL, 'Mobile custom CSS theme', VALUE_OPTIONAL), 158 'tool_mobile_disabledfeatures' => new external_value(PARAM_RAW, 'Disabled features in the app', VALUE_OPTIONAL), 159 'identityproviders' => new external_multiple_structure( 160 new external_single_structure( 161 array( 162 'name' => new external_value(PARAM_TEXT, 'The identity provider name.'), 163 'iconurl' => new external_value(PARAM_URL, 'The icon URL for the provider.'), 164 'url' => new external_value(PARAM_URL, 'The URL of the provider.'), 165 ) 166 ), 167 'Identity providers', VALUE_OPTIONAL 168 ), 169 'country' => new external_value(PARAM_NOTAGS, 'Default site country', VALUE_OPTIONAL), 170 'agedigitalconsentverification' => new external_value(PARAM_BOOL, 'Whether age digital consent verification 171 is enabled.', VALUE_OPTIONAL), 172 'supportname' => new external_value(PARAM_NOTAGS, 'Site support contact name 173 (only if age verification is enabled).', VALUE_OPTIONAL), 174 'supportemail' => new external_value(PARAM_EMAIL, 'Site support contact email 175 (only if age verification is enabled).', VALUE_OPTIONAL), 176 'supportpage' => new external_value(PARAM_URL, 'Site support page link.', VALUE_OPTIONAL), 177 'supportavailability' => new external_value(PARAM_INT, 'Determines who has access to contact site support.', 178 VALUE_OPTIONAL), 179 'autolang' => new external_value(PARAM_INT, 'Whether to detect default language 180 from browser setting.', VALUE_OPTIONAL), 181 'lang' => new external_value(PARAM_LANG, 'Default language for the site.', VALUE_OPTIONAL), 182 'langmenu' => new external_value(PARAM_INT, 'Whether the language menu should be displayed.', VALUE_OPTIONAL), 183 'langlist' => new external_value(PARAM_RAW, 'Languages on language menu.', VALUE_OPTIONAL), 184 'locale' => new external_value(PARAM_RAW, 'Sitewide locale.', VALUE_OPTIONAL), 185 'tool_mobile_minimumversion' => new external_value(PARAM_NOTAGS, 'Minimum required version to access.', 186 VALUE_OPTIONAL), 187 'tool_mobile_iosappid' => new external_value(PARAM_ALPHANUM, 'iOS app\'s unique identifier.', 188 VALUE_OPTIONAL), 189 'tool_mobile_androidappid' => new external_value(PARAM_NOTAGS, 'Android app\'s unique identifier.', 190 VALUE_OPTIONAL), 191 'tool_mobile_setuplink' => new external_value(PARAM_URL, 'App download page.', VALUE_OPTIONAL), 192 'tool_mobile_qrcodetype' => new external_value(PARAM_INT, 'QR login configuration.', VALUE_OPTIONAL), 193 'warnings' => new external_warnings(), 194 ) 195 ); 196 } 197 198 /** 199 * Returns description of get_config() parameters. 200 * 201 * @return external_function_parameters 202 * @since Moodle 3.2 203 */ 204 public static function get_config_parameters() { 205 return new external_function_parameters( 206 array( 207 'section' => new external_value(PARAM_ALPHANUMEXT, 'Settings section name.', VALUE_DEFAULT, ''), 208 ) 209 ); 210 } 211 212 /** 213 * Returns a list of site settings, filtering by section. 214 * 215 * @param string $section settings section name 216 * @return array with the settings and warnings 217 * @since Moodle 3.2 218 */ 219 public static function get_config($section = '') { 220 221 $params = self::validate_parameters(self::get_config_parameters(), array('section' => $section)); 222 223 $settings = api::get_config($params['section']); 224 $result['settings'] = array(); 225 foreach ($settings as $name => $value) { 226 $result['settings'][] = array( 227 'name' => $name, 228 'value' => $value, 229 ); 230 } 231 232 $result['warnings'] = array(); 233 return $result; 234 } 235 236 /** 237 * Returns description of get_config() result value. 238 * 239 * @return \core_external\external_description 240 * @since Moodle 3.2 241 */ 242 public static function get_config_returns() { 243 return new external_single_structure( 244 array( 245 'settings' => new external_multiple_structure( 246 new external_single_structure( 247 array( 248 'name' => new external_value(PARAM_RAW, 'The name of the setting'), 249 'value' => new external_value(PARAM_RAW, 'The value of the setting'), 250 ) 251 ), 252 'Settings' 253 ), 254 'warnings' => new external_warnings(), 255 ) 256 ); 257 } 258 259 /** 260 * Returns description of get_autologin_key() parameters. 261 * 262 * @return external_function_parameters 263 * @since Moodle 3.2 264 */ 265 public static function get_autologin_key_parameters() { 266 return new external_function_parameters ( 267 array( 268 'privatetoken' => new external_value(PARAM_ALPHANUM, 'Private token, usually generated by login/token.php'), 269 ) 270 ); 271 } 272 273 /** 274 * Creates an auto-login key for the current user. Is created only in https sites and is restricted by time and ip address. 275 * 276 * Please note that it only works if the request comes from the Moodle mobile or desktop app. 277 * 278 * @param string $privatetoken the user private token for validating the request 279 * @return array with the settings and warnings 280 * @since Moodle 3.2 281 */ 282 public static function get_autologin_key($privatetoken) { 283 global $CFG, $DB, $USER; 284 285 $params = self::validate_parameters(self::get_autologin_key_parameters(), array('privatetoken' => $privatetoken)); 286 $privatetoken = $params['privatetoken']; 287 288 $context = context_system::instance(); 289 290 // We must toletare these two exceptions: forcepasswordchangenotice and usernotfullysetup. 291 try { 292 self::validate_context($context); 293 } catch (moodle_exception $e) { 294 if ($e->errorcode != 'usernotfullysetup' && $e->errorcode != 'forcepasswordchangenotice') { 295 // In case we receive a different exception, throw it. 296 throw $e; 297 } 298 } 299 300 // Only requests from the Moodle mobile or desktop app. This enhances security to avoid any type of XSS attack. 301 // This code goes intentionally here and not inside the check_autologin_prerequisites() function because it 302 // is used by other PHP scripts that can be opened in any browser. 303 if (!\core_useragent::is_moodle_app()) { 304 throw new moodle_exception('apprequired', 'tool_mobile'); 305 } 306 api::check_autologin_prerequisites($USER->id); 307 308 if (isset($_GET['privatetoken']) or empty($privatetoken)) { 309 throw new moodle_exception('invalidprivatetoken', 'tool_mobile'); 310 } 311 312 // Check the request counter, we must limit the number of times the privatetoken is sent. 313 // Between each request 6 minutes are required. 314 $last = get_user_preferences('tool_mobile_autologin_request_last', 0, $USER); 315 // Check if we must reset the count. 316 $mintimereq = get_config('tool_mobile', 'autologinmintimebetweenreq'); 317 $mintimereq = empty($mintimereq) ? 6 * MINSECS : $mintimereq; 318 $timenow = time(); 319 if ($timenow - $last < $mintimereq) { 320 $minutes = $mintimereq / MINSECS; 321 throw new moodle_exception('autologinkeygenerationlockout', 'tool_mobile', '', $minutes); 322 } 323 set_user_preference('tool_mobile_autologin_request_last', $timenow, $USER); 324 325 // We are expecting a privatetoken linked to the current token being used. 326 // This WS is only valid when using mobile services via REST (this is intended). 327 $currenttoken = required_param('wstoken', PARAM_ALPHANUM); 328 $conditions = array( 329 'userid' => $USER->id, 330 'token' => $currenttoken, 331 'privatetoken' => $privatetoken, 332 ); 333 if (!$token = $DB->get_record('external_tokens', $conditions)) { 334 throw new moodle_exception('invalidprivatetoken', 'tool_mobile'); 335 } 336 337 $result = array(); 338 $result['key'] = api::get_autologin_key(); 339 $autologinurl = new moodle_url("/$CFG->admin/tool/mobile/autologin.php"); 340 $result['autologinurl'] = $autologinurl->out(false); 341 $result['warnings'] = array(); 342 return $result; 343 } 344 345 /** 346 * Returns description of get_autologin_key() result value. 347 * 348 * @return \core_external\external_description 349 * @since Moodle 3.2 350 */ 351 public static function get_autologin_key_returns() { 352 return new external_single_structure( 353 array( 354 'key' => new external_value(PARAM_ALPHANUMEXT, 'Auto-login key for a single usage with time expiration.'), 355 'autologinurl' => new external_value(PARAM_URL, 'Auto-login URL.'), 356 'warnings' => new external_warnings(), 357 ) 358 ); 359 } 360 361 /** 362 * Returns description of get_content() parameters 363 * 364 * @return external_function_parameters 365 * @since Moodle 3.5 366 */ 367 public static function get_content_parameters() { 368 return new external_function_parameters( 369 array( 370 'component' => new external_value(PARAM_COMPONENT, 'Component where the class is e.g. mod_assign.'), 371 'method' => new external_value(PARAM_ALPHANUMEXT, 'Method to execute in class \$component\output\mobile.'), 372 'args' => new external_multiple_structure( 373 new external_single_structure( 374 array( 375 'name' => new external_value(PARAM_ALPHANUMEXT, 'Param name.'), 376 'value' => new external_value(PARAM_RAW, 'Param value.') 377 ) 378 ), 'Args for the method are optional.', VALUE_OPTIONAL 379 ) 380 ) 381 ); 382 } 383 384 /** 385 * Returns a piece of content to be displayed in the Mobile app, it usually returns a template, javascript and 386 * other structured data that will be used to render a view in the Mobile app. 387 * 388 * Callbacks (placed in \$component\output\mobile) that are called by this web service are responsible for doing the 389 * appropriate security checks to access the information to be returned. 390 * 391 * @param string $component name of the component. 392 * @param string $method function method name in class \$component\output\mobile. 393 * @param array $args optional arguments for the method. 394 * @return array HTML, JavaScript and other required data and information to create a view in the app. 395 * @since Moodle 3.5 396 * @throws coding_exception 397 */ 398 public static function get_content($component, $method, $args = array()) { 399 global $OUTPUT, $PAGE, $USER; 400 401 $params = self::validate_parameters(self::get_content_parameters(), 402 array( 403 'component' => $component, 404 'method' => $method, 405 'args' => $args 406 ) 407 ); 408 409 // Reformat arguments into something less unwieldy. 410 $arguments = array(); 411 foreach ($params['args'] as $paramargument) { 412 $arguments[$paramargument['name']] = $paramargument['value']; 413 } 414 415 // The component was validated via the PARAM_COMPONENT parameter type. 416 $classname = '\\' . $params['component'] .'\output\mobile'; 417 if (!method_exists($classname, $params['method'])) { 418 throw new coding_exception("Missing method in $classname"); 419 } 420 $result = call_user_func_array(array($classname, $params['method']), array($arguments)); 421 422 // Populate otherdata. 423 $otherdata = array(); 424 if (!empty($result['otherdata'])) { 425 $result['otherdata'] = (array) $result['otherdata']; 426 foreach ($result['otherdata'] as $name => $value) { 427 $otherdata[] = array( 428 'name' => $name, 429 'value' => $value 430 ); 431 } 432 } 433 434 return array( 435 'templates' => !empty($result['templates']) ? $result['templates'] : array(), 436 'javascript' => !empty($result['javascript']) ? $result['javascript'] : '', 437 'otherdata' => $otherdata, 438 'files' => !empty($result['files']) ? $result['files'] : array(), 439 'restrict' => !empty($result['restrict']) ? $result['restrict'] : array(), 440 'disabled' => !empty($result['disabled']) ? true : false, 441 ); 442 } 443 444 /** 445 * Returns description of get_content() result value 446 * 447 * @return array 448 * @since Moodle 3.5 449 */ 450 public static function get_content_returns() { 451 return new external_single_structure( 452 array( 453 'templates' => new external_multiple_structure( 454 new external_single_structure( 455 array( 456 'id' => new external_value(PARAM_TEXT, 'ID of the template.'), 457 'html' => new external_value(PARAM_RAW, 'HTML code.'), 458 ) 459 ), 460 'Templates required by the generated content.' 461 ), 462 'javascript' => new external_value(PARAM_RAW, 'JavaScript code.'), 463 'otherdata' => new external_multiple_structure( 464 new external_single_structure( 465 array( 466 'name' => new external_value(PARAM_RAW, 'Field name.'), 467 'value' => new external_value(PARAM_RAW, 'Field value.') 468 ) 469 ), 470 'Other data that can be used or manipulated by the template via 2-way data-binding.' 471 ), 472 'files' => new external_files('Files in the content.'), 473 'restrict' => new external_single_structure( 474 array( 475 'users' => new external_multiple_structure( 476 new external_value(PARAM_INT, 'user id'), 'List of allowed users.', VALUE_OPTIONAL 477 ), 478 'courses' => new external_multiple_structure( 479 new external_value(PARAM_INT, 'course id'), 'List of allowed courses.', VALUE_OPTIONAL 480 ), 481 ), 482 'Restrict this content to certain users or courses.' 483 ), 484 'disabled' => new external_value(PARAM_BOOL, 'Whether we consider this disabled or not.', VALUE_OPTIONAL), 485 ) 486 ); 487 } 488 489 /** 490 * Returns description of method parameters 491 * 492 * @return external_function_parameters 493 * @since Moodle 3.7 494 */ 495 public static function call_external_functions_parameters() { 496 return new external_function_parameters([ 497 'requests' => new external_multiple_structure( 498 new external_single_structure([ 499 'function' => new external_value(PARAM_ALPHANUMEXT, 'Function name'), 500 'arguments' => new external_value(PARAM_RAW, 'JSON-encoded object with named arguments', VALUE_DEFAULT, '{}'), 501 'settingraw' => new external_value(PARAM_BOOL, 'Return raw text', VALUE_DEFAULT, false), 502 'settingfilter' => new external_value(PARAM_BOOL, 'Filter text', VALUE_DEFAULT, false), 503 'settingfileurl' => new external_value(PARAM_BOOL, 'Rewrite plugin file URLs', VALUE_DEFAULT, true), 504 'settinglang' => new external_value(PARAM_LANG, 'Session language', VALUE_DEFAULT, ''), 505 ]) 506 ) 507 ]); 508 } 509 510 /** 511 * Call multiple external functions and return all responses. 512 * 513 * @param array $requests List of requests. 514 * @return array Responses. 515 * @since Moodle 3.7 516 */ 517 public static function call_external_functions($requests) { 518 global $SESSION; 519 520 $params = self::validate_parameters(self::call_external_functions_parameters(), ['requests' => $requests]); 521 522 // We need to check if the functions being called are included in the service of the current token. 523 // This function only works when using mobile services via REST (this is intended). 524 $webservicemanager = new \webservice; 525 $token = $webservicemanager->get_user_ws_token(required_param('wstoken', PARAM_ALPHANUM)); 526 527 $settings = external_settings::get_instance(); 528 $defaultlang = current_language(); 529 $responses = []; 530 531 foreach ($params['requests'] as $request) { 532 // Some external functions modify _GET or $_POST data, we need to restore the original data after each call. 533 $originalget = fullclone($_GET); 534 $originalpost = fullclone($_POST); 535 536 // Set external settings and language. 537 $settings->set_raw($request['settingraw']); 538 $settings->set_filter($request['settingfilter']); 539 $settings->set_fileurl($request['settingfileurl']); 540 $settings->set_lang($request['settinglang']); 541 $SESSION->lang = $request['settinglang'] ?: $defaultlang; 542 543 // Parse arguments to an array, validation is done in external_api::call_external_function. 544 $args = @json_decode($request['arguments'], true); 545 if (!is_array($args)) { 546 $args = []; 547 } 548 549 if ($webservicemanager->service_function_exists($request['function'], $token->externalserviceid)) { 550 $response = external_api::call_external_function($request['function'], $args, false); 551 } else { 552 // Function not included in the service, return an access exception. 553 $response = [ 554 'error' => true, 555 'exception' => [ 556 'errorcode' => 'accessexception', 557 'module' => 'webservice' 558 ] 559 ]; 560 if (debugging('', DEBUG_DEVELOPER)) { 561 $response['exception']['debuginfo'] = 'Access to the function is not allowed.'; 562 } 563 } 564 565 if (isset($response['data'])) { 566 $response['data'] = json_encode($response['data']); 567 } 568 if (isset($response['exception'])) { 569 $response['exception'] = json_encode($response['exception']); 570 } 571 $responses[] = $response; 572 573 // Restore original $_GET and $_POST. 574 $_GET = $originalget; 575 $_POST = $originalpost; 576 577 if ($response['error']) { 578 // Do not process the remaining requests. 579 break; 580 } 581 } 582 583 return ['responses' => $responses]; 584 } 585 586 /** 587 * Returns description of method result value 588 * 589 * @return external_single_structure 590 * @since Moodle 3.7 591 */ 592 public static function call_external_functions_returns() { 593 return new external_function_parameters([ 594 'responses' => new external_multiple_structure( 595 new external_single_structure([ 596 'error' => new external_value(PARAM_BOOL, 'Whether an exception was thrown.'), 597 'data' => new external_value(PARAM_RAW, 'JSON-encoded response data', VALUE_OPTIONAL), 598 'exception' => new external_value(PARAM_RAW, 'JSON-encoed exception info', VALUE_OPTIONAL), 599 ]) 600 ) 601 ]); 602 } 603 604 /** 605 * Returns description of get_tokens_for_qr_login() parameters. 606 * 607 * @return external_function_parameters 608 * @since Moodle 3.9 609 */ 610 public static function get_tokens_for_qr_login_parameters() { 611 return new external_function_parameters ( 612 [ 613 'qrloginkey' => new external_value(PARAM_ALPHANUMEXT, 'The user key for validating the request.'), 614 'userid' => new external_value(PARAM_INT, 'The user the key belongs to.'), 615 ] 616 ); 617 } 618 619 /** 620 * Returns a WebService token (and private token) for QR login 621 * 622 * @param string $qrloginkey the user key generated and embedded into the QR code for validating the request 623 * @param int $userid the user the key belongs to 624 * @return array with the tokens and warnings 625 * @since Moodle 3.9 626 */ 627 public static function get_tokens_for_qr_login($qrloginkey, $userid) { 628 global $PAGE, $DB; 629 630 $params = self::validate_parameters(self::get_tokens_for_qr_login_parameters(), 631 ['qrloginkey' => $qrloginkey, 'userid' => $userid]); 632 633 $context = context_system::instance(); 634 // We need this to make work the format text functions. 635 $PAGE->set_context($context); 636 637 $qrcodetype = get_config('tool_mobile', 'qrcodetype'); 638 if ($qrcodetype != api::QR_CODE_LOGIN) { 639 throw new moodle_exception('qrcodedisabled', 'tool_mobile'); 640 } 641 642 // Only requests from the Moodle mobile or desktop app. This enhances security to avoid any type of XSS attack. 643 // This code goes intentionally here and not inside the check_autologin_prerequisites() function because it 644 // is used by other PHP scripts that can be opened in any browser. 645 if (!\core_useragent::is_moodle_app()) { 646 throw new moodle_exception('apprequired', 'tool_mobile'); 647 } 648 api::check_autologin_prerequisites($params['userid']); // Checks https, avoid site admins using this... 649 650 // Validate and delete the key. 651 $key = validate_user_key($params['qrloginkey'], 'tool_mobile', null); 652 delete_user_key('tool_mobile', $params['userid']); 653 654 // Double check key belong to user. 655 if ($key->userid != $params['userid']) { 656 throw new moodle_exception('invalidkey'); 657 } 658 659 // Key validated, check user. 660 $user = core_user::get_user($key->userid, '*', MUST_EXIST); 661 core_user::require_active_user($user, true, true); 662 663 // Generate WS tokens. 664 \core\session\manager::set_user($user); 665 666 // Check if the service exists and is enabled. 667 $service = $DB->get_record('external_services', ['shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE, 'enabled' => 1]); 668 if (empty($service)) { 669 // will throw exception if no token found 670 throw new moodle_exception('servicenotavailable', 'webservice'); 671 } 672 673 // Get an existing token or create a new one. 674 $token = \core_external\util::generate_token_for_current_user($service); 675 $privatetoken = $token->privatetoken; // Save it here, the next function removes it. 676 \core_external\util::log_token_request($token); 677 678 $result = [ 679 'token' => $token->token, 680 'privatetoken' => $privatetoken ?: '', 681 'warnings' => [], 682 ]; 683 return $result; 684 } 685 686 /** 687 * Returns description of get_tokens_for_qr_login() result value. 688 * 689 * @return \core_external\external_description 690 * @since Moodle 3.9 691 */ 692 public static function get_tokens_for_qr_login_returns() { 693 return new external_single_structure( 694 [ 695 'token' => new external_value(PARAM_ALPHANUM, 'A valid WebService token for the official mobile app service.'), 696 'privatetoken' => new external_value(PARAM_ALPHANUM, 'Private token used for auto-login processes.'), 697 'warnings' => new external_warnings(), 698 ] 699 ); 700 } 701 702 /** 703 * Returns description of validate_subscription_key() parameters. 704 * 705 * @return external_function_parameters 706 * @since Moodle 3.9 707 */ 708 public static function validate_subscription_key_parameters() { 709 return new external_function_parameters( 710 [ 711 'key' => new external_value(PARAM_RAW, 'Site subscription temporary key.'), 712 ] 713 ); 714 } 715 716 /** 717 * Check if the given site subscription key is valid 718 * 719 * @param string $key subscriptiion temporary key 720 * @return array with the settings and warnings 721 * @since Moodle 3.9 722 */ 723 public static function validate_subscription_key(string $key): array { 724 global $CFG, $PAGE; 725 726 $params = self::validate_parameters(self::validate_subscription_key_parameters(), ['key' => $key]); 727 728 $context = context_system::instance(); 729 $PAGE->set_context($context); 730 731 $validated = false; 732 $sitesubscriptionkey = get_config('tool_mobile', 'sitesubscriptionkey'); 733 if (!empty($sitesubscriptionkey) && $CFG->enablemobilewebservice && empty($CFG->disablemobileappsubscription)) { 734 $sitesubscriptionkey = json_decode($sitesubscriptionkey); 735 $validated = time() < $sitesubscriptionkey->validuntil && $params['key'] === $sitesubscriptionkey->key; 736 // Delete existing, even if not validated to enforce security and attacks prevention. 737 unset_config('sitesubscriptionkey', 'tool_mobile'); 738 } 739 740 return [ 741 'validated' => $validated, 742 'warnings' => [], 743 ]; 744 } 745 746 /** 747 * Returns description of validate_subscription_key() result value. 748 * 749 * @return \core_external\external_description 750 * @since Moodle 3.9 751 */ 752 public static function validate_subscription_key_returns() { 753 return new external_single_structure( 754 [ 755 'validated' => new external_value(PARAM_BOOL, 'Whether the key is validated or not.'), 756 'warnings' => new external_warnings(), 757 ] 758 ); 759 } 760 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body