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