@stacksjs/rpx 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -6
- package/dist/cli.js +432 -176
- package/dist/hosts.d.ts +5 -0
- package/dist/https.d.ts +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +451 -190
- package/dist/start.d.ts +1 -1
- package/dist/types.d.ts +2 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -77,14 +77,15 @@ var config = await loadConfig({
|
|
|
77
77
|
validityDays: 180,
|
|
78
78
|
verbose: false
|
|
79
79
|
},
|
|
80
|
+
etcHostsCleanup: false,
|
|
80
81
|
verbose: true
|
|
81
82
|
}
|
|
82
83
|
});
|
|
83
|
-
// src/
|
|
84
|
-
import
|
|
85
|
-
import
|
|
86
|
-
import
|
|
87
|
-
import
|
|
84
|
+
// src/hosts.ts
|
|
85
|
+
import { spawn } from "child_process";
|
|
86
|
+
import fs from "fs";
|
|
87
|
+
import os3 from "os";
|
|
88
|
+
import path2 from "path";
|
|
88
89
|
import process3 from "process";
|
|
89
90
|
|
|
90
91
|
// node_modules/@stacksjs/cli/dist/index.js
|
|
@@ -20395,8 +20396,167 @@ var quotes = collect([
|
|
|
20395
20396
|
"Security is mostly a superstition. Life is either a daring adventure or nothing."
|
|
20396
20397
|
]);
|
|
20397
20398
|
var export_prompts = import_prompts.default;
|
|
20398
|
-
|
|
20399
|
-
|
|
20399
|
+
|
|
20400
|
+
// src/utils.ts
|
|
20401
|
+
function debugLog(category, message, verbose) {
|
|
20402
|
+
if (verbose || config.verbose) {
|
|
20403
|
+
console.debug(`[rpx:${category}] ${message}`);
|
|
20404
|
+
}
|
|
20405
|
+
}
|
|
20406
|
+
|
|
20407
|
+
// src/hosts.ts
|
|
20408
|
+
var hostsFilePath = process3.platform === "win32" ? path2.join(process3.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
20409
|
+
async function sudoWrite(operation, content) {
|
|
20410
|
+
return new Promise((resolve3, reject) => {
|
|
20411
|
+
if (process3.platform === "win32") {
|
|
20412
|
+
reject(new Error("Administrator privileges required on Windows"));
|
|
20413
|
+
return;
|
|
20414
|
+
}
|
|
20415
|
+
const tmpFile = path2.join(os3.tmpdir(), "hosts.tmp");
|
|
20416
|
+
try {
|
|
20417
|
+
if (operation === "append") {
|
|
20418
|
+
const currentContent = fs.readFileSync(hostsFilePath, "utf8");
|
|
20419
|
+
fs.writeFileSync(tmpFile, currentContent + content, "utf8");
|
|
20420
|
+
} else {
|
|
20421
|
+
fs.writeFileSync(tmpFile, content, "utf8");
|
|
20422
|
+
}
|
|
20423
|
+
const sudo = spawn("sudo", ["cp", tmpFile, hostsFilePath]);
|
|
20424
|
+
sudo.on("close", (code) => {
|
|
20425
|
+
try {
|
|
20426
|
+
fs.unlinkSync(tmpFile);
|
|
20427
|
+
if (code === 0)
|
|
20428
|
+
resolve3();
|
|
20429
|
+
else
|
|
20430
|
+
reject(new Error(`sudo process exited with code ${code}`));
|
|
20431
|
+
} catch (err2) {
|
|
20432
|
+
reject(err2);
|
|
20433
|
+
}
|
|
20434
|
+
});
|
|
20435
|
+
sudo.on("error", (err2) => {
|
|
20436
|
+
try {
|
|
20437
|
+
fs.unlinkSync(tmpFile);
|
|
20438
|
+
} catch {
|
|
20439
|
+
}
|
|
20440
|
+
reject(err2);
|
|
20441
|
+
});
|
|
20442
|
+
} catch (err2) {
|
|
20443
|
+
reject(err2);
|
|
20444
|
+
}
|
|
20445
|
+
});
|
|
20446
|
+
}
|
|
20447
|
+
async function addHosts(hosts) {
|
|
20448
|
+
debugLog("hosts", `Adding hosts: ${hosts.join(", ")}`, config.verbose);
|
|
20449
|
+
debugLog("hosts", `Using hosts file at: ${hostsFilePath}`, config.verbose);
|
|
20450
|
+
try {
|
|
20451
|
+
const existingContent = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20452
|
+
const newEntries = hosts.filter((host) => {
|
|
20453
|
+
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
20454
|
+
const ipv6Entry = `::1 ${host}`;
|
|
20455
|
+
return !existingContent.includes(ipv4Entry) && !existingContent.includes(ipv6Entry);
|
|
20456
|
+
});
|
|
20457
|
+
if (newEntries.length === 0) {
|
|
20458
|
+
debugLog("hosts", "All hosts already exist in hosts file", config.verbose);
|
|
20459
|
+
log.info("All hosts are already in the hosts file");
|
|
20460
|
+
return;
|
|
20461
|
+
}
|
|
20462
|
+
const hostEntries = newEntries.map((host) => `\n# Added by rpx\n127.0.0.1 ${host}\n::1 ${host}`).join("\n");
|
|
20463
|
+
try {
|
|
20464
|
+
await fs.promises.appendFile(hostsFilePath, hostEntries, { flag: "a" });
|
|
20465
|
+
log.success(`Added new hosts: ${newEntries.join(", ")}`);
|
|
20466
|
+
} catch (writeErr) {
|
|
20467
|
+
if (writeErr.code === "EACCES") {
|
|
20468
|
+
debugLog("hosts", "Permission denied, attempting with sudo", config.verbose);
|
|
20469
|
+
try {
|
|
20470
|
+
await sudoWrite("append", hostEntries);
|
|
20471
|
+
log.success(`Added new hosts with sudo: ${newEntries.join(", ")}`);
|
|
20472
|
+
} catch (sudoErr) {
|
|
20473
|
+
log.error("Failed to modify hosts file automatically");
|
|
20474
|
+
log.warn("Please add these entries to your hosts file manually:");
|
|
20475
|
+
hostEntries.split("\n").forEach((entry) => log.warn(entry));
|
|
20476
|
+
if (process3.platform === "win32") {
|
|
20477
|
+
log.warn("\nOn Windows:");
|
|
20478
|
+
log.warn("1. Run notepad as administrator");
|
|
20479
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
20480
|
+
} else {
|
|
20481
|
+
log.warn("\nOn Unix systems:");
|
|
20482
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
20483
|
+
}
|
|
20484
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
20485
|
+
}
|
|
20486
|
+
} else {
|
|
20487
|
+
throw writeErr;
|
|
20488
|
+
}
|
|
20489
|
+
}
|
|
20490
|
+
} catch (err2) {
|
|
20491
|
+
const error = err2;
|
|
20492
|
+
log.error(`Failed to manage hosts file: ${error.message}`);
|
|
20493
|
+
throw error;
|
|
20494
|
+
}
|
|
20495
|
+
}
|
|
20496
|
+
async function removeHosts(hosts) {
|
|
20497
|
+
debugLog("hosts", `Removing hosts: ${hosts.join(", ")}`, config.verbose);
|
|
20498
|
+
try {
|
|
20499
|
+
const content = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20500
|
+
const lines = content.split("\n");
|
|
20501
|
+
const filteredLines = lines.filter((line, index) => {
|
|
20502
|
+
if (line.trim() === "# Added by rpx") {
|
|
20503
|
+
lines.splice(index + 1, 2);
|
|
20504
|
+
return false;
|
|
20505
|
+
}
|
|
20506
|
+
return true;
|
|
20507
|
+
});
|
|
20508
|
+
while (filteredLines[filteredLines.length - 1]?.trim() === "")
|
|
20509
|
+
filteredLines.pop();
|
|
20510
|
+
const newContent = `${filteredLines.join("\n")}\n`;
|
|
20511
|
+
try {
|
|
20512
|
+
await fs.promises.writeFile(hostsFilePath, newContent);
|
|
20513
|
+
log.success("Hosts removed successfully");
|
|
20514
|
+
} catch (writeErr) {
|
|
20515
|
+
if (writeErr.code === "EACCES") {
|
|
20516
|
+
debugLog("hosts", "Permission denied, attempting with sudo", config.verbose);
|
|
20517
|
+
try {
|
|
20518
|
+
await sudoWrite("write", newContent);
|
|
20519
|
+
log.success("Hosts removed successfully with sudo");
|
|
20520
|
+
} catch (sudoErr) {
|
|
20521
|
+
log.error("Failed to modify hosts file automatically");
|
|
20522
|
+
log.warn("Please remove these entries from your hosts file manually:");
|
|
20523
|
+
hosts.forEach((host) => {
|
|
20524
|
+
log.warn("# Added by rpx");
|
|
20525
|
+
log.warn(`127.0.0.1 ${host}`);
|
|
20526
|
+
log.warn(`::1 ${host}`);
|
|
20527
|
+
});
|
|
20528
|
+
if (process3.platform === "win32") {
|
|
20529
|
+
log.warn("\nOn Windows:");
|
|
20530
|
+
log.warn("1. Run notepad as administrator");
|
|
20531
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
20532
|
+
} else {
|
|
20533
|
+
log.warn("\nOn Unix systems:");
|
|
20534
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
20535
|
+
}
|
|
20536
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
20537
|
+
}
|
|
20538
|
+
} else {
|
|
20539
|
+
throw writeErr;
|
|
20540
|
+
}
|
|
20541
|
+
}
|
|
20542
|
+
} catch (err2) {
|
|
20543
|
+
const error = err2;
|
|
20544
|
+
log.error(`Failed to remove hosts: ${error.message}`);
|
|
20545
|
+
throw error;
|
|
20546
|
+
}
|
|
20547
|
+
}
|
|
20548
|
+
async function checkHosts(hosts) {
|
|
20549
|
+
debugLog("hosts", `Checking hosts: ${hosts}`, config.verbose);
|
|
20550
|
+
const content = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20551
|
+
return hosts.map((host) => {
|
|
20552
|
+
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
20553
|
+
const ipv6Entry = `::1 ${host}`;
|
|
20554
|
+
return content.includes(ipv4Entry) || content.includes(ipv6Entry);
|
|
20555
|
+
});
|
|
20556
|
+
}
|
|
20557
|
+
// src/https.ts
|
|
20558
|
+
import os7 from "os";
|
|
20559
|
+
import path6 from "path";
|
|
20400
20560
|
|
|
20401
20561
|
// node_modules/@stacksjs/tlsx/dist/index.js
|
|
20402
20562
|
import fs2 from "fs";
|
|
@@ -20435,7 +20595,7 @@ import process8 from "process";
|
|
|
20435
20595
|
import process102 from "process";
|
|
20436
20596
|
import process182 from "process";
|
|
20437
20597
|
import process112 from "process";
|
|
20438
|
-
import
|
|
20598
|
+
import os5 from "os";
|
|
20439
20599
|
import tty32 from "tty";
|
|
20440
20600
|
import process142 from "process";
|
|
20441
20601
|
import process132 from "process";
|
|
@@ -20444,10 +20604,10 @@ import process162 from "process";
|
|
|
20444
20604
|
import process172 from "process";
|
|
20445
20605
|
import process192 from "process";
|
|
20446
20606
|
import os22 from "os";
|
|
20447
|
-
import
|
|
20607
|
+
import path4 from "path";
|
|
20448
20608
|
import { resolve as resolve3 } from "path";
|
|
20449
20609
|
import process22 from "process";
|
|
20450
|
-
import
|
|
20610
|
+
import fs3 from "fs";
|
|
20451
20611
|
import path22 from "path";
|
|
20452
20612
|
var __create3 = Object.create;
|
|
20453
20613
|
var __getProtoOf3 = Object.getPrototypeOf;
|
|
@@ -32497,14 +32657,14 @@ var require_tls = __commonJS2((exports, module) => {
|
|
|
32497
32657
|
c2.version = c2.session.version = session.version;
|
|
32498
32658
|
c2.session.sp = session.sp;
|
|
32499
32659
|
} else {
|
|
32500
|
-
var
|
|
32660
|
+
var version;
|
|
32501
32661
|
for (var i = 1;i < tls.SupportedVersions.length; ++i) {
|
|
32502
|
-
|
|
32503
|
-
if (
|
|
32662
|
+
version = tls.SupportedVersions[i];
|
|
32663
|
+
if (version.minor <= msg.version.minor) {
|
|
32504
32664
|
break;
|
|
32505
32665
|
}
|
|
32506
32666
|
}
|
|
32507
|
-
c2.version = { major:
|
|
32667
|
+
c2.version = { major: version.major, minor: version.minor };
|
|
32508
32668
|
c2.session.version = c2.version;
|
|
32509
32669
|
}
|
|
32510
32670
|
if (session !== null) {
|
|
@@ -32675,8 +32835,8 @@ var require_tls = __commonJS2((exports, module) => {
|
|
|
32675
32835
|
try {
|
|
32676
32836
|
var sp = c2.session.sp;
|
|
32677
32837
|
sp.pre_master_secret = privateKey.decrypt(msg.enc_pre_master_secret);
|
|
32678
|
-
var
|
|
32679
|
-
if (
|
|
32838
|
+
var version = c2.session.clientHelloVersion;
|
|
32839
|
+
if (version.major !== sp.pre_master_secret.charCodeAt(0) || version.minor !== sp.pre_master_secret.charCodeAt(1)) {
|
|
32680
32840
|
throw new Error("TLS version rollback attack detected.");
|
|
32681
32841
|
}
|
|
32682
32842
|
} catch (ex) {
|
|
@@ -38619,16 +38779,16 @@ var require_isIP2 = __commonJS22((exports, module) => {
|
|
|
38619
38779
|
var IPv6SegmentFormat = "(?:[0-9a-fA-F]{1,4})";
|
|
38620
38780
|
var IPv6AddressRegExp = new RegExp("^(" + "(?:".concat(IPv6SegmentFormat, ":){7}(?:").concat(IPv6SegmentFormat, "|:)|") + "(?:".concat(IPv6SegmentFormat, ":){6}(?:").concat(IPv4AddressFormat, "|:").concat(IPv6SegmentFormat, "|:)|") + "(?:".concat(IPv6SegmentFormat, ":){5}(?::").concat(IPv4AddressFormat, "|(:").concat(IPv6SegmentFormat, "){1,2}|:)|") + "(?:".concat(IPv6SegmentFormat, ":){4}(?:(:").concat(IPv6SegmentFormat, "){0,1}:").concat(IPv4AddressFormat, "|(:").concat(IPv6SegmentFormat, "){1,3}|:)|") + "(?:".concat(IPv6SegmentFormat, ":){3}(?:(:").concat(IPv6SegmentFormat, "){0,2}:").concat(IPv4AddressFormat, "|(:").concat(IPv6SegmentFormat, "){1,4}|:)|") + "(?:".concat(IPv6SegmentFormat, ":){2}(?:(:").concat(IPv6SegmentFormat, "){0,3}:").concat(IPv4AddressFormat, "|(:").concat(IPv6SegmentFormat, "){1,5}|:)|") + "(?:".concat(IPv6SegmentFormat, ":){1}(?:(:").concat(IPv6SegmentFormat, "){0,4}:").concat(IPv4AddressFormat, "|(:").concat(IPv6SegmentFormat, "){1,6}|:)|") + "(?::((?::".concat(IPv6SegmentFormat, "){0,5}:").concat(IPv4AddressFormat, "|(?::").concat(IPv6SegmentFormat, "){1,7}|:))") + ")(%[0-9a-zA-Z-.:]{1,})?$");
|
|
38621
38781
|
function isIP(str) {
|
|
38622
|
-
var
|
|
38782
|
+
var version = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
38623
38783
|
(0, _assertString.default)(str);
|
|
38624
|
-
|
|
38625
|
-
if (!
|
|
38784
|
+
version = String(version);
|
|
38785
|
+
if (!version) {
|
|
38626
38786
|
return isIP(str, 4) || isIP(str, 6);
|
|
38627
38787
|
}
|
|
38628
|
-
if (
|
|
38788
|
+
if (version === "4") {
|
|
38629
38789
|
return IPv4AddressRegExp.test(str);
|
|
38630
38790
|
}
|
|
38631
|
-
if (
|
|
38791
|
+
if (version === "6") {
|
|
38632
38792
|
return IPv6AddressRegExp.test(str);
|
|
38633
38793
|
}
|
|
38634
38794
|
return false;
|
|
@@ -39150,9 +39310,9 @@ var require_isUUID2 = __commonJS22((exports, module) => {
|
|
|
39150
39310
|
7: /^[0-9A-F]{8}-[0-9A-F]{4}-7[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
|
39151
39311
|
all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
|
|
39152
39312
|
};
|
|
39153
|
-
function isUUID(str,
|
|
39313
|
+
function isUUID(str, version) {
|
|
39154
39314
|
(0, _assertString.default)(str);
|
|
39155
|
-
var pattern = uuid[![undefined, null].includes(
|
|
39315
|
+
var pattern = uuid[![undefined, null].includes(version) ? version : "all"];
|
|
39156
39316
|
return !!pattern && pattern.test(str);
|
|
39157
39317
|
}
|
|
39158
39318
|
module.exports = exports.default;
|
|
@@ -51329,7 +51489,7 @@ var uuidRule2 = createRule2((value, options2, field) => {
|
|
|
51329
51489
|
field.report(messages2.uuid, "uuid", field);
|
|
51330
51490
|
}
|
|
51331
51491
|
} else {
|
|
51332
|
-
const matchesAnyVersion = options2.version.find((
|
|
51492
|
+
const matchesAnyVersion = options2.version.find((version) => helpers32.isUUID(value, version));
|
|
51333
51493
|
if (!matchesAnyVersion) {
|
|
51334
51494
|
field.report(messages2.uuid, "uuid", field, options2);
|
|
51335
51495
|
}
|
|
@@ -51424,8 +51584,8 @@ var VineString2 = class _VineString2 extends BaseLiteralType2 {
|
|
|
51424
51584
|
mobile(...args) {
|
|
51425
51585
|
return this.use(mobileRule2(...args));
|
|
51426
51586
|
}
|
|
51427
|
-
ipAddress(
|
|
51428
|
-
return this.use(ipAddressRule2(
|
|
51587
|
+
ipAddress(version) {
|
|
51588
|
+
return this.use(ipAddressRule2(version ? { version } : undefined));
|
|
51429
51589
|
}
|
|
51430
51590
|
hexCode() {
|
|
51431
51591
|
return this.use(hexCodeRule2());
|
|
@@ -53938,7 +54098,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
53938
54098
|
return min;
|
|
53939
54099
|
}
|
|
53940
54100
|
if (process112.platform === "win32") {
|
|
53941
|
-
const osRelease =
|
|
54101
|
+
const osRelease = os5.release().split(".");
|
|
53942
54102
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
53943
54103
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
53944
54104
|
}
|
|
@@ -56505,18 +56665,18 @@ var config42 = await loadConfig2({
|
|
|
56505
56665
|
defaultConfig: {
|
|
56506
56666
|
altNameIPs: ["127.0.0.1"],
|
|
56507
56667
|
altNameURIs: ["localhost"],
|
|
56508
|
-
organizationName: "
|
|
56668
|
+
organizationName: "Local Development",
|
|
56509
56669
|
countryName: "US",
|
|
56510
56670
|
stateName: "California",
|
|
56511
56671
|
localityName: "Playa Vista",
|
|
56512
56672
|
commonName: "stacks.localhost",
|
|
56513
56673
|
validityDays: 180,
|
|
56514
56674
|
hostCertCN: "stacks.localhost",
|
|
56515
|
-
domain: "localhost",
|
|
56675
|
+
domain: "stacks.localhost",
|
|
56516
56676
|
rootCAObject: { certificate: "", privateKey: "" },
|
|
56517
|
-
caCertPath:
|
|
56518
|
-
certPath:
|
|
56519
|
-
keyPath:
|
|
56677
|
+
caCertPath: path4.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
56678
|
+
certPath: path4.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
56679
|
+
keyPath: path4.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`),
|
|
56520
56680
|
verbose: false
|
|
56521
56681
|
}
|
|
56522
56682
|
});
|
|
@@ -56532,10 +56692,10 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56532
56692
|
const result = [];
|
|
56533
56693
|
function search(dir) {
|
|
56534
56694
|
try {
|
|
56535
|
-
const files =
|
|
56695
|
+
const files = fs3.readdirSync(dir);
|
|
56536
56696
|
for (const file of files) {
|
|
56537
56697
|
const filePath = path22.join(dir, file);
|
|
56538
|
-
const stats =
|
|
56698
|
+
const stats = fs3.lstatSync(filePath);
|
|
56539
56699
|
if (stats.isDirectory()) {
|
|
56540
56700
|
search(filePath);
|
|
56541
56701
|
} else if (file === fileName) {
|
|
@@ -56549,29 +56709,29 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56549
56709
|
search(rootDir);
|
|
56550
56710
|
return result;
|
|
56551
56711
|
}
|
|
56552
|
-
function
|
|
56712
|
+
function debugLog2(category, message, verbose) {
|
|
56553
56713
|
if (verbose || config42.verbose) {
|
|
56554
56714
|
console.debug(`[tlsx:${category}] ${message}`);
|
|
56555
56715
|
}
|
|
56556
56716
|
}
|
|
56557
56717
|
function randomSerialNumber(verbose) {
|
|
56558
|
-
|
|
56718
|
+
debugLog2("cert", "Generating random serial number", verbose);
|
|
56559
56719
|
const serialNumber = makeNumberPositive(import_node_forge2.default.util.bytesToHex(import_node_forge2.default.random.getBytesSync(20)));
|
|
56560
|
-
|
|
56720
|
+
debugLog2("cert", `Generated serial number: ${serialNumber}`, verbose);
|
|
56561
56721
|
return serialNumber;
|
|
56562
56722
|
}
|
|
56563
56723
|
function getCertNotBefore(verbose) {
|
|
56564
|
-
|
|
56724
|
+
debugLog2("cert", "Calculating certificate not-before date", verbose);
|
|
56565
56725
|
const twoDaysAgo = new Date(Date.now() - 172800000);
|
|
56566
56726
|
const year = twoDaysAgo.getFullYear();
|
|
56567
56727
|
const month = (twoDaysAgo.getMonth() + 1).toString().padStart(2, "0");
|
|
56568
56728
|
const day = twoDaysAgo.getDate().toString().padStart(2, "0");
|
|
56569
56729
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56570
|
-
|
|
56730
|
+
debugLog2("cert", `Certificate not-before date: ${date.toISOString()}`, verbose);
|
|
56571
56731
|
return date;
|
|
56572
56732
|
}
|
|
56573
56733
|
function getCertNotAfter(notBefore, verbose) {
|
|
56574
|
-
|
|
56734
|
+
debugLog2("cert", "Calculating certificate not-after date", verbose);
|
|
56575
56735
|
const validityDays = config42.validityDays;
|
|
56576
56736
|
const daysInMillis = validityDays * 60 * 60 * 24 * 1000;
|
|
56577
56737
|
const notAfterDate = new Date(notBefore.getTime() + daysInMillis);
|
|
@@ -56579,27 +56739,27 @@ function getCertNotAfter(notBefore, verbose) {
|
|
|
56579
56739
|
const month = (notAfterDate.getMonth() + 1).toString().padStart(2, "0");
|
|
56580
56740
|
const day = notAfterDate.getDate().toString().padStart(2, "0");
|
|
56581
56741
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56582
|
-
|
|
56742
|
+
debugLog2("cert", `Certificate not-after date: ${date.toISOString()} (${validityDays} days validity)`, verbose);
|
|
56583
56743
|
return date;
|
|
56584
56744
|
}
|
|
56585
56745
|
function getCANotAfter(notBefore, verbose) {
|
|
56586
|
-
|
|
56746
|
+
debugLog2("cert", "Calculating CA not-after date", verbose);
|
|
56587
56747
|
const year = notBefore.getFullYear() + 100;
|
|
56588
56748
|
const month = (notBefore.getMonth() + 1).toString().padStart(2, "0");
|
|
56589
56749
|
const day = notBefore.getDate().toString().padStart(2, "0");
|
|
56590
56750
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56591
|
-
|
|
56751
|
+
debugLog2("cert", `CA not-after date: ${date.toISOString()} (100 years validity)`, verbose);
|
|
56592
56752
|
return date;
|
|
56593
56753
|
}
|
|
56594
56754
|
async function createRootCA(options22) {
|
|
56595
|
-
|
|
56596
|
-
|
|
56755
|
+
debugLog2("ca", "Creating new Root CA Certificate", options22?.verbose);
|
|
56756
|
+
debugLog2("ca", "Generating 2048-bit RSA key pair", options22?.verbose);
|
|
56597
56757
|
const { privateKey, publicKey } = import_node_forge2.pki.rsa.generateKeyPair(2048);
|
|
56598
56758
|
const mergedOptions = {
|
|
56599
56759
|
...config42,
|
|
56600
56760
|
...options22 || {}
|
|
56601
56761
|
};
|
|
56602
|
-
|
|
56762
|
+
debugLog2("ca", "Setting certificate attributes", options22?.verbose);
|
|
56603
56763
|
const attributes = [
|
|
56604
56764
|
{ shortName: "C", value: mergedOptions.countryName },
|
|
56605
56765
|
{ shortName: "ST", value: mergedOptions.stateName },
|
|
@@ -56607,7 +56767,7 @@ async function createRootCA(options22) {
|
|
|
56607
56767
|
{ shortName: "O", value: "Local Development CA" },
|
|
56608
56768
|
{ shortName: "CN", value: "Local Development Root CA" }
|
|
56609
56769
|
];
|
|
56610
|
-
|
|
56770
|
+
debugLog2("ca", "Setting certificate extensions", options22?.verbose);
|
|
56611
56771
|
const extensions = [
|
|
56612
56772
|
{
|
|
56613
56773
|
name: "basicConstraints",
|
|
@@ -56624,7 +56784,7 @@ async function createRootCA(options22) {
|
|
|
56624
56784
|
name: "subjectKeyIdentifier"
|
|
56625
56785
|
}
|
|
56626
56786
|
];
|
|
56627
|
-
|
|
56787
|
+
debugLog2("ca", "Creating CA certificate", options22?.verbose);
|
|
56628
56788
|
const caCert = import_node_forge2.pki.createCertificate();
|
|
56629
56789
|
caCert.publicKey = publicKey;
|
|
56630
56790
|
caCert.serialNumber = randomSerialNumber(options22?.verbose);
|
|
@@ -56633,11 +56793,11 @@ async function createRootCA(options22) {
|
|
|
56633
56793
|
caCert.setSubject(attributes);
|
|
56634
56794
|
caCert.setIssuer(attributes);
|
|
56635
56795
|
caCert.setExtensions(extensions);
|
|
56636
|
-
|
|
56796
|
+
debugLog2("ca", "Signing certificate with SHA-256", options22?.verbose);
|
|
56637
56797
|
caCert.sign(privateKey, import_node_forge2.default.md.sha256.create());
|
|
56638
56798
|
const pemCert = import_node_forge2.pki.certificateToPem(caCert);
|
|
56639
56799
|
const pemKey = import_node_forge2.pki.privateKeyToPem(privateKey);
|
|
56640
|
-
|
|
56800
|
+
debugLog2("ca", "Root CA Certificate created successfully", options22?.verbose);
|
|
56641
56801
|
return {
|
|
56642
56802
|
certificate: pemCert,
|
|
56643
56803
|
privateKey: pemKey,
|
|
@@ -56646,34 +56806,41 @@ async function createRootCA(options22) {
|
|
|
56646
56806
|
};
|
|
56647
56807
|
}
|
|
56648
56808
|
async function generateCert(options22) {
|
|
56649
|
-
|
|
56650
|
-
|
|
56809
|
+
debugLog2("cert", "Generating new host certificate", options22?.verbose);
|
|
56810
|
+
debugLog2("cert", `Options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
56651
56811
|
if (!options22?.hostCertCN?.trim()) {
|
|
56652
|
-
|
|
56812
|
+
debugLog2("cert", "Error: hostCertCN is required", options22?.verbose);
|
|
56653
56813
|
throw new Error('"hostCertCN" must be a String');
|
|
56654
56814
|
}
|
|
56655
56815
|
if (!options22.domain?.trim()) {
|
|
56656
|
-
|
|
56816
|
+
debugLog2("cert", "Error: domain is required", options22?.verbose);
|
|
56657
56817
|
throw new Error('"domain" must be a String');
|
|
56658
56818
|
}
|
|
56659
56819
|
if (!options22.rootCAObject || !options22.rootCAObject.certificate || !options22.rootCAObject.privateKey) {
|
|
56660
|
-
|
|
56820
|
+
debugLog2("cert", "Error: rootCAObject is invalid or missing", options22?.verbose);
|
|
56661
56821
|
throw new Error('"rootCAObject" must be an Object with the properties "certificate" & "privateKey"');
|
|
56662
56822
|
}
|
|
56663
|
-
|
|
56823
|
+
debugLog2("cert", "Converting Root CA PEM to forge objects", options22?.verbose);
|
|
56664
56824
|
const caCert = import_node_forge2.pki.certificateFromPem(options22.rootCAObject.certificate);
|
|
56665
56825
|
const caKey = import_node_forge2.pki.privateKeyFromPem(options22.rootCAObject.privateKey);
|
|
56666
|
-
|
|
56826
|
+
debugLog2("cert", "Generating 2048-bit RSA key pair for host certificate", options22?.verbose);
|
|
56667
56827
|
const hostKeys = import_node_forge2.pki.rsa.generateKeyPair(2048);
|
|
56668
|
-
|
|
56828
|
+
debugLog2("cert", "Setting certificate attributes", options22?.verbose);
|
|
56669
56829
|
const attributes = [
|
|
56670
|
-
{ shortName: "C", value: config42.countryName },
|
|
56671
|
-
{ shortName: "ST", value: config42.stateName },
|
|
56672
|
-
{ shortName: "L", value: config42.localityName },
|
|
56673
|
-
{ shortName: "O", value:
|
|
56674
|
-
{ shortName: "CN", value:
|
|
56830
|
+
{ shortName: "C", value: options22.countryName || config42.countryName },
|
|
56831
|
+
{ shortName: "ST", value: options22.stateName || config42.stateName },
|
|
56832
|
+
{ shortName: "L", value: options22.localityName || config42.localityName },
|
|
56833
|
+
{ shortName: "O", value: options22.organizationName || config42.organizationName },
|
|
56834
|
+
{ shortName: "CN", value: options22.commonName || config42.commonName }
|
|
56835
|
+
];
|
|
56836
|
+
const domain = options22.domain || config42.domain;
|
|
56837
|
+
const wildcardDomain = `*.${domain.includes(".") ? domain.split(".").slice(1).join(".") : domain}`;
|
|
56838
|
+
const altNames = [
|
|
56839
|
+
{ type: 2, value: wildcardDomain },
|
|
56840
|
+
{ type: 2, value: "localhost" },
|
|
56841
|
+
{ type: 2, value: domain }
|
|
56675
56842
|
];
|
|
56676
|
-
|
|
56843
|
+
debugLog2("cert", "Setting certificate extensions", options22?.verbose);
|
|
56677
56844
|
const extensions = [
|
|
56678
56845
|
{
|
|
56679
56846
|
name: "basicConstraints",
|
|
@@ -56693,30 +56860,25 @@ async function generateCert(options22) {
|
|
|
56693
56860
|
},
|
|
56694
56861
|
{
|
|
56695
56862
|
name: "subjectAltName",
|
|
56696
|
-
altNames
|
|
56697
|
-
{ type: 2, value: "*.localhost" },
|
|
56698
|
-
{ type: 2, value: "localhost" },
|
|
56699
|
-
{ type: 2, value: "stacks.localhost" },
|
|
56700
|
-
{ type: 2, value: options22.domain }
|
|
56701
|
-
]
|
|
56863
|
+
altNames
|
|
56702
56864
|
}
|
|
56703
56865
|
];
|
|
56704
|
-
|
|
56866
|
+
debugLog2("cert", "Creating new host certificate", options22?.verbose);
|
|
56705
56867
|
const newHostCert = import_node_forge2.pki.createCertificate();
|
|
56706
56868
|
newHostCert.publicKey = hostKeys.publicKey;
|
|
56707
|
-
|
|
56869
|
+
debugLog2("cert", "Setting certificate properties", options22?.verbose);
|
|
56708
56870
|
newHostCert.serialNumber = randomSerialNumber(options22?.verbose);
|
|
56709
56871
|
newHostCert.validity.notBefore = getCertNotBefore(options22?.verbose);
|
|
56710
56872
|
newHostCert.validity.notAfter = getCertNotAfter(newHostCert.validity.notBefore, options22?.verbose);
|
|
56711
56873
|
newHostCert.setSubject(attributes);
|
|
56712
56874
|
newHostCert.setIssuer(caCert.subject.attributes);
|
|
56713
56875
|
newHostCert.setExtensions(extensions);
|
|
56714
|
-
|
|
56876
|
+
debugLog2("cert", "Signing certificate with SHA-256", options22?.verbose);
|
|
56715
56877
|
newHostCert.sign(caKey, import_node_forge2.default.md.sha256.create());
|
|
56716
|
-
|
|
56878
|
+
debugLog2("cert", "Converting certificate to PEM format", options22?.verbose);
|
|
56717
56879
|
const pemHostCert = import_node_forge2.pki.certificateToPem(newHostCert);
|
|
56718
56880
|
const pemHostKey = import_node_forge2.pki.privateKeyToPem(hostKeys.privateKey);
|
|
56719
|
-
|
|
56881
|
+
debugLog2("cert", "Host certificate generated successfully", options22?.verbose);
|
|
56720
56882
|
return {
|
|
56721
56883
|
certificate: pemHostCert,
|
|
56722
56884
|
privateKey: pemHostKey,
|
|
@@ -56725,81 +56887,81 @@ async function generateCert(options22) {
|
|
|
56725
56887
|
};
|
|
56726
56888
|
}
|
|
56727
56889
|
async function addCertToSystemTrustStoreAndSaveCert(cert, caCert, options22) {
|
|
56728
|
-
|
|
56729
|
-
|
|
56890
|
+
debugLog2("trust", `Adding certificate to system trust store with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
56891
|
+
debugLog2("trust", "Storing certificate and private key", options22?.verbose);
|
|
56730
56892
|
const certPath = storeCert(cert, options22);
|
|
56731
|
-
|
|
56893
|
+
debugLog2("trust", "Storing CA certificate", options22?.verbose);
|
|
56732
56894
|
const caCertPath = storeCACert(caCert, options22);
|
|
56733
56895
|
const platform22 = os4.platform();
|
|
56734
|
-
|
|
56896
|
+
debugLog2("trust", `Detected platform: ${platform22}`, options22?.verbose);
|
|
56735
56897
|
const args = "TC, C, C";
|
|
56736
56898
|
if (platform22 === "darwin") {
|
|
56737
|
-
|
|
56899
|
+
debugLog2("trust", "Adding certificate to macOS keychain", options22?.verbose);
|
|
56738
56900
|
await runCommand(`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${caCertPath}`);
|
|
56739
56901
|
} else if (platform22 === "win32") {
|
|
56740
|
-
|
|
56902
|
+
debugLog2("trust", "Adding certificate to Windows certificate store", options22?.verbose);
|
|
56741
56903
|
await runCommand(`certutil -f -v -addstore -enterprise Root ${caCertPath}`);
|
|
56742
56904
|
} else if (platform22 === "linux") {
|
|
56743
|
-
|
|
56905
|
+
debugLog2("trust", "Adding certificate to Linux certificate store", options22?.verbose);
|
|
56744
56906
|
const rootDirectory = os4.homedir();
|
|
56745
56907
|
const targetFileName = "cert9.db";
|
|
56746
|
-
|
|
56908
|
+
debugLog2("trust", `Searching for certificate databases in ${rootDirectory}`, options22?.verbose);
|
|
56747
56909
|
const foldersWithFile = findFoldersWithFile(rootDirectory, targetFileName);
|
|
56748
56910
|
for (const folder of foldersWithFile) {
|
|
56749
|
-
|
|
56911
|
+
debugLog2("trust", `Processing certificate database in ${folder}`, options22?.verbose);
|
|
56750
56912
|
try {
|
|
56751
|
-
|
|
56913
|
+
debugLog2("trust", `Attempting to delete existing cert for ${config42.commonName}`, options22?.verbose);
|
|
56752
56914
|
await runCommand(`certutil -d sql:${folder} -D -n ${config42.commonName}`);
|
|
56753
56915
|
} catch (error) {
|
|
56754
|
-
|
|
56916
|
+
debugLog2("trust", `Warning: Error deleting existing cert: ${error}`, options22?.verbose);
|
|
56755
56917
|
console.warn(`Error deleting existing cert: ${error}`);
|
|
56756
56918
|
}
|
|
56757
|
-
|
|
56919
|
+
debugLog2("trust", `Adding new certificate to ${folder}`, options22?.verbose);
|
|
56758
56920
|
await runCommand(`certutil -d sql:${folder} -A -t ${args} -n ${config42.commonName} -i ${caCertPath}`);
|
|
56759
56921
|
log2.info(`Cert added to ${folder}`);
|
|
56760
56922
|
}
|
|
56761
56923
|
} else {
|
|
56762
|
-
|
|
56924
|
+
debugLog2("trust", `Error: Unsupported platform ${platform22}`, options22?.verbose);
|
|
56763
56925
|
throw new Error(`Unsupported platform: ${platform22}`);
|
|
56764
56926
|
}
|
|
56765
|
-
|
|
56927
|
+
debugLog2("trust", "Certificate successfully added to system trust store", options22?.verbose);
|
|
56766
56928
|
return certPath;
|
|
56767
56929
|
}
|
|
56768
56930
|
function storeCert(cert, options22) {
|
|
56769
|
-
|
|
56931
|
+
debugLog2("storage", `Storing certificate and private key with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
56770
56932
|
const certPath = options22?.certPath || config42.certPath;
|
|
56771
56933
|
const certKeyPath = options22?.keyPath || config42.keyPath;
|
|
56772
|
-
|
|
56773
|
-
|
|
56934
|
+
debugLog2("storage", `Certificate path: ${certPath}`, options22?.verbose);
|
|
56935
|
+
debugLog2("storage", `Private key path: ${certKeyPath}`, options22?.verbose);
|
|
56774
56936
|
const certDir = path3.dirname(certPath);
|
|
56775
56937
|
if (!fs2.existsSync(certDir)) {
|
|
56776
|
-
|
|
56938
|
+
debugLog2("storage", `Creating certificate directory: ${certDir}`, options22?.verbose);
|
|
56777
56939
|
fs2.mkdirSync(certDir, { recursive: true });
|
|
56778
56940
|
}
|
|
56779
|
-
|
|
56941
|
+
debugLog2("storage", "Writing certificate file", options22?.verbose);
|
|
56780
56942
|
fs2.writeFileSync(certPath, cert.certificate);
|
|
56781
56943
|
const certKeyDir = path3.dirname(certKeyPath);
|
|
56782
56944
|
if (!fs2.existsSync(certKeyDir)) {
|
|
56783
|
-
|
|
56945
|
+
debugLog2("storage", `Creating private key directory: ${certKeyDir}`, options22?.verbose);
|
|
56784
56946
|
fs2.mkdirSync(certKeyDir, { recursive: true });
|
|
56785
56947
|
}
|
|
56786
|
-
|
|
56948
|
+
debugLog2("storage", "Writing private key file", options22?.verbose);
|
|
56787
56949
|
fs2.writeFileSync(certKeyPath, cert.privateKey);
|
|
56788
|
-
|
|
56950
|
+
debugLog2("storage", "Certificate and private key stored successfully", options22?.verbose);
|
|
56789
56951
|
return certPath;
|
|
56790
56952
|
}
|
|
56791
56953
|
function storeCACert(caCert, options22) {
|
|
56792
|
-
|
|
56954
|
+
debugLog2("storage", "Storing CA certificate", options22?.verbose);
|
|
56793
56955
|
const caCertPath = options22?.caCertPath || config42.caCertPath;
|
|
56794
|
-
|
|
56956
|
+
debugLog2("storage", `CA certificate path: ${caCertPath}`, options22?.verbose);
|
|
56795
56957
|
const caCertDir = path3.dirname(caCertPath);
|
|
56796
56958
|
if (!fs2.existsSync(caCertDir)) {
|
|
56797
|
-
|
|
56959
|
+
debugLog2("storage", `Creating CA certificate directory: ${caCertDir}`, options22?.verbose);
|
|
56798
56960
|
fs2.mkdirSync(caCertDir, { recursive: true });
|
|
56799
56961
|
}
|
|
56800
|
-
|
|
56962
|
+
debugLog2("storage", "Writing CA certificate file", options22?.verbose);
|
|
56801
56963
|
fs2.writeFileSync(caCertPath, caCert);
|
|
56802
|
-
|
|
56964
|
+
debugLog2("storage", "CA certificate stored successfully", options22?.verbose);
|
|
56803
56965
|
return caCertPath;
|
|
56804
56966
|
}
|
|
56805
56967
|
var export_tls = import_node_forge2.tls;
|
|
@@ -56807,8 +56969,37 @@ var export_pki = import_node_forge2.pki;
|
|
|
56807
56969
|
var export_forge = import_node_forge2.default;
|
|
56808
56970
|
|
|
56809
56971
|
// src/https.ts
|
|
56972
|
+
function httpsConfig() {
|
|
56973
|
+
const domain = config.to || "stacks.localhost";
|
|
56974
|
+
const defaultConfig = {
|
|
56975
|
+
domain,
|
|
56976
|
+
hostCertCN: domain,
|
|
56977
|
+
caCertPath: path6.join(os7.homedir(), ".stacks", "ssl", `${domain}.ca.crt`),
|
|
56978
|
+
certPath: path6.join(os7.homedir(), ".stacks", "ssl", `${domain}.crt`),
|
|
56979
|
+
keyPath: path6.join(os7.homedir(), ".stacks", "ssl", `${domain}.crt.key`),
|
|
56980
|
+
altNameIPs: ["127.0.0.1"],
|
|
56981
|
+
altNameURIs: ["localhost"],
|
|
56982
|
+
organizationName: "stacksjs.org",
|
|
56983
|
+
countryName: "US",
|
|
56984
|
+
stateName: "California",
|
|
56985
|
+
localityName: "Playa Vista",
|
|
56986
|
+
commonName: domain,
|
|
56987
|
+
validityDays: 180,
|
|
56988
|
+
verbose: false
|
|
56989
|
+
};
|
|
56990
|
+
if (config.https === true)
|
|
56991
|
+
return defaultConfig;
|
|
56992
|
+
return {
|
|
56993
|
+
...defaultConfig,
|
|
56994
|
+
...config.https
|
|
56995
|
+
};
|
|
56996
|
+
}
|
|
56810
56997
|
async function generateCertificate(domain) {
|
|
56811
|
-
|
|
56998
|
+
if (config.https === true)
|
|
56999
|
+
config.https = httpsConfig();
|
|
57000
|
+
else if (config.https === false)
|
|
57001
|
+
return;
|
|
57002
|
+
domain = domain ?? config.https.domain;
|
|
56812
57003
|
log.info(`Generating a self-signed SSL certificate for: ${domain}`);
|
|
56813
57004
|
const caCert = await createRootCA(config.https);
|
|
56814
57005
|
const hostCert = await generateCert({
|
|
@@ -56830,71 +57021,100 @@ async function generateCertificate(domain) {
|
|
|
56830
57021
|
await addCertToSystemTrustStoreAndSaveCert(hostCert, caCert.certificate, config.https);
|
|
56831
57022
|
log.success("Certificate generated");
|
|
56832
57023
|
}
|
|
56833
|
-
|
|
56834
|
-
|
|
56835
|
-
|
|
56836
|
-
|
|
56837
|
-
|
|
56838
|
-
|
|
56839
|
-
|
|
57024
|
+
// src/start.ts
|
|
57025
|
+
import * as fs5 from "fs";
|
|
57026
|
+
import * as http from "http";
|
|
57027
|
+
import * as https from "https";
|
|
57028
|
+
import * as net from "net";
|
|
57029
|
+
import os8 from "os";
|
|
57030
|
+
import path7 from "path";
|
|
57031
|
+
import process9 from "process";
|
|
57032
|
+
// package.json
|
|
57033
|
+
var version = "0.3.0";
|
|
56840
57034
|
|
|
56841
57035
|
// src/start.ts
|
|
56842
57036
|
var activeServers = new Set;
|
|
56843
|
-
function cleanup() {
|
|
56844
|
-
|
|
57037
|
+
async function cleanup() {
|
|
57038
|
+
debugLog("cleanup", "Starting cleanup process", config.verbose);
|
|
56845
57039
|
console.log(`\n`);
|
|
56846
57040
|
log.info("Shutting down proxy servers...");
|
|
56847
|
-
const
|
|
57041
|
+
const cleanupPromises = [];
|
|
57042
|
+
const serverClosePromises = Array.from(activeServers).map((server) => new Promise((resolve4) => {
|
|
56848
57043
|
server.close(() => {
|
|
56849
|
-
|
|
57044
|
+
debugLog("cleanup", "Server closed successfully", config.verbose);
|
|
56850
57045
|
resolve4();
|
|
56851
57046
|
});
|
|
56852
57047
|
}));
|
|
56853
|
-
|
|
56854
|
-
|
|
56855
|
-
|
|
56856
|
-
|
|
56857
|
-
|
|
56858
|
-
|
|
56859
|
-
|
|
56860
|
-
|
|
56861
|
-
|
|
57048
|
+
cleanupPromises.push(...serverClosePromises);
|
|
57049
|
+
if (config.etcHostsCleanup) {
|
|
57050
|
+
debugLog("cleanup", "Cleaning up hosts file entries", config.verbose);
|
|
57051
|
+
try {
|
|
57052
|
+
const toUrl = new URL(config.to.startsWith("http") ? config.to : `http://${config.to}`);
|
|
57053
|
+
const hostname = toUrl.hostname;
|
|
57054
|
+
if (!hostname.includes("localhost") && !hostname.includes("127.0.0.1")) {
|
|
57055
|
+
log.info("Cleaning up hosts file entries...");
|
|
57056
|
+
cleanupPromises.push(removeHosts([hostname]).then(() => {
|
|
57057
|
+
debugLog("cleanup", `Removed hosts entry for ${hostname}`, config.verbose);
|
|
57058
|
+
}).catch((err3) => {
|
|
57059
|
+
debugLog("cleanup", `Failed to remove hosts entry: ${err3}`, config.verbose);
|
|
57060
|
+
log.warn(`Failed to clean up hosts file entry for ${hostname}:`, err3);
|
|
57061
|
+
}));
|
|
57062
|
+
}
|
|
57063
|
+
} catch (err3) {
|
|
57064
|
+
debugLog("cleanup", `Error parsing URL during hosts cleanup: ${err3}`, config.verbose);
|
|
57065
|
+
log.warn("Failed to parse URL for hosts cleanup:", err3);
|
|
57066
|
+
}
|
|
57067
|
+
}
|
|
57068
|
+
try {
|
|
57069
|
+
await Promise.all(cleanupPromises);
|
|
57070
|
+
debugLog("cleanup", "All cleanup tasks completed successfully", config.verbose);
|
|
57071
|
+
log.success("All cleanup tasks completed successfully");
|
|
57072
|
+
process9.exit(0);
|
|
57073
|
+
} catch (err3) {
|
|
57074
|
+
debugLog("cleanup", `Error during cleanup: ${err3}`, config.verbose);
|
|
57075
|
+
log.error("Error during cleanup:", err3);
|
|
57076
|
+
process9.exit(1);
|
|
57077
|
+
}
|
|
56862
57078
|
}
|
|
56863
|
-
|
|
56864
|
-
|
|
56865
|
-
|
|
56866
|
-
|
|
57079
|
+
process9.on("SIGINT", cleanup);
|
|
57080
|
+
process9.on("SIGTERM", cleanup);
|
|
57081
|
+
process9.on("uncaughtException", (err3) => {
|
|
57082
|
+
debugLog("process", `Uncaught exception: ${err3}`, config.verbose);
|
|
56867
57083
|
log.error("Uncaught exception:", err3);
|
|
56868
57084
|
cleanup();
|
|
56869
57085
|
});
|
|
56870
57086
|
async function loadSSLConfig(options3) {
|
|
56871
|
-
|
|
57087
|
+
debugLog("ssl", "Loading SSL configuration", options3.verbose);
|
|
57088
|
+
if (options3.https === true)
|
|
57089
|
+
options3.https = httpsConfig();
|
|
57090
|
+
else if (options3.https === false)
|
|
57091
|
+
return null;
|
|
56872
57092
|
if (!options3.https?.keyPath && !options3.https?.certPath) {
|
|
56873
|
-
|
|
57093
|
+
debugLog("ssl", "No SSL configuration provided", options3.verbose);
|
|
56874
57094
|
return null;
|
|
56875
57095
|
}
|
|
56876
57096
|
if (options3.https?.keyPath && !options3.https?.certPath || !options3.https?.keyPath && options3.https?.certPath) {
|
|
56877
57097
|
const missing = !options3.https?.keyPath ? "keyPath" : "certPath";
|
|
56878
|
-
|
|
57098
|
+
debugLog("ssl", `Invalid SSL configuration - missing ${missing}`, options3.verbose);
|
|
56879
57099
|
throw new Error(`SSL Configuration requires both keyPath and certPath. Missing: ${missing}`);
|
|
56880
57100
|
}
|
|
56881
57101
|
try {
|
|
56882
57102
|
if (!options3.https?.keyPath || !options3.https?.certPath)
|
|
56883
57103
|
return null;
|
|
56884
57104
|
try {
|
|
56885
|
-
|
|
56886
|
-
const key = await
|
|
56887
|
-
const cert = await
|
|
56888
|
-
|
|
57105
|
+
debugLog("ssl", "Reading SSL certificate files", options3.verbose);
|
|
57106
|
+
const key = await fs5.promises.readFile(options3.https?.keyPath, "utf8");
|
|
57107
|
+
const cert = await fs5.promises.readFile(options3.https?.certPath, "utf8");
|
|
57108
|
+
debugLog("ssl", "SSL configuration loaded successfully", options3.verbose);
|
|
56889
57109
|
return { key, cert };
|
|
56890
57110
|
} catch (error) {
|
|
56891
57111
|
if (error.code === "ENOENT") {
|
|
56892
|
-
|
|
56893
|
-
await generateCertificate();
|
|
56894
|
-
|
|
56895
|
-
const key = await
|
|
56896
|
-
const cert = await
|
|
56897
|
-
|
|
57112
|
+
debugLog("ssl", "Certificates not found, generating new ones", options3.verbose);
|
|
57113
|
+
await generateCertificate(options3.to);
|
|
57114
|
+
debugLog("ssl", "Reading newly generated certificates", options3.verbose);
|
|
57115
|
+
const key = await fs5.promises.readFile(options3.https?.keyPath, "utf8");
|
|
57116
|
+
const cert = await fs5.promises.readFile(options3.https?.certPath, "utf8");
|
|
57117
|
+
debugLog("ssl", "New SSL certificates loaded successfully", options3.verbose);
|
|
56898
57118
|
return { key, cert };
|
|
56899
57119
|
}
|
|
56900
57120
|
throw error;
|
|
@@ -56902,22 +57122,22 @@ async function loadSSLConfig(options3) {
|
|
|
56902
57122
|
} catch (err3) {
|
|
56903
57123
|
const error = err3;
|
|
56904
57124
|
const detail = error.code === "ENOENT" ? `File not found: ${error.path}` : error.message;
|
|
56905
|
-
|
|
57125
|
+
debugLog("ssl", `SSL configuration error: ${error}`, options3.verbose);
|
|
56906
57126
|
throw new Error(`SSL Configuration Error: ${detail}`);
|
|
56907
57127
|
}
|
|
56908
57128
|
}
|
|
56909
57129
|
function isPortInUse(port, hostname, verbose) {
|
|
56910
|
-
|
|
57130
|
+
debugLog("port", `Checking if port ${port} is in use on ${hostname}`, verbose);
|
|
56911
57131
|
return new Promise((resolve4) => {
|
|
56912
57132
|
const server = net.createServer();
|
|
56913
57133
|
server.once("error", (err3) => {
|
|
56914
57134
|
if (err3.code === "EADDRINUSE") {
|
|
56915
|
-
|
|
57135
|
+
debugLog("port", `Port ${port} is in use`, verbose);
|
|
56916
57136
|
resolve4(true);
|
|
56917
57137
|
}
|
|
56918
57138
|
});
|
|
56919
57139
|
server.once("listening", () => {
|
|
56920
|
-
|
|
57140
|
+
debugLog("port", `Port ${port} is available`, verbose);
|
|
56921
57141
|
server.close();
|
|
56922
57142
|
resolve4(false);
|
|
56923
57143
|
});
|
|
@@ -56925,17 +57145,17 @@ function isPortInUse(port, hostname, verbose) {
|
|
|
56925
57145
|
});
|
|
56926
57146
|
}
|
|
56927
57147
|
async function findAvailablePort(startPort, hostname, verbose) {
|
|
56928
|
-
|
|
57148
|
+
debugLog("port", `Finding available port starting from ${startPort}`, verbose);
|
|
56929
57149
|
let port = startPort;
|
|
56930
57150
|
while (await isPortInUse(port, hostname, verbose)) {
|
|
56931
|
-
|
|
57151
|
+
debugLog("port", `Port ${port} is in use, trying ${port + 1}`, verbose);
|
|
56932
57152
|
port++;
|
|
56933
57153
|
}
|
|
56934
|
-
|
|
57154
|
+
debugLog("port", `Found available port: ${port}`, verbose);
|
|
56935
57155
|
return port;
|
|
56936
57156
|
}
|
|
56937
57157
|
async function testConnection(hostname, port, verbose) {
|
|
56938
|
-
|
|
57158
|
+
debugLog("connection", `Testing connection to ${hostname}:${port}`, verbose);
|
|
56939
57159
|
return new Promise((resolve4, reject) => {
|
|
56940
57160
|
const socket = net.connect({
|
|
56941
57161
|
host: hostname,
|
|
@@ -56943,54 +57163,89 @@ async function testConnection(hostname, port, verbose) {
|
|
|
56943
57163
|
timeout: 5000
|
|
56944
57164
|
});
|
|
56945
57165
|
socket.once("connect", () => {
|
|
56946
|
-
|
|
57166
|
+
debugLog("connection", `Successfully connected to ${hostname}:${port}`, verbose);
|
|
56947
57167
|
socket.end();
|
|
56948
57168
|
resolve4();
|
|
56949
57169
|
});
|
|
56950
57170
|
socket.once("timeout", () => {
|
|
56951
|
-
|
|
57171
|
+
debugLog("connection", `Connection to ${hostname}:${port} timed out`, verbose);
|
|
56952
57172
|
socket.destroy();
|
|
56953
57173
|
reject(new Error(`Connection to ${hostname}:${port} timed out`));
|
|
56954
57174
|
});
|
|
56955
57175
|
socket.once("error", (err3) => {
|
|
56956
|
-
|
|
57176
|
+
debugLog("connection", `Failed to connect to ${hostname}:${port}: ${err3}`, verbose);
|
|
56957
57177
|
socket.destroy();
|
|
56958
57178
|
reject(new Error(`Failed to connect to ${hostname}:${port}: ${err3.message}`));
|
|
56959
57179
|
});
|
|
56960
57180
|
});
|
|
56961
57181
|
}
|
|
56962
57182
|
async function startServer(options3) {
|
|
56963
|
-
|
|
57183
|
+
debugLog("server", `Starting server with options: ${JSON.stringify(options3)}`, options3?.verbose);
|
|
56964
57184
|
if (!options3)
|
|
56965
57185
|
options3 = config;
|
|
56966
57186
|
if (!options3.from)
|
|
56967
57187
|
options3.from = config.from;
|
|
56968
57188
|
if (!options3.to)
|
|
56969
57189
|
options3.to = config.to;
|
|
56970
|
-
if (config.https) {
|
|
56971
|
-
const domain = config.https.altNameURIs?.[0] || new URL(options3.to).hostname;
|
|
56972
|
-
options3.keyPath = config.https.keyPath || `/Users/${process3.env.USER}/.stacks/ssl/${domain}.crt.key`;
|
|
56973
|
-
options3.certPath = config.https.certPath || `/Users/${process3.env.USER}/.stacks/ssl/${domain}.crt`;
|
|
56974
|
-
debugLog2("server", `HTTPS enabled, using cert paths: ${options3.keyPath}, ${options3.certPath}`, options3.verbose);
|
|
56975
|
-
}
|
|
56976
57190
|
const fromUrl = new URL(options3.from.startsWith("http") ? options3.from : `http://${options3.from}`);
|
|
56977
57191
|
const toUrl = new URL(options3.to.startsWith("http") ? options3.to : `http://${options3.to}`);
|
|
56978
57192
|
const fromPort = Number.parseInt(fromUrl.port) || (fromUrl.protocol.includes("https:") ? 443 : 80);
|
|
56979
|
-
|
|
57193
|
+
const hostsToCheck = [toUrl.hostname];
|
|
57194
|
+
if (!toUrl.hostname.includes("localhost") && !toUrl.hostname.includes("127.0.0.1")) {
|
|
57195
|
+
debugLog("hosts", `Checking if hosts file entry exists for: ${toUrl.hostname}`, options3.verbose);
|
|
57196
|
+
try {
|
|
57197
|
+
const hostsExist = await checkHosts(hostsToCheck);
|
|
57198
|
+
if (!hostsExist[0]) {
|
|
57199
|
+
log.info(`Adding ${toUrl.hostname} to hosts file...`);
|
|
57200
|
+
log.info("This may require sudo/administrator privileges");
|
|
57201
|
+
try {
|
|
57202
|
+
await addHosts(hostsToCheck);
|
|
57203
|
+
} catch (addError) {
|
|
57204
|
+
log.error("Failed to add hosts entry:", addError.message);
|
|
57205
|
+
log.warn("You can manually add this entry to your hosts file:");
|
|
57206
|
+
log.warn(`127.0.0.1 ${toUrl.hostname}`);
|
|
57207
|
+
log.warn(`::1 ${toUrl.hostname}`);
|
|
57208
|
+
if (process9.platform === "win32") {
|
|
57209
|
+
log.warn("On Windows:");
|
|
57210
|
+
log.warn("1. Run notepad as administrator");
|
|
57211
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
57212
|
+
} else {
|
|
57213
|
+
log.warn("On Unix systems:");
|
|
57214
|
+
log.warn("sudo nano /etc/hosts");
|
|
57215
|
+
}
|
|
57216
|
+
}
|
|
57217
|
+
} else {
|
|
57218
|
+
debugLog("hosts", `Host entry already exists for ${toUrl.hostname}`, options3.verbose);
|
|
57219
|
+
}
|
|
57220
|
+
} catch (checkError) {
|
|
57221
|
+
log.error("Failed to check hosts file:", checkError.message);
|
|
57222
|
+
}
|
|
57223
|
+
}
|
|
57224
|
+
if (config.https) {
|
|
57225
|
+
if (config.https === true)
|
|
57226
|
+
config.https = httpsConfig();
|
|
57227
|
+
const domain = toUrl.hostname;
|
|
57228
|
+
if (typeof options3.https !== "boolean" && options3.https) {
|
|
57229
|
+
options3.https.keyPath = config.https.keyPath || path7.join(os8.homedir(), ".stacks", "ssl", `${domain}.crt.key`);
|
|
57230
|
+
options3.https.certPath = config.https.certPath || path7.join(os8.homedir(), ".stacks", "ssl", `${domain}.crt`);
|
|
57231
|
+
debugLog("server", `HTTPS enabled, using cert paths: ${options3.https.keyPath}, ${options3.https.certPath}`, options3.verbose);
|
|
57232
|
+
}
|
|
57233
|
+
}
|
|
57234
|
+
debugLog("server", `Parsed URLs - from: ${fromUrl}, to: ${toUrl}`, options3.verbose);
|
|
56980
57235
|
try {
|
|
56981
57236
|
await testConnection(fromUrl.hostname, fromPort, options3.verbose);
|
|
56982
57237
|
} catch (err3) {
|
|
56983
|
-
|
|
57238
|
+
debugLog("server", `Connection test failed: ${err3}`, options3.verbose);
|
|
56984
57239
|
log.error(err3.message);
|
|
56985
|
-
|
|
57240
|
+
process9.exit(1);
|
|
56986
57241
|
}
|
|
56987
57242
|
let sslConfig = null;
|
|
56988
57243
|
if (config.https) {
|
|
56989
57244
|
try {
|
|
56990
57245
|
sslConfig = await loadSSLConfig(options3);
|
|
56991
57246
|
} catch (err3) {
|
|
56992
|
-
|
|
56993
|
-
await generateCertificate();
|
|
57247
|
+
debugLog("server", `SSL config failed, attempting to generate certificates: ${err3}`, options3.verbose);
|
|
57248
|
+
await generateCertificate(options3.to);
|
|
56994
57249
|
sslConfig = await loadSSLConfig(options3);
|
|
56995
57250
|
}
|
|
56996
57251
|
}
|
|
@@ -57007,9 +57262,9 @@ async function startServer(options3) {
|
|
|
57007
57262
|
});
|
|
57008
57263
|
}
|
|
57009
57264
|
async function createProxyServer(from, to, fromPort, listenPort, hostname, sourceUrl, ssl, verbose) {
|
|
57010
|
-
|
|
57265
|
+
debugLog("proxy", `Creating proxy server ${from} -> ${to}`, verbose);
|
|
57011
57266
|
const requestHandler = (req, res) => {
|
|
57012
|
-
|
|
57267
|
+
debugLog("request", `Incoming request: ${req.method} ${req.url}`, verbose);
|
|
57013
57268
|
const proxyOptions = {
|
|
57014
57269
|
hostname: sourceUrl.hostname,
|
|
57015
57270
|
port: fromPort,
|
|
@@ -57020,9 +57275,9 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57020
57275
|
host: sourceUrl.host
|
|
57021
57276
|
}
|
|
57022
57277
|
};
|
|
57023
|
-
|
|
57278
|
+
debugLog("request", `Proxy request options: ${JSON.stringify(proxyOptions)}`, verbose);
|
|
57024
57279
|
const proxyReq = http.request(proxyOptions, (proxyRes) => {
|
|
57025
|
-
|
|
57280
|
+
debugLog("response", `Proxy response received with status ${proxyRes.statusCode}`, verbose);
|
|
57026
57281
|
const headers = {
|
|
57027
57282
|
...proxyRes.headers,
|
|
57028
57283
|
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
|
@@ -57032,7 +57287,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57032
57287
|
proxyRes.pipe(res);
|
|
57033
57288
|
});
|
|
57034
57289
|
proxyReq.on("error", (err3) => {
|
|
57035
|
-
|
|
57290
|
+
debugLog("request", `Proxy request failed: ${err3}`, verbose);
|
|
57036
57291
|
log.error("Proxy request failed:", err3);
|
|
57037
57292
|
res.writeHead(502);
|
|
57038
57293
|
res.end(`Proxy Error: ${err3.message}`);
|
|
@@ -57059,11 +57314,11 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57059
57314
|
allowHTTP1: true,
|
|
57060
57315
|
ALPNProtocols: ["h2", "http/1.1"]
|
|
57061
57316
|
} : undefined;
|
|
57062
|
-
|
|
57317
|
+
debugLog("server", `Creating server with SSL config: ${!!ssl}`, verbose);
|
|
57063
57318
|
const server = ssl && serverOptions ? https.createServer(serverOptions, requestHandler) : http.createServer(requestHandler);
|
|
57064
57319
|
if (ssl) {
|
|
57065
57320
|
server.on("secureConnection", (tlsSocket) => {
|
|
57066
|
-
|
|
57321
|
+
debugLog("tls", `TLS Connection established: ${JSON.stringify({
|
|
57067
57322
|
protocol: tlsSocket.getProtocol?.(),
|
|
57068
57323
|
cipher: tlsSocket.getCipher?.(),
|
|
57069
57324
|
authorized: tlsSocket.authorized,
|
|
@@ -57074,7 +57329,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57074
57329
|
activeServers.add(server);
|
|
57075
57330
|
return new Promise((resolve4, reject) => {
|
|
57076
57331
|
server.listen(listenPort, hostname, () => {
|
|
57077
|
-
|
|
57332
|
+
debugLog("server", `Server listening on port ${listenPort}`, verbose);
|
|
57078
57333
|
console.log("");
|
|
57079
57334
|
console.log(` ${green(bold("reverse-proxy"))} ${green(`v${version}`)}`);
|
|
57080
57335
|
console.log("");
|
|
@@ -57091,13 +57346,13 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57091
57346
|
resolve4();
|
|
57092
57347
|
});
|
|
57093
57348
|
server.on("error", (err3) => {
|
|
57094
|
-
|
|
57349
|
+
debugLog("server", `Server error: ${err3}`, verbose);
|
|
57095
57350
|
reject(err3);
|
|
57096
57351
|
});
|
|
57097
57352
|
});
|
|
57098
57353
|
}
|
|
57099
57354
|
async function setupReverseProxy(options3) {
|
|
57100
|
-
|
|
57355
|
+
debugLog("setup", `Setting up reverse proxy: ${JSON.stringify(options3)}`, options3.verbose);
|
|
57101
57356
|
const { from, to, fromPort, sourceUrl, ssl, verbose } = options3;
|
|
57102
57357
|
const httpPort = 80;
|
|
57103
57358
|
const httpsPort = 443;
|
|
@@ -57106,73 +57361,72 @@ async function setupReverseProxy(options3) {
|
|
|
57106
57361
|
if (ssl) {
|
|
57107
57362
|
const isHttpPortBusy = await isPortInUse(httpPort, hostname, verbose);
|
|
57108
57363
|
if (!isHttpPortBusy) {
|
|
57109
|
-
|
|
57364
|
+
debugLog("setup", "Starting HTTP redirect server", verbose);
|
|
57110
57365
|
startHttpRedirectServer(verbose);
|
|
57111
57366
|
} else {
|
|
57112
|
-
|
|
57367
|
+
debugLog("setup", "Port 80 is in use, skipping HTTP redirect", verbose);
|
|
57113
57368
|
log.warn("Port 80 is in use, HTTP to HTTPS redirect will not be available");
|
|
57114
57369
|
}
|
|
57115
57370
|
}
|
|
57116
57371
|
const targetPort = ssl ? httpsPort : httpPort;
|
|
57117
57372
|
const isTargetPortBusy = await isPortInUse(targetPort, hostname, verbose);
|
|
57118
57373
|
if (isTargetPortBusy) {
|
|
57119
|
-
|
|
57374
|
+
debugLog("setup", `Port ${targetPort} is busy, finding alternative`, verbose);
|
|
57120
57375
|
const availablePort = await findAvailablePort(ssl ? 8443 : 8080, hostname, verbose);
|
|
57121
57376
|
log.warn(`Port ${targetPort} is in use. Using port ${availablePort} instead.`);
|
|
57122
57377
|
log.info(`You can use 'sudo lsof -i :${targetPort}' (Unix) or 'netstat -ano | findstr :${targetPort}' (Windows) to check what's using the port.`);
|
|
57123
57378
|
await createProxyServer(from, to, fromPort, availablePort, hostname, sourceUrl, ssl, verbose);
|
|
57124
57379
|
} else {
|
|
57125
|
-
|
|
57380
|
+
debugLog("setup", `Using default port ${targetPort}`, verbose);
|
|
57126
57381
|
await createProxyServer(from, to, fromPort, targetPort, hostname, sourceUrl, ssl, verbose);
|
|
57127
57382
|
}
|
|
57128
57383
|
} catch (err3) {
|
|
57129
|
-
|
|
57384
|
+
debugLog("setup", `Setup failed: ${err3}`, verbose);
|
|
57130
57385
|
log.error(`Failed to setup reverse proxy: ${err3.message}`);
|
|
57131
57386
|
cleanup();
|
|
57132
57387
|
}
|
|
57133
57388
|
}
|
|
57134
57389
|
function startHttpRedirectServer(verbose) {
|
|
57135
|
-
|
|
57390
|
+
debugLog("redirect", "Starting HTTP redirect server", verbose);
|
|
57136
57391
|
const server = http.createServer((req, res) => {
|
|
57137
57392
|
const host = req.headers.host || "";
|
|
57138
|
-
|
|
57393
|
+
debugLog("redirect", `Redirecting request from ${host}${req.url} to HTTPS`, verbose);
|
|
57139
57394
|
res.writeHead(301, {
|
|
57140
57395
|
Location: `https://${host}${req.url}`
|
|
57141
57396
|
});
|
|
57142
57397
|
res.end();
|
|
57143
57398
|
}).listen(80);
|
|
57144
57399
|
activeServers.add(server);
|
|
57145
|
-
|
|
57400
|
+
debugLog("redirect", "HTTP redirect server started", verbose);
|
|
57146
57401
|
}
|
|
57147
57402
|
function startProxy(options3) {
|
|
57148
57403
|
const finalOptions = {
|
|
57149
57404
|
...config,
|
|
57150
57405
|
...options3
|
|
57151
57406
|
};
|
|
57152
|
-
|
|
57407
|
+
debugLog("proxy", `Starting proxy with options: ${JSON.stringify({
|
|
57153
57408
|
from: finalOptions.from,
|
|
57154
57409
|
to: finalOptions.to,
|
|
57155
|
-
|
|
57156
|
-
certPath: finalOptions.https.certPath
|
|
57410
|
+
https: finalOptions.https
|
|
57157
57411
|
})}`, finalOptions.verbose);
|
|
57158
57412
|
startServer(finalOptions).catch((err3) => {
|
|
57159
|
-
|
|
57413
|
+
debugLog("proxy", `Failed to start proxy: ${err3}`, finalOptions.verbose);
|
|
57160
57414
|
log.error(`Failed to start proxy: ${err3.message}`);
|
|
57161
57415
|
cleanup();
|
|
57162
57416
|
});
|
|
57163
57417
|
}
|
|
57164
57418
|
function startProxies(options3) {
|
|
57165
57419
|
if (Array.isArray(options3)) {
|
|
57166
|
-
|
|
57420
|
+
debugLog("proxies", `Starting multiple proxies: ${options3.length}`, options3[0]?.verbose);
|
|
57167
57421
|
Promise.all(options3.map((option) => startServer(option))).catch((err3) => {
|
|
57168
|
-
|
|
57422
|
+
debugLog("proxies", `Failed to start proxies: ${err3}`, options3[0]?.verbose);
|
|
57169
57423
|
log.error("Failed to start proxies:", err3);
|
|
57170
57424
|
cleanup();
|
|
57171
57425
|
});
|
|
57172
57426
|
} else if (options3) {
|
|
57173
|
-
|
|
57427
|
+
debugLog("proxies", "Starting single proxy", options3.verbose);
|
|
57174
57428
|
startServer(options3).catch((err3) => {
|
|
57175
|
-
|
|
57429
|
+
debugLog("proxies", `Failed to start proxy: ${err3}`, options3.verbose);
|
|
57176
57430
|
log.error("Failed to start proxy:", err3);
|
|
57177
57431
|
cleanup();
|
|
57178
57432
|
});
|
|
@@ -57184,5 +57438,12 @@ export {
|
|
|
57184
57438
|
startProxies,
|
|
57185
57439
|
startHttpRedirectServer,
|
|
57186
57440
|
setupReverseProxy,
|
|
57187
|
-
|
|
57441
|
+
removeHosts,
|
|
57442
|
+
httpsConfig,
|
|
57443
|
+
hostsFilePath,
|
|
57444
|
+
generateCertificate,
|
|
57445
|
+
config,
|
|
57446
|
+
cleanup,
|
|
57447
|
+
checkHosts,
|
|
57448
|
+
addHosts
|
|
57188
57449
|
};
|