mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2025-04-17 18:18:11 +00:00
[FEAT] Check port access in docker before showing a default error (#961)
* [FEAT] Added port checks in updateENV.validDockerizedUrl to prevent docker from assuming it cannot access localhost URLs * [CHORE] Updated error message to include Linux URL * Patch port checking for general loopbacks * typo --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
1cd9e1336b
commit
e9199bac12
2 changed files with 74 additions and 9 deletions
server/utils/helpers
46
server/utils/helpers/portAvailabilityChecker.js
Normal file
46
server/utils/helpers/portAvailabilityChecker.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Get all loopback addresses that are available for use or binding.
|
||||
function getLocalHosts() {
|
||||
const os = require("os");
|
||||
const interfaces = os.networkInterfaces();
|
||||
const results = new Set([undefined, "0.0.0.0"]);
|
||||
|
||||
for (const _interface of Object.values(interfaces)) {
|
||||
for (const config of _interface) {
|
||||
results.add(config.address);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(results);
|
||||
}
|
||||
|
||||
function checkPort(options = {}) {
|
||||
const net = require("net");
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
server.unref();
|
||||
server.on("error", reject);
|
||||
|
||||
server.listen(options, () => {
|
||||
server.close(() => {
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function isPortInUse(port, host) {
|
||||
try {
|
||||
await checkPort({ port, host });
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (!["EADDRNOTAVAIL", "EINVAL"].includes(error.code)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isPortInUse,
|
||||
getLocalHosts,
|
||||
};
|
|
@ -462,14 +462,28 @@ function isDownloadedModel(input = "") {
|
|||
return files.includes(input);
|
||||
}
|
||||
|
||||
function validDockerizedUrl(input = "") {
|
||||
async function validDockerizedUrl(input = "") {
|
||||
if (process.env.ANYTHING_LLM_RUNTIME !== "docker") return null;
|
||||
|
||||
try {
|
||||
const { hostname } = new URL(input);
|
||||
if (["localhost", "127.0.0.1", "0.0.0.0"].includes(hostname.toLowerCase()))
|
||||
return "Localhost, 127.0.0.1, or 0.0.0.0 origins cannot be reached from inside the AnythingLLM container. Please use host.docker.internal, a real machine ip, or domain to connect to your service.";
|
||||
return null;
|
||||
} catch {}
|
||||
const { isPortInUse, getLocalHosts } = require("./portAvailabilityChecker");
|
||||
const localInterfaces = getLocalHosts();
|
||||
const url = new URL(input);
|
||||
const hostname = url.hostname.toLowerCase();
|
||||
const port = parseInt(url.port, 10);
|
||||
|
||||
// If not a loopback, skip this check.
|
||||
if (!localInterfaces.includes(hostname)) return null;
|
||||
if (isNaN(port)) return "Invalid URL: Port is not specified or invalid";
|
||||
|
||||
const isPortAvailableFromDocker = await isPortInUse(port, hostname);
|
||||
if (isPortAvailableFromDocker)
|
||||
return "Port is not running a reachable service on loopback address from inside the AnythingLLM container. Please use host.docker.internal (for linux use 172.17.0.1), a real machine ip, or domain to connect to your service.";
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
return "An error occurred while validating the URL";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -504,10 +518,8 @@ async function updateENV(newENVs = {}, force = false, userId = null) {
|
|||
const { envKey, checks, postUpdate = [] } = KEY_MAPPING[key];
|
||||
const prevValue = process.env[envKey];
|
||||
const nextValue = newENVs[key];
|
||||
const errors = checks
|
||||
.map((validityCheck) => validityCheck(nextValue, force))
|
||||
.filter((err) => typeof err === "string");
|
||||
|
||||
const errors = await executeValidationChecks(checks, nextValue, force);
|
||||
if (errors.length > 0) {
|
||||
error += errors.join("\n");
|
||||
break;
|
||||
|
@ -524,6 +536,13 @@ async function updateENV(newENVs = {}, force = false, userId = null) {
|
|||
return { newValues, error: error?.length > 0 ? error : false };
|
||||
}
|
||||
|
||||
async function executeValidationChecks(checks, value, force) {
|
||||
const results = await Promise.all(
|
||||
checks.map((validator) => validator(value, force))
|
||||
);
|
||||
return results.filter((err) => typeof err === "string");
|
||||
}
|
||||
|
||||
async function logChangesToEventLog(newValues = {}, userId = null) {
|
||||
const { EventLogs } = require("../../models/eventLogs");
|
||||
const eventMapping = {
|
||||
|
|
Loading…
Add table
Reference in a new issue