Files
BetterDesk/web-nodejs/services/agentBundleConnection.js
T
UNITRONIX ed96e94806 refactor(agent): enhance session management and input handling
- Updated session control mechanisms to ensure proper handling of remote input and clipboard operations.
- Introduced session authorization checks to validate operator permissions before starting desktop sessions.
- Improved input injection logic to prevent unauthorized access during active sessions.
- Added new capabilities for managing session flags and controls, ensuring a more robust and secure desktop experience.
- Enhanced error handling and logging for better traceability of session-related actions.
2026-08-06 00:50:02 +02:00

147 lines
4.4 KiB
JavaScript

/**
* Connection profile helpers for the support-agent bundle generator.
* Operators supply a public hostname/IP; the console injects API URLs,
* server public key, and a backend-issued enrollment token.
*/
'use strict';
const config = require('../config/config');
const HOST_RE = /^[a-zA-Z0-9](?:[a-zA-Z0-9.-]{0,253}[a-zA-Z0-9])?$/;
const IP_V4_RE = /^(?:\d{1,3}\.){3}\d{1,3}$/;
const CERT_PIN_RE = /^[a-f0-9]{64}$/;
function clip(s, max) {
if (typeof s !== 'string') return '';
return s.trim().slice(0, max);
}
/** Default API port from console config (BetterDesk Go API). */
function defaultApiPort() {
try {
const raw = config.hbbsApiUrl || config.betterdeskApiUrl || '';
const u = new URL(raw.includes('://') ? raw : `http://${raw}`);
if (u.port) return u.port;
return u.protocol === 'https:' ? '443' : '21114';
} catch (_) {
return '21114';
}
}
/** CDAP WebSocket gateway port (BetterDesk Go server). */
function defaultCdapPort() {
const fromEnv = parseInt(process.env.CDAP_PORT || process.env.SIGNAL_PORT, 10);
if (Number.isFinite(fromEnv) && fromEnv > 0) return fromEnv;
return 21122;
}
function formatOrigin(scheme, hostPart, port) {
const omitPort = (scheme === 'https' && port === 443) || (scheme === 'http' && port === 80);
return omitPort ? `${scheme}://${hostPart}` : `${scheme}://${hostPart}:${port}`;
}
function configuredCertificatePin() {
const normalized = String(config.agentServerCertPin || '')
.replace(/:/g, '')
.trim()
.toLowerCase();
return CERT_PIN_RE.test(normalized) ? normalized : '';
}
/** Suggested host prefill from local server config. */
function defaultServerHost() {
try {
const raw = config.hbbsApiUrl || config.betterdeskApiUrl || '';
const u = new URL(raw.includes('://') ? raw : `http://${raw}`);
return u.hostname || '';
} catch (_) {
return '';
}
}
function defaultUseHttps() {
try {
const raw = config.hbbsApiUrl || config.betterdeskApiUrl || '';
const u = new URL(raw.includes('://') ? raw : `http://${raw}`);
return u.protocol === 'https:';
} catch (_) {
return false;
}
}
/**
* Normalize operator input: strip scheme/path/port — keep hostname or IPv4.
*/
function normalizeServerHost(input) {
let host = clip(input, 253);
if (!host) return { valid: false, error: 'server_host_required', host: '' };
host = host.replace(/^https?:\/\//i, '');
host = host.split('/')[0];
host = host.split(':')[0];
host = host.replace(/^\[|\]$/g, '');
const valid = HOST_RE.test(host) || IP_V4_RE.test(host);
if (!valid) {
return { valid: false, error: 'server_host_invalid', host: '' };
}
return { valid: true, host };
}
/**
* Build server { address, api_url, cdap/console ports and URLs } from host + TLS.
*/
function buildServerUrls(host, useHttps, apiPort) {
const port = String(apiPort || defaultApiPort());
const scheme = useHttps ? 'https' : 'http';
const wsScheme = useHttps ? 'wss' : 'ws';
const omitPort = (scheme === 'https' && port === '443') || (scheme === 'http' && port === '80');
const hostPart = host.includes(':') ? `[${host}]` : host;
const authority = omitPort ? hostPart : `${hostPart}:${port}`;
const origin = `${scheme}://${authority}`;
const cdapPort = defaultCdapPort();
const cdapUrl = `${wsScheme}://${hostPart}:${cdapPort}/cdap`;
return {
address: origin,
api_url: `${origin}/api`,
cert_pin: configuredCertificatePin(),
cdap_port: cdapPort,
cdap_url: cdapUrl,
};
}
function hostFromBranding(branding) {
if (branding?.server_host) return branding.server_host;
const addr = branding?.server?.address;
if (!addr) return '';
try {
return new URL(addr).hostname;
} catch (_) {
return String(addr).replace(/^https?:\/\//i, '').split(/[/:]/)[0];
}
}
function tlsFromBranding(branding) {
if (typeof branding?.use_https === 'boolean') return branding.use_https;
const addr = branding?.server?.address || '';
return addr.startsWith('https://');
}
function connectionFingerprint(branding) {
return `${hostFromBranding(branding)}|${tlsFromBranding(branding)}`;
}
module.exports = {
defaultApiPort,
defaultCdapPort,
defaultServerHost,
defaultUseHttps,
normalizeServerHost,
buildServerUrls,
configuredCertificatePin,
connectionFingerprint,
};