diff --git a/lib/adminlib.php b/lib/adminlib.php index 0f86306e1b4..54ea2fd7103 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -3645,16 +3645,11 @@ class admin_setting_configmixedhostiplist extends admin_setting_configtextarea { $entries = explode("\n", $data); foreach ($entries as $key => $entry) { $entry = trim($entry); - // This regex matches any string which: - // a) contains at least one non-ascii unicode character AND - // b) starts with a-zA-Z0-9 or any non-ascii unicode character AND - // c) ends with a-zA-Z0-9 or any non-ascii unicode character - // d) contains a-zA-Z0-9, hyphen, dot or any non-ascii unicode characters in the middle. - if (preg_match('/^(?=[^\x00-\x7f])([^\x00-\x7f]|[a-zA-Z0-9])([^\x00-\x7f]|[a-zA-Z0-9-.])*([^\x00-\x7f]|[a-zA-Z0-9])$/', - $entry)) { + // This regex matches any string that has non-ascii character. + if (preg_match('/[^\x00-\x7f]/', $entry)) { // If we can convert the unicode string to an idn, do so. // Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail). - $val = idn_to_ascii($entry); + $val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); $entries[$key] = $val ? $val : $entry; } } @@ -3672,7 +3667,7 @@ class admin_setting_configmixedhostiplist extends admin_setting_configtextarea { foreach ($entries as $key => $entry) { $entry = trim($entry); if (strpos($entry, 'xn--') !== false) { - $entries[$key] = idn_to_utf8($entry); + $entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); } } return implode("\n", $entries); diff --git a/lib/tests/admintree_test.php b/lib/tests/admintree_test.php index f6d581d6afa..dd6b93ef0c6 100644 --- a/lib/tests/admintree_test.php +++ b/lib/tests/admintree_test.php @@ -323,4 +323,58 @@ class core_admintree_testcase extends advanced_testcase { $setting->write_setting('/mm/nn'); $this->assertSame('', get_config('abc_cde', 'execpath')); } + + /** + * Test setting for blocked hosts + * + * For testing the admin settings element only. Test for blocked hosts functionality can be found + * in lib/tests/curl_security_helper_test.php + */ + public function test_mixedhostiplist() { + $this->resetAfterTest(); + + $adminsetting = new admin_setting_configmixedhostiplist('abc_cde/hostiplist', 'some desc', '', ''); + + // Test valid settings. + $validsimplesettings = [ + 'localhost', + "localhost\n127.0.0.1", + '192.168.10.1', + '0:0:0:0:0:0:0:1', + '::1', + 'fe80::', + '231.54.211.0/20', + 'fe80::/64', + '231.3.56.10-20', + 'fe80::1111-bbbb', + '*.example.com', + '*.sub.example.com', + ]; + + foreach ($validsimplesettings as $setting) { + $errormessage = $adminsetting->write_setting($setting); + $this->assertEmpty($errormessage, $errormessage); + $this->assertSame($setting, get_config('abc_cde', 'hostiplist')); + $this->assertSame($setting, $adminsetting->get_setting()); + } + + // Test valid international site names. + $valididnsettings = [ + 'правительство.рф' => 'xn--80aealotwbjpid2k.xn--p1ai', + 'faß.de' => 'xn--fa-hia.de', + 'ß.ß' => 'xn--zca.xn--zca', + '*.tharkûn.com' => '*.xn--tharkn-0ya.com', + ]; + + foreach ($valididnsettings as $setting => $encodedsetting) { + $errormessage = $adminsetting->write_setting($setting); + $this->assertEmpty($errormessage, $errormessage); + $this->assertSame($encodedsetting, get_config('abc_cde', 'hostiplist')); + $this->assertSame($setting, $adminsetting->get_setting()); + } + + // Invalid settings. + $this->assertEquals('These entries are invalid: nonvalid site name', $adminsetting->write_setting('nonvalid site name')); + $this->assertEquals('Empty lines are not valid', $adminsetting->write_setting("localhost\n")); + } }