UNPKG

homebridge-config-ui-x

Version:

A web based management, configuration and control platform for Homebridge.

250 lines • 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FreeBSDInstaller = void 0; const node_child_process_1 = require("node:child_process"); const node_os_1 = require("node:os"); const node_path_1 = require("node:path"); const node_process_1 = __importDefault(require("node:process")); const fs_extra_1 = require("fs-extra"); const base_platform_1 = require("../base-platform"); class FreeBSDInstaller extends base_platform_1.BasePlatform { get rcServiceName() { return this.hbService.serviceName.toLowerCase(); } get rcServicePath() { return (0, node_path_1.resolve)('/usr/local/etc/rc.d', this.rcServiceName); } async install() { this.checkForRoot(); await this.checkUser(); this.setupSudo(); await this.hbService.portCheck(); await this.hbService.storagePathCheck(); await this.hbService.configCheck(); try { await this.createRCService(); await this.enableService(); await this.start(); await this.hbService.printPostInstallInstructions(); } catch (e) { console.error(e.toString()); this.hbService.logger('ERROR: Failed Operation', 'fail'); } } async uninstall() { this.checkForRoot(); await this.stop(); await this.disableService(); try { if ((0, fs_extra_1.existsSync)(this.rcServicePath)) { this.hbService.logger(`Removed ${this.rcServiceName} Service`, 'succeed'); (0, fs_extra_1.unlinkSync)(this.rcServicePath); } else { this.hbService.logger(`Could not find installed ${this.rcServiceName} Service.`, 'fail'); } } catch (e) { console.error(e.toString()); this.hbService.logger('ERROR: Failed Operation', 'fail'); } } async start() { this.checkForRoot(); try { this.hbService.logger(`Starting ${this.rcServiceName} Service...`); (0, node_child_process_1.execSync)(`service ${this.rcServiceName} start`, { stdio: 'inherit' }); this.hbService.logger(`${this.rcServiceName} Started`, 'succeed'); } catch (e) { this.hbService.logger(`Failed to start ${this.rcServiceName}`, 'fail'); } } async stop() { this.checkForRoot(); try { this.hbService.logger(`Stopping ${this.rcServiceName} Service...`); (0, node_child_process_1.execSync)(`service ${this.rcServiceName} stop`, { stdio: 'inherit' }); this.hbService.logger(`${this.rcServiceName} Stopped`, 'succeed'); } catch (e) { this.hbService.logger(`Failed to stop ${this.rcServiceName}`, 'fail'); } } async restart() { this.checkForRoot(); try { this.hbService.logger(`Restarting ${this.rcServiceName} Service...`); (0, node_child_process_1.execSync)(`service ${this.rcServiceName} restart`, { stdio: 'inherit' }); this.hbService.logger(`${this.rcServiceName} Restarted`, 'succeed'); } catch (e) { this.hbService.logger(`Failed to restart ${this.rcServiceName}`, 'fail'); } } async rebuild(all = false) { try { this.checkForRoot(); const npmGlobalPath = (0, node_child_process_1.execSync)('/bin/echo -n "$(npm -g prefix)/lib/node_modules"', { env: Object.assign({ npm_config_loglevel: 'silent', npm_update_notifier: 'false', }, node_process_1.default.env), }).toString('utf8'); const targetNodeVersion = (0, node_child_process_1.execSync)('node -v').toString('utf8').trim(); (0, node_child_process_1.execSync)('npm rebuild --unsafe-perm', { cwd: node_process_1.default.env.UIX_BASE_PATH, stdio: 'inherit', }); if (all === true) { try { (0, node_child_process_1.execSync)('npm rebuild --unsafe-perm', { cwd: npmGlobalPath, stdio: 'inherit', }); } catch (e) { this.hbService.logger('Could not rebuild all modules - check Homebridge logs.', 'warn'); } } this.hbService.logger(`Rebuilt modules in ${node_process_1.default.env.UIX_BASE_PATH} for Node.js ${targetNodeVersion}.`, 'succeed'); } catch (e) { console.error(e.toString()); this.hbService.logger('ERROR: Failed Operation', 'fail'); } } async getId() { if ((node_process_1.default.getuid() === 0 && this.hbService.asUser) || node_process_1.default.env.SUDO_USER) { const uid = (0, node_child_process_1.execSync)(`id -u ${this.hbService.asUser || node_process_1.default.env.SUDO_USER}`).toString('utf8'); const gid = (0, node_child_process_1.execSync)(`id -g ${this.hbService.asUser || node_process_1.default.env.SUDO_USER}`).toString('utf8'); return { uid: Number.parseInt(uid, 10), gid: Number.parseInt(gid, 10), }; } else { return { uid: (0, node_os_1.userInfo)().uid, gid: (0, node_os_1.userInfo)().gid, }; } } getPidOfPort(port) { try { return (0, node_child_process_1.execSync)(`sockstat -P tcp -p ${port} -l -q 2> /dev/null | awk '{print $3}' | head -n 1`).toString('utf8').trim(); } catch (e) { return null; } } async enableService() { try { (0, node_child_process_1.execSync)(`sysrc ${this.rcServiceName}_enable="YES" 2> /dev/null`); } catch (e) { this.hbService.logger(`WARNING: failed to run "sysrc ${this.rcServiceName}_enable=\"YES\"`, 'warn'); } } async disableService() { try { (0, node_child_process_1.execSync)(`sysrc ${this.rcServiceName}_enable="NO" 2> /dev/null`); } catch (e) { this.hbService.logger(`WARNING: failed to run "sysrc ${this.rcServiceName}_enable=\"NO\"`, 'warn'); } } checkForRoot() { if (node_process_1.default.getuid() !== 0) { this.hbService.logger('ERROR: This command must be executed using sudo on FreeBSD', 'fail'); this.hbService.logger(`EXAMPLE: sudo hb-service ${this.hbService.action}`, 'fail'); node_process_1.default.exit(1); } if (this.hbService.action === 'install' && !node_process_1.default.env.SUDO_USER && !this.hbService.asUser) { this.hbService.logger('ERROR: Could not detect user. Pass in the user you want to run Homebridge as using the --user flag eg.', 'fail'); this.hbService.logger(`EXAMPLE: sudo hb-service ${this.hbService.action} --user your-user`, 'fail'); node_process_1.default.exit(1); } } async checkUser() { try { (0, node_child_process_1.execSync)(`id ${this.hbService.asUser} 2> /dev/null`); } catch (e) { (0, node_child_process_1.execSync)(`pw useradd -q -n ${this.hbService.asUser} -s /usr/sbin/nologin 2> /dev/null`); this.hbService.logger(`Created service user: ${this.hbService.asUser}`, 'info'); } } setupSudo() { try { const npmPath = (0, node_child_process_1.execSync)('which npm').toString('utf8').trim(); const sudoersEntry = `${this.hbService.asUser} ALL=(ALL) NOPASSWD:SETENV: ${npmPath}, /usr/local/bin/npm`; const sudoers = (0, fs_extra_1.readFileSync)('/usr/local/etc/sudoers', 'utf-8'); if (sudoers.includes(sudoersEntry)) { return; } (0, node_child_process_1.execSync)(`echo '${sudoersEntry}' | sudo EDITOR='tee -a' visudo`); } catch (e) { this.hbService.logger('WARNING: Failed to setup /etc/sudoers, you may not be able to shutdown/restart your server from the Homebridge UI.', 'warn'); } } async updateNodejs(job) { this.hbService.logger('Update Node.js using pkg manually.', 'fail'); node_process_1.default.exit(1); } async createRCService() { const rcFileContents = [ '#!/bin/sh', '#', `# PROVIDE: ${this.rcServiceName}`, '# REQUIRE: NETWORKING SYSLOG', '# KEYWORD: shutdown', '#', `# Add the following lines to /etc/rc.conf to enable ${this.rcServiceName}:`, '#', `#${this.rcServiceName}_enable="YES"`, '', '. /etc/rc.subr', '', `name="${this.rcServiceName}"`, `rcvar="${this.rcServiceName}_enable"`, '', 'load_rc_config $name', '', `: \${${this.rcServiceName}_user:="${this.hbService.asUser}"}`, `: \${${this.rcServiceName}_enable:="NO"}`, `: \${${this.rcServiceName}_facility:="daemon"}`, `: \${${this.rcServiceName}_priority:="debug"}`, `: \${${this.rcServiceName}_storage_path:="${this.hbService.storagePath}"}`, '', 'export HOME="$(eval echo ~${homebridge_user})"', 'export PATH=/usr/local/bin:${PATH}', 'export HOMEBRIDGE_CONFIG_UI_TERMINAL=1', 'export UIX_STORAGE_PATH="${homebridge_storage_path}"', '', 'pidfile="/var/run/${name}.pid"', 'command="/usr/sbin/daemon"', 'procname="daemon"', `command_args=" -c -f -R 3 -P \${pidfile} ${this.hbService.selfPath} run -U \${homebridge_storage_path}"`, 'start_precmd="homebridge_precmd"', '', 'homebridge_precmd()', '{', ' sleep 10', ' chown -R ${homebridge_user}: ${homebridge_storage_path}', ' install -o ${homebridge_user} /dev/null ${pidfile}', '}', '', 'run_rc_command "$1"', ].filter(x => x).join('\n'); await (0, fs_extra_1.outputFile)(this.rcServicePath, rcFileContents); await (0, fs_extra_1.chmod)(this.rcServicePath, '755'); } } exports.FreeBSDInstaller = FreeBSDInstaller; //# sourceMappingURL=freebsd.js.map