Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/net-util/export/HostInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ export class HostInfo extends IntfDeconstructable {
constructor(nameString, portNumber) {
super();

// Note: The regex is a bit lenient, though notably it _does_ at least
// guarantee that there are no uppercase letters. TODO: Maybe it should be
// more restrictive?
this.#nameString = MustBe.string(nameString, /^[-_.:a-z0-9]+$/);
// Validates canonicalized hostname formats:
// - IPv6: hex digits and colons (must contain at least one colon)
// - IPv4: digits with dot separators
// - DNS: labels separated by dots, each starting/ending with alphanumeric,
// hyphens allowed mid-label only
this.#nameString = MustBe.string(nameString, HostInfo.#NAME_REGEX);
Comment thread
danfuzz marked this conversation as resolved.
Outdated

this.#portNumber = AskIf.string(portNumber, /^0*[0-9]{1,5}$/)
? Number(portNumber)
Expand Down Expand Up @@ -223,6 +225,17 @@ export class HostInfo extends IntfDeconstructable {
// Static members
//

/**
* Regex for validating canonicalized hostname strings. Accepts:
* - IPv6 addresses (lowercase hex with colons)
* - IPv4 addresses (digits with dot separators)
* - DNS names (labels of alphanumerics/hyphens, starting and ending with
* alphanumeric, separated by dots)
*
* @type {RegExp}
*/
static #NAME_REGEX = /^(?:[a-f0-9]*:[a-f0-9:]*|[0-9]+(?:\.[0-9]+)*|[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\.[a-z0-9](?:[-a-z0-9]*[a-z0-9])?)*)$/;

/**
* Gets an instance of this class from a URL or the string form of same,
* returning `null` if the
Expand Down
25 changes: 20 additions & 5 deletions src/net-util/tests/HostInfo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ describe('constructor', () => {
${1}
${['x']}
${''}
${'[a::b]'} // IPv6 addresses must not use brackets.
${'[a::b]'} // IPv6 addresses must not use brackets.
${'--bad'} // Starts with hyphen.
${'.leading'} // Starts with dot.
${'trailing.'} // Ends with dot.
${'double..dot'} // Consecutive dots.
${'-start'} // Label starts with hyphen.
${'end-'} // Label ends with hyphen.
${'mid.-bad'} // Label starts with hyphen after dot.
${'bad-.mid'} // Label ends with hyphen before dot.
`('fails when passing name as $arg', ({ arg }) => {
expect(() => new HostInfo(arg, 123)).toThrow();
});
Expand Down Expand Up @@ -82,10 +90,17 @@ describe('constructor', () => {
arg
${'host'}
${'host.sub'}
${'1.2.3.4'}
${'01.02.03.04'}
${'a:b::c:d'}
${'0a:0123:0:0::987a'}
${'a'} // Single character.
${'localhost'} // Single label.
${'my-host'} // Hyphen mid-label.
${'a1.b2.c3'} // Alphanumeric labels.
${'example.com'} // Typical domain.
${'sub.example.com'} // Multi-level domain.
${'1.2.3.4'} // IPv4 address.
${'01.02.03.04'} // IPv4 with leading zeros.
${'a:b::c:d'} // IPv6 address.
${'0a:0123:0:0::987a'} // IPv6 with leading zeros.
${'::1'} // IPv6 loopback.
`('accepts valid host name $arg', ({ arg }) => {
expect(() => new HostInfo(arg, 1)).not.toThrow();
});
Expand Down
Loading