diff --git a/src/HostnameValidator.vala b/src/HostnameValidator.vala index 27e7e9fb5..069722c78 100644 --- a/src/HostnameValidator.vala +++ b/src/HostnameValidator.vala @@ -4,40 +4,50 @@ * SPDX-License-Identifier: MIT */ -namespace Utils { - private bool hostname_is_valid_char (char c) { - return (c.isalnum () || - c == '-' || - c == '.'); - } +/** + * Validate a hostname according to [IETF RFC 1123](https://tools.ietf.org/html/rfc1123) + * + * Based on https://github.com/pop-os/hostname-validator/blob/458fa5a1df98cb663f0456dffb542e1a907861c9/src/lib.rs#L29 + */ - // Based on https://github.com/pop-os/hostname-validator/blob/458fa5a1df98cb663f0456dffb542e1a907861c9/src/lib.rs#L29 - /// Validate a hostname according to [IETF RFC 1123](https://tools.ietf.org/html/rfc1123). - /// - /// A hostname is valid if the following condition are true: - /// - /// - It does not start or end with `-` or `.`. - /// - It does not contain any characters outside of the alphanumeric range, except for `-` and `.`. - /// - It is not empty. - /// - It is 253 or fewer characters. - /// - Its labels (characters separated by `.`) are not empty. - /// - Its labels are 63 or fewer characters. - /// - Its labels do not start or end with '-' or '.'. +namespace Utils { public bool hostname_is_valid (string hostname) { + // It is not empty + if (hostname.char_count () == 0) { + return false; + } + + // It is 253 or fewer characters + if (hostname.length > 253) { + return false; + } + + // It does not contain any characters outside of the alphanumeric range, except for `-` and `.` for (int i = 0; i < hostname.char_count (); i++) { char c = hostname[i]; - if (!hostname_is_valid_char (c)) { + if (!(c.isalnum () || c == '-' || c == '.')) { return false; } } string[] labels = hostname.split (".", -1); foreach (string label in labels) { - if (label.char_count () == 0 || label.length > 63 || label[0] == '-' || label[label.length - 1] == '-') { + // Its labels (characters separated by `.`) are not empty. + if (label.char_count () == 0) { + return false; + } + + // Its labels do not start or end with '-' or '.' + if (label.has_prefix ("-") || label.has_suffix ("-") || label.has_prefix (".") || label.has_suffix (".")) { + return false; + } + + // Its labels are 63 or fewer characters. + if (label.length > 63) { return false; } } - return !(hostname.char_count () == 0 || hostname.length > 253); + return true; } } diff --git a/test/HostnameValidatorTest.vala b/test/HostnameValidatorTest.vala index 7399c553e..a1803cf13 100644 --- a/test/HostnameValidatorTest.vala +++ b/test/HostnameValidatorTest.vala @@ -1,4 +1,12 @@ -void add_hostname_validator_tests () { +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) + */ + +// Validate a hostname according to [IETF RFC 1123](https://tools.ietf.org/html/rfc1123) +private void main (string[] args) { + Test.init (ref args); + Test.add_func ("/valid", () => { assert (Utils.hostname_is_valid ("VaLiD-HoStNaMe")); assert (Utils.hostname_is_valid ("50-name")); @@ -9,16 +17,33 @@ void add_hostname_validator_tests () { }); Test.add_func ("/invalid", () => { - assert (!Utils.hostname_is_valid ("-invalid-name")); - assert (!Utils.hostname_is_valid ("also-invalid-")); + // It is not empty + assert (!Utils.hostname_is_valid ("")); + + // It is 253 or fewer characters + assert (!Utils.hostname_is_valid ("foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo")); + + // It does not contain any characters outside of the alphanumeric range, except for `-` and `.` assert (!Utils.hostname_is_valid ("asdf@fasd")); assert (!Utils.hostname_is_valid ("@asdfl")); assert (!Utils.hostname_is_valid ("asd f@")); + + // It does not start or end with `-` or `.` + assert (!Utils.hostname_is_valid ("-invalid-name")); + assert (!Utils.hostname_is_valid ("also-invalid-")); assert (!Utils.hostname_is_valid (".invalid")); assert (!Utils.hostname_is_valid ("invalid.name.")); - assert (!Utils.hostname_is_valid ("foo.label-is-way-to-longgggggggggggggggggggggggggggggggggggggggggggg.org")); + + // Its labels (characters separated by `.`) are not empty. + assert (!Utils.hostname_is_valid ("empty..label")); + + // Its labels do not start or end with '-' or '.' assert (!Utils.hostname_is_valid ("invalid.-starting.char")); assert (!Utils.hostname_is_valid ("invalid.ending-.char")); - assert (!Utils.hostname_is_valid ("empty..label")); + + // Its labels are 63 or fewer characters. + assert (!Utils.hostname_is_valid ("foo.label-is-way-to-longgggggggggggggggggggggggggggggggggggggggggggg.org")); }); + + Test.run (); } diff --git a/test/Test.vala b/test/Test.vala deleted file mode 100644 index de40a0434..000000000 --- a/test/Test.vala +++ /dev/null @@ -1,5 +0,0 @@ -void main (string[] args) { - Test.init (ref args); - add_hostname_validator_tests (); - Test.run (); -} diff --git a/test/meson.build b/test/meson.build index 1ef64043d..389e4cc59 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,13 +1,9 @@ -test_dependencies = [ - glib_dep, -] - -tests = executable( - meson.project_name() + '-tests', +hostname_validator_test = executable( + 'HostnameValidatorTest', 'HostnameValidatorTest.vala', - 'Test.vala', - meson.project_source_root() + '/src/HostnameValidator.vala', - dependencies: test_dependencies + meson.project_source_root() / 'src' / 'HostnameValidator.vala', + dependencies: glib_dep, + install: false ) -test('Test', tests) +test('HostnameValidator Test', hostname_validator_test)