"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigService = void 0;
const node_crypto_1 = require("node:crypto");
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const node_process_1 = __importDefault(require("node:process"));
const common_1 = require("@nestjs/common");
const fs_extra_1 = require("fs-extra");
const lodash_1 = require("lodash");
const semver_1 = require("semver");
let ConfigService = class ConfigService {
    constructor() {
        this.name = 'homebridge-config-ui-x';
        this.configPath = node_process_1.default.env.UIX_CONFIG_PATH || (0, node_path_1.resolve)((0, node_os_1.homedir)(), '.homebridge/config.json');
        this.storagePath = node_process_1.default.env.UIX_STORAGE_PATH || (0, node_path_1.resolve)((0, node_os_1.homedir)(), '.homebridge');
        this.customPluginPath = node_process_1.default.env.UIX_CUSTOM_PLUGIN_PATH;
        this.strictPluginResolution = (node_process_1.default.env.UIX_STRICT_PLUGIN_RESOLUTION === '1');
        this.secretPath = (0, node_path_1.resolve)(this.storagePath, '.uix-secrets');
        this.authPath = (0, node_path_1.resolve)(this.storagePath, 'auth.json');
        this.accessoryLayoutPath = (0, node_path_1.resolve)(this.storagePath, 'accessories', 'uiAccessoriesLayout.json');
        this.configBackupPath = (0, node_path_1.resolve)(this.storagePath, 'backups/config-backups');
        this.instanceBackupPath = (0, node_path_1.resolve)(this.storagePath, 'backups/instance-backups');
        this.homebridgeInsecureMode = Boolean(node_process_1.default.env.UIX_INSECURE_MODE === '1');
        this.minimumNodeVersion = '20.19.0';
        this.runningInDocker = Boolean(node_process_1.default.env.HOMEBRIDGE_CONFIG_UI === '1');
        this.runningInSynologyPackage = Boolean(node_process_1.default.env.HOMEBRIDGE_SYNOLOGY_PACKAGE === '1');
        this.runningInPackageMode = Boolean(node_process_1.default.env.HOMEBRIDGE_APT_PACKAGE === '1');
        this.runningInLinux = (!this.runningInDocker && !this.runningInSynologyPackage && !this.runningInPackageMode && (0, node_os_1.platform)() === 'linux');
        this.runningInFreeBSD = ((0, node_os_1.platform)() === 'freebsd');
        this.canShutdownRestartHost = (this.runningInLinux || node_process_1.default.env.UIX_CAN_SHUTDOWN_RESTART_HOST === '1');
        this.enableTerminalAccess = (this.runningInDocker && node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_TERMINAL !== '0')
            || (this.runningInPackageMode && node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_TERMINAL !== '0')
            || this.runningInSynologyPackage
            || Boolean(node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_TERMINAL === '1');
        this.usePluginBundles = (node_process_1.default.env.UIX_USE_PLUGIN_BUNDLES === '1');
        this.recommendChildBridges = ((0, node_os_1.totalmem)() > 2e+9);
        this.runningOnRaspberryPi = false;
        this.startupScript = (0, node_path_1.resolve)(this.storagePath, 'startup.sh');
        this.dockerOfflineUpdate = this.runningInDocker && (0, semver_1.satisfies)(node_process_1.default.env.CONFIG_UI_VERSION, '>=4.6.2 <=4.44.1', { includePrerelease: true });
        this.package = (0, fs_extra_1.readJsonSync)((0, node_path_1.resolve)(node_process_1.default.env.UIX_BASE_PATH, 'package.json'));
        this.hbStartupSettings = (0, fs_extra_1.pathExistsSync)((0, node_path_1.resolve)(this.storagePath, '.uix-hb-service-homebridge-startup.json'))
            ? (0, fs_extra_1.readJsonSync)((0, node_path_1.resolve)(this.storagePath, '.uix-hb-service-homebridge-startup.json'))
            : {};
        this.setupWizardComplete = true;
        this.hbServiceUiRestartRequired = false;
        const homebridgeConfig = (0, fs_extra_1.readJSONSync)(this.configPath);
        this.parseConfig(homebridgeConfig);
        this.checkIfRunningOnRaspberryPi();
    }
    parseConfig(homebridgeConfig) {
        this.homebridgeConfig = homebridgeConfig;
        if (!this.homebridgeConfig.bridge) {
            this.homebridgeConfig.bridge = {};
        }
        this.ui = Array.isArray(this.homebridgeConfig.platforms) ? this.homebridgeConfig.platforms.find(x => x.platform === 'config') : undefined;
        if (!this.ui) {
            this.ui = {
                name: 'Config',
            };
        }
        node_process_1.default.env.UIX_PLUGIN_NAME = this.ui.name || 'homebridge-config-ui-x';
        if (this.runningInDocker) {
            this.setConfigForDocker();
        }
        this.setConfig();
        if (!this.ui.port) {
            this.ui.port = 8080;
        }
        if (!this.ui.sessionTimeout) {
            this.ui.sessionTimeout = this.ui.auth === 'none' ? 1296000 : 28800;
        }
        if (this.ui.scheduledBackupPath) {
            this.instanceBackupPath = this.ui.scheduledBackupPath;
        }
        else {
            this.instanceBackupPath = (0, node_path_1.resolve)(this.storagePath, 'backups/instance-backups');
        }
        this.secrets = this.getSecrets();
        this.instanceId = this.getInstanceId();
        this.freezeUiSettings();
        this.getCustomWallpaperHash();
    }
    uiSettings(authorized = false) {
        const toReturn = {
            env: {
                canShutdownRestartHost: this.canShutdownRestartHost,
                customWallpaperHash: this.customWallpaperHash,
                dockerOfflineUpdate: this.dockerOfflineUpdate,
                homebridgeVersion: this.homebridgeVersion || null,
                homebridgeInstanceName: this.homebridgeConfig.bridge.name,
                instanceId: this.instanceId,
                lang: this.ui.lang === 'auto' ? null : this.ui.lang,
                packageName: this.package.name,
                packageVersion: this.package.version,
                platform: (0, node_os_1.platform)(),
                port: this.ui.port,
                setupWizardComplete: this.setupWizardComplete,
                scheduledBackupDisable: Boolean(this.ui.scheduledBackupDisable),
                scheduledBackupPath: this.ui.scheduledBackupPath || this.instanceBackupPath,
            },
            formAuth: Boolean(this.ui.auth !== 'none'),
            sessionTimeout: this.ui.sessionTimeout || 28800,
            sessionTimeoutInactivityBased: Boolean(this.ui.sessionTimeoutInactivityBased),
            lightingMode: this.ui.lightingMode || 'auto',
            serverTimestamp: new Date().toISOString(),
            theme: this.ui.theme || 'deep-purple',
            menuMode: this.ui.menuMode || 'default',
        };
        if (!authorized) {
            return toReturn;
        }
        return {
            ...toReturn,
            env: {
                ...toReturn.env,
                enableAccessories: this.homebridgeInsecureMode,
                enableTerminalAccess: this.enableTerminalAccess,
                nodeVersion: node_process_1.default.version,
                recommendChildBridges: this.recommendChildBridges,
                runningInDocker: this.runningInDocker,
                runningInSynologyPackage: this.runningInSynologyPackage,
                runningInPackageMode: this.runningInPackageMode,
                runningInLinux: this.runningInLinux,
                runningInFreeBSD: this.runningInFreeBSD,
                runningOnRaspberryPi: this.runningOnRaspberryPi,
                temperatureUnits: this.ui.tempUnits || 'c',
                temp: this.ui.temp,
                log: {
                    maxSize: this.ui.log?.maxSize,
                    truncateSize: this.ui.log?.truncateSize,
                },
                ssl: {
                    key: this.ui.ssl?.key,
                    cert: this.ui.ssl?.cert,
                    pfx: this.ui.ssl?.pfx,
                    passphrase: this.ui.ssl?.passphrase,
                },
                accessoryControl: {
                    debug: this.ui.accessoryControl?.debug,
                    instanceBlacklist: this.ui.accessoryControl?.instanceBlacklist || [],
                },
                plugins: {
                    hideUpdatesFor: this.ui.plugins?.hideUpdatesFor || [],
                    alwaysShowBetas: Boolean(this.ui.plugins?.alwaysShowBetas),
                },
                linux: {
                    shutdown: this.ui.linux?.shutdown,
                    restart: this.ui.linux?.restart,
                },
                terminal: {
                    persistence: this.ui.terminal?.persistence,
                    hideWarning: this.ui.terminal?.hideWarning,
                    bufferSize: this.ui.terminal?.bufferSize || globalThis.terminal.bufferSize,
                },
            },
            menuMode: this.ui.menuMode || 'default',
            wallpaper: this.ui.wallpaper,
            host: this.ui.host || '',
            webroot: this.ui.webroot || '',
            originalWebroot: this.originalWebroot || '',
            proxyHost: this.ui.proxyHost || '',
            homebridgePackagePath: this.ui.homebridgePackagePath,
            disableServerMetricsMonitoring: this.ui.disableServerMetricsMonitoring,
            keepOrphans: this.hbStartupSettings?.keepOrphans || false,
        };
    }
    setOriginalWebroot(webroot) {
        this.originalWebroot = webroot;
    }
    async uiRestartRequired() {
        if (this.hbServiceUiRestartRequired) {
            return true;
        }
        const currentPackage = await (0, fs_extra_1.readJson)((0, node_path_1.resolve)(node_process_1.default.env.UIX_BASE_PATH, 'package.json'));
        if (currentPackage.version !== this.package.version) {
            return true;
        }
        return !((0, lodash_1.isEqual)(this.ui, this.uiFreeze) && (0, lodash_1.isEqual)(this.homebridgeConfig.bridge, this.bridgeFreeze));
    }
    freezeUiSettings() {
        if (!this.uiFreeze) {
            this.uiFreeze = {};
            Object.assign(this.uiFreeze, this.ui);
        }
        if (!this.bridgeFreeze) {
            this.bridgeFreeze = {};
            Object.assign(this.bridgeFreeze, this.homebridgeConfig.bridge);
        }
    }
    setConfigForDocker() {
        this.ui.restart = 'killall -15 homebridge; sleep 5.1; killall -9 homebridge; kill -9 $(pidof homebridge-config-ui-x);';
        this.homebridgeInsecureMode = Boolean(node_process_1.default.env.HOMEBRIDGE_INSECURE === '1');
        this.ui.sudo = false;
        this.ui.log = {
            method: 'file',
            path: '/homebridge/logs/homebridge.log',
            maxSize: this.ui.log?.maxSize,
            truncateSize: this.ui.log?.truncateSize,
        };
        if (!this.ui.port && node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_PORT) {
            this.ui.port = Number.parseInt(node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_PORT, 10);
        }
        this.ui.theme = this.ui.theme || node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_THEME || 'deep-purple';
        this.ui.auth = this.ui.auth || node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_AUTH || 'form';
        this.ui.wallpaper = this.ui.wallpaper || node_process_1.default.env.HOMEBRIDGE_CONFIG_UI_LOGIN_WALLPAPER || undefined;
    }
    setConfig() {
        this.homebridgeInsecureMode = Boolean(node_process_1.default.env.UIX_INSECURE_MODE === '1');
        this.ui.restart = undefined;
        this.ui.sudo = ((0, node_os_1.platform)() === 'linux' && !this.runningInDocker && !this.runningInSynologyPackage && !this.runningInPackageMode) || (0, node_os_1.platform)() === 'freebsd';
        this.ui.log = {
            method: 'native',
            path: (0, node_path_1.resolve)(this.storagePath, 'homebridge.log'),
            maxSize: this.ui.log?.maxSize,
            truncateSize: this.ui.log?.truncateSize,
        };
    }
    getSecrets() {
        if ((0, fs_extra_1.pathExistsSync)(this.secretPath)) {
            try {
                const secrets = (0, fs_extra_1.readJsonSync)(this.secretPath);
                if (!secrets.secretKey) {
                    return this.generateSecretToken();
                }
                else {
                    return secrets;
                }
            }
            catch (e) {
                return this.generateSecretToken();
            }
        }
        else {
            return this.generateSecretToken();
        }
    }
    generateSecretToken() {
        const secrets = {
            secretKey: (0, node_crypto_1.randomBytes)(32).toString('hex'),
        };
        (0, fs_extra_1.writeJsonSync)(this.secretPath, secrets);
        return secrets;
    }
    getInstanceId() {
        return (0, node_crypto_1.createHash)('sha256').update(this.secrets.secretKey).digest('hex');
    }
    async getCustomWallpaperHash() {
        try {
            if (this.ui.wallpaper) {
                const filePath = (0, node_path_1.resolve)(this.storagePath, this.ui.wallpaper);
                const fileStat = await (0, fs_extra_1.stat)(filePath);
                const hash = (0, node_crypto_1.createHash)('sha256');
                hash.update(`${fileStat.birthtime}${fileStat.ctime}${fileStat.size}${fileStat.blocks}`);
                this.customWallpaperHash = `${hash.digest('hex')}.jpg`;
            }
        }
        catch (e) {
        }
    }
    removeWallpaperCache() {
        this.customWallpaperHash = undefined;
    }
    streamCustomWallpaper() {
        return (0, fs_extra_1.createReadStream)((0, node_path_1.resolve)(this.storagePath, this.ui.wallpaper));
    }
    async checkIfRunningOnRaspberryPi() {
        try {
            this.runningOnRaspberryPi = await (0, fs_extra_1.pathExists)('/usr/bin/vcgencmd') && await (0, fs_extra_1.pathExists)('/usr/bin/raspi-config');
        }
        catch (e) {
            this.runningOnRaspberryPi = false;
        }
    }
};
exports.ConfigService = ConfigService;
exports.ConfigService = ConfigService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [])
], ConfigService);
//# sourceMappingURL=config.service.js.map