diff --git a/README.md b/README.md index b3333da..9dbf1fa 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,8 @@ A Plutonium launcher that aims to make old CoD games more accessible ----- Currently being written from scratch, please be patient. + +## To do +- Make each HTTPS request its own function instead of binding them to an event +- De-duplicate code (HTTPS requests in src/main.js for example) +- Make a better UI/UX diff --git a/src/main.js b/src/main.js index 9173146..2ac2e81 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,6 @@ const path = require("node:path"); const fs = require("node:fs"); +const fsPromises = require("node:fs/promises"); const https = require("node:https"); const process = require("node:process"); const os = require("node:os"); @@ -43,6 +44,15 @@ let userInfo = { "emailVerified": false, "avatar": "https://forum.plutonium.pw/assets/uploads/system/avatar-default.png" }; +let config = { + "user-info": userInfo, + "game-directories": { + "iw5": "", + "t4": "", + "t5": "", + "t6": "" + } +}; function createMainWindow() { mainWindow = new electron.BrowserWindow({ @@ -65,6 +75,34 @@ function createMainWindow() { }); } +function readConfig(filePath) { + return new Promise(function (resolve, reject) { + if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) return reject(new Error("Config file doesn't exist or is not a file.")); + + fsPromises.readFile(filePath, "utf-8").then(function (contents) { + try { + let data = JSON.parse(contents); + + resolve(data); + } catch (error) { + reject(error); + } + }).catch(function (error) { + reject(error); + }); + }); +} + +function writeConfig(filePath, data = {}) { + return new Promise(function (resolve, reject) { + fsPromises.writeFile(filePath, JSON.stringify(data, null, "\t")).then(function () { + resolve(); + }).catch(function (error) { + reject(error); + }); + }); +} + function fetchPlutoniumManifest() { return new Promise(function (resolve, reject) { let request = https.request("https://cdn.plutonium.pw/updater/prod/info.json", { @@ -99,6 +137,62 @@ function fetchPlutoniumManifest() { }); } +function validatePlutoniumLogin(token) { + return new Promise(function (resolve, reject) { + let request = https.request("https://nix.plutonium.pw/api/auth/validate", { + "method": "GET", + "headers": { + "Content-Length": 0, + "Authorization": "UserToken " + token, + "X-Plutonium-Revision": String(plutoniumManifest.revision), + "User-Agent": "Nix/3.0" + } + }, function (response) { + if (response.statusCode !== 200) { + return resolve({ + "status": "unauthenticated", + "successful": false + }); + } + + response.setEncoding("utf-8"); + + let body = ""; + response.on("data", function (chunk) { + body += chunk; + }); + response.on("end", function () { + try { + let data = JSON.parse(body); + + if (!("userId" in data)) { + reject(new Error("Authentication seems to be successful but no user identifier was returned.")); + } + + resolve({ + "status": "authenticated", + "successful": true, + ...data + }); + + userInfo = { + "token": token, + ...data + }; + } catch (error) { + reject(error); + } + }); + }); + + request.on("error", function (error) { + reject(error); + }); + + request.end(); + }); +} + function getPlutoniumSession(game, token) { return new Promise(function (resolve, reject) { let payload = JSON.stringify({ @@ -180,6 +274,7 @@ function launch(plutoniumInstallDirectory, game, gameInstallDirectory, online) { } let gameProcess = child_process.spawn(bootstrapperBinary, bootstrapperArguments, { + "cwd": plutoniumInstallDirectory, "detached": true, "stdio": "ignore" }); @@ -201,6 +296,33 @@ electron.app.once("ready", function () { }).catch(function (error) { electron.dialog.showErrorBox("Error", "The Plutonium launcher manifest could not be fetched, auto-updating might not be possible.\n" + error.message); }); + + if (fs.existsSync(configFilePath)) { + readConfig(configFilePath).then(function (data) { + config = data; + + if (config["user-info"].token === "V3ryS3cr3t4uth3nt1c4t10nT0k3n") { + return; + } else { + validatePlutoniumLogin(config["user-info"].token).then(function (data) { + if (!data.successful) { + config["user-info"].token = "V3ryS3cr3t4uth3nt1c4t10nT0k3n"; + return writeConfig(configFilePath, config).catch(function (error) { + console.error(error); + }); + } + + mainWindow.loadFile(path.join(__dirname, "src", "views", "games.html")); + }); + } + }).catch(function (error) { + electron.dialog.showErrorBox("Error", "Configuration file could not be read.\n" + error.message); + }); + } else { + writeConfig(configFilePath, config).catch(function (error) { + electron.dialog.showErrorBox("Error", "Configuration file doesn't exist and could not be created.\n" + error.message); + }); + } }); electron.app.on("window-all-closed", function () { @@ -252,6 +374,10 @@ electron.ipcMain.handle("login", function (event, username, password) { }); userInfo = data; + config["user-info"] = userInfo; + writeConfig(configFilePath, config).catch(function (error) { + console.error(error); + }); mainWindow.loadFile(path.join(__dirname, "src", "views", "games.html")); } catch (error) {