Skip to content

Instantly share code, notes, and snippets.

@chmike
Last active August 20, 2024 02:29
Show Gist options
  • Save chmike/d4126a3247a6d9a70922fc0e8b4f4013 to your computer and use it in GitHub Desktop.
Save chmike/d4126a3247a6d9a70922fc0e8b4f4013 to your computer and use it in GitHub Desktop.
Check domain name validity in Go
// Please use the package https://github.com/chmike/domain as is it maintained up to date with tests.
// checkDomain returns an error if the domain name is not valid.
// See https://tools.ietf.org/html/rfc1034#section-3.5 and
// https://tools.ietf.org/html/rfc1123#section-2.
func checkDomain(name string) error {
switch {
case len(name) == 0:
return nil // an empty domain name will result in a cookie without a domain restriction
case len(name) > 255:
return fmt.Errorf("domain name length is %d, can't exceed 255", len(name))
}
var l int
for i := 0; i < len(name); i++ {
b := name[i]
if b == '.' {
// check domain labels validity
switch {
case i == l:
return fmt.Errorf("domain has invalid character '.' at offset %d, label can't begin with a period", i)
case i-l > 63:
return fmt.Errorf("domain byte length of label '%s' is %d, can't exceed 63", name[l:i], i-l)
case name[l] == '-':
return fmt.Errorf("domain label '%s' at offset %d begins with a hyphen", name[l:i], l)
case name[i-1] == '-':
return fmt.Errorf("domain label '%s' at offset %d ends with a hyphen", name[l:i], l)
}
l = i + 1
continue
}
// test label character validity, note: tests are ordered by decreasing validity frequency
if !(b >= 'a' && b <= 'z' || b >= '0' && b <= '9' || b == '-' || b >= 'A' && b <= 'Z') {
// show the printable unicode character starting at byte offset i
c, _ := utf8.DecodeRuneInString(name[i:])
if c == utf8.RuneError {
return fmt.Errorf("domain has invalid rune at offset %d", i)
}
return fmt.Errorf("domain has invalid character '%c' at offset %d", c, i)
}
}
// check top level domain validity
switch {
case l == len(name):
return fmt.Errorf("domain has missing top level domain, domain can't end with a period")
case len(name)-l > 63:
return fmt.Errorf("domain's top level domain '%s' has byte length %d, can't exceed 63", name[l:], len(name)-l)
case name[l] == '-':
return fmt.Errorf("domain's top level domain '%s' at offset %d begin with a hyphen", name[l:], l)
case name[len(name)-1] == '-':
return fmt.Errorf("domain's top level domain '%s' at offset %d ends with a hyphen", name[l:], l)
case name[l] >= '0' && name[l] <= '9':
return fmt.Errorf("domain's top level domain '%s' at offset %d begins with a digit", name[l:], l)
}
return nil
}
@seantcanavan
Copy link

seantcanavan commented Dec 1, 2023

@chmike this is super useful thank you! but your gist has no licensing information attached which means by default others cannot reproduce, distribute, or create derivative works from this code.

additionally, only needing this function, your securecookie repo has the MIT license so the function cannot be used there either without explicitly attaching the MIT license. can you please update this gist with a license section, perhaps the unlicense? (this code has already been scraped by chatGPT anyways I'm sure since the gist is public...)

@chmike
Copy link
Author

chmike commented Dec 1, 2023

Thank you very much.

As I explained a few comments above, there is a dedicated git module/package for this function which is available here: https://github.com/chmike/domain

It has a BSD license which is better than MIT, I assume. This should answer your request.

You can add dependency to the package to detect updates or copy the function if you want. I don't mind.

@seantcanavan
Copy link

oh I missed that - apologies. thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment