Files
BetterDesk/web-nodejs/services/clientConfigHost.js
T
UNITRONIX 0b82160592 fix(console): persist Public Client Endpoints across Docker recreate (#291)
Store PUBLIC_* on the console-data volume so panel settings survive compose recreate; keep Compose env override and .env mirror for IaC and bare-metal.
2026-07-21 17:32:43 +02:00

124 lines
3.6 KiB
JavaScript

/**
* Resolve the hostname/IP shown in RustDesk client configuration.
* Clients must reach the server on a public or LAN-routable address, which may
* differ from the Host header when operators open the panel on localhost.
*/
'use strict';
const conn = require('./agentBundleConnection');
const keyService = require('./keyService');
const publicEndpoints = require('./rustDeskPublicEndpointsService');
function stripRequestHost(rawHost) {
const raw = String(rawHost || 'localhost');
const firstHost = raw.split(',')[0].trim();
if (firstHost.startsWith('[')) {
const end = firstHost.indexOf(']');
return end > 0 ? firstHost.slice(1, end) : firstHost;
}
const colonCount = (firstHost.match(/:/g) || []).length;
if (colonCount === 1) {
return firstHost.split(':')[0];
}
return firstHost;
}
/** Same precedence as PUBLIC_*: non-empty process.env → durable → .env */
function readPanelPublicHost() {
return publicEndpoints.readPanelPublicHostValue();
}
/**
* @param {import('express').Request} [req]
* @param {string} [queryHost] - optional ?host= override from API caller
*/
function resolveClientFacingHost(req, queryHost) {
const envOverrides = publicEndpoints.readPublicEndpointEnv();
if (envOverrides.public_server_id) {
return envOverrides.public_server_id;
}
if (queryHost) {
const normalized = conn.normalizeServerHost(queryHost);
if (normalized.valid) {
return normalized.host;
}
}
const panelHost = readPanelPublicHost();
if (panelHost) {
const normalized = conn.normalizeServerHost(panelHost);
if (normalized.valid) {
return normalized.host;
}
}
const fromApi = conn.defaultServerHost();
if (fromApi) {
return fromApi;
}
if (req) {
const rawHost = req.headers['x-forwarded-host'] || req.headers.host || req.hostname || 'localhost';
return stripRequestHost(rawHost);
}
return 'localhost';
}
function detectHostSource(req, queryHost, envOverrides) {
if (envOverrides.public_server_id) return 'env';
if (queryHost) {
const normalized = conn.normalizeServerHost(queryHost);
if (normalized.valid) return 'query';
}
const panelHost = readPanelPublicHost();
if (panelHost) {
const normalized = conn.normalizeServerHost(panelHost);
if (normalized.valid) return 'panel_host';
}
if (conn.defaultServerHost()) return 'config';
if (req) return 'request';
return 'default';
}
/**
* Resolve RustDesk client-facing ID, relay, and API endpoints.
* @param {import('express').Request} [req]
* @param {string} [queryHost]
*/
function resolveRustDeskEndpoints(req, queryHost) {
const envOverrides = publicEndpoints.readPublicEndpointEnv();
const host = resolveClientFacingHost(req, queryHost);
const relay = envOverrides.public_relay_server || host;
const api = envOverrides.public_api_url
|| keyService.apiUrlForHost(host, conn.defaultUseHttps());
const hostSource = detectHostSource(req, queryHost, envOverrides);
const relaySource = envOverrides.public_relay_server ? 'env' : hostSource;
const apiSource = envOverrides.public_api_url ? 'env' : (hostSource === 'env' ? 'derived' : hostSource);
return {
host,
relay,
api,
sources: {
host: hostSource,
relay: relaySource,
api: apiSource,
},
env_override_active: publicEndpoints.isEnvOverrideActive(envOverrides),
};
}
module.exports = {
resolveClientFacingHost,
resolveRustDeskEndpoints,
stripRequestHost,
readPanelPublicHost,
};