#!/usr/bin/env python3 """Restore corrupted The Lounge config.js on production VPS.""" from __future__ import annotations import paramiko import os from load_dev_env import ssh_config HOST, USER, SSH_PASSWORD = ssh_config() INSPECT = [ "cat /var/lib/thelounge/config.js 2>&1 | head -20", "ls -la /var/lib/thelounge/ 2>&1", "ls -la /var/lib/thelounge/*.bak /var/lib/thelounge/config.js.* 2>&1 || true", "cat /etc/systemd/system/thelounge.service 2>&1", "sudo ls -la /var/lib/thelounge/ 2>&1", ] LOUNGE_CONFIG = r"""'use strict'; module.exports = { host: '127.0.0.1', port: 9000, public: true, theme: 'morning', prefetch: false, disableLog: false, fileUpload: false, transports: ['websocket', 'polling'], defaults: { name: 'NomadCNA', username: 'nomad', realname: 'NomadCNA Community', join: '#nomadcna,#online-events', }, lockNetwork: true, messageStorage: [], useHexIp: false, maxHistory: 10000, displayNetwork: true, networks: [ { name: 'NomadCNA', host: '127.0.0.1', port: 6667, tls: false, rejectUnauthorized: false, nick: 'nomad', username: 'nomad', realname: 'NomadCNA Community', join: '#nomadcna,#online-events', commands: [], }, ], }; """ def run(commands: list[str]) -> None: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=PASSWORD, timeout=25) try: for cmd in commands: print(f"\n=== {cmd} ===") _, stdout, stderr = client.exec_command(cmd, timeout=60, get_pty=True) out = stdout.read().decode("utf-8", errors="replace") err = stderr.read().decode("utf-8", errors="replace") if out: print(out.rstrip()) if err: print("ERR:", err.rstrip()) finally: client.close() def restore() -> None: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=PASSWORD, timeout=25) try: sftp = client.open_sftp() remote_tmp = "/tmp/thelounge-config.js" with sftp.file(remote_tmp, "w") as f: f.write(LOUNGE_CONFIG) sftp.close() cmds = [ f"echo '{PASSWORD}' | sudo -S cp /var/lib/thelounge/config.js /var/lib/thelounge/config.js.broken-$(date +%Y%m%d%H%M%S) 2>/dev/null || true", f"echo '{PASSWORD}' | sudo -S cp {remote_tmp} /var/lib/thelounge/config.js", f"echo '{PASSWORD}' | sudo -S chown thelounge:thelounge /var/lib/thelounge/config.js", f"echo '{PASSWORD}' | sudo -S chmod 640 /var/lib/thelounge/config.js", f"echo '{PASSWORD}' | sudo -S systemctl restart thelounge.service", "sleep 3", "systemctl is-active thelounge.service", "curl -sI http://127.0.0.1:9000/ | head -8", "curl -sI https://lounge.nomadro.cn/ | head -8", "journalctl -u thelounge.service -n 15 --no-pager", ] for cmd in cmds: print(f"\n=== {cmd.replace(PASSWORD, '***')} ===") _, stdout, stderr = client.exec_command(cmd, timeout=60, get_pty=True) out = stdout.read().decode("utf-8", errors="replace") err = stderr.read().decode("utf-8", errors="replace") if out: print(out.rstrip()) if err: print("ERR:", err.rstrip()) finally: client.close() VERIFY = [ "systemctl is-active thelounge.service ergo.service", "curl -s 'https://lounge.nomadro.cn/socket.io/?EIO=4&transport=polling&t=health' | cut -c1-120", "{ printf 'NICK health\\r\\nUSER health 0 * :NomadCNA Health\\r\\nJOIN #nomadcna\\r\\nQUIT :healthcheck\\r\\n'; sleep 1; } | timeout 5s nc 127.0.0.1 6667 2>&1 | head -5", "curl -sI 'https://lounge.nomadro.cn/' | head -3", ] if __name__ == "__main__": import sys if len(sys.argv) > 1 and sys.argv[1] == "restore": restore() elif len(sys.argv) > 1 and sys.argv[1] == "verify": run(VERIFY) else: run(INSPECT)