Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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   * Contains the test class testing the \core\ip_utils static helper class functions.
  19   *
  20   * @package    core
  21   * @copyright  2016 Jake Dallimore <jrhdallimore@gmail.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * This tests the static helper functions contained in the class '\core\ip_utils'.
  29   *
  30   * @package    core
  31   * @copyright  2016 Jake Dallimore <jrhdallimore@gmail.com>
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class core_ip_utils_testcase extends basic_testcase {
  35      /**
  36       * Test for \core\ip_utils::is_domain_name().
  37       *
  38       * @param string $domainname the domain name to validate.
  39       * @param bool $expected the expected result.
  40       * @dataProvider domain_name_data_provider
  41       */
  42      public function test_is_domain_name($domainname, $expected) {
  43          $this->assertEquals($expected, \core\ip_utils::is_domain_name($domainname));
  44      }
  45  
  46      /**
  47       * Data provider for test_is_domain_name().
  48       *
  49       * @return array
  50       */
  51      public function domain_name_data_provider() {
  52          return [
  53              ["com", true],
  54              ["i.net", true], // Single char, alpha tertiary domain.
  55              ["0.org", true], // Single char, non-alpha tertiary domain.
  56              ["0.a", true], // Single char, alpha top level domain.
  57              ["0.1", false], // Single char, non-alpha top level domain.
  58              ["example.com", true],
  59              ["sub.example.com", true],
  60              ["sub-domain.example-domain.net", true],
  61              ["123.com", true],
  62              ["123.a11", true],
  63              [str_repeat('sub.', 60) . "1-example.com", true], // Max length without null label is 253 octets = 253 ascii chars.
  64              [str_repeat('example', 9) . ".com", true], // Max number of octets per label is 63  = 63 ascii chars.
  65              ["localhost", true],
  66              [" example.com", false],
  67              ["example.com ", false],
  68              ["example.com/", false],
  69              ["*.example.com", false],
  70              ["*example.com", false],
  71              ["example.123", false],
  72              ["-example.com", false],
  73              ["example-.com", false],
  74              [".example.com", false],
  75              ["127.0.0.1", false],
  76              [str_repeat('sub.', 60) . "11-example.com", false], // Name length is 254 chars, which exceeds the max allowed.
  77              [str_repeat('example', 9) . "1.com", false], // Label length is 64 chars, which exceed the max allowed.
  78              ["example.com.", true], // Null label explicitly provided - this is valid.
  79              [".example.com.", false],
  80              ["見.香港", false], // IDNs are invalid.
  81              [null, false], // Non-strings are invalid.
  82          ];
  83      }
  84  
  85      /**
  86       * Test for \core\ip_utils::is_domain_matching_pattern().
  87       *
  88       * @param string $str the string to evaluate.
  89       * @param bool $expected the expected result.
  90       * @dataProvider domain_matching_patterns_data_provider
  91       */
  92      public function test_is_domain_matching_pattern($str, $expected) {
  93          $this->assertEquals($expected, \core\ip_utils::is_domain_matching_pattern($str));
  94      }
  95  
  96      /**
  97       * Data provider for test_is_domain_matching_pattern().
  98       *
  99       * @return array
 100       */
 101      public function domain_matching_patterns_data_provider() {
 102          return [
 103              ["*.com", true],
 104              ["*.example.com", true],
 105              ["*.example.com", true],
 106              ["*.sub.example.com", true],
 107              ["*.sub-domain.example-domain.com", true],
 108              ["*." . str_repeat('sub.', 60) . "example.com", true], // Max number of domain name chars = 253.
 109              ["*." . str_repeat('example', 9) . ".com", true], // Max number of domain name label chars = 63.
 110              ["*com", false],
 111              ["*example.com", false],
 112              [" *.example.com", false],
 113              ["*.example.com ", false],
 114              ["*-example.com", false],
 115              ["*.-example.com", false],
 116              ["*.example.com/", false],
 117              ["sub.*.example.com", false],
 118              ["sub.*example.com", false],
 119              ["*.*.example.com", false],
 120              ["example.com", false],
 121              ["*." . str_repeat('sub.', 60) . "1example.com", false], // Name length is 254 chars, which exceeds the max allowed.
 122              ["*." . str_repeat('example', 9) . "1.com", false], // Label length is 64 chars, which exceed the max allowed.
 123              ["*.example.com.", true], // Null label explicitly provided - this is valid.
 124              [".*.example.com.", false],
 125              ["*.香港", false], // IDNs are invalid.
 126              [null, false], // None-strings are invalid.
 127          ];
 128      }
 129  
 130      /**
 131       * Test for \core\ip_utils::is_ip_address().
 132       *
 133       * @param string $address the address to validate.
 134       * @param bool $expected the expected result.
 135       * @dataProvider ip_address_data_provider
 136       */
 137      public function test_is_ip_address($address, $expected) {
 138          $this->assertEquals($expected, \core\ip_utils::is_ip_address($address));
 139      }
 140  
 141      /**
 142       * Data provider for test_is_ip_address().
 143       *
 144       * @return array
 145       */
 146      public function ip_address_data_provider() {
 147          return [
 148              ["127.0.0.1", true],
 149              ["10.1", false],
 150              ["0.0.0.0", true],
 151              ["255.255.255.255", true],
 152              ["256.0.0.1", false],
 153              ["256.0.0.1", false],
 154              ["127.0.0.0/24", false],
 155              ["127.0.0.0-255", false],
 156              ["::", true],
 157              ["::0", true],
 158              ["0::", true],
 159              ["0::0", true],
 160              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80", true],
 161              ["fe80::ffff", true],
 162              ["fe80::f", true],
 163              ["fe80::", true],
 164              ["0", false],
 165              ["127.0.0.0/24", false],
 166              ["fe80::fe80/128", false],
 167              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80/128", false],
 168              ["fe80:", false],
 169              ["fe80:: ", false],
 170              [" fe80::", false],
 171              ["fe80::ddddd", false],
 172              ["fe80::gggg", false],
 173              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80", false],
 174          ];
 175      }
 176  
 177      /**
 178       * Test for \core\ip_utils::is_ipv4_address().
 179       *
 180       * @param string $address the address to validate.
 181       * @param bool $expected the expected result.
 182       * @dataProvider ipv4_address_data_provider
 183       */
 184      public function test_is_ipv4_address($address, $expected) {
 185          $this->assertEquals($expected, \core\ip_utils::is_ipv4_address($address));
 186      }
 187  
 188      /**
 189       * Data provider for test_is_ipv4_address().
 190       *
 191       * @return array
 192       */
 193      public function ipv4_address_data_provider() {
 194          return [
 195              ["127.0.0.1", true],
 196              ["0.0.0.0", true],
 197              ["255.255.255.255", true],
 198              [" 127.0.0.1", false],
 199              ["127.0.0.1 ", false],
 200              ["-127.0.0.1", false],
 201              ["127.0.1", false],
 202              ["127.0.0.0.1", false],
 203              ["a.b.c.d", false],
 204              ["localhost", false],
 205              ["fe80::1", false],
 206              ["256.0.0.1", false],
 207              ["256.0.0.1", false],
 208              ["127.0.0.0/24", false],
 209              ["127.0.0.0-255", false],
 210          ];
 211      }
 212  
 213      /**
 214       * Test for \core\ip_utils::is_ipv4_range().
 215       *
 216       * @param string $addressrange the address range to validate.
 217       * @param bool $expected the expected result.
 218       * @dataProvider ipv4_range_data_provider
 219       */
 220      public function test_is_ipv4_range($addressrange, $expected) {
 221          $this->assertEquals($expected, \core\ip_utils::is_ipv4_range($addressrange));
 222      }
 223  
 224      /**
 225       * Data provider for test_is_ipv4_range().
 226       *
 227       * @return array
 228       */
 229      public function ipv4_range_data_provider() {
 230          return [
 231              ["127.0.0.1/24", true],
 232              ["127.0.0.20-20", true],
 233              ["127.0.0.20-50", true],
 234              ["127.0.0.0-255", true],
 235              ["127.0.0.1-1", true],
 236              ["255.255.255.0-255", true],
 237              ["127.0.0.1", false],
 238              ["127.0", false],
 239              [" 127.0.0.0/24", false],
 240              ["127.0.0.0/24 ", false],
 241              ["a.b.c.d/24", false],
 242              ["256.0.0.0-80", false],
 243              ["127.0.0.0/a", false],
 244              ["256.0.0.0/24", false],
 245              ["127.0.0.0/-1", false],
 246              ["127.0.0.0/33", false],
 247              ["127.0.0.0-127.0.0.10", false],
 248              ["127.0.0.30-20", false],
 249              ["127.0.0.0-256", false],
 250              ["fe80::fe80/64", false],
 251          ];
 252      }
 253  
 254      /**
 255       * Test for \core\ip_utils::is_ipv6_address().
 256       *
 257       * @param string $address the address to validate.
 258       * @param bool $expected the expected result.
 259       * @dataProvider ipv6_address_data_provider
 260       */
 261      public function test_is_ipv6_address($address, $expected) {
 262          $this->assertEquals($expected, \core\ip_utils::is_ipv6_address($address));
 263      }
 264  
 265      /**
 266       * Data provider for test_is_ipv6_address().
 267       *
 268       * @return array
 269       */
 270      public function ipv6_address_data_provider() {
 271          return [
 272              ["::", true],
 273              ["::0", true],
 274              ["0::", true],
 275              ["0::0", true],
 276              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80", true],
 277              ["fe80::ffff", true],
 278              ["fe80::f", true],
 279              ["fe80::", true],
 280              ["0", false],
 281              ["127.0.0.0", false],
 282              ["127.0.0.0/24", false],
 283              ["fe80::fe80/128", false],
 284              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80/128", false],
 285              ["fe80:", false],
 286              ["fe80:: ", false],
 287              [" fe80::", false],
 288              ["fe80::ddddd", false],
 289              ["fe80::gggg", false],
 290              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80", false],
 291          ];
 292      }
 293  
 294      /**
 295       * Test for \core\ip_utils::is_ipv6_range().
 296       *
 297       * @param string $addressrange the address range to validate.
 298       * @param bool $expected the expected result.
 299       * @dataProvider ipv6_range_data_provider
 300       */
 301      public function test_is_ipv6_range($addressrange, $expected) {
 302          $this->assertEquals($expected, \core\ip_utils::is_ipv6_range($addressrange));
 303      }
 304  
 305      /**
 306       * Data provider for test_is_ipv6_range().
 307       *
 308       * @return array
 309       */
 310      public function ipv6_range_data_provider() {
 311          return [
 312              ["::/128", true],
 313              ["::1/128", true],
 314              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80/128", true],
 315              ["fe80::dddd/128", true],
 316              ["fe80::/64", true],
 317              ["fe80::dddd-ffff", true],
 318              ["::0-ffff", true],
 319              ["::a-ffff", true],
 320              ["0", false],
 321              ["::1", false],
 322              ["fe80::fe80", false],
 323              ["::/128 ", false],
 324              [" ::/128", false],
 325              ["::/a", false],
 326              ["::/-1", false],
 327              ["fe80::fe80/129", false],
 328              ["fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80", false],
 329              ["fe80::bbbb-aaaa", false],
 330              ["fe80::0-fffg", false],
 331              ["fe80::0-fffff", false],
 332              ["fe80::0 - ffff", false],
 333              [" fe80::0-ffff", false],
 334              ["fe80::0-ffff ", false],
 335              ["192.0.0.0/24", false],
 336              ["fe80:::fe80/128", false],
 337              ["fe80:::aaaa-dddd", false],
 338          ];
 339      }
 340  
 341      /**
 342       * Test checking domains against a list of allowed domains.
 343       *
 344       * @param  bool $expected Expected result
 345       * @param  string $domain domain address
 346       * @dataProvider data_domain_addresses
 347       */
 348      public function test_check_domain_against_allowed_domains($expected, $domain) {
 349          $alloweddomains = ['example.com',
 350                             '*.moodle.com',
 351                             '*.per.this.penny-arcade.com',
 352                             'bad.*.url.com',
 353                             ' trouble.com.au'];
 354          $this->assertEquals($expected, \core\ip_utils::is_domain_in_allowed_list($domain, $alloweddomains));
 355      }
 356  
 357      /**
 358       * Data provider for test_check_domain_against_allowed_domains.
 359       *
 360       * @return array
 361       */
 362      public function data_domain_addresses() {
 363          return [
 364              [true, 'example.com'],
 365              [false, 'sub.example.com'],
 366              [false, 'example.com.au'],
 367              [false, ' example.com'], // A space at the front of the domain is invalid.
 368              [false, 'example.123'], // Numbers at the end is invalid.
 369              [false, 'test.example.com'],
 370              [false, 'moodle.com'],
 371              [true, 'test.moodle.com'],
 372              [false, 'test.moodle.com.au'],
 373              [true, 'nice.address.per.this.penny-arcade.com'],
 374              [false, 'normal.per.this.penny-arcade.com.au'],
 375              [false, 'bad.thing.url.com'], // The allowed domain (above) has a bad wildcard and so this address will return false.
 376              [false, 'trouble.com.au'] // The allowed domain (above) has a space at the front and so will return false.
 377          ];
 378      }
 379  
 380      /**
 381       * Data provider for test_is_ip_in_subnet_list.
 382       *
 383       * @return array
 384       */
 385      public function data_is_ip_in_subnet_list() {
 386          return [
 387              [true, '1.1.1.1', '1.1.1.1', "\n"],
 388              [false, '1.1.1.1', '2.2.2.2', "\n"],
 389              [true, '1.1.1.1', "1.1.1.5\n1.1.1.1", "\n"],
 390              [true, '1.1.1.1', "1.1.1.5,1.1.1.1", ","],
 391          ];
 392      }
 393  
 394      /**
 395       * Test checking ips against a list of allowed domains.
 396       *
 397       * @param  bool $expected Expected result
 398       * @param  string $ip IP address
 399       * @param  string $list list of  IP subnets
 400       * @param  string $delim delimiter of list
 401       * @dataProvider data_is_ip_in_subnet_list
 402       */
 403      public function test_is_ip_in_subnet_list($expected, $ip, $list, $delim) {
 404          $this->assertEquals($expected, \core\ip_utils::is_ip_in_subnet_list($ip, $list, $delim));
 405      }
 406  
 407  }