const { app, desktopCapturer, dialog, Tray, Menu, shell } = require('electron'); const { platform, hostname } = require('node:os'); const { existsSync, readFileSync } = require('node:fs'); const axios = require('axios'); const si = require('systeminformation'); global.luna_version = "1.4.0"; global.dsb_version = 7; global.lastSentData = {}; global.clientsList = {}; global.lastDataUpdate = 0; global.proxyStatus = 0; global.computerId = ""; function timeAgo(time) { if (!isNaN(parseInt(time))) { time = new Date(time).getTime(); } if (time === 0) return "never"; let periods = ["sec", "min", "hr", "d", "wk", "mo", "y", "ages"]; let lengths = ["60", "60", "24", "7", "4.35", "12", "100"]; let now = new Date().getTime(); let difference = Math.round((now - time) / 1000); let tense; let period; if (difference <= 10 && difference >= 0) { return "now"; } else if (difference > 0) { tense = "ago"; } else { tense = "later"; } let j; for (j = 0; difference >= lengths[j] && j < lengths.length - 1; j++) { difference /= lengths[j]; } difference = Math.round(difference); period = periods[j]; return `${difference} ${period} ${tense}`; } app.whenReady().then(() => { global.tray = new Tray(__dirname + '/icons/tray/16x16Template@2x.png'); updateTray(); }) function updateTray() { let template = [ { label: 'Luna ' + luna_version + '-' + dsb_version, type: 'normal', enabled: false, icon: __dirname + "/icons/menu/16x16@2x.png" }, { label: 'Last updated ' + timeAgo(global.lastDataUpdate), type: 'normal', enabled: false }, ]; template.push(...[ { type: 'separator' }, { label: "View on Cold Haze", accelerator: "CmdOrCtrl+O", click: () => { shell.openExternal("https://ponies.equestria.horse/-/computers/" + global.computerId) } }, { label: 'Quit', type: 'normal', role: 'quit', accelerator: "CmdOrCtrl+Q" } ]); const contextMenu = Menu.buildFromTemplate(template); tray.setToolTip('Luna ' + luna_version + '-' + dsb_version); tray.setContextMenu(contextMenu); } process.on('uncaughtException', (e) => { console.error(e); }) global.token = ""; async function systemProfile() { let osInfo = await si.osInfo(); let baseboard = await si.baseboard(); let processes = (await si.processes()).list; let data = { luna_version, dsb: { platform: "desktop", version: dsb_version }, top_sites: null, remote_control: false, host: hostname(), os: osInfo.distro + " " + osInfo.release, kernel: osInfo.platform.substring(0, 1).toUpperCase() + osInfo.platform.substring(1) + " " + osInfo.kernel + " (" + osInfo.arch + ")", serial: baseboard.serial ?? osInfo.serial, serial_source: baseboard.serial ? "hardware" : "software", date: new Date().toISOString(), screens: [], windows: [], cpu: (await si.cpu()), temperature: (await si.cpuTemperature()), ram: (await si.mem()), ram_chips: (await si.memLayout()), battery: (await si.battery()), os_info: (await si.osInfo()), gpu: (await si.graphics()), uuid: (await si.uuid()), versions: (await si.versions()), users: (await si.users()), filesystems: (await si.fsSize()), fs_stats: (await si.fsStats()), usb: (await si.usb()), audio: (await si.audio()), network: (await si.networkInterfaces()), connections: (await si.networkConnections()), processes: processes.map((i) => { return { pid: i.pid, name: i.name, cpu: i.cpu, ram: i.mem, date: new Date(i.started).toISOString(), user: i.user, path: i.path } }).sort((a, b) => { return b.cpu - a.cpu; }) } global.lastSentData = data; let sources = await desktopCapturer.getSources({ types: ['screen'], thumbnailSize: { width: 445, height: 256 } }); for (let source of sources) { data.screens.push({ id: source.display_id, gid: source.id, name: source.name, }); } try { global.computerId = (await axios("https://ponies.equestria.horse/api/computer?type=data", { method: "post", data, headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} })).data; global.lastDataUpdate = new Date().getTime(); } catch (e) { console.error(e); } } async function refresh() { let sources = await desktopCapturer.getSources({ types: ['screen'], thumbnailSize: { width: 445, height: 256 } }); for (let source of sources) { try { (await axios("https://ponies.equestria.horse/api/computer?type=screenshot", { method: "post", data: { host: hostname(), id: source.display_id, data: source.thumbnail.toJPEG(80).toString("base64") }, headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} })).data; } catch (e) { console.error(e); } } } global.i1 = global.i2 = global.i3 = global.i4 = null; global.startApp = async () => { let data = app.getPath('userData'); if (platform() === "darwin") app.dock.hide(); if (!existsSync(data + "/newtoken.txt")) { require('./auth')(); return; } else { global.token = readFileSync(data + "/newtoken.txt").toString().trim(); } try { if (!(await axios("https://ponies.equestria.horse/api/session", { headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} })).data['created']) { clearInterval(global.i1); clearInterval(global.i2); clearInterval(global.i3); clearInterval(global.i4); require('./auth')(); return; } } catch (e) { console.error(e); } try { await axios("https://ponies.equestria.horse/api/rename?name=" + encodeURIComponent("Luna " + luna_version + " (Desktop DSB " + dsb_version + ", " + hostname() + ", " + ((await si.osInfo()).distro) + ")"), { headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} }); } catch (e) {} refresh(); systemProfile(); global.i1 = setInterval(() => { updateTray(); }, 1000); global.i2 = setInterval(async () => { try { if (!(await axios("https://ponies.equestria.horse/api/session", { headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} })).data['created']) { clearInterval(global.i1); clearInterval(global.i2); clearInterval(global.i3); clearInterval(global.i4); require('./auth')(); return; } } catch (e) { console.error(e); } try { await axios("https://ponies.equestria.horse/api/rename?name=" + encodeURIComponent("Luna " + luna_version + " (Desktop DSB " + dsb_version + ", " + hostname() + ", " + ((await si.osInfo()).distro) + ")"), { headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} }); } catch (e) { console.error(e); } try { await axios("https://ponies.equestria.horse/api/computer?type=heartbeat", { method: "POST", data: { host: hostname() }, headers: {'Cookie': 'PEH2_SESSION_TOKEN=' + token} }); } catch (e) { console.error(e); } }, 5000); global.i3 = setInterval(() => { refresh(); }, 60000); global.i4 = setInterval(() => { systemProfile(); }, 600000); } app.whenReady().then(startApp)