CI / Build & Test (push) Successful in 2m54s
Add docs/CONTRIBUTING.md covering the build system, dev workflow, all npm scripts, how to add new native host message types, code style, and debugging guidance. Add CHANGELOG.md at the project root documenting all features and fixes across the 1.0.0 release. Add JSDoc (@param, @returns) to all previously undocumented exported functions across 35 JS files: - native-host/holesail-manager/ (index, virtual-hosts, service-tunnels, servers, port-allocator) - native-host top-level managers (startup, connect-proxy, https-proxy, certificate-authority, ssh-manager, rdp-manager) - extension/background/ (logs, native-messaging, proxy, message-router) - extension/dashboard/core/ (utils, navigation, init) - extension/dashboard/ui/ (modal, toast, state-tag) - extension/dashboard/pages/ (all 10 page files) - extension/dashboard/refresh.js, events.js - extension/dashboard/data/hostname-validator.js - scripts/ (build-host, run-install)
56 lines
2.3 KiB
JavaScript
56 lines
2.3 KiB
JavaScript
// Depends on: data/tlds.js (REAL_TLDS, REAL_SLD_TLDS)
|
|
|
|
/**
|
|
* Validate a virtual host hostname.
|
|
* Rules:
|
|
* 1. Must have at least 2 dots (3 labels minimum: host.second.tld)
|
|
* 2. Each label: only [a-z0-9-], no leading/trailing hyphen, non-empty
|
|
* 3. The last two labels (base domain, e.g. "hole.sail") must not be a
|
|
* real public TLD or second-level public suffix
|
|
* Returns { ok: true } or { ok: false, error: string }
|
|
*/
|
|
function isValidVhostHostname(hostname) {
|
|
if (!hostname) return { ok: false, error: 'Hostname is required' };
|
|
const labels = hostname.split('.');
|
|
if (labels.length < 3) {
|
|
return { ok: false, error: 'Hostname must have the form host.second.tld (e.g. myapp.hole.sail) — single-dot names are not allowed' };
|
|
}
|
|
for (const label of labels) {
|
|
if (!label) return { ok: false, error: 'Hostname contains empty labels' };
|
|
if (!/^[a-z0-9-]+$/.test(label)) return { ok: false, error: 'Hostname contains invalid characters — only letters, digits and hyphens allowed' };
|
|
if (label.startsWith('-') || label.endsWith('-')) return { ok: false, error: 'Hostname labels must not start or end with a hyphen' };
|
|
}
|
|
const tld = labels[labels.length - 1];
|
|
const baseDomain = labels.slice(-2).join('.');
|
|
if (REAL_TLDS.has(tld) || REAL_SLD_TLDS.has(baseDomain)) {
|
|
return { ok: false, error: 'The TLD ".' + baseDomain + '" is a real registered domain — use a private TLD like .hole.sail or .my.internal' };
|
|
}
|
|
return { ok: true };
|
|
}
|
|
|
|
/**
|
|
* Extract the two-label base domain from a hostname.
|
|
* @example extractBaseDomain('myapp.hole.sail') // => 'hole.sail'
|
|
* @param {string} hostname
|
|
* @returns {string}
|
|
*/
|
|
function extractBaseDomain(hostname) {
|
|
const parts = hostname.split('.');
|
|
return parts.slice(-2).join('.');
|
|
}
|
|
|
|
/**
|
|
* Extract unique two-label base domains from a list of virtual host objects.
|
|
* Always includes `hole.sail` as the baseline TLD.
|
|
* @param {Array<{hostname: string}>} virtualHosts
|
|
* @returns {string[]} Array of TLD suffixes with leading dot (e.g. `['.hole.sail', '.hs']`).
|
|
*/
|
|
function extractActiveTlds(virtualHosts) {
|
|
const seen = new Set();
|
|
seen.add('hole.sail'); // always include baseline
|
|
for (const v of (virtualHosts || [])) {
|
|
if (v.hostname) seen.add(extractBaseDomain(v.hostname));
|
|
}
|
|
return Array.from(seen).map(b => '.' + b);
|
|
}
|