Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 * Tests for core_message_inbound to test Variable Envelope Return Path functionality. 19 * 20 * @package core_message 21 * @copyright 2014 Andrew Nicols <andrew@nicols.co.uk> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 require_once (__DIR__ . '/fixtures/inbound_fixtures.php'); 27 28 /** 29 * Tests for core_message_inbound to test Variable Envelope Return Path functionality. 30 * 31 * @copyright 2014 Andrew Nicols <andrew@nicols.co.uk> 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class core_message_inbound_testcase extends advanced_testcase { 35 36 /** 37 * Perform setup tasks generic to each test. 38 * This includes: 39 * * configuring the messageinbound_mailbox. 40 */ 41 public function setUp(): void { 42 global $CFG; 43 44 $this->resetAfterTest(true); 45 46 // Setup the default Inbound Message mailbox settings. 47 $CFG->messageinbound_domain = 'example.com'; 48 $CFG->messageinbound_enabled = true; 49 50 // Must be no longer than 15 characters. 51 $CFG->messageinbound_mailbox = 'moodlemoodle123'; 52 } 53 54 /** 55 * Helper to create a new Inbound Message handler. 56 * 57 * @param $handlerclass The class of the handler to create 58 * @param $enabled Whether the handler should be enabled 59 * @param $component The component 60 * @param $namepace The namepace 61 */ 62 public function helper_create_handler($handlerclass, $enabled = true, $component = 'core_test', $namespace = '\\core\\test\\') { 63 global $DB; 64 65 $classname = $namespace . $handlerclass; 66 $record = \core\message\inbound\manager::record_from_handler(new $classname()); 67 $record->component = $component; 68 $record->enabled = $enabled; 69 $record->id = $DB->insert_record('messageinbound_handlers', $record); 70 $handler = \core_message_inbound_test_manager::handler_from_record($record); 71 72 return $handler; 73 } 74 75 /** 76 * Test that the enabled check perform as expected. 77 */ 78 public function test_is_enabled() { 79 global $CFG; 80 81 // First clear all of the settings set in the setUp. 82 $CFG->messageinbound_domain = null; 83 $CFG->messageinbound_enabled = null; 84 $CFG->messageinbound_mailbox = null; 85 86 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 87 88 // Check whether only setting the enabled flag keeps it disabled. 89 $CFG->messageinbound_enabled = true; 90 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 91 92 // Check that the mailbox entry on it's own does not enable Inbound Message handling. 93 $CFG->messageinbound_mailbox = 'moodlemoodle123'; 94 $CFG->messageinbound_domain = null; 95 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 96 97 // And that the domain on it's own does not. 98 $CFG->messageinbound_domain = 'example.com'; 99 $CFG->messageinbound_mailbox = null; 100 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 101 102 // And that an invalid mailbox does not. 103 $CFG->messageinbound_mailbox = ''; 104 $CFG->messageinbound_domain = 'example.com'; 105 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 106 107 // And that an invalid domain does not. 108 $CFG->messageinbound_domain = ''; 109 $CFG->messageinbound_mailbox = 'moodlemoodle123'; 110 $this->assertFalse(\core\message\inbound\manager::is_enabled()); 111 112 // Finally a test that ensures that all settings correct enables the system. 113 $CFG->messageinbound_mailbox = 'moodlemoodle123'; 114 $CFG->messageinbound_domain = 'example.com'; 115 $CFG->messageinbound_enabled = true; 116 117 $this->assertTrue(\core\message\inbound\manager::is_enabled()); 118 } 119 120 /** 121 * Test that data items conform to RFCs 5231, and 5322 standards for 122 * addressing, and to RFC 5233 for sub-addressing. 123 */ 124 public function test_address_constraints() { 125 $handler = $this->helper_create_handler('handler_one'); 126 127 // Using the handler created, generate an address for our data entry. 128 $processor = new core_message_inbound_test_helper(); 129 $processor->set_handler($handler->classname); 130 131 // Generate some IDs for the data and generate addresses for them. 132 $dataids = array( 133 -1, 134 0, 135 42, 136 1073741823, 137 2147483647, 138 ); 139 140 $user = $this->getDataGenerator()->create_user(); 141 foreach ($dataids as $dataid) { 142 $processor->set_data($dataid); 143 $address = $processor->generate($user->id); 144 $this->assertNotNull($address); 145 $this->assertTrue(strlen($address) > 0, 'No address generated.'); 146 $this->assertTrue(strpos($address, '@') !== false, 'No domain found.'); 147 $this->assertTrue(strpos($address, '+') !== false, 'No subaddress found.'); 148 149 // The localpart must be less than 64 characters. 150 list($localpart) = explode('@', $address); 151 $this->assertTrue(strlen($localpart) <= 64, 'Localpart section of address too long'); 152 153 // And the data section should be no more than 48 characters. 154 list(, $datasection) = explode('+', $localpart); 155 $this->assertTrue(strlen($datasection) <= 48, 'Data section of address too long'); 156 } 157 } 158 159 /** 160 * Test that the generated e-mail addresses are sufficiently random by 161 * testing the multiple handlers, multiple users, and multiple data 162 * items. 163 */ 164 public function test_address_uniqueness() { 165 // Generate a set of handlers. These are in two components, and each 166 // component has two different generators. 167 $handlers = array(); 168 $handlers[] = $this->helper_create_handler('handler_one', true, 'core_test'); 169 $handlers[] = $this->helper_create_handler('handler_two', true, 'core_test'); 170 $handlers[] = $this->helper_create_handler('handler_three', true, 'core_test_example'); 171 $handlers[] = $this->helper_create_handler('handler_four', true, 'core_test_example'); 172 173 // Generate some IDs for the data and generate addresses for them. 174 $dataids = array( 175 0, 176 42, 177 1073741823, 178 2147483647, 179 ); 180 181 $users = array(); 182 for ($i = 0; $i < 5; $i++) { 183 $users[] = $this->getDataGenerator()->create_user(); 184 } 185 186 // Store the addresses for later comparison. 187 $addresses = array(); 188 189 foreach ($handlers as $handler) { 190 $processor = new core_message_inbound_test_helper(); 191 $processor->set_handler($handler->classname); 192 193 // Check each dataid. 194 foreach ($dataids as $dataid) { 195 $processor->set_data($dataid); 196 197 // Check each user. 198 foreach ($users as $user) { 199 $address = $processor->generate($user->id); 200 $this->assertFalse(isset($addresses[$address])); 201 $addresses[$address] = true; 202 } 203 } 204 } 205 } 206 207 /** 208 * Test address parsing of a generated address. 209 */ 210 public function test_address_parsing() { 211 $dataid = 42; 212 213 // Generate a handler to use for this set of tests. 214 $handler = $this->helper_create_handler('handler_one'); 215 216 // And a user. 217 $user = $this->getDataGenerator()->create_user(); 218 219 // Using the handler created, generate an address for our data entry. 220 $processor = new core_message_inbound_test_helper(); 221 $processor->set_handler($handler->classname); 222 $processor->set_data($dataid); 223 $address = $processor->generate($user->id); 224 225 // We should be able to parse the address. 226 $parser = new core_message_inbound_test_helper(); 227 $parser->process($address); 228 $parsedresult = $parser->get_data(); 229 $this->assertEquals($user->id, $parsedresult->userid); 230 $this->assertEquals($dataid, $parsedresult->datavalue); 231 $this->assertEquals($dataid, $parsedresult->data->datavalue); 232 $this->assertEquals($handler->id, $parsedresult->handlerid); 233 $this->assertEquals($handler->id, $parsedresult->data->handler); 234 } 235 236 /** 237 * Test address parsing of an address with an unrecognised format. 238 */ 239 public function test_address_validation_invalid_format_failure() { 240 // Create test data. 241 $user = $this->getDataGenerator()->create_user(); 242 $handler = $this->helper_create_handler('handler_one'); 243 $dataid = 42; 244 245 $parser = new core_message_inbound_test_helper(); 246 247 $generator = new core_message_inbound_test_helper(); 248 $generator->set_handler($handler->classname); 249 250 // Check that validation fails when no address has been processed. 251 $result = $parser->validate($user->email); 252 $this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result); 253 254 // Test that an address without data fails validation. 255 $parser->process('bob@example.com'); 256 $result = $parser->validate($user->email); 257 $this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result); 258 259 // Test than address with a subaddress but invalid data fails with VALIDATION_UNKNOWN_DATAKEY. 260 $parser->process('bob+nodata@example.com'); 261 $result = $parser->validate($user->email); 262 $this->assertEquals(\core\message\inbound\address_manager::VALIDATION_INVALID_ADDRESS_FORMAT, $result); 263 } 264 265 /** 266 * Test address parsing of an address with an unknown handler. 267 */ 268 public function test_address_validation_unknown_handler() { 269 global $DB; 270 271 // Create test data. 272 $user = $this->getDataGenerator()->create_user(); 273 $handler = $this->helper_create_handler('handler_one'); 274 $dataid = 42; 275 276 $parser = new core_message_inbound_test_helper(); 277 278 $generator = new core_message_inbound_test_helper(); 279 $generator->set_handler($handler->classname); 280 $generator->set_data($dataid); 281 $address = $generator->generate($user->id); 282 283 // Remove the handler record to invalidate it. 284 $DB->delete_records('messageinbound_handlers', array( 285 'id' => $handler->id, 286 )); 287 288 $parser->process($address); 289 $result = $parser->validate($user->email); 290 $expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_HANDLER; 291 $this->assertEquals($expectedfail, $result & $expectedfail); 292 } 293 294 /** 295 * Test address parsing of an address with a disabled handler. 296 */ 297 public function test_address_validation_disabled_handler() { 298 global $DB; 299 300 // Create test data. 301 $user = $this->getDataGenerator()->create_user(); 302 $handler = $this->helper_create_handler('handler_one'); 303 $dataid = 42; 304 305 $parser = new core_message_inbound_test_helper(); 306 307 $generator = new core_message_inbound_test_helper(); 308 $generator->set_handler($handler->classname); 309 $generator->set_data($dataid); 310 $address = $generator->generate($user->id); 311 312 // Disable the handler. 313 $record = \core\message\inbound\manager::record_from_handler($handler); 314 $record->enabled = false; 315 $DB->update_record('messageinbound_handlers', $record); 316 317 $parser->process($address); 318 $result = $parser->validate($user->email); 319 $expectedfail = \core\message\inbound\address_manager::VALIDATION_DISABLED_HANDLER; 320 $this->assertEquals($expectedfail, $result & $expectedfail); 321 } 322 323 /** 324 * Test address parsing of an address for an invalid user. 325 */ 326 public function test_address_validation_invalid_user() { 327 global $DB; 328 329 // Create test data. 330 $user = $this->getDataGenerator()->create_user(); 331 $handler = $this->helper_create_handler('handler_one'); 332 $dataid = 42; 333 334 $parser = new core_message_inbound_test_helper(); 335 336 $generator = new core_message_inbound_test_helper(); 337 $generator->set_handler($handler->classname); 338 $generator->set_data($dataid); 339 $address = $generator->generate(-1); 340 341 $parser->process($address); 342 $result = $parser->validate($user->email); 343 $expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_USER; 344 $this->assertEquals($expectedfail, $result & $expectedfail); 345 } 346 347 /** 348 * Test address parsing of an address for a disabled user. 349 */ 350 public function test_address_validation_disabled_user() { 351 global $DB; 352 353 // Create test data. 354 $user = $this->getDataGenerator()->create_user(); 355 $handler = $this->helper_create_handler('handler_one'); 356 $dataid = 42; 357 358 $parser = new core_message_inbound_test_helper(); 359 360 $generator = new core_message_inbound_test_helper(); 361 $generator->set_handler($handler->classname); 362 $generator->set_data($dataid); 363 $address = $generator->generate($user->id); 364 365 // Unconfirm the user. 366 $user->confirmed = 0; 367 $DB->update_record('user', $user); 368 369 $parser->process($address); 370 $result = $parser->validate($user->email); 371 $expectedfail = \core\message\inbound\address_manager::VALIDATION_DISABLED_USER; 372 $this->assertEquals($expectedfail, $result & $expectedfail); 373 } 374 375 /** 376 * Test address parsing of an address for an invalid key. 377 */ 378 public function test_address_validation_invalid_key() { 379 global $DB; 380 381 // Create test data. 382 $user = $this->getDataGenerator()->create_user(); 383 $handler = $this->helper_create_handler('handler_one'); 384 $dataid = 42; 385 386 $parser = new core_message_inbound_test_helper(); 387 388 $generator = new core_message_inbound_test_helper(); 389 $generator->set_handler($handler->classname); 390 $generator->set_data($dataid); 391 $address = $generator->generate($user->id); 392 393 // Remove the data record to invalidate it. 394 $DB->delete_records('messageinbound_datakeys', array( 395 'handler' => $handler->id, 396 'datavalue' => $dataid, 397 )); 398 399 $parser->process($address); 400 $result = $parser->validate($user->email); 401 $expectedfail = \core\message\inbound\address_manager::VALIDATION_UNKNOWN_DATAKEY; 402 $this->assertEquals($expectedfail, $result & $expectedfail); 403 } 404 405 /** 406 * Test address parsing of an address for an expired key. 407 */ 408 public function test_address_validation_expired_key() { 409 global $DB; 410 411 // Create test data. 412 $user = $this->getDataGenerator()->create_user(); 413 $handler = $this->helper_create_handler('handler_one'); 414 $dataid = 42; 415 416 $parser = new core_message_inbound_test_helper(); 417 418 $generator = new core_message_inbound_test_helper(); 419 $generator->set_handler($handler->classname); 420 $generator->set_data($dataid); 421 $address = $generator->generate($user->id); 422 423 // Expire the key by setting it's expiry time in the past. 424 $key = $DB->get_record('messageinbound_datakeys', array( 425 'handler' => $handler->id, 426 'datavalue' => $dataid, 427 )); 428 429 $key->expires = time() - 3600; 430 $DB->update_record('messageinbound_datakeys', $key); 431 432 $parser->process($address); 433 $result = $parser->validate($user->email); 434 $expectedfail = \core\message\inbound\address_manager::VALIDATION_EXPIRED_DATAKEY; 435 $this->assertEquals($expectedfail, $result & $expectedfail); 436 } 437 438 /** 439 * Test address parsing of an address for an invalid hash. 440 */ 441 public function test_address_validation_invalid_hash() { 442 global $DB; 443 444 // Create test data. 445 $user = $this->getDataGenerator()->create_user(); 446 $handler = $this->helper_create_handler('handler_one'); 447 $dataid = 42; 448 449 $parser = new core_message_inbound_test_helper(); 450 451 $generator = new core_message_inbound_test_helper(); 452 $generator->set_handler($handler->classname); 453 $generator->set_data($dataid); 454 $address = $generator->generate($user->id); 455 456 // Expire the key by setting it's expiry time in the past. 457 $key = $DB->get_record('messageinbound_datakeys', array( 458 'handler' => $handler->id, 459 'datavalue' => $dataid, 460 )); 461 462 $key->datakey = 'invalid value'; 463 $DB->update_record('messageinbound_datakeys', $key); 464 465 $parser->process($address); 466 $result = $parser->validate($user->email); 467 $expectedfail = \core\message\inbound\address_manager::VALIDATION_INVALID_HASH; 468 $this->assertEquals($expectedfail, $result & $expectedfail); 469 } 470 471 /** 472 * Test address parsing of an address for an invalid sender. 473 */ 474 public function test_address_validation_invalid_sender() { 475 global $DB; 476 477 // Create test data. 478 $user = $this->getDataGenerator()->create_user(); 479 $handler = $this->helper_create_handler('handler_one'); 480 $dataid = 42; 481 482 $parser = new core_message_inbound_test_helper(); 483 484 $generator = new core_message_inbound_test_helper(); 485 $generator->set_handler($handler->classname); 486 $generator->set_data($dataid); 487 $address = $generator->generate($user->id); 488 489 $parser->process($address); 490 $result = $parser->validate('incorrectuser@example.com'); 491 $expectedfail = \core\message\inbound\address_manager::VALIDATION_ADDRESS_MISMATCH; 492 $this->assertEquals($expectedfail, $result & $expectedfail); 493 } 494 495 /** 496 * Test address parsing of an address for an address which is correct. 497 */ 498 public function test_address_validation_success() { 499 global $DB; 500 501 // Create test data. 502 $user = $this->getDataGenerator()->create_user(); 503 $handler = $this->helper_create_handler('handler_one'); 504 $dataid = 42; 505 506 $parser = new core_message_inbound_test_helper(); 507 508 $generator = new core_message_inbound_test_helper(); 509 $generator->set_handler($handler->classname); 510 $generator->set_data($dataid); 511 $address = $generator->generate($user->id); 512 513 $parser->process($address); 514 $result = $parser->validate($user->email); 515 $this->assertEquals(\core\message\inbound\address_manager::VALIDATION_SUCCESS, $result); 516 517 } 518 519 /** 520 * Test that a handler with no default expiration does not have an 521 * expiration time applied. 522 */ 523 public function test_default_hander_expiry_unlimited() { 524 global $DB; 525 526 // Set the default expiry of the handler to 0 - no expiration. 527 $expiration = 0; 528 529 // Create test data. 530 $user = $this->getDataGenerator()->create_user(); 531 $handler = $this->helper_create_handler('handler_one'); 532 533 $record = \core\message\inbound\manager::record_from_handler($handler); 534 $record->defaultexpiration = $expiration; 535 $DB->update_record('messageinbound_handlers', $record); 536 537 // Generate an address for the handler. 538 $dataid = 42; 539 540 $generator = new core_message_inbound_test_helper(); 541 $generator->set_handler($handler->classname); 542 $generator->set_data($dataid); 543 $address = $generator->generate($user->id); 544 545 // Check that the datakey created matches the expirytime. 546 $key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid)); 547 548 $this->assertNull($key->expires); 549 } 550 551 /** 552 * Test application of the default expiry on a handler. 553 */ 554 public function test_default_hander_expiry_low() { 555 global $DB; 556 557 // Set the default expiry of the handler to 60 seconds. 558 $expiration = 60; 559 560 // Create test data. 561 $user = $this->getDataGenerator()->create_user(); 562 $handler = $this->helper_create_handler('handler_one'); 563 564 $record = \core\message\inbound\manager::record_from_handler($handler); 565 $record->defaultexpiration = $expiration; 566 $DB->update_record('messageinbound_handlers', $record); 567 568 // Generate an address for the handler. 569 $dataid = 42; 570 571 $generator = new core_message_inbound_test_helper(); 572 $generator->set_handler($handler->classname); 573 $generator->set_data($dataid); 574 $address = $generator->generate($user->id); 575 576 // Check that the datakey created matches the expirytime. 577 $key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid)); 578 579 $this->assertEquals($key->timecreated + $expiration, $key->expires); 580 } 581 582 /** 583 * Test application of the default expiry on a handler. 584 */ 585 public function test_default_hander_expiry_medium() { 586 global $DB; 587 588 // Set the default expiry of the handler to 3600 seconds. 589 $expiration = 3600; 590 591 // Create test data. 592 $user = $this->getDataGenerator()->create_user(); 593 $handler = $this->helper_create_handler('handler_one'); 594 595 $record = \core\message\inbound\manager::record_from_handler($handler); 596 $record->defaultexpiration = $expiration; 597 $DB->update_record('messageinbound_handlers', $record); 598 599 // Generate an address for the handler. 600 $dataid = 42; 601 602 $generator = new core_message_inbound_test_helper(); 603 $generator->set_handler($handler->classname); 604 $generator->set_data($dataid); 605 $address = $generator->generate($user->id); 606 607 // Check that the datakey created matches the expirytime. 608 $key = $DB->get_record('messageinbound_datakeys', array('handler' => $record->id, 'datavalue' => $dataid)); 609 610 $this->assertEquals($key->timecreated + $expiration, $key->expires); 611 } 612 613 } 614 615 /** 616 * A helper function for unit testing to expose protected functions in the core_message_inbound API for testing. 617 * 618 * @copyright 2014 Andrew Nicols <andrew@nicols.co.uk> 619 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 620 */ 621 class core_message_inbound_test_helper extends \core\message\inbound\address_manager { 622 /** 623 * The validate function. 624 * 625 * @param string $address 626 * @return int 627 */ 628 public function validate($address) { 629 return parent::validate($address); 630 } 631 632 /** 633 * The get_data function. 634 * 635 * @return stdClass 636 */ 637 public function get_data() { 638 return parent::get_data(); 639 } 640 641 /** 642 * The address processor function. 643 * 644 * @param string $address 645 * @return void 646 */ 647 public function process($address) { 648 return parent::process($address); 649 } 650 } 651 652 /** 653 * A helper function for unit testing to expose protected functions in the core_message_inbound API for testing. 654 * 655 * @copyright 2014 Andrew Nicols <andrew@nicols.co.uk> 656 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 657 */ 658 class core_message_inbound_test_manager extends \core\message\inbound\manager { 659 /** 660 * Helper to fetch make the handler_from_record public for unit testing. 661 * 662 * @param $record The handler record to fetch 663 */ 664 public static function handler_from_record($record) { 665 return parent::handler_from_record($record); 666 } 667 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body