123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.resolveHostAndAssignPorts = exports.waitForPortClosed = exports.checkListenable = void 0;
- const clc = require("colorette");
- const tcpport = require("tcp-port-used");
- const node_net_1 = require("node:net");
- const error_1 = require("../error");
- const utils = require("../utils");
- const dns_1 = require("./dns");
- const types_1 = require("./types");
- const constants_1 = require("./constants");
- const emulatorLogger_1 = require("./emulatorLogger");
- const node_child_process_1 = require("node:child_process");
- const RESTRICTED_PORTS = new Set([
- 1,
- 7,
- 9,
- 11,
- 13,
- 15,
- 17,
- 19,
- 20,
- 21,
- 22,
- 23,
- 25,
- 37,
- 42,
- 43,
- 53,
- 77,
- 79,
- 87,
- 95,
- 101,
- 102,
- 103,
- 104,
- 109,
- 110,
- 111,
- 113,
- 115,
- 117,
- 119,
- 123,
- 135,
- 139,
- 143,
- 179,
- 389,
- 427,
- 465,
- 512,
- 513,
- 514,
- 515,
- 526,
- 530,
- 531,
- 532,
- 540,
- 548,
- 556,
- 563,
- 587,
- 601,
- 636,
- 993,
- 995,
- 2049,
- 3659,
- 4045,
- 6000,
- 6665,
- 6666,
- 6667,
- 6668,
- 6669,
- 6697,
- ]);
- function isRestricted(port) {
- return RESTRICTED_PORTS.has(port);
- }
- function suggestUnrestricted(port) {
- if (!isRestricted(port)) {
- return port;
- }
- let newPort = port;
- while (isRestricted(newPort)) {
- newPort++;
- }
- return newPort;
- }
- async function checkListenable(arg1, port) {
- const addr = port === undefined ? arg1 : listenSpec(arg1, port);
- return new Promise((resolve, reject) => {
- if (process.platform === "darwin") {
- try {
- (0, node_child_process_1.execSync)(`lsof -i :${addr.port} -sTCP:LISTEN`);
- return resolve(false);
- }
- catch (e) {
- }
- }
- const dummyServer = (0, node_net_1.createServer)();
- dummyServer.once("error", (err) => {
- dummyServer.removeAllListeners();
- const e = err;
- if (e.code === "EADDRINUSE" || e.code === "EACCES") {
- resolve(false);
- }
- else {
- reject(e);
- }
- });
- dummyServer.once("listening", () => {
- dummyServer.removeAllListeners();
- dummyServer.close((err) => {
- dummyServer.removeAllListeners();
- if (err) {
- reject(err);
- }
- else {
- resolve(true);
- }
- });
- });
- dummyServer.listen({ host: addr.address, port: addr.port, ipv6Only: addr.family === "IPv6" });
- });
- }
- exports.checkListenable = checkListenable;
- async function waitForPortClosed(port, host) {
- const interval = 250;
- const timeout = 60000;
- try {
- await tcpport.waitUntilUsedOnHost(port, host, interval, timeout);
- }
- catch (e) {
- throw new error_1.FirebaseError(`TIMEOUT: Port ${port} on ${host} was not active within ${timeout}ms`);
- }
- }
- exports.waitForPortClosed = waitForPortClosed;
- const EMULATOR_CAN_LISTEN_ON_PRIMARY_ONLY = {
- database: true,
- firestore: true,
- "firestore.websocket": true,
- pubsub: true,
- hub: false,
- ui: false,
- auth: true,
- eventarc: true,
- extensions: true,
- functions: true,
- logging: true,
- storage: true,
- hosting: true,
- };
- const MAX_PORT = 65535;
- async function resolveHostAndAssignPorts(listenConfig) {
- const lookupForHost = new Map();
- const takenPorts = new Map();
- const result = {};
- const tasks = [];
- for (const name of Object.keys(listenConfig)) {
- const config = listenConfig[name];
- if (!config) {
- continue;
- }
- else if (config instanceof Array) {
- result[name] = config;
- for (const { port } of config) {
- takenPorts.set(port, name);
- }
- continue;
- }
- const { host, port, portFixed } = config;
- let lookup = lookupForHost.get(host);
- if (!lookup) {
- lookup = dns_1.Resolver.DEFAULT.lookupAll(host);
- lookupForHost.set(host, lookup);
- }
- const findAddrs = lookup.then(async (addrs) => {
- const emuLogger = emulatorLogger_1.EmulatorLogger.forEmulator(name === "firestore.websocket" ? types_1.Emulators.FIRESTORE : name);
- if (addrs.some((addr) => addr.address === dns_1.IPV6_UNSPECIFIED.address)) {
- if (!addrs.some((addr) => addr.address === dns_1.IPV4_UNSPECIFIED.address)) {
- emuLogger.logLabeled("DEBUG", name, `testing listening on IPv4 wildcard in addition to IPv6. To listen on IPv6 only, use "::0" instead.`);
- addrs.push(dns_1.IPV4_UNSPECIFIED);
- }
- }
- for (let p = port; p <= MAX_PORT; p++) {
- if (takenPorts.has(p)) {
- continue;
- }
- if (!portFixed && RESTRICTED_PORTS.has(p)) {
- emuLogger.logLabeled("DEBUG", name, `portUtils: skipping restricted port ${p}`);
- continue;
- }
- if (p === 5001 && /^hosting/i.exec(name)) {
- continue;
- }
- const available = [];
- const unavailable = [];
- let i;
- for (i = 0; i < addrs.length; i++) {
- const addr = addrs[i];
- const listen = listenSpec(addr, p);
- let listenable;
- try {
- listenable = await checkListenable(listen);
- }
- catch (err) {
- emuLogger.logLabeled("WARN", name, `Error when trying to check port ${p} on ${addr.address}: ${err}`);
- unavailable.push(addr.address);
- continue;
- }
- if (listenable) {
- available.push(listen);
- }
- else {
- if (!portFixed) {
- if (i > 0) {
- emuLogger.logLabeled("DEBUG", name, `Port ${p} taken on secondary address ${addr.address}, will keep searching to find a better port.`);
- }
- break;
- }
- unavailable.push(addr.address);
- }
- }
- if (i === addrs.length) {
- if (unavailable.length > 0) {
- if (unavailable[0] === addrs[0].address) {
- return fixedPortNotAvailable(name, host, port, emuLogger, unavailable);
- }
- warnPartiallyAvailablePort(emuLogger, port, available, unavailable);
- }
- if (takenPorts.has(p)) {
- continue;
- }
- takenPorts.set(p, name);
- if (RESTRICTED_PORTS.has(p)) {
- const suggested = suggestUnrestricted(port);
- emuLogger.logLabeled("WARN", name, `Port ${port} is restricted by some web browsers, including Chrome. You may want to choose a different port such as ${suggested}.`);
- }
- if (p !== port && name !== "firestore.websocket") {
- emuLogger.logLabeled("WARN", `${portDescription(name)} unable to start on port ${port}, starting on ${p} instead.`);
- }
- if (available.length > 1 && EMULATOR_CAN_LISTEN_ON_PRIMARY_ONLY[name]) {
- emuLogger.logLabeled("DEBUG", name, `${portDescription(name)} only supports listening on one address (${available[0].address}). Not listening on ${addrs
- .slice(1)
- .map((s) => s.address)
- .join(",")}`);
- result[name] = [available[0]];
- }
- else {
- result[name] = available;
- }
- return;
- }
- }
- return utils.reject(`Could not find any open port in ${port}-${MAX_PORT} for ${portDescription(name)}`, {});
- });
- tasks.push(findAddrs);
- }
- await Promise.all(tasks);
- return result;
- }
- exports.resolveHostAndAssignPorts = resolveHostAndAssignPorts;
- function portDescription(name) {
- return name === "firestore.websocket"
- ? `websocket server for ${types_1.Emulators.FIRESTORE}`
- : constants_1.Constants.description(name);
- }
- function warnPartiallyAvailablePort(emuLogger, port, available, unavailable) {
- emuLogger.logLabeled("WARN", `Port ${port} is available on ` +
- available.map((s) => s.address).join(",") +
- ` but not ${unavailable.join(",")}. This may cause issues with some clients.`);
- emuLogger.logLabeled("WARN", `If you encounter connectivity issues, consider switching to a different port or explicitly specifying ${clc.yellow('"host": "<ip address>"')} instead of hostname in firebase.json`);
- }
- function fixedPortNotAvailable(name, host, port, emuLogger, unavailableAddrs) {
- if (unavailableAddrs.length !== 1 || unavailableAddrs[0] !== host) {
- host = `${host} (${unavailableAddrs.join(",")})`;
- }
- const description = portDescription(name);
- emuLogger.logLabeled("WARN", `Port ${port} is not open on ${host}, could not start ${description}.`);
- if (name === "firestore.websocket") {
- emuLogger.logLabeled("WARN", `To select a different port, specify that port in a firebase.json config file:
- {
- // ...
- "emulators": {
- "${types_1.Emulators.FIRESTORE}": {
- "host": "${clc.yellow("HOST")}",
- ...
- "websocketPort": "${clc.yellow("WEBSOCKET_PORT")}"
- }
- }
- }`);
- }
- else {
- emuLogger.logLabeled("WARN", `To select a different host/port, specify that host/port in a firebase.json config file:
- {
- // ...
- "emulators": {
- "${emuLogger.name}": {
- "host": "${clc.yellow("HOST")}",
- "port": "${clc.yellow("PORT")}"
- }
- }
- }`);
- }
- return utils.reject(`Could not start ${description}, port taken.`, {});
- }
- function listenSpec(lookup, port) {
- if (lookup.family !== 4 && lookup.family !== 6) {
- throw new Error(`Unsupported address family "${lookup.family}" for address ${lookup.address}.`);
- }
- return {
- address: lookup.address,
- family: lookup.family === 4 ? "IPv4" : "IPv6",
- port: port,
- };
- }
|