mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 09:35:39 +00:00
34ef01e17d
Require stricter client/server TLS options, centralize device auth on agent APIs, constrain Linux privileged update helpers, and harden filebrowser path checks with supporting audit notes. Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
109 lines
3.1 KiB
JavaScript
109 lines
3.1 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execFileSync } = require('child_process');
|
|
|
|
const ALLOWED_SYSTEMD_UNITS = new Set([
|
|
'/etc/systemd/system/betterdesk-server.service',
|
|
'/etc/systemd/system/betterdesk-console.service',
|
|
]);
|
|
|
|
function resolveSystemdUnitScriptPath(consoleRoot) {
|
|
return path.join(consoleRoot, 'scripts/linux-write-systemd-unit.js');
|
|
}
|
|
|
|
function normalizeUnitPath(filePath) {
|
|
if (!filePath || typeof filePath !== 'string') return null;
|
|
const trimmed = filePath.trim();
|
|
if (!path.isAbsolute(trimmed)) return null;
|
|
return path.resolve(trimmed);
|
|
}
|
|
|
|
function isAllowedSystemdUnitPath(filePath) {
|
|
const normalized = normalizeUnitPath(filePath);
|
|
if (!normalized) return false;
|
|
try {
|
|
const real = fs.existsSync(normalized) ? fs.realpathSync(normalized) : normalized;
|
|
return ALLOWED_SYSTEMD_UNITS.has(real);
|
|
} catch (_) {
|
|
return ALLOWED_SYSTEMD_UNITS.has(normalized);
|
|
}
|
|
}
|
|
|
|
function isRoot() {
|
|
return typeof process.getuid === 'function' && process.getuid() === 0;
|
|
}
|
|
|
|
function canUsePasswordlessSudo() {
|
|
if (isRoot()) return true;
|
|
try {
|
|
execFileSync('sudo', ['-n', 'true'], { stdio: 'pipe', timeout: 3000 });
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function invokeSystemdUnitScript(payload, consoleRoot) {
|
|
void payload;
|
|
void consoleRoot;
|
|
throw new Error(
|
|
'Systemd unit access requires a root maintenance run; '
|
|
+ 'the panel must not execute repository scripts as root',
|
|
);
|
|
}
|
|
|
|
function readSystemdUnitPrivileged(filePath, consoleRoot) {
|
|
if (!isAllowedSystemdUnitPath(filePath)) {
|
|
throw new Error(`Systemd unit path not allowed: ${filePath}`);
|
|
}
|
|
const normalized = normalizeUnitPath(filePath);
|
|
|
|
try {
|
|
return fs.readFileSync(normalized, 'utf8');
|
|
} catch (err) {
|
|
if (err.code !== 'EACCES' && err.code !== 'EPERM') throw err;
|
|
}
|
|
|
|
throw new Error(
|
|
`Cannot read protected systemd unit as the console user: ${normalized}. `
|
|
+ privilegedSystemdUnitHint(),
|
|
);
|
|
}
|
|
|
|
function writeSystemdUnitPrivileged(filePath, content, consoleRoot) {
|
|
if (!isAllowedSystemdUnitPath(filePath)) {
|
|
throw new Error(`Systemd unit path not allowed: ${filePath}`);
|
|
}
|
|
const normalized = normalizeUnitPath(filePath);
|
|
|
|
try {
|
|
fs.writeFileSync(normalized, content, { encoding: 'utf8', mode: 0o644 });
|
|
return;
|
|
} catch (err) {
|
|
if (err.code !== 'EACCES' && err.code !== 'EPERM') throw err;
|
|
}
|
|
|
|
void content;
|
|
throw new Error(
|
|
`Cannot write protected systemd unit as the console user: ${normalized}. `
|
|
+ privilegedSystemdUnitHint(),
|
|
);
|
|
}
|
|
|
|
function privilegedSystemdUnitHint() {
|
|
return 'Run once as root: sudo node web-nodejs/scripts/linux-ensure-console-user.js';
|
|
}
|
|
|
|
module.exports = {
|
|
ALLOWED_SYSTEMD_UNITS,
|
|
resolveSystemdUnitScriptPath,
|
|
normalizeUnitPath,
|
|
isAllowedSystemdUnitPath,
|
|
canUsePasswordlessSudo,
|
|
readSystemdUnitPrivileged,
|
|
writeSystemdUnitPrivileged,
|
|
privilegedSystemdUnitHint,
|
|
};
|