Files
BetterDesk/web-nodejs/services/keyService.js
T
UNITRONIX 0496b1dbc4 Add client API, sysinfo endpoints and Docker
Add RustDesk-compatible client API and telemetry support and introduce a single-container Docker build. New client_api_handlers.go implements /api/login, /api/login-options, /api/logout, /api/currentUser, /api/ab, /api/heartbeat, /api/sysinfo and /api/sysinfo_ver with TOTP flow and an in-memory TFA session store; auth middleware and Server registration updated accordingly. Database interface and SQLite/Postgres implementations gain UpdatePeerSysinfo (with tests), audit actions for sysinfo, and handleGetPeer now returns live_online/live_status. Also add Dockerfile, docker-compose.single.yml, supervisord entrypoint, UI fixes (QR color inversion, 403 error view), labels file, README updates, and other ancillary changes.

Co-Authored-By: MrBrodacz - Design <215021251+MrBrodacz2025@users.noreply.github.com>
Co-Authored-By: boruto79 <176351662+boruto79@users.noreply.github.com>
Co-Authored-By: marcosacramento <marcosacramento@gmail.com>
Co-Authored-By: Charles Olivier Savignac <1275666+sircharlo@users.noreply.github.com>
2026-03-06 01:08:10 +01:00

136 lines
3.4 KiB
JavaScript

/**
* BetterDesk Console - Key Service
* Reads public key and API key from filesystem
*/
const fs = require('fs');
const QRCode = require('qrcode');
const config = require('../config/config');
/**
* Read public key from file
*/
function getPublicKey() {
try {
if (fs.existsSync(config.pubKeyPath)) {
return fs.readFileSync(config.pubKeyPath, 'utf8').trim();
}
return null;
} catch (err) {
console.warn('Could not read public key:', err.message);
return null;
}
}
/**
* Get API key (masked for display)
*/
function getApiKey(masked = true) {
try {
if (fs.existsSync(config.apiKeyPath)) {
const key = fs.readFileSync(config.apiKeyPath, 'utf8').trim();
if (masked && key.length > 8) {
return key.substring(0, 4) + '****' + key.substring(key.length - 4);
}
return key;
}
return null;
} catch (err) {
console.warn('Could not read API key:', err.message);
return null;
}
}
/**
* Generate QR code containing the RustDesk configuration URI.
* Format: rustdesk://config/<base64-encoded-json>
* The JSON contains: { host, relay, api, key }
* @param {string} serverHost - server host/IP used for the config
*/
async function getServerConfigQR(serverHost) {
const pubKey = getPublicKey();
if (!pubKey) {
return null;
}
try {
const apiKey = getApiKey(false); // unmasked
const configPayload = {
host: serverHost || 'localhost',
relay: serverHost || 'localhost',
api: `http://${serverHost || 'localhost'}:${config.apiPort}`,
key: pubKey
};
if (apiKey) {
configPayload.key = pubKey;
}
const jsonStr = JSON.stringify(configPayload);
const b64 = Buffer.from(jsonStr).toString('base64');
const configUri = `rustdesk://config/${b64}`;
const qrDataUrl = await QRCode.toDataURL(configUri, {
errorCorrectionLevel: 'M',
type: 'image/png',
width: 256,
margin: 2,
color: {
dark: '#000000',
light: '#ffffff'
}
});
return qrDataUrl;
} catch (err) {
console.warn('Could not generate config QR code:', err.message);
return null;
}
}
/**
* Generate QR code for public key (legacy — raw key text)
*/
async function getPublicKeyQR() {
const pubKey = getPublicKey();
if (!pubKey) {
return null;
}
try {
const qrDataUrl = await QRCode.toDataURL(pubKey, {
errorCorrectionLevel: 'M',
type: 'image/png',
width: 256,
margin: 2,
color: {
dark: '#000000',
light: '#ffffff'
}
});
return qrDataUrl;
} catch (err) {
console.warn('Could not generate QR code:', err.message);
return null;
}
}
/**
* Get server configuration info
*/
function getServerConfig() {
return {
publicKey: getPublicKey(),
apiKeyMasked: getApiKey(true),
hbbsApiUrl: config.hbbsApiUrl,
dbPath: config.dbPath,
pubKeyPath: config.pubKeyPath,
apiKeyPath: config.apiKeyPath
};
}
module.exports = {
getPublicKey,
getApiKey,
getPublicKeyQR,
getServerConfigQR,
getServerConfig
};