"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LinuxInstaller = 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 semver_1 = require("semver");
const systeminformation_1 = require("systeminformation");
const node_version_constants_1 = require("../../core/node-version.constants");
const base_platform_1 = require("../base-platform");
class LinuxInstaller extends base_platform_1.BasePlatform {
    get systemdServiceName() {
        return this.hbService.serviceName.toLowerCase();
    }
    get systemdServicePath() {
        return (0, node_path_1.resolve)('/etc/systemd/system', `${this.systemdServiceName}.service`);
    }
    get systemdEnvPath() {
        return (0, node_path_1.resolve)('/etc/default', this.systemdServiceName);
    }
    get runPartsPath() {
        return (0, node_path_1.resolve)('/etc/hb-service', this.hbService.serviceName.toLowerCase(), 'prestart.d');
    }
    async install() {
        this.checkForRoot();
        await this.checkUser();
        this.setupSudo();
        await this.hbService.portCheck();
        await this.hbService.storagePathCheck();
        await this.hbService.configCheck();
        try {
            await this.createSystemdEnvFile();
            await this.createSystemdService();
            await this.createRunPartsPath();
            await this.reloadSystemd();
            await this.enableService();
            await this.createFirewallRules();
            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.systemdServicePath)) {
                (0, fs_extra_1.unlinkSync)(this.systemdServicePath);
            }
            if ((0, fs_extra_1.existsSync)(this.systemdEnvPath)) {
                (0, fs_extra_1.unlinkSync)(this.systemdEnvPath);
            }
            await this.reloadSystemd();
            this.hbService.logger(`Removed ${this.hbService.serviceName} Service`, 'succeed');
        }
        catch (e) {
            console.error(e.toString());
            this.hbService.logger('ERROR: Failed Operation', 'fail');
        }
    }
    async viewLogs() {
        try {
            const ret = (0, node_child_process_1.execSync)(`journalctl -n 50 -u ${this.systemdServiceName} --no-pager`).toString();
            console.log(ret);
        }
        catch (e) {
            this.hbService.logger(`Failed to start ${this.hbService.serviceName} - ${e}`, 'fail');
        }
    }
    async start() {
        this.checkForRoot();
        this.fixPermissions();
        try {
            this.hbService.logger(`Starting ${this.hbService.serviceName} Service...`);
            (0, node_child_process_1.execSync)(`systemctl start ${this.systemdServiceName}`);
            (0, node_child_process_1.execSync)(`systemctl status ${this.systemdServiceName} --no-pager`);
        }
        catch (e) {
            this.hbService.logger(`Failed to start ${this.hbService.serviceName} - ${e}`, 'fail');
            node_process_1.default.exit(1);
        }
    }
    async stop() {
        this.checkForRoot();
        try {
            this.hbService.logger(`Stopping ${this.hbService.serviceName} Service...`);
            (0, node_child_process_1.execSync)(`systemctl stop ${this.systemdServiceName}`);
            this.hbService.logger(`${this.hbService.serviceName} Stopped`, 'succeed');
        }
        catch (e) {
            this.hbService.logger(`Failed to stop ${this.systemdServiceName} - ${e}`, 'fail');
        }
    }
    async restart() {
        this.checkForRoot();
        this.fixPermissions();
        try {
            this.hbService.logger(`Restarting ${this.hbService.serviceName} Service...`);
            (0, node_child_process_1.execSync)(`systemctl restart ${this.systemdServiceName}`);
            (0, node_child_process_1.execSync)(`systemctl status ${this.systemdServiceName} --no-pager`);
            this.hbService.logger(`${this.hbService.serviceName} Restarted`, 'succeed');
        }
        catch (e) {
            this.hbService.logger(`Failed to restart ${this.hbService.serviceName} - ${e}`, 'fail');
        }
    }
    async beforeStart() {
        if ([
            '/usr/local/lib/node_modules',
            '/usr/lib/node_modules',
        ].includes((0, node_path_1.dirname)(node_process_1.default.env.UIX_BASE_PATH))) {
            setTimeout(() => {
                node_process_1.default.exit(0);
            }, 60000);
            const modulesPath = (0, node_path_1.dirname)(node_process_1.default.env.UIX_BASE_PATH);
            const temporaryDirectoriesToClean = (await (0, fs_extra_1.readdir)(modulesPath)).filter((x) => {
                return x.startsWith('.homebridge-');
            });
            for (const directory of temporaryDirectoriesToClean) {
                const pathToRemove = (0, node_path_1.join)(modulesPath, directory);
                try {
                    console.log('Removing stale temporary directory:', pathToRemove);
                    await (0, fs_extra_1.rm)(pathToRemove, { recursive: true, force: true });
                }
                catch (e) {
                    console.error('Failed to remove:', pathToRemove, e);
                }
            }
        }
        node_process_1.default.exit(0);
    }
    async rebuild(all = false) {
        try {
            if (this.isPackage()) {
                this.checkIsNotRoot();
            }
            else {
                this.checkForRoot();
            }
            const targetNodeVersion = (0, node_child_process_1.execSync)('node -v').toString('utf8').trim();
            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');
            (0, node_child_process_1.execSync)('npm rebuild --unsafe-perm', {
                cwd: node_process_1.default.env.UIX_BASE_PATH,
                stdio: 'inherit',
            });
            this.hbService.logger(`Rebuilt homebridge-config-ui-x for Node.js ${targetNodeVersion}.`, 'succeed');
            if (all === true) {
                try {
                    (0, node_child_process_1.execSync)('npm rebuild --unsafe-perm', {
                        cwd: npmGlobalPath,
                        stdio: 'inherit',
                    });
                    this.hbService.logger(`Rebuilt plugins in ${npmGlobalPath} for Node.js ${targetNodeVersion}.`, 'succeed');
                }
                catch (e) {
                    this.hbService.logger('Could not rebuild all plugins - check logs.', 'warn');
                }
            }
        }
        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) {
            const uid = (0, node_child_process_1.execSync)(`id -u ${this.hbService.asUser}`).toString('utf8');
            const gid = (0, node_child_process_1.execSync)(`id -g ${this.hbService.asUser}`).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 {
            if (this.hbService.docker) {
                return (0, node_child_process_1.execSync)('pidof homebridge').toString('utf8').trim();
            }
            else {
                return (0, node_child_process_1.execSync)(`fuser ${port}/tcp 2>/dev/null`).toString('utf8').trim();
            }
        }
        catch (e) {
            return null;
        }
    }
    async updateNodejs(job) {
        if (this.isPackage()) {
            this.checkIsNotRoot();
        }
        else {
            this.checkForRoot();
        }
        if ((0, semver_1.gte)(job.target, '24.0.0')) {
            if (!(0, node_version_constants_1.isNodeV24SupportedArchitecture)()) {
                this.hbService.logger(`Node.js ${job.target} is not supported on ${node_process_1.default.arch} architecture.`, 'fail');
                this.hbService.logger('Node.js v24 requires a 64-bit architecture. Please use Node.js v22 instead.', 'fail');
                node_process_1.default.exit(1);
            }
        }
        const targetPath = (0, node_path_1.dirname)((0, node_path_1.dirname)(node_process_1.default.execPath));
        if (targetPath !== '/usr' && targetPath !== '/usr/local' && targetPath !== '/opt/homebridge' && !targetPath.endsWith('/@appstore/homebridge/app')) {
            this.hbService.logger(`Cannot update Node.js on your system. Non-standard installation path detected: ${targetPath}`, 'fail');
            node_process_1.default.exit(1);
        }
        if (targetPath === '/usr' && await (0, fs_extra_1.pathExists)('/etc/apt/sources.list.d/nodesource.list')) {
            await this.updateNodeFromNodesource(job);
        }
        else {
            await this.updateNodeFromTarball(job, targetPath);
        }
        if (job.rebuild) {
            this.hbService.logger(`Rebuilding for Node.js ${job.target}...`);
            await this.rebuild(true);
        }
        if (await (0, fs_extra_1.pathExists)(this.systemdServicePath)) {
            await this.restart();
        }
        else {
            this.hbService.logger('Please restart Homebridge for the changes to take effect.', 'warn');
        }
    }
    async glibcVersionCheck(target) {
        const glibcVersion = Number.parseFloat((0, node_child_process_1.execSync)('getconf GNU_LIBC_VERSION 2>/dev/null').toString().split('glibc')[1].trim());
        if (glibcVersion < 2.23) {
            this.hbService.logger('Your version of Linux does not meet the GLIBC version requirements to use this tool to upgrade Node.js. '
                + `Wanted: >=2.23. Installed: ${glibcVersion} - see https://homebridge.io/w/JJSun`, 'fail');
            node_process_1.default.exit(1);
        }
        if ((0, semver_1.gte)(target, '18.0.0') && glibcVersion < 2.28) {
            this.hbService.logger('Your version of Linux does not meet the GLIBC version requirements to use this tool to upgrade Node.js. '
                + `Wanted: >=2.28. Installed: ${glibcVersion} - see https://homebridge.io/w/JJSun`, 'fail');
            node_process_1.default.exit(1);
        }
        if ((0, semver_1.gte)(target, '20.0.0') && glibcVersion < 2.31) {
            this.hbService.logger('Your version of Linux does not meet the GLIBC version requirements to use this tool to upgrade Node.js. '
                + `Wanted: >=2.31. Installed: ${glibcVersion} - see https://homebridge.io/w/JJSun`, 'fail');
            node_process_1.default.exit(1);
        }
    }
    async updateNodeFromTarball(job, targetPath) {
        try {
            if (node_process_1.default.env.HOMEBRIDGE_SYNOLOGY_PACKAGE === '1') {
                if ((0, semver_1.gte)(job.target, '18.0.0')) {
                    this.hbService.logger('Cannot update Node.js on your system. Synology DSM 7 does not currently support Node.js 18 or later.', 'fail');
                    node_process_1.default.exit(1);
                }
            }
            else {
                await this.glibcVersionCheck(job.target);
            }
        }
        catch (e) {
            const os = await (0, systeminformation_1.osInfo)();
            if (os.distro === 'Alpine Linux') {
                this.hbService.logger('Updating Node.js on Alpine Linux / Docker is not supported by this command.', 'fail');
                this.hbService.logger('To update Node.js you should pull down the latest version of the homebridge/homebridge Docker image.', 'fail');
            }
            else {
                this.hbService.logger('Updating Node.js using this tool is not supported on your version of Linux.');
            }
            node_process_1.default.exit(1);
        }
        const uname = (0, node_child_process_1.execSync)('uname -m').toString().trim();
        let downloadUrl;
        switch (uname) {
            case 'x86_64':
                downloadUrl = `https://nodejs.org/dist/${job.target}/node-${job.target}-linux-x64.tar.gz`;
                break;
            case 'aarch64':
                if ((0, node_child_process_1.execSync)('getconf LONG_BIT')?.toString()?.trim() === '32') {
                    downloadUrl = `https://nodejs.org/dist/${job.target}/node-${job.target}-linux-armv7l.tar.gz`;
                }
                else {
                    downloadUrl = `https://nodejs.org/dist/${job.target}/node-${job.target}-linux-arm64.tar.gz`;
                }
                break;
            case 'armv7l':
                downloadUrl = `https://nodejs.org/dist/${job.target}/node-${job.target}-linux-armv7l.tar.gz`;
                break;
            case 'armv6l':
                downloadUrl = `https://unofficial-builds.nodejs.org/download/release/${job.target}/node-${job.target}-linux-armv6l.tar.gz`;
                break;
            default:
                this.hbService.logger(`Architecture not supported: ${node_process_1.default.arch}.`, 'fail');
                node_process_1.default.exit(1);
        }
        this.hbService.logger(`Target: ${targetPath}`);
        try {
            const archivePath = await this.hbService.downloadNodejs(downloadUrl);
            const extractConfig = {
                file: archivePath,
                cwd: targetPath,
                strip: 1,
                preserveOwner: false,
                unlink: true,
            };
            await this.hbService.removeNpmPackage((0, node_path_1.resolve)(targetPath, 'lib', 'node_modules', 'npm'));
            await this.hbService.extractNodejs(job.target, extractConfig);
            await (0, fs_extra_1.remove)(archivePath);
        }
        catch (e) {
            this.hbService.logger(`Failed to update Node.js: ${e.message}`, 'fail');
            node_process_1.default.exit(1);
        }
    }
    async updateNodeFromNodesource(job) {
        this.hbService.logger('Updating from NodeSource...');
        try {
            await this.glibcVersionCheck(job.target);
            const majorVersion = (0, semver_1.parse)(job.target).major;
            (0, node_child_process_1.execSync)('apt-get update --allow-releaseinfo-change && sudo apt-get install -y ca-certificates curl gnupg', {
                stdio: 'inherit',
            });
            (0, node_child_process_1.execSync)('mkdir -p /etc/apt/keyrings', {
                stdio: 'inherit',
            });
            (0, node_child_process_1.execSync)('curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor --yes -o /etc/apt/keyrings/nodes', {
                stdio: 'inherit',
            });
            if (await (0, fs_extra_1.pathExists)('/usr/share/keyrings/nodesource.gpg')) {
                (0, node_child_process_1.execSync)('rm -f /usr/share/keyrings/nodesource.gpg', {
                    stdio: 'inherit',
                });
            }
            (0, node_child_process_1.execSync)(`echo "deb [signed-by=/etc/apt/keyrings/nodes] https://deb.nodesource.com/node_${majorVersion}.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list`, {
                stdio: 'inherit',
            });
            if (majorVersion < (0, semver_1.parse)(node_process_1.default.version).major) {
                (0, node_child_process_1.execSync)('apt-get remove -y nodejs', {
                    stdio: 'inherit',
                });
            }
            (0, node_child_process_1.execSync)('apt-get update && apt-get install -y nodejs', {
                stdio: 'inherit',
            });
        }
        catch (e) {
            this.hbService.logger(`Failed to update Node.js: ${e.message}`, 'fail');
            node_process_1.default.exit(1);
        }
    }
    async reloadSystemd() {
        try {
            (0, node_child_process_1.execSync)('systemctl daemon-reload');
        }
        catch (e) {
            this.hbService.logger('WARNING: failed to run "systemctl daemon-reload"', 'warn');
        }
    }
    async enableService() {
        try {
            (0, node_child_process_1.execSync)(`systemctl enable ${this.systemdServiceName} 2> /dev/null`);
        }
        catch (e) {
            this.hbService.logger(`WARNING: failed to run "systemctl enable ${this.systemdServiceName}"`, 'warn');
        }
    }
    async disableService() {
        try {
            (0, node_child_process_1.execSync)(`systemctl disable ${this.systemdServiceName} 2> /dev/null`);
        }
        catch (e) {
            this.hbService.logger(`WARNING: failed to run "systemctl disable ${this.systemdServiceName}"`, 'warn');
        }
    }
    checkForRoot() {
        if (this.isPackage()) {
            this.hbService.logger('ERROR: This command is not available.', 'fail');
            node_process_1.default.exit(1);
        }
        if (node_process_1.default.getuid() !== 0) {
            this.hbService.logger('ERROR: This command must be executed using sudo on Linux', 'fail');
            this.hbService.logger(`EXAMPLE: sudo hb-service ${this.hbService.action}`, 'fail');
            node_process_1.default.exit(1);
        }
        if (this.hbService.action === 'install' && !this.hbService.asUser) {
            this.hbService.logger('ERROR: User parameter missing. 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);
        }
    }
    checkIsNotRoot() {
        if (node_process_1.default.getuid() === 0 && !this.hbService.allowRunRoot && node_process_1.default.env.HOMEBRIDGE_CONFIG_UI !== '1') {
            this.hbService.logger('ERROR: This command must not be executed as root or with sudo', 'fail');
            this.hbService.logger('ERROR: If you know what you are doing; you can override this by adding --allow-root', '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)(`useradd -m --system ${this.hbService.asUser}`);
            this.hbService.logger(`Created service user: ${this.hbService.asUser}`, 'info');
            if (this.hbService.addGroup) {
                (0, node_child_process_1.execSync)(`usermod -a -G ${this.hbService.addGroup} ${this.hbService.asUser}`, { timeout: 10000 });
                this.hbService.logger(`Added ${this.hbService.asUser} to group ${this.hbService.addGroup}`, 'info');
            }
        }
        try {
            const os = await (0, systeminformation_1.osInfo)();
            if (os.distro === 'Raspbian GNU/Linux') {
                (0, node_child_process_1.execSync)(`usermod -a -G audio,bluetooth,dialout,gpio,video ${this.hbService.asUser} 2> /dev/null`);
                (0, node_child_process_1.execSync)(`usermod -a -G input,i2c,spi ${this.hbService.asUser} 2> /dev/null`);
            }
        }
        catch (e) {
        }
    }
    setupSudo() {
        try {
            const npmPath = (0, node_child_process_1.execSync)('which npm').toString('utf8').trim();
            const shutdownPath = (0, node_child_process_1.execSync)('which shutdown').toString('utf8').trim();
            const sudoersEntry = `${this.hbService.asUser}    ALL=(ALL) NOPASSWD:SETENV: ${shutdownPath}, ${npmPath}, /usr/bin/npm, /usr/local/bin/npm`;
            const sudoers = (0, fs_extra_1.readFileSync)('/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');
        }
    }
    isPackage() {
        return (Boolean(node_process_1.default.env.HOMEBRIDGE_SYNOLOGY_PACKAGE === '1')
            || Boolean(node_process_1.default.env.HOMEBRIDGE_APT_PACKAGE === '1'));
    }
    fixPermissions() {
        if ((0, fs_extra_1.existsSync)(this.systemdServicePath) && (0, fs_extra_1.existsSync)(this.systemdEnvPath)) {
            try {
                const serviceUser = (0, node_child_process_1.execSync)(`cat "${this.systemdServicePath}" | grep "User=" | awk -F'=' '{print $2}'`)
                    .toString('utf8')
                    .trim();
                const storagePath = (0, node_child_process_1.execSync)(`cat "${this.systemdEnvPath}" | grep "UIX_STORAGE_PATH" | awk -F'=' '{print $2}' | sed -e 's/^"//' -e 's/"$//'`)
                    .toString('utf8')
                    .trim();
                if (storagePath.length > 5 && (0, fs_extra_1.existsSync)(storagePath)) {
                    (0, node_child_process_1.execSync)(`chown -R ${serviceUser}: "${storagePath}"`);
                }
                (0, node_child_process_1.execSync)(`chmod a+x ${this.hbService.selfPath}`);
            }
            catch (e) {
                this.hbService.logger('WARNING: Failed to set permissions', 'warn');
            }
        }
    }
    async createFirewallRules() {
        if (await (0, fs_extra_1.pathExists)('/usr/sbin/ufw')) {
            return await this.createUfwRules();
        }
        if (await (0, fs_extra_1.pathExists)('/usr/bin/firewall-cmd')) {
            return await this.createFirewallCmdRules();
        }
    }
    async createUfwRules() {
        try {
            const status = (0, node_child_process_1.execSync)('/bin/echo -n "$(ufw status)" 2> /dev/null').toString('utf8');
            if (!status.includes('Status: active')) {
                return;
            }
            const currentConfig = await (0, fs_extra_1.readJson)(node_process_1.default.env.UIX_CONFIG_PATH);
            const bridgePort = currentConfig.bridge?.port;
            (0, node_child_process_1.execSync)(`ufw allow ${this.hbService.uiPort}/tcp 2> /dev/null`);
            this.hbService.logger(`Added firewall rule to allow inbound traffic on port ${this.hbService.uiPort}/tcp`, 'info');
            if (bridgePort) {
                (0, node_child_process_1.execSync)(`ufw allow ${bridgePort}/tcp 2> /dev/null`);
                this.hbService.logger(`Added firewall rule to allow inbound traffic on port ${bridgePort}/tcp`, 'info');
            }
        }
        catch (e) {
            this.hbService.logger('WARNING: failed to allow ports through firewall.', 'warn');
        }
    }
    async createFirewallCmdRules() {
        try {
            const status = (0, node_child_process_1.execSync)('/bin/echo -n "$(firewall-cmd --state)" 2> /dev/null').toString('utf8');
            if (status !== 'running') {
                return;
            }
            const currentConfig = await (0, fs_extra_1.readJson)(node_process_1.default.env.UIX_CONFIG_PATH);
            const bridgePort = currentConfig.bridge?.port;
            (0, node_child_process_1.execSync)(`firewall-cmd --permanent --add-port=${this.hbService.uiPort}/tcp 2> /dev/null`);
            this.hbService.logger(`Added firewall rule to allow inbound traffic on port ${this.hbService.uiPort}/tcp`, 'info');
            if (bridgePort) {
                (0, node_child_process_1.execSync)(`firewall-cmd --permanent --add-port=${bridgePort}/tcp 2> /dev/null`);
                this.hbService.logger(`Added firewall rule to allow inbound traffic on port ${bridgePort}/tcp`, 'info');
            }
            (0, node_child_process_1.execSync)('firewall-cmd --reload 2> /dev/null');
            this.hbService.logger('Firewall reloaded', 'info');
        }
        catch (e) {
            this.hbService.logger('WARNING: failed to allow ports through firewall.', 'warn');
        }
    }
    async createRunPartsPath() {
        await (0, fs_extra_1.mkdirp)(this.runPartsPath);
        const permissionScriptPath = (0, node_path_1.resolve)(this.runPartsPath, '10-fix-permissions');
        const permissionScript = [
            '#!/bin/sh',
            '',
            '# Ensure the storage path permissions are correct',
            'if [ -n "$UIX_STORAGE_PATH" ] && [ -n "$USER" ]; then',
            '  echo "Ensuring $UIX_STORAGE_PATH is owned by $USER"',
            '  [ -d $UIX_STORAGE_PATH ] || mkdir -p $UIX_STORAGE_PATH',
            '  chown -R $USER: $UIX_STORAGE_PATH',
            'fi',
        ].filter(x => x !== null).join('\n');
        await (0, fs_extra_1.writeFile)(permissionScriptPath, permissionScript);
        await (0, fs_extra_1.chmod)(permissionScriptPath, '755');
    }
    async createSystemdEnvFile() {
        const envFile = [
            `HOMEBRIDGE_OPTS=-I -U "${this.hbService.storagePath}"`,
            `UIX_STORAGE_PATH="${this.hbService.storagePath}"`,
            '',
            '# To enable web terminals via homebridge-config-ui-x uncomment the following line',
            'HOMEBRIDGE_CONFIG_UI_TERMINAL=1',
            '',
            'DISABLE_OPENCOLLECTIVE=true',
        ].filter(x => x !== null).join('\n');
        await (0, fs_extra_1.writeFile)(this.systemdEnvPath, envFile);
    }
    async createSystemdService() {
        const serviceFile = [
            '[Unit]',
            `Description=${this.hbService.serviceName}`,
            'Wants=network-online.target',
            'After=syslog.target network-online.target',
            '',
            '[Service]',
            'Type=simple',
            `User=${this.hbService.asUser}`,
            'PermissionsStartOnly=true',
            `WorkingDirectory=${this.hbService.storagePath}`,
            `EnvironmentFile=/etc/default/${this.systemdServiceName}`,
            `ExecStartPre=-/bin/run-parts ${this.runPartsPath}`,
            `ExecStartPre=-${this.hbService.selfPath} before-start $HOMEBRIDGE_OPTS`,
            `ExecStart=${this.hbService.selfPath} run $HOMEBRIDGE_OPTS`,
            'Restart=always',
            'RestartSec=3',
            'KillMode=process',
            'CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_CHOWN CAP_FOWNER CAP_DAC_OVERRIDE CAP_AUDIT_WRITE CAP_SYS_ADMIN',
            'AmbientCapabilities=CAP_NET_RAW CAP_NET_BIND_SERVICE',
            '',
            '[Install]',
            'WantedBy=multi-user.target',
        ].filter(x => x !== null).join('\n');
        await (0, fs_extra_1.writeFile)(this.systemdServicePath, serviceFile);
    }
}
exports.LinuxInstaller = LinuxInstaller;
//# sourceMappingURL=linux.js.map