@stacksjs/rpx 0.2.0 → 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 +1 -0
- package/dist/cli.js +423 -216
- package/dist/hosts.d.ts +5 -0
- package/dist/https.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +441 -230
- package/dist/start.d.ts +1 -1
- package/dist/types.d.ts +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -77,16 +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
|
|
88
|
-
import os7 from "os";
|
|
89
|
-
import path6 from "path";
|
|
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";
|
|
90
89
|
import process3 from "process";
|
|
91
90
|
|
|
92
91
|
// node_modules/@stacksjs/cli/dist/index.js
|
|
@@ -20397,12 +20396,167 @@ var quotes = collect([
|
|
|
20397
20396
|
"Security is mostly a superstition. Life is either a daring adventure or nothing."
|
|
20398
20397
|
]);
|
|
20399
20398
|
var export_prompts = import_prompts.default;
|
|
20400
|
-
// package.json
|
|
20401
|
-
var version = "0.2.0";
|
|
20402
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
|
+
}
|
|
20403
20557
|
// src/https.ts
|
|
20404
|
-
import
|
|
20405
|
-
import
|
|
20558
|
+
import os7 from "os";
|
|
20559
|
+
import path6 from "path";
|
|
20406
20560
|
|
|
20407
20561
|
// node_modules/@stacksjs/tlsx/dist/index.js
|
|
20408
20562
|
import fs2 from "fs";
|
|
@@ -20441,7 +20595,7 @@ import process8 from "process";
|
|
|
20441
20595
|
import process102 from "process";
|
|
20442
20596
|
import process182 from "process";
|
|
20443
20597
|
import process112 from "process";
|
|
20444
|
-
import
|
|
20598
|
+
import os5 from "os";
|
|
20445
20599
|
import tty32 from "tty";
|
|
20446
20600
|
import process142 from "process";
|
|
20447
20601
|
import process132 from "process";
|
|
@@ -20450,10 +20604,10 @@ import process162 from "process";
|
|
|
20450
20604
|
import process172 from "process";
|
|
20451
20605
|
import process192 from "process";
|
|
20452
20606
|
import os22 from "os";
|
|
20453
|
-
import
|
|
20607
|
+
import path4 from "path";
|
|
20454
20608
|
import { resolve as resolve3 } from "path";
|
|
20455
20609
|
import process22 from "process";
|
|
20456
|
-
import
|
|
20610
|
+
import fs3 from "fs";
|
|
20457
20611
|
import path22 from "path";
|
|
20458
20612
|
var __create3 = Object.create;
|
|
20459
20613
|
var __getProtoOf3 = Object.getPrototypeOf;
|
|
@@ -32503,14 +32657,14 @@ var require_tls = __commonJS2((exports, module) => {
|
|
|
32503
32657
|
c2.version = c2.session.version = session.version;
|
|
32504
32658
|
c2.session.sp = session.sp;
|
|
32505
32659
|
} else {
|
|
32506
|
-
var
|
|
32660
|
+
var version;
|
|
32507
32661
|
for (var i = 1;i < tls.SupportedVersions.length; ++i) {
|
|
32508
|
-
|
|
32509
|
-
if (
|
|
32662
|
+
version = tls.SupportedVersions[i];
|
|
32663
|
+
if (version.minor <= msg.version.minor) {
|
|
32510
32664
|
break;
|
|
32511
32665
|
}
|
|
32512
32666
|
}
|
|
32513
|
-
c2.version = { major:
|
|
32667
|
+
c2.version = { major: version.major, minor: version.minor };
|
|
32514
32668
|
c2.session.version = c2.version;
|
|
32515
32669
|
}
|
|
32516
32670
|
if (session !== null) {
|
|
@@ -32681,8 +32835,8 @@ var require_tls = __commonJS2((exports, module) => {
|
|
|
32681
32835
|
try {
|
|
32682
32836
|
var sp = c2.session.sp;
|
|
32683
32837
|
sp.pre_master_secret = privateKey.decrypt(msg.enc_pre_master_secret);
|
|
32684
|
-
var
|
|
32685
|
-
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)) {
|
|
32686
32840
|
throw new Error("TLS version rollback attack detected.");
|
|
32687
32841
|
}
|
|
32688
32842
|
} catch (ex) {
|
|
@@ -38625,16 +38779,16 @@ var require_isIP2 = __commonJS22((exports, module) => {
|
|
|
38625
38779
|
var IPv6SegmentFormat = "(?:[0-9a-fA-F]{1,4})";
|
|
38626
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,})?$");
|
|
38627
38781
|
function isIP(str) {
|
|
38628
|
-
var
|
|
38782
|
+
var version = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
38629
38783
|
(0, _assertString.default)(str);
|
|
38630
|
-
|
|
38631
|
-
if (!
|
|
38784
|
+
version = String(version);
|
|
38785
|
+
if (!version) {
|
|
38632
38786
|
return isIP(str, 4) || isIP(str, 6);
|
|
38633
38787
|
}
|
|
38634
|
-
if (
|
|
38788
|
+
if (version === "4") {
|
|
38635
38789
|
return IPv4AddressRegExp.test(str);
|
|
38636
38790
|
}
|
|
38637
|
-
if (
|
|
38791
|
+
if (version === "6") {
|
|
38638
38792
|
return IPv6AddressRegExp.test(str);
|
|
38639
38793
|
}
|
|
38640
38794
|
return false;
|
|
@@ -39156,9 +39310,9 @@ var require_isUUID2 = __commonJS22((exports, module) => {
|
|
|
39156
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,
|
|
39157
39311
|
all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
|
|
39158
39312
|
};
|
|
39159
|
-
function isUUID(str,
|
|
39313
|
+
function isUUID(str, version) {
|
|
39160
39314
|
(0, _assertString.default)(str);
|
|
39161
|
-
var pattern = uuid[![undefined, null].includes(
|
|
39315
|
+
var pattern = uuid[![undefined, null].includes(version) ? version : "all"];
|
|
39162
39316
|
return !!pattern && pattern.test(str);
|
|
39163
39317
|
}
|
|
39164
39318
|
module.exports = exports.default;
|
|
@@ -51335,7 +51489,7 @@ var uuidRule2 = createRule2((value, options2, field) => {
|
|
|
51335
51489
|
field.report(messages2.uuid, "uuid", field);
|
|
51336
51490
|
}
|
|
51337
51491
|
} else {
|
|
51338
|
-
const matchesAnyVersion = options2.version.find((
|
|
51492
|
+
const matchesAnyVersion = options2.version.find((version) => helpers32.isUUID(value, version));
|
|
51339
51493
|
if (!matchesAnyVersion) {
|
|
51340
51494
|
field.report(messages2.uuid, "uuid", field, options2);
|
|
51341
51495
|
}
|
|
@@ -51430,8 +51584,8 @@ var VineString2 = class _VineString2 extends BaseLiteralType2 {
|
|
|
51430
51584
|
mobile(...args) {
|
|
51431
51585
|
return this.use(mobileRule2(...args));
|
|
51432
51586
|
}
|
|
51433
|
-
ipAddress(
|
|
51434
|
-
return this.use(ipAddressRule2(
|
|
51587
|
+
ipAddress(version) {
|
|
51588
|
+
return this.use(ipAddressRule2(version ? { version } : undefined));
|
|
51435
51589
|
}
|
|
51436
51590
|
hexCode() {
|
|
51437
51591
|
return this.use(hexCodeRule2());
|
|
@@ -53944,7 +54098,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
53944
54098
|
return min;
|
|
53945
54099
|
}
|
|
53946
54100
|
if (process112.platform === "win32") {
|
|
53947
|
-
const osRelease =
|
|
54101
|
+
const osRelease = os5.release().split(".");
|
|
53948
54102
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
53949
54103
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
53950
54104
|
}
|
|
@@ -56511,18 +56665,18 @@ var config42 = await loadConfig2({
|
|
|
56511
56665
|
defaultConfig: {
|
|
56512
56666
|
altNameIPs: ["127.0.0.1"],
|
|
56513
56667
|
altNameURIs: ["localhost"],
|
|
56514
|
-
organizationName: "
|
|
56668
|
+
organizationName: "Local Development",
|
|
56515
56669
|
countryName: "US",
|
|
56516
56670
|
stateName: "California",
|
|
56517
56671
|
localityName: "Playa Vista",
|
|
56518
56672
|
commonName: "stacks.localhost",
|
|
56519
56673
|
validityDays: 180,
|
|
56520
56674
|
hostCertCN: "stacks.localhost",
|
|
56521
|
-
domain: "localhost",
|
|
56675
|
+
domain: "stacks.localhost",
|
|
56522
56676
|
rootCAObject: { certificate: "", privateKey: "" },
|
|
56523
|
-
caCertPath:
|
|
56524
|
-
certPath:
|
|
56525
|
-
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`),
|
|
56526
56680
|
verbose: false
|
|
56527
56681
|
}
|
|
56528
56682
|
});
|
|
@@ -56538,10 +56692,10 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56538
56692
|
const result = [];
|
|
56539
56693
|
function search(dir) {
|
|
56540
56694
|
try {
|
|
56541
|
-
const files =
|
|
56695
|
+
const files = fs3.readdirSync(dir);
|
|
56542
56696
|
for (const file of files) {
|
|
56543
56697
|
const filePath = path22.join(dir, file);
|
|
56544
|
-
const stats =
|
|
56698
|
+
const stats = fs3.lstatSync(filePath);
|
|
56545
56699
|
if (stats.isDirectory()) {
|
|
56546
56700
|
search(filePath);
|
|
56547
56701
|
} else if (file === fileName) {
|
|
@@ -56555,29 +56709,29 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56555
56709
|
search(rootDir);
|
|
56556
56710
|
return result;
|
|
56557
56711
|
}
|
|
56558
|
-
function
|
|
56712
|
+
function debugLog2(category, message, verbose) {
|
|
56559
56713
|
if (verbose || config42.verbose) {
|
|
56560
56714
|
console.debug(`[tlsx:${category}] ${message}`);
|
|
56561
56715
|
}
|
|
56562
56716
|
}
|
|
56563
56717
|
function randomSerialNumber(verbose) {
|
|
56564
|
-
|
|
56718
|
+
debugLog2("cert", "Generating random serial number", verbose);
|
|
56565
56719
|
const serialNumber = makeNumberPositive(import_node_forge2.default.util.bytesToHex(import_node_forge2.default.random.getBytesSync(20)));
|
|
56566
|
-
|
|
56720
|
+
debugLog2("cert", `Generated serial number: ${serialNumber}`, verbose);
|
|
56567
56721
|
return serialNumber;
|
|
56568
56722
|
}
|
|
56569
56723
|
function getCertNotBefore(verbose) {
|
|
56570
|
-
|
|
56724
|
+
debugLog2("cert", "Calculating certificate not-before date", verbose);
|
|
56571
56725
|
const twoDaysAgo = new Date(Date.now() - 172800000);
|
|
56572
56726
|
const year = twoDaysAgo.getFullYear();
|
|
56573
56727
|
const month = (twoDaysAgo.getMonth() + 1).toString().padStart(2, "0");
|
|
56574
56728
|
const day = twoDaysAgo.getDate().toString().padStart(2, "0");
|
|
56575
56729
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56576
|
-
|
|
56730
|
+
debugLog2("cert", `Certificate not-before date: ${date.toISOString()}`, verbose);
|
|
56577
56731
|
return date;
|
|
56578
56732
|
}
|
|
56579
56733
|
function getCertNotAfter(notBefore, verbose) {
|
|
56580
|
-
|
|
56734
|
+
debugLog2("cert", "Calculating certificate not-after date", verbose);
|
|
56581
56735
|
const validityDays = config42.validityDays;
|
|
56582
56736
|
const daysInMillis = validityDays * 60 * 60 * 24 * 1000;
|
|
56583
56737
|
const notAfterDate = new Date(notBefore.getTime() + daysInMillis);
|
|
@@ -56585,27 +56739,27 @@ function getCertNotAfter(notBefore, verbose) {
|
|
|
56585
56739
|
const month = (notAfterDate.getMonth() + 1).toString().padStart(2, "0");
|
|
56586
56740
|
const day = notAfterDate.getDate().toString().padStart(2, "0");
|
|
56587
56741
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56588
|
-
|
|
56742
|
+
debugLog2("cert", `Certificate not-after date: ${date.toISOString()} (${validityDays} days validity)`, verbose);
|
|
56589
56743
|
return date;
|
|
56590
56744
|
}
|
|
56591
56745
|
function getCANotAfter(notBefore, verbose) {
|
|
56592
|
-
|
|
56746
|
+
debugLog2("cert", "Calculating CA not-after date", verbose);
|
|
56593
56747
|
const year = notBefore.getFullYear() + 100;
|
|
56594
56748
|
const month = (notBefore.getMonth() + 1).toString().padStart(2, "0");
|
|
56595
56749
|
const day = notBefore.getDate().toString().padStart(2, "0");
|
|
56596
56750
|
const date = new Date(`${year}-${month}-${day}T23:59:59Z`);
|
|
56597
|
-
|
|
56751
|
+
debugLog2("cert", `CA not-after date: ${date.toISOString()} (100 years validity)`, verbose);
|
|
56598
56752
|
return date;
|
|
56599
56753
|
}
|
|
56600
56754
|
async function createRootCA(options22) {
|
|
56601
|
-
|
|
56602
|
-
|
|
56755
|
+
debugLog2("ca", "Creating new Root CA Certificate", options22?.verbose);
|
|
56756
|
+
debugLog2("ca", "Generating 2048-bit RSA key pair", options22?.verbose);
|
|
56603
56757
|
const { privateKey, publicKey } = import_node_forge2.pki.rsa.generateKeyPair(2048);
|
|
56604
56758
|
const mergedOptions = {
|
|
56605
56759
|
...config42,
|
|
56606
56760
|
...options22 || {}
|
|
56607
56761
|
};
|
|
56608
|
-
|
|
56762
|
+
debugLog2("ca", "Setting certificate attributes", options22?.verbose);
|
|
56609
56763
|
const attributes = [
|
|
56610
56764
|
{ shortName: "C", value: mergedOptions.countryName },
|
|
56611
56765
|
{ shortName: "ST", value: mergedOptions.stateName },
|
|
@@ -56613,7 +56767,7 @@ async function createRootCA(options22) {
|
|
|
56613
56767
|
{ shortName: "O", value: "Local Development CA" },
|
|
56614
56768
|
{ shortName: "CN", value: "Local Development Root CA" }
|
|
56615
56769
|
];
|
|
56616
|
-
|
|
56770
|
+
debugLog2("ca", "Setting certificate extensions", options22?.verbose);
|
|
56617
56771
|
const extensions = [
|
|
56618
56772
|
{
|
|
56619
56773
|
name: "basicConstraints",
|
|
@@ -56630,7 +56784,7 @@ async function createRootCA(options22) {
|
|
|
56630
56784
|
name: "subjectKeyIdentifier"
|
|
56631
56785
|
}
|
|
56632
56786
|
];
|
|
56633
|
-
|
|
56787
|
+
debugLog2("ca", "Creating CA certificate", options22?.verbose);
|
|
56634
56788
|
const caCert = import_node_forge2.pki.createCertificate();
|
|
56635
56789
|
caCert.publicKey = publicKey;
|
|
56636
56790
|
caCert.serialNumber = randomSerialNumber(options22?.verbose);
|
|
@@ -56639,11 +56793,11 @@ async function createRootCA(options22) {
|
|
|
56639
56793
|
caCert.setSubject(attributes);
|
|
56640
56794
|
caCert.setIssuer(attributes);
|
|
56641
56795
|
caCert.setExtensions(extensions);
|
|
56642
|
-
|
|
56796
|
+
debugLog2("ca", "Signing certificate with SHA-256", options22?.verbose);
|
|
56643
56797
|
caCert.sign(privateKey, import_node_forge2.default.md.sha256.create());
|
|
56644
56798
|
const pemCert = import_node_forge2.pki.certificateToPem(caCert);
|
|
56645
56799
|
const pemKey = import_node_forge2.pki.privateKeyToPem(privateKey);
|
|
56646
|
-
|
|
56800
|
+
debugLog2("ca", "Root CA Certificate created successfully", options22?.verbose);
|
|
56647
56801
|
return {
|
|
56648
56802
|
certificate: pemCert,
|
|
56649
56803
|
privateKey: pemKey,
|
|
@@ -56652,34 +56806,41 @@ async function createRootCA(options22) {
|
|
|
56652
56806
|
};
|
|
56653
56807
|
}
|
|
56654
56808
|
async function generateCert(options22) {
|
|
56655
|
-
|
|
56656
|
-
|
|
56809
|
+
debugLog2("cert", "Generating new host certificate", options22?.verbose);
|
|
56810
|
+
debugLog2("cert", `Options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
56657
56811
|
if (!options22?.hostCertCN?.trim()) {
|
|
56658
|
-
|
|
56812
|
+
debugLog2("cert", "Error: hostCertCN is required", options22?.verbose);
|
|
56659
56813
|
throw new Error('"hostCertCN" must be a String');
|
|
56660
56814
|
}
|
|
56661
56815
|
if (!options22.domain?.trim()) {
|
|
56662
|
-
|
|
56816
|
+
debugLog2("cert", "Error: domain is required", options22?.verbose);
|
|
56663
56817
|
throw new Error('"domain" must be a String');
|
|
56664
56818
|
}
|
|
56665
56819
|
if (!options22.rootCAObject || !options22.rootCAObject.certificate || !options22.rootCAObject.privateKey) {
|
|
56666
|
-
|
|
56820
|
+
debugLog2("cert", "Error: rootCAObject is invalid or missing", options22?.verbose);
|
|
56667
56821
|
throw new Error('"rootCAObject" must be an Object with the properties "certificate" & "privateKey"');
|
|
56668
56822
|
}
|
|
56669
|
-
|
|
56823
|
+
debugLog2("cert", "Converting Root CA PEM to forge objects", options22?.verbose);
|
|
56670
56824
|
const caCert = import_node_forge2.pki.certificateFromPem(options22.rootCAObject.certificate);
|
|
56671
56825
|
const caKey = import_node_forge2.pki.privateKeyFromPem(options22.rootCAObject.privateKey);
|
|
56672
|
-
|
|
56826
|
+
debugLog2("cert", "Generating 2048-bit RSA key pair for host certificate", options22?.verbose);
|
|
56673
56827
|
const hostKeys = import_node_forge2.pki.rsa.generateKeyPair(2048);
|
|
56674
|
-
|
|
56828
|
+
debugLog2("cert", "Setting certificate attributes", options22?.verbose);
|
|
56675
56829
|
const attributes = [
|
|
56676
|
-
{ shortName: "C", value: config42.countryName },
|
|
56677
|
-
{ shortName: "ST", value: config42.stateName },
|
|
56678
|
-
{ shortName: "L", value: config42.localityName },
|
|
56679
|
-
{ shortName: "O", value:
|
|
56680
|
-
{ 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 }
|
|
56681
56842
|
];
|
|
56682
|
-
|
|
56843
|
+
debugLog2("cert", "Setting certificate extensions", options22?.verbose);
|
|
56683
56844
|
const extensions = [
|
|
56684
56845
|
{
|
|
56685
56846
|
name: "basicConstraints",
|
|
@@ -56699,30 +56860,25 @@ async function generateCert(options22) {
|
|
|
56699
56860
|
},
|
|
56700
56861
|
{
|
|
56701
56862
|
name: "subjectAltName",
|
|
56702
|
-
altNames
|
|
56703
|
-
{ type: 2, value: "*.localhost" },
|
|
56704
|
-
{ type: 2, value: "localhost" },
|
|
56705
|
-
{ type: 2, value: "stacks.localhost" },
|
|
56706
|
-
{ type: 2, value: options22.domain }
|
|
56707
|
-
]
|
|
56863
|
+
altNames
|
|
56708
56864
|
}
|
|
56709
56865
|
];
|
|
56710
|
-
|
|
56866
|
+
debugLog2("cert", "Creating new host certificate", options22?.verbose);
|
|
56711
56867
|
const newHostCert = import_node_forge2.pki.createCertificate();
|
|
56712
56868
|
newHostCert.publicKey = hostKeys.publicKey;
|
|
56713
|
-
|
|
56869
|
+
debugLog2("cert", "Setting certificate properties", options22?.verbose);
|
|
56714
56870
|
newHostCert.serialNumber = randomSerialNumber(options22?.verbose);
|
|
56715
56871
|
newHostCert.validity.notBefore = getCertNotBefore(options22?.verbose);
|
|
56716
56872
|
newHostCert.validity.notAfter = getCertNotAfter(newHostCert.validity.notBefore, options22?.verbose);
|
|
56717
56873
|
newHostCert.setSubject(attributes);
|
|
56718
56874
|
newHostCert.setIssuer(caCert.subject.attributes);
|
|
56719
56875
|
newHostCert.setExtensions(extensions);
|
|
56720
|
-
|
|
56876
|
+
debugLog2("cert", "Signing certificate with SHA-256", options22?.verbose);
|
|
56721
56877
|
newHostCert.sign(caKey, import_node_forge2.default.md.sha256.create());
|
|
56722
|
-
|
|
56878
|
+
debugLog2("cert", "Converting certificate to PEM format", options22?.verbose);
|
|
56723
56879
|
const pemHostCert = import_node_forge2.pki.certificateToPem(newHostCert);
|
|
56724
56880
|
const pemHostKey = import_node_forge2.pki.privateKeyToPem(hostKeys.privateKey);
|
|
56725
|
-
|
|
56881
|
+
debugLog2("cert", "Host certificate generated successfully", options22?.verbose);
|
|
56726
56882
|
return {
|
|
56727
56883
|
certificate: pemHostCert,
|
|
56728
56884
|
privateKey: pemHostKey,
|
|
@@ -56731,81 +56887,81 @@ async function generateCert(options22) {
|
|
|
56731
56887
|
};
|
|
56732
56888
|
}
|
|
56733
56889
|
async function addCertToSystemTrustStoreAndSaveCert(cert, caCert, options22) {
|
|
56734
|
-
|
|
56735
|
-
|
|
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);
|
|
56736
56892
|
const certPath = storeCert(cert, options22);
|
|
56737
|
-
|
|
56893
|
+
debugLog2("trust", "Storing CA certificate", options22?.verbose);
|
|
56738
56894
|
const caCertPath = storeCACert(caCert, options22);
|
|
56739
56895
|
const platform22 = os4.platform();
|
|
56740
|
-
|
|
56896
|
+
debugLog2("trust", `Detected platform: ${platform22}`, options22?.verbose);
|
|
56741
56897
|
const args = "TC, C, C";
|
|
56742
56898
|
if (platform22 === "darwin") {
|
|
56743
|
-
|
|
56899
|
+
debugLog2("trust", "Adding certificate to macOS keychain", options22?.verbose);
|
|
56744
56900
|
await runCommand(`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${caCertPath}`);
|
|
56745
56901
|
} else if (platform22 === "win32") {
|
|
56746
|
-
|
|
56902
|
+
debugLog2("trust", "Adding certificate to Windows certificate store", options22?.verbose);
|
|
56747
56903
|
await runCommand(`certutil -f -v -addstore -enterprise Root ${caCertPath}`);
|
|
56748
56904
|
} else if (platform22 === "linux") {
|
|
56749
|
-
|
|
56905
|
+
debugLog2("trust", "Adding certificate to Linux certificate store", options22?.verbose);
|
|
56750
56906
|
const rootDirectory = os4.homedir();
|
|
56751
56907
|
const targetFileName = "cert9.db";
|
|
56752
|
-
|
|
56908
|
+
debugLog2("trust", `Searching for certificate databases in ${rootDirectory}`, options22?.verbose);
|
|
56753
56909
|
const foldersWithFile = findFoldersWithFile(rootDirectory, targetFileName);
|
|
56754
56910
|
for (const folder of foldersWithFile) {
|
|
56755
|
-
|
|
56911
|
+
debugLog2("trust", `Processing certificate database in ${folder}`, options22?.verbose);
|
|
56756
56912
|
try {
|
|
56757
|
-
|
|
56913
|
+
debugLog2("trust", `Attempting to delete existing cert for ${config42.commonName}`, options22?.verbose);
|
|
56758
56914
|
await runCommand(`certutil -d sql:${folder} -D -n ${config42.commonName}`);
|
|
56759
56915
|
} catch (error) {
|
|
56760
|
-
|
|
56916
|
+
debugLog2("trust", `Warning: Error deleting existing cert: ${error}`, options22?.verbose);
|
|
56761
56917
|
console.warn(`Error deleting existing cert: ${error}`);
|
|
56762
56918
|
}
|
|
56763
|
-
|
|
56919
|
+
debugLog2("trust", `Adding new certificate to ${folder}`, options22?.verbose);
|
|
56764
56920
|
await runCommand(`certutil -d sql:${folder} -A -t ${args} -n ${config42.commonName} -i ${caCertPath}`);
|
|
56765
56921
|
log2.info(`Cert added to ${folder}`);
|
|
56766
56922
|
}
|
|
56767
56923
|
} else {
|
|
56768
|
-
|
|
56924
|
+
debugLog2("trust", `Error: Unsupported platform ${platform22}`, options22?.verbose);
|
|
56769
56925
|
throw new Error(`Unsupported platform: ${platform22}`);
|
|
56770
56926
|
}
|
|
56771
|
-
|
|
56927
|
+
debugLog2("trust", "Certificate successfully added to system trust store", options22?.verbose);
|
|
56772
56928
|
return certPath;
|
|
56773
56929
|
}
|
|
56774
56930
|
function storeCert(cert, options22) {
|
|
56775
|
-
|
|
56931
|
+
debugLog2("storage", `Storing certificate and private key with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
56776
56932
|
const certPath = options22?.certPath || config42.certPath;
|
|
56777
56933
|
const certKeyPath = options22?.keyPath || config42.keyPath;
|
|
56778
|
-
|
|
56779
|
-
|
|
56934
|
+
debugLog2("storage", `Certificate path: ${certPath}`, options22?.verbose);
|
|
56935
|
+
debugLog2("storage", `Private key path: ${certKeyPath}`, options22?.verbose);
|
|
56780
56936
|
const certDir = path3.dirname(certPath);
|
|
56781
56937
|
if (!fs2.existsSync(certDir)) {
|
|
56782
|
-
|
|
56938
|
+
debugLog2("storage", `Creating certificate directory: ${certDir}`, options22?.verbose);
|
|
56783
56939
|
fs2.mkdirSync(certDir, { recursive: true });
|
|
56784
56940
|
}
|
|
56785
|
-
|
|
56941
|
+
debugLog2("storage", "Writing certificate file", options22?.verbose);
|
|
56786
56942
|
fs2.writeFileSync(certPath, cert.certificate);
|
|
56787
56943
|
const certKeyDir = path3.dirname(certKeyPath);
|
|
56788
56944
|
if (!fs2.existsSync(certKeyDir)) {
|
|
56789
|
-
|
|
56945
|
+
debugLog2("storage", `Creating private key directory: ${certKeyDir}`, options22?.verbose);
|
|
56790
56946
|
fs2.mkdirSync(certKeyDir, { recursive: true });
|
|
56791
56947
|
}
|
|
56792
|
-
|
|
56948
|
+
debugLog2("storage", "Writing private key file", options22?.verbose);
|
|
56793
56949
|
fs2.writeFileSync(certKeyPath, cert.privateKey);
|
|
56794
|
-
|
|
56950
|
+
debugLog2("storage", "Certificate and private key stored successfully", options22?.verbose);
|
|
56795
56951
|
return certPath;
|
|
56796
56952
|
}
|
|
56797
56953
|
function storeCACert(caCert, options22) {
|
|
56798
|
-
|
|
56954
|
+
debugLog2("storage", "Storing CA certificate", options22?.verbose);
|
|
56799
56955
|
const caCertPath = options22?.caCertPath || config42.caCertPath;
|
|
56800
|
-
|
|
56956
|
+
debugLog2("storage", `CA certificate path: ${caCertPath}`, options22?.verbose);
|
|
56801
56957
|
const caCertDir = path3.dirname(caCertPath);
|
|
56802
56958
|
if (!fs2.existsSync(caCertDir)) {
|
|
56803
|
-
|
|
56959
|
+
debugLog2("storage", `Creating CA certificate directory: ${caCertDir}`, options22?.verbose);
|
|
56804
56960
|
fs2.mkdirSync(caCertDir, { recursive: true });
|
|
56805
56961
|
}
|
|
56806
|
-
|
|
56962
|
+
debugLog2("storage", "Writing CA certificate file", options22?.verbose);
|
|
56807
56963
|
fs2.writeFileSync(caCertPath, caCert);
|
|
56808
|
-
|
|
56964
|
+
debugLog2("storage", "CA certificate stored successfully", options22?.verbose);
|
|
56809
56965
|
return caCertPath;
|
|
56810
56966
|
}
|
|
56811
56967
|
var export_tls = import_node_forge2.tls;
|
|
@@ -56813,28 +56969,37 @@ var export_pki = import_node_forge2.pki;
|
|
|
56813
56969
|
var export_forge = import_node_forge2.default;
|
|
56814
56970
|
|
|
56815
56971
|
// src/https.ts
|
|
56816
|
-
|
|
56817
|
-
domain
|
|
56818
|
-
|
|
56819
|
-
|
|
56820
|
-
|
|
56821
|
-
|
|
56822
|
-
|
|
56823
|
-
|
|
56824
|
-
|
|
56825
|
-
|
|
56826
|
-
|
|
56827
|
-
|
|
56828
|
-
|
|
56829
|
-
|
|
56830
|
-
|
|
56831
|
-
|
|
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
|
+
}
|
|
56832
56997
|
async function generateCertificate(domain) {
|
|
56833
56998
|
if (config.https === true)
|
|
56834
|
-
config.https =
|
|
56999
|
+
config.https = httpsConfig();
|
|
56835
57000
|
else if (config.https === false)
|
|
56836
57001
|
return;
|
|
56837
|
-
domain = domain ?? config.https.
|
|
57002
|
+
domain = domain ?? config.https.domain;
|
|
56838
57003
|
log.info(`Generating a self-signed SSL certificate for: ${domain}`);
|
|
56839
57004
|
const caCert = await createRootCA(config.https);
|
|
56840
57005
|
const hostCert = await generateCert({
|
|
@@ -56856,91 +57021,100 @@ async function generateCertificate(domain) {
|
|
|
56856
57021
|
await addCertToSystemTrustStoreAndSaveCert(hostCert, caCert.certificate, config.https);
|
|
56857
57022
|
log.success("Certificate generated");
|
|
56858
57023
|
}
|
|
56859
|
-
|
|
56860
|
-
|
|
56861
|
-
|
|
56862
|
-
|
|
56863
|
-
|
|
56864
|
-
|
|
56865
|
-
|
|
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";
|
|
56866
57034
|
|
|
56867
57035
|
// src/start.ts
|
|
56868
57036
|
var activeServers = new Set;
|
|
56869
|
-
function cleanup() {
|
|
56870
|
-
|
|
57037
|
+
async function cleanup() {
|
|
57038
|
+
debugLog("cleanup", "Starting cleanup process", config.verbose);
|
|
56871
57039
|
console.log(`\n`);
|
|
56872
57040
|
log.info("Shutting down proxy servers...");
|
|
56873
|
-
const
|
|
57041
|
+
const cleanupPromises = [];
|
|
57042
|
+
const serverClosePromises = Array.from(activeServers).map((server) => new Promise((resolve4) => {
|
|
56874
57043
|
server.close(() => {
|
|
56875
|
-
|
|
57044
|
+
debugLog("cleanup", "Server closed successfully", config.verbose);
|
|
56876
57045
|
resolve4();
|
|
56877
57046
|
});
|
|
56878
57047
|
}));
|
|
56879
|
-
|
|
56880
|
-
|
|
56881
|
-
|
|
56882
|
-
|
|
56883
|
-
|
|
56884
|
-
|
|
56885
|
-
|
|
56886
|
-
|
|
56887
|
-
|
|
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
|
+
}
|
|
56888
57078
|
}
|
|
56889
|
-
|
|
56890
|
-
|
|
56891
|
-
|
|
56892
|
-
|
|
57079
|
+
process9.on("SIGINT", cleanup);
|
|
57080
|
+
process9.on("SIGTERM", cleanup);
|
|
57081
|
+
process9.on("uncaughtException", (err3) => {
|
|
57082
|
+
debugLog("process", `Uncaught exception: ${err3}`, config.verbose);
|
|
56893
57083
|
log.error("Uncaught exception:", err3);
|
|
56894
57084
|
cleanup();
|
|
56895
57085
|
});
|
|
56896
57086
|
async function loadSSLConfig(options3) {
|
|
56897
|
-
|
|
56898
|
-
if (options3.https === true)
|
|
56899
|
-
options3.https =
|
|
56900
|
-
|
|
56901
|
-
hostCertCN: "stacks.localhost",
|
|
56902
|
-
caCertPath: path6.join(os7.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
56903
|
-
certPath: path6.join(os7.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
56904
|
-
keyPath: path6.join(os7.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`),
|
|
56905
|
-
altNameIPs: ["127.0.0.1"],
|
|
56906
|
-
altNameURIs: ["localhost"],
|
|
56907
|
-
organizationName: "stacksjs.org",
|
|
56908
|
-
countryName: "US",
|
|
56909
|
-
stateName: "California",
|
|
56910
|
-
localityName: "Playa Vista",
|
|
56911
|
-
commonName: "stacks.localhost",
|
|
56912
|
-
validityDays: 180,
|
|
56913
|
-
verbose: false
|
|
56914
|
-
};
|
|
56915
|
-
} else if (options3.https === false) {
|
|
57087
|
+
debugLog("ssl", "Loading SSL configuration", options3.verbose);
|
|
57088
|
+
if (options3.https === true)
|
|
57089
|
+
options3.https = httpsConfig();
|
|
57090
|
+
else if (options3.https === false)
|
|
56916
57091
|
return null;
|
|
56917
|
-
}
|
|
56918
57092
|
if (!options3.https?.keyPath && !options3.https?.certPath) {
|
|
56919
|
-
|
|
57093
|
+
debugLog("ssl", "No SSL configuration provided", options3.verbose);
|
|
56920
57094
|
return null;
|
|
56921
57095
|
}
|
|
56922
57096
|
if (options3.https?.keyPath && !options3.https?.certPath || !options3.https?.keyPath && options3.https?.certPath) {
|
|
56923
57097
|
const missing = !options3.https?.keyPath ? "keyPath" : "certPath";
|
|
56924
|
-
|
|
57098
|
+
debugLog("ssl", `Invalid SSL configuration - missing ${missing}`, options3.verbose);
|
|
56925
57099
|
throw new Error(`SSL Configuration requires both keyPath and certPath. Missing: ${missing}`);
|
|
56926
57100
|
}
|
|
56927
57101
|
try {
|
|
56928
57102
|
if (!options3.https?.keyPath || !options3.https?.certPath)
|
|
56929
57103
|
return null;
|
|
56930
57104
|
try {
|
|
56931
|
-
|
|
56932
|
-
const key = await
|
|
56933
|
-
const cert = await
|
|
56934
|
-
|
|
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);
|
|
56935
57109
|
return { key, cert };
|
|
56936
57110
|
} catch (error) {
|
|
56937
57111
|
if (error.code === "ENOENT") {
|
|
56938
|
-
|
|
56939
|
-
await generateCertificate();
|
|
56940
|
-
|
|
56941
|
-
const key = await
|
|
56942
|
-
const cert = await
|
|
56943
|
-
|
|
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);
|
|
56944
57118
|
return { key, cert };
|
|
56945
57119
|
}
|
|
56946
57120
|
throw error;
|
|
@@ -56948,22 +57122,22 @@ async function loadSSLConfig(options3) {
|
|
|
56948
57122
|
} catch (err3) {
|
|
56949
57123
|
const error = err3;
|
|
56950
57124
|
const detail = error.code === "ENOENT" ? `File not found: ${error.path}` : error.message;
|
|
56951
|
-
|
|
57125
|
+
debugLog("ssl", `SSL configuration error: ${error}`, options3.verbose);
|
|
56952
57126
|
throw new Error(`SSL Configuration Error: ${detail}`);
|
|
56953
57127
|
}
|
|
56954
57128
|
}
|
|
56955
57129
|
function isPortInUse(port, hostname, verbose) {
|
|
56956
|
-
|
|
57130
|
+
debugLog("port", `Checking if port ${port} is in use on ${hostname}`, verbose);
|
|
56957
57131
|
return new Promise((resolve4) => {
|
|
56958
57132
|
const server = net.createServer();
|
|
56959
57133
|
server.once("error", (err3) => {
|
|
56960
57134
|
if (err3.code === "EADDRINUSE") {
|
|
56961
|
-
|
|
57135
|
+
debugLog("port", `Port ${port} is in use`, verbose);
|
|
56962
57136
|
resolve4(true);
|
|
56963
57137
|
}
|
|
56964
57138
|
});
|
|
56965
57139
|
server.once("listening", () => {
|
|
56966
|
-
|
|
57140
|
+
debugLog("port", `Port ${port} is available`, verbose);
|
|
56967
57141
|
server.close();
|
|
56968
57142
|
resolve4(false);
|
|
56969
57143
|
});
|
|
@@ -56971,17 +57145,17 @@ function isPortInUse(port, hostname, verbose) {
|
|
|
56971
57145
|
});
|
|
56972
57146
|
}
|
|
56973
57147
|
async function findAvailablePort(startPort, hostname, verbose) {
|
|
56974
|
-
|
|
57148
|
+
debugLog("port", `Finding available port starting from ${startPort}`, verbose);
|
|
56975
57149
|
let port = startPort;
|
|
56976
57150
|
while (await isPortInUse(port, hostname, verbose)) {
|
|
56977
|
-
|
|
57151
|
+
debugLog("port", `Port ${port} is in use, trying ${port + 1}`, verbose);
|
|
56978
57152
|
port++;
|
|
56979
57153
|
}
|
|
56980
|
-
|
|
57154
|
+
debugLog("port", `Found available port: ${port}`, verbose);
|
|
56981
57155
|
return port;
|
|
56982
57156
|
}
|
|
56983
57157
|
async function testConnection(hostname, port, verbose) {
|
|
56984
|
-
|
|
57158
|
+
debugLog("connection", `Testing connection to ${hostname}:${port}`, verbose);
|
|
56985
57159
|
return new Promise((resolve4, reject) => {
|
|
56986
57160
|
const socket = net.connect({
|
|
56987
57161
|
host: hostname,
|
|
@@ -56989,58 +57163,89 @@ async function testConnection(hostname, port, verbose) {
|
|
|
56989
57163
|
timeout: 5000
|
|
56990
57164
|
});
|
|
56991
57165
|
socket.once("connect", () => {
|
|
56992
|
-
|
|
57166
|
+
debugLog("connection", `Successfully connected to ${hostname}:${port}`, verbose);
|
|
56993
57167
|
socket.end();
|
|
56994
57168
|
resolve4();
|
|
56995
57169
|
});
|
|
56996
57170
|
socket.once("timeout", () => {
|
|
56997
|
-
|
|
57171
|
+
debugLog("connection", `Connection to ${hostname}:${port} timed out`, verbose);
|
|
56998
57172
|
socket.destroy();
|
|
56999
57173
|
reject(new Error(`Connection to ${hostname}:${port} timed out`));
|
|
57000
57174
|
});
|
|
57001
57175
|
socket.once("error", (err3) => {
|
|
57002
|
-
|
|
57176
|
+
debugLog("connection", `Failed to connect to ${hostname}:${port}: ${err3}`, verbose);
|
|
57003
57177
|
socket.destroy();
|
|
57004
57178
|
reject(new Error(`Failed to connect to ${hostname}:${port}: ${err3.message}`));
|
|
57005
57179
|
});
|
|
57006
57180
|
});
|
|
57007
57181
|
}
|
|
57008
57182
|
async function startServer(options3) {
|
|
57009
|
-
|
|
57183
|
+
debugLog("server", `Starting server with options: ${JSON.stringify(options3)}`, options3?.verbose);
|
|
57010
57184
|
if (!options3)
|
|
57011
57185
|
options3 = config;
|
|
57012
57186
|
if (!options3.from)
|
|
57013
57187
|
options3.from = config.from;
|
|
57014
57188
|
if (!options3.to)
|
|
57015
57189
|
options3.to = config.to;
|
|
57190
|
+
const fromUrl = new URL(options3.from.startsWith("http") ? options3.from : `http://${options3.from}`);
|
|
57191
|
+
const toUrl = new URL(options3.to.startsWith("http") ? options3.to : `http://${options3.to}`);
|
|
57192
|
+
const fromPort = Number.parseInt(fromUrl.port) || (fromUrl.protocol.includes("https:") ? 443 : 80);
|
|
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
|
+
}
|
|
57016
57224
|
if (config.https) {
|
|
57017
57225
|
if (config.https === true)
|
|
57018
|
-
config.https =
|
|
57019
|
-
const domain =
|
|
57226
|
+
config.https = httpsConfig();
|
|
57227
|
+
const domain = toUrl.hostname;
|
|
57020
57228
|
if (typeof options3.https !== "boolean" && options3.https) {
|
|
57021
|
-
options3.https.keyPath = config.https.keyPath ||
|
|
57022
|
-
options3.https.certPath = config.https.certPath ||
|
|
57023
|
-
|
|
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);
|
|
57024
57232
|
}
|
|
57025
57233
|
}
|
|
57026
|
-
|
|
57027
|
-
const toUrl = new URL(options3.to.startsWith("http") ? options3.to : `http://${options3.to}`);
|
|
57028
|
-
const fromPort = Number.parseInt(fromUrl.port) || (fromUrl.protocol.includes("https:") ? 443 : 80);
|
|
57029
|
-
debugLog2("server", `Parsed URLs - from: ${fromUrl}, to: ${toUrl}`, options3.verbose);
|
|
57234
|
+
debugLog("server", `Parsed URLs - from: ${fromUrl}, to: ${toUrl}`, options3.verbose);
|
|
57030
57235
|
try {
|
|
57031
57236
|
await testConnection(fromUrl.hostname, fromPort, options3.verbose);
|
|
57032
57237
|
} catch (err3) {
|
|
57033
|
-
|
|
57238
|
+
debugLog("server", `Connection test failed: ${err3}`, options3.verbose);
|
|
57034
57239
|
log.error(err3.message);
|
|
57035
|
-
|
|
57240
|
+
process9.exit(1);
|
|
57036
57241
|
}
|
|
57037
57242
|
let sslConfig = null;
|
|
57038
57243
|
if (config.https) {
|
|
57039
57244
|
try {
|
|
57040
57245
|
sslConfig = await loadSSLConfig(options3);
|
|
57041
57246
|
} catch (err3) {
|
|
57042
|
-
|
|
57043
|
-
await generateCertificate();
|
|
57247
|
+
debugLog("server", `SSL config failed, attempting to generate certificates: ${err3}`, options3.verbose);
|
|
57248
|
+
await generateCertificate(options3.to);
|
|
57044
57249
|
sslConfig = await loadSSLConfig(options3);
|
|
57045
57250
|
}
|
|
57046
57251
|
}
|
|
@@ -57057,9 +57262,9 @@ async function startServer(options3) {
|
|
|
57057
57262
|
});
|
|
57058
57263
|
}
|
|
57059
57264
|
async function createProxyServer(from, to, fromPort, listenPort, hostname, sourceUrl, ssl, verbose) {
|
|
57060
|
-
|
|
57265
|
+
debugLog("proxy", `Creating proxy server ${from} -> ${to}`, verbose);
|
|
57061
57266
|
const requestHandler = (req, res) => {
|
|
57062
|
-
|
|
57267
|
+
debugLog("request", `Incoming request: ${req.method} ${req.url}`, verbose);
|
|
57063
57268
|
const proxyOptions = {
|
|
57064
57269
|
hostname: sourceUrl.hostname,
|
|
57065
57270
|
port: fromPort,
|
|
@@ -57070,9 +57275,9 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57070
57275
|
host: sourceUrl.host
|
|
57071
57276
|
}
|
|
57072
57277
|
};
|
|
57073
|
-
|
|
57278
|
+
debugLog("request", `Proxy request options: ${JSON.stringify(proxyOptions)}`, verbose);
|
|
57074
57279
|
const proxyReq = http.request(proxyOptions, (proxyRes) => {
|
|
57075
|
-
|
|
57280
|
+
debugLog("response", `Proxy response received with status ${proxyRes.statusCode}`, verbose);
|
|
57076
57281
|
const headers = {
|
|
57077
57282
|
...proxyRes.headers,
|
|
57078
57283
|
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
|
@@ -57082,7 +57287,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57082
57287
|
proxyRes.pipe(res);
|
|
57083
57288
|
});
|
|
57084
57289
|
proxyReq.on("error", (err3) => {
|
|
57085
|
-
|
|
57290
|
+
debugLog("request", `Proxy request failed: ${err3}`, verbose);
|
|
57086
57291
|
log.error("Proxy request failed:", err3);
|
|
57087
57292
|
res.writeHead(502);
|
|
57088
57293
|
res.end(`Proxy Error: ${err3.message}`);
|
|
@@ -57109,11 +57314,11 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57109
57314
|
allowHTTP1: true,
|
|
57110
57315
|
ALPNProtocols: ["h2", "http/1.1"]
|
|
57111
57316
|
} : undefined;
|
|
57112
|
-
|
|
57317
|
+
debugLog("server", `Creating server with SSL config: ${!!ssl}`, verbose);
|
|
57113
57318
|
const server = ssl && serverOptions ? https.createServer(serverOptions, requestHandler) : http.createServer(requestHandler);
|
|
57114
57319
|
if (ssl) {
|
|
57115
57320
|
server.on("secureConnection", (tlsSocket) => {
|
|
57116
|
-
|
|
57321
|
+
debugLog("tls", `TLS Connection established: ${JSON.stringify({
|
|
57117
57322
|
protocol: tlsSocket.getProtocol?.(),
|
|
57118
57323
|
cipher: tlsSocket.getCipher?.(),
|
|
57119
57324
|
authorized: tlsSocket.authorized,
|
|
@@ -57124,7 +57329,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57124
57329
|
activeServers.add(server);
|
|
57125
57330
|
return new Promise((resolve4, reject) => {
|
|
57126
57331
|
server.listen(listenPort, hostname, () => {
|
|
57127
|
-
|
|
57332
|
+
debugLog("server", `Server listening on port ${listenPort}`, verbose);
|
|
57128
57333
|
console.log("");
|
|
57129
57334
|
console.log(` ${green(bold("reverse-proxy"))} ${green(`v${version}`)}`);
|
|
57130
57335
|
console.log("");
|
|
@@ -57141,13 +57346,13 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57141
57346
|
resolve4();
|
|
57142
57347
|
});
|
|
57143
57348
|
server.on("error", (err3) => {
|
|
57144
|
-
|
|
57349
|
+
debugLog("server", `Server error: ${err3}`, verbose);
|
|
57145
57350
|
reject(err3);
|
|
57146
57351
|
});
|
|
57147
57352
|
});
|
|
57148
57353
|
}
|
|
57149
57354
|
async function setupReverseProxy(options3) {
|
|
57150
|
-
|
|
57355
|
+
debugLog("setup", `Setting up reverse proxy: ${JSON.stringify(options3)}`, options3.verbose);
|
|
57151
57356
|
const { from, to, fromPort, sourceUrl, ssl, verbose } = options3;
|
|
57152
57357
|
const httpPort = 80;
|
|
57153
57358
|
const httpsPort = 443;
|
|
@@ -57156,72 +57361,72 @@ async function setupReverseProxy(options3) {
|
|
|
57156
57361
|
if (ssl) {
|
|
57157
57362
|
const isHttpPortBusy = await isPortInUse(httpPort, hostname, verbose);
|
|
57158
57363
|
if (!isHttpPortBusy) {
|
|
57159
|
-
|
|
57364
|
+
debugLog("setup", "Starting HTTP redirect server", verbose);
|
|
57160
57365
|
startHttpRedirectServer(verbose);
|
|
57161
57366
|
} else {
|
|
57162
|
-
|
|
57367
|
+
debugLog("setup", "Port 80 is in use, skipping HTTP redirect", verbose);
|
|
57163
57368
|
log.warn("Port 80 is in use, HTTP to HTTPS redirect will not be available");
|
|
57164
57369
|
}
|
|
57165
57370
|
}
|
|
57166
57371
|
const targetPort = ssl ? httpsPort : httpPort;
|
|
57167
57372
|
const isTargetPortBusy = await isPortInUse(targetPort, hostname, verbose);
|
|
57168
57373
|
if (isTargetPortBusy) {
|
|
57169
|
-
|
|
57374
|
+
debugLog("setup", `Port ${targetPort} is busy, finding alternative`, verbose);
|
|
57170
57375
|
const availablePort = await findAvailablePort(ssl ? 8443 : 8080, hostname, verbose);
|
|
57171
57376
|
log.warn(`Port ${targetPort} is in use. Using port ${availablePort} instead.`);
|
|
57172
57377
|
log.info(`You can use 'sudo lsof -i :${targetPort}' (Unix) or 'netstat -ano | findstr :${targetPort}' (Windows) to check what's using the port.`);
|
|
57173
57378
|
await createProxyServer(from, to, fromPort, availablePort, hostname, sourceUrl, ssl, verbose);
|
|
57174
57379
|
} else {
|
|
57175
|
-
|
|
57380
|
+
debugLog("setup", `Using default port ${targetPort}`, verbose);
|
|
57176
57381
|
await createProxyServer(from, to, fromPort, targetPort, hostname, sourceUrl, ssl, verbose);
|
|
57177
57382
|
}
|
|
57178
57383
|
} catch (err3) {
|
|
57179
|
-
|
|
57384
|
+
debugLog("setup", `Setup failed: ${err3}`, verbose);
|
|
57180
57385
|
log.error(`Failed to setup reverse proxy: ${err3.message}`);
|
|
57181
57386
|
cleanup();
|
|
57182
57387
|
}
|
|
57183
57388
|
}
|
|
57184
57389
|
function startHttpRedirectServer(verbose) {
|
|
57185
|
-
|
|
57390
|
+
debugLog("redirect", "Starting HTTP redirect server", verbose);
|
|
57186
57391
|
const server = http.createServer((req, res) => {
|
|
57187
57392
|
const host = req.headers.host || "";
|
|
57188
|
-
|
|
57393
|
+
debugLog("redirect", `Redirecting request from ${host}${req.url} to HTTPS`, verbose);
|
|
57189
57394
|
res.writeHead(301, {
|
|
57190
57395
|
Location: `https://${host}${req.url}`
|
|
57191
57396
|
});
|
|
57192
57397
|
res.end();
|
|
57193
57398
|
}).listen(80);
|
|
57194
57399
|
activeServers.add(server);
|
|
57195
|
-
|
|
57400
|
+
debugLog("redirect", "HTTP redirect server started", verbose);
|
|
57196
57401
|
}
|
|
57197
57402
|
function startProxy(options3) {
|
|
57198
57403
|
const finalOptions = {
|
|
57199
57404
|
...config,
|
|
57200
57405
|
...options3
|
|
57201
57406
|
};
|
|
57202
|
-
|
|
57407
|
+
debugLog("proxy", `Starting proxy with options: ${JSON.stringify({
|
|
57203
57408
|
from: finalOptions.from,
|
|
57204
57409
|
to: finalOptions.to,
|
|
57205
57410
|
https: finalOptions.https
|
|
57206
57411
|
})}`, finalOptions.verbose);
|
|
57207
57412
|
startServer(finalOptions).catch((err3) => {
|
|
57208
|
-
|
|
57413
|
+
debugLog("proxy", `Failed to start proxy: ${err3}`, finalOptions.verbose);
|
|
57209
57414
|
log.error(`Failed to start proxy: ${err3.message}`);
|
|
57210
57415
|
cleanup();
|
|
57211
57416
|
});
|
|
57212
57417
|
}
|
|
57213
57418
|
function startProxies(options3) {
|
|
57214
57419
|
if (Array.isArray(options3)) {
|
|
57215
|
-
|
|
57420
|
+
debugLog("proxies", `Starting multiple proxies: ${options3.length}`, options3[0]?.verbose);
|
|
57216
57421
|
Promise.all(options3.map((option) => startServer(option))).catch((err3) => {
|
|
57217
|
-
|
|
57422
|
+
debugLog("proxies", `Failed to start proxies: ${err3}`, options3[0]?.verbose);
|
|
57218
57423
|
log.error("Failed to start proxies:", err3);
|
|
57219
57424
|
cleanup();
|
|
57220
57425
|
});
|
|
57221
57426
|
} else if (options3) {
|
|
57222
|
-
|
|
57427
|
+
debugLog("proxies", "Starting single proxy", options3.verbose);
|
|
57223
57428
|
startServer(options3).catch((err3) => {
|
|
57224
|
-
|
|
57429
|
+
debugLog("proxies", `Failed to start proxy: ${err3}`, options3.verbose);
|
|
57225
57430
|
log.error("Failed to start proxy:", err3);
|
|
57226
57431
|
cleanup();
|
|
57227
57432
|
});
|
|
@@ -57233,6 +57438,12 @@ export {
|
|
|
57233
57438
|
startProxies,
|
|
57234
57439
|
startHttpRedirectServer,
|
|
57235
57440
|
setupReverseProxy,
|
|
57441
|
+
removeHosts,
|
|
57442
|
+
httpsConfig,
|
|
57443
|
+
hostsFilePath,
|
|
57444
|
+
generateCertificate,
|
|
57236
57445
|
config,
|
|
57237
|
-
cleanup
|
|
57446
|
+
cleanup,
|
|
57447
|
+
checkHosts,
|
|
57448
|
+
addHosts
|
|
57238
57449
|
};
|