-
Notifications
You must be signed in to change notification settings - Fork 1
Tighten hostname validation in HostInfo constructor #470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,27 +149,73 @@ export class HostUtil { | |
| static parseHostnameElseNull(name, allowWildcard = false) { | ||
| MustBe.string(name); | ||
|
|
||
| const result = this.#pathArrayFromHostnameElseNull(name, allowWildcard); | ||
|
|
||
| if (!result) { | ||
| return null; | ||
| } | ||
|
|
||
| return new PathKey(result.pathArray, result.wildcard); | ||
| } | ||
|
|
||
| /** | ||
| * Validates that the given value is a valid hostname string, returning it | ||
| * (canonicalized) if so. This accepts both DNS names and IP addresses | ||
| * (including bracketed IPv6), but not wildcards. | ||
| * | ||
| * @param {*} value Value to check. | ||
| * @returns {string} `value` canonicalized if it is a valid hostname. | ||
| * @throws {Error} Thrown if `value` is not a valid hostname string. | ||
| */ | ||
| static mustBeHostname(value) { | ||
| if (typeof value !== 'string') { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More apologies (same reason as stated in |
||
| throw new Error(`Expected hostname string, got: ${typeof value}`); | ||
| } | ||
|
|
||
| const result = this.canonicalizeHostnameElseNull(value, false); | ||
|
|
||
| if (result === null) { | ||
| throw new Error(`Invalid hostname: ${value}`); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * Private helper that validates a hostname and returns its path array | ||
| * representation, or `null` if invalid. | ||
| * | ||
| * @param {*} name Hostname to parse. | ||
| * @param {boolean} allowWildcard Is a wildcard form allowed? | ||
| * @returns {?{pathArray: string[], wildcard: boolean}} The path array and | ||
| * wildcard flag, or `null` if invalid. | ||
| */ | ||
| static #pathArrayFromHostnameElseNull(name, allowWildcard) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This no longer needs to be extracted. |
||
| if (typeof name !== 'string') { | ||
| return null; | ||
| } | ||
|
|
||
| // Handle IP address cases. | ||
| const canonicalIp = EndpointAddress.canonicalizeAddressElseNull(name, false); | ||
| if (canonicalIp) { | ||
| return new PathKey([canonicalIp], false); | ||
| return { pathArray: [canonicalIp], wildcard: false }; | ||
| } | ||
|
|
||
| if (!AskIf.string(name, this.#HOSTNAME_REGEX)) { | ||
| return null; | ||
| } | ||
|
|
||
| const path = name.toLowerCase().split('.').reverse(); | ||
| const pathArray = name.toLowerCase().split('.').reverse(); | ||
|
|
||
| if (path[path.length - 1] === '*') { | ||
| if (pathArray[pathArray.length - 1] === '*') { | ||
| if (allowWildcard) { | ||
| path.pop(); | ||
| return new PathKey(path, true); | ||
| pathArray.pop(); | ||
| return { pathArray, wildcard: true }; | ||
| } else { | ||
| return null; | ||
| } | ||
| } else { | ||
| return new PathKey(path, false); | ||
| return { pathArray, wildcard: false }; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, super-duper sorry about this (I am still paging this code back into my head):
The word "maybe" in the
TODOcomment is pretty load-bearing in this case, and the point of the note wasn't to say "this should definitely happen, but with low priority," but rather, "I am really not sure if it should be done at all." Specifically, the only way this constructor ever gets invoked in practice is through thestaticmethods on the class, and all of those do canonicalization and validation of some sort or another. To the extent that we add more here, it shouldn't be duplicative of anything already done. So, the right path forward will look more like doing stuff here (including canonicalization, not just error checking) and also getting rid of the stuff in the clients of this constructor which is thereby rendered moot.As such, arguably we don't need the new method in
HostUtil.I'm leaving the comments I made in
HostUtil(which I made before writing this one), more for reference/advice about general stuff than necessarily to be acted on in this PR.