mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
os/hostname: switch to std.Io.net.HostName.validate
Zig 0.16's hostname validation routine is RFC 1123-compliant, so we can
use it directly rather than rolling our own.
Ref: efe649b13e
Ref: https://github.com/ziglang/zig/pull/25710
This commit is contained in:
@@ -411,9 +411,9 @@ pub fn isValidCacheKey(key: []const u8) bool {
|
||||
fn isValidHost(host: []const u8) bool {
|
||||
// First check for valid hostnames because this is assumed to be the more
|
||||
// likely ssh host format.
|
||||
if (internal_os.hostname.isValid(host)) {
|
||||
if (std.Io.net.HostName.validate(host)) |_| {
|
||||
return true;
|
||||
}
|
||||
} else |_| {}
|
||||
|
||||
// We also accept valid IP addresses. In practice, IPv4 addresses are also
|
||||
// considered valid hostnames due to their overlapping syntax, so we can
|
||||
|
||||
@@ -7,91 +7,6 @@ pub const LocalHostnameValidationError = error{
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
/// Validates a hostname according to [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123)
|
||||
///
|
||||
/// std.net.isValidHostname is (currently) too generous. It considers strings like
|
||||
/// ".example.com", "exa..mple.com", and "-example.com" to be valid hostnames, which
|
||||
/// is incorrect.
|
||||
pub fn isValid(hostname: []const u8) bool {
|
||||
if (hostname.len == 0) return false;
|
||||
if (hostname[0] == '.') return false;
|
||||
|
||||
// Ignore trailing dot (FQDN). It doesn't count toward our length.
|
||||
const end = if (hostname[hostname.len - 1] == '.') end: {
|
||||
if (hostname.len == 1) return false;
|
||||
break :end hostname.len - 1;
|
||||
} else hostname.len;
|
||||
|
||||
if (end > 253) return false;
|
||||
|
||||
// Hostnames are divided into dot-separated "labels", which:
|
||||
//
|
||||
// - Start with a letter or digit
|
||||
// - Can contain letters, digits, or hyphens
|
||||
// - Must end with a letter or digit
|
||||
// - Have a minimum of 1 character and a maximum of 63
|
||||
var label_start: usize = 0;
|
||||
var label_len: usize = 0;
|
||||
for (hostname[0..end], 0..) |c, i| {
|
||||
switch (c) {
|
||||
'.' => {
|
||||
if (label_len == 0 or label_len > 63) return false;
|
||||
if (!std.ascii.isAlphanumeric(hostname[label_start])) return false;
|
||||
if (!std.ascii.isAlphanumeric(hostname[i - 1])) return false;
|
||||
|
||||
label_start = i + 1;
|
||||
label_len = 0;
|
||||
},
|
||||
'-' => {
|
||||
label_len += 1;
|
||||
},
|
||||
else => {
|
||||
if (!std.ascii.isAlphanumeric(c)) return false;
|
||||
label_len += 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the final label
|
||||
if (label_len == 0 or label_len > 63) return false;
|
||||
if (!std.ascii.isAlphanumeric(hostname[label_start])) return false;
|
||||
if (!std.ascii.isAlphanumeric(hostname[end - 1])) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
test isValid {
|
||||
const testing = std.testing;
|
||||
|
||||
// Valid hostnames
|
||||
try testing.expect(isValid("example"));
|
||||
try testing.expect(isValid("example.com"));
|
||||
try testing.expect(isValid("www.example.com"));
|
||||
try testing.expect(isValid("sub.domain.example.com"));
|
||||
try testing.expect(isValid("example.com."));
|
||||
try testing.expect(isValid("host-name.example.com."));
|
||||
try testing.expect(isValid("123.example.com."));
|
||||
try testing.expect(isValid("a-b.com"));
|
||||
try testing.expect(isValid("a.b.c.d.e.f.g"));
|
||||
try testing.expect(isValid("127.0.0.1")); // Also a valid hostname
|
||||
try testing.expect(isValid("a" ** 63 ++ ".com")); // Label exactly 63 chars (valid)
|
||||
try testing.expect(isValid("a." ** 126 ++ "a")); // Total length 253 (valid)
|
||||
|
||||
// Invalid hostnames
|
||||
try testing.expect(!isValid(""));
|
||||
try testing.expect(!isValid(".example.com"));
|
||||
try testing.expect(!isValid("example.com.."));
|
||||
try testing.expect(!isValid("host..domain"));
|
||||
try testing.expect(!isValid("-hostname"));
|
||||
try testing.expect(!isValid("hostname-"));
|
||||
try testing.expect(!isValid("a.-.b"));
|
||||
try testing.expect(!isValid("host_name.com"));
|
||||
try testing.expect(!isValid("."));
|
||||
try testing.expect(!isValid(".."));
|
||||
try testing.expect(!isValid("a" ** 64 ++ ".com")); // Label length 64 (too long)
|
||||
try testing.expect(!isValid("a." ** 126 ++ "ab")); // Total length 254 (too long)
|
||||
}
|
||||
|
||||
/// Checks if a hostname is local to the current machine. This matches
|
||||
/// both "localhost" and the current hostname of the machine (as returned
|
||||
/// by `gethostname`).
|
||||
|
||||
Reference in New Issue
Block a user