This commit is contained in:
Gilles Lazures 2025-05-01 18:42:39 +02:00
parent 6ee1cd793f
commit 5657184b08
8 changed files with 1112 additions and 49 deletions

View File

@ -27,6 +27,9 @@
</button> </button>
</summary> </summary>
<article> <article>
<button class="classic" style="width: 100%;" onclick="system.call('app::devtools')">
Déconnexion
</button>
<button class="classic" style="background-color: #aa3939; width: 100%;" onclick="logout()"> <button class="classic" style="background-color: #aa3939; width: 100%;" onclick="logout()">
Déconnexion Déconnexion
</button> </button>

View File

@ -3,12 +3,15 @@
"base": "http://localhost:8535", "base": "http://localhost:8535",
"endpoints": { "endpoints": {
"fileHash": "/api/v1/file/hash/", "fileHash": "/api/v1/file/hash/",
"checkBanStatus": "/api/v1/ban/iam" "checkBanStatus": "/api/v1/ban/iam",
"telemetry": "/api/v1/telemetry",
"gameFiles": "/api/v1/file/game",
"downloadFile": "/api/v1/file/game/download"
}, },
"websockets": { "websockets": {
"base": "wss://localhost:8535", "base": {
"rooms": { "host": "wss://localhost",
"updateGameFiles": "/game/updates" "port": "8535"
} }
} }
}, },

89
main.js
View File

@ -1,14 +1,24 @@
const { BrowserWindow, app, net, dialog, ipcMain, nativeImage, session, shell } = require("electron") const { BrowserWindow, app, net, dialog, ipcMain, nativeImage, session, shell } = require("electron")
const msmc = require("msmc") const msmc = require("msmc")
const os = require("os") const os = require("node:os")
const hwid = require("./modules/hwid") const fs = require("node:fs")
const path = require("node:path") const path = require("node:path")
const hwid = require("./modules/hwid")
const serverPing = require("./modules/serverPing") const serverPing = require("./modules/serverPing")
const gameOptions = require("./modules/gameOptions") const gameOptions = require("./modules/gameOptions")
const launcherSettings = require("./modules/launcherSettings") const launcherSettings = require("./modules/launcherSettings")
const config = require("./config.json") const config = require("./config.json")
const { Authenticator } = require("minecraft-launcher-core") const { Authenticator, Client } = require("minecraft-launcher-core")
let launcherWindow, auth const fileManager = require("./modules/fileManager")
const launcher = new Client()
const { io } = require("socket.io-client")
const download = require("download")
const socket = io({
host: config.api.websockets.base.host,
port: config.api.websockets.base.port
})
let launcherWindow, auth, gamePlayable = false
async function createLauncherWindow() { async function createLauncherWindow() {
gameOptions.initOptions(path.join(app.getPath("appData"), ".catboat", "options.txt")) gameOptions.initOptions(path.join(app.getPath("appData"), ".catboat", "options.txt"))
@ -62,7 +72,6 @@ async function createLauncherWindow() {
redirectURL: redirectUrl redirectURL: redirectUrl
}) })
}) })
session.defaultSession.webRequest.onHeadersReceived({ session.defaultSession.webRequest.onHeadersReceived({
urls: [ urls: [
"https://www.twitch.tv/*", "https://www.twitch.tv/*",
@ -87,7 +96,7 @@ async function createLauncherWindow() {
`) `)
} }
} catch (error) { } catch (error) {
dialog.showErrorBox("Erreur", error) dialog.showErrorBox("Erreur", error.toString())
} }
} else { } else {
dialog.showErrorBox("Connexion internet", "Le launcher requiert une connexion internet.") dialog.showErrorBox("Connexion internet", "Le launcher requiert une connexion internet.")
@ -171,6 +180,7 @@ ipcMain.on("call", async (event, data) => {
case "auth::mojang": case "auth::mojang":
if (data.args.trim() != "") { if (data.args.trim() != "") {
auth = Authenticator.getAuth(data.args.username, data.args.password) auth = Authenticator.getAuth(data.args.username, data.args.password)
await fetch(`${config.api.base}${config.api.endpoints.telemetry}/${hwid.getHWID()}/${(await auth).uuid}`)
await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html")) await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html"))
} else { } else {
dialog.showErrorBox("Erreur", "Le mot de passe n'est pas défini. Les comptes crackés ne sont pas supporté par le launcher.") dialog.showErrorBox("Erreur", "Le mot de passe n'est pas défini. Les comptes crackés ne sont pas supporté par le launcher.")
@ -182,10 +192,10 @@ ipcMain.on("call", async (event, data) => {
const xboxManager = await authManager.launch("raw") const xboxManager = await authManager.launch("raw")
const token = await xboxManager.getMinecraft() const token = await xboxManager.getMinecraft()
auth = token.mclc() auth = token.mclc()
console.log(auth) await fetch(`${config.api.base}${config.api.endpoints.telemetry}/${hwid.getHWID()}/${auth.uuid}`)
await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html")) await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html"))
} catch (error) { } catch (error) {
console.log(error) console.error(error)
if (error == "error.gui.closed") { if (error == "error.gui.closed") {
launcherWindow.webContents.send("Response<auth::microsoft>") launcherWindow.webContents.send("Response<auth::microsoft>")
} }
@ -200,18 +210,20 @@ ipcMain.on("call", async (event, data) => {
const minecraft = await xboxManager.getMinecraft() const minecraft = await xboxManager.getMinecraft()
auth = minecraft.mclc() auth = minecraft.mclc()
await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html")) await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html"))
await fetch(`${config.api.base}${config.api.endpoints.telemetry}/${hwid.getHWID()}/${auth.uuid}`)
} catch (error) { } catch (error) {
dialog.showErrorBox("Erreur lors de la connexion via token", error) dialog.showErrorBox("Erreur lors de la connexion via token", error)
console.log(error) console.error(error)
launcherWindow.webContents.send("Response<auth::refresh>") launcherWindow.webContents.send("Response<auth::refresh>")
} }
} else { } else {
try { try {
auth = Authenticator.refreshAuth(user.access_token, user.client_token) auth = Authenticator.refreshAuth(user.access_token, user.client_token)
await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html")) await launcherWindow.loadFile(path.join(__dirname, "app", "logged.html"))
await fetch(`${config.api.base}${config.api.endpoints.telemetry}/${hwid.getHWID()}/${(await auth).uuid}`)
} catch (error) { } catch (error) {
dialog.showErrorBox("Erreur lors de la connexion via token", error) dialog.showErrorBox("Erreur lors de la connexion via token", error)
console.log(error) console.error(error)
launcherWindow.webContents.send("Response<auth::refresh>") launcherWindow.webContents.send("Response<auth::refresh>")
} }
} }
@ -255,5 +267,62 @@ ipcMain.on("call", async (event, data) => {
const $launcherSettings = launcherSettings.readSettings() const $launcherSettings = launcherSettings.readSettings()
launcherWindow.webContents.send("Response<settings::read>", $launcherSettings) launcherWindow.webContents.send("Response<settings::read>", $launcherSettings)
break break
case "game::launch":
const downloadQueue = []
const remoteFiles = await fileManager.getRemoteFiles()
const localFiles = fs.readdirSync(path.join(app.getPath("appData"), ".catboat"), { recursive: true })
launcherWindow.setProgressBar(10, {
mode: "indeterminate"
})
for (const remoteFile of remoteFiles) {
try {
const localFile = localFiles.find(file => file === remoteFile)
if (!localFile) {
downloadQueue.push(remoteFile)
continue
}
const localHash = await fileManager.getFileHash(path.join(app.getPath("appData"), ".catboat", localFile))
const remoteHash = await fileManager.getRemoteFileHash(localFile)
if (localHash != remoteHash) {
downloadQueue.push(localFile)
}
} catch (error) {
console.error(error)
break
}
}
for (const localFile of localFiles) {
if (!remoteFiles.find(remoteFile => remoteFile.path == localFile) && localFile.startsWith("/mods")) {
fs.unlinkSync(path.join(app.getPath("appData"), ".catboat", localFile))
}
}
for (const item of downloadQueue) {
const url = `${config.api.base}${config.api.endpoints.downloadFile}/${new String(item).replace(/\\/g, "/")}`
try {
await download(url, path.join(app.getPath("appData"), ".catboat", path.dirname(item)))
launcherWindow.setProgressBar(((downloadQueue.indexOf(item) + 1) / downloadQueue.length) * 100, {
mode: "normal"
})
} catch (error) {
launcherWindow.setProgressBar(((downloadQueue.indexOf(item) + 1) / downloadQueue.length) * 100, {
mode: "error"
})
dialog.showErrorBox("Erreur lors du téléchargement des fichiers", error.toString())
continue
}
}
launcherWindow.setProgressBar(0, {
mode: "none"
})
dialog.showMessageBox(launcherWindow, {
title: "Téléchargement des fichiers",
message: "Téléchargement fini."
})
break
case "app::devtools":
launcherWindow.webContents.openDevTools()
break
} }
}) })

View File

@ -1,18 +0,0 @@
const msmc = require("msmc")
const { Authenticator } = require("minecraft-launcher-core")
async function getMicrosoftAuth() {
const authManager = new msmc.Auth("select_account")
const xboxManager = await authManager.launch("raw")
const token = await xboxManager.getMinecraft()
return token.mclc()
}
function getMojangAuth(username, password) {
return Authenticator.getAuth(username, password)
}
module.exports = {
getMicrosoftAuth,
getMojangAuth
}

View File

@ -4,6 +4,17 @@ const https = require("node:https")
const crypto = require("node:crypto") const crypto = require("node:crypto")
const config = require("../config.json") const config = require("../config.json")
async function getRemoteFiles() {
try {
const response = await fetch(`${config.api.base}${config.api.endpoints.gameFiles}`)
console.log(response.url)
const json = await response.json()
return json
} catch (error) {
throw error
}
}
async function downloadFile(url, destination, hash) { async function downloadFile(url, destination, hash) {
const file = fs.createWriteStream(destination) const file = fs.createWriteStream(destination)
const protocol = url.startsWith("https://") ? http : https const protocol = url.startsWith("https://") ? http : https
@ -73,8 +84,21 @@ async function checkFilesHash(root) {
} }
} }
async function getRemoteFileHash(filePath) {
try {
const response = await fetch(`${config.api.base}${config.api.endpoints.fileHash}/${filePath}`)
const text = await response.text()
return text
} catch (error) {
throw error
}
}
module.exports = { module.exports = {
getFileHash,
downloadFile, downloadFile,
checkFileHash, checkFileHash,
checkFilesHash checkFilesHash,
getRemoteFiles,
getRemoteFileHash
} }

0
modules/gameFiles.js Normal file
View File

1013
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
}, },
"dependencies": { "dependencies": {
"discord-rpc": "^4.0.1", "discord-rpc": "^4.0.1",
"download": "^8.0.0",
"minecraft-launcher-core": "^3.18.2", "minecraft-launcher-core": "^3.18.2",
"msmc": "^5.0.5", "msmc": "^5.0.5",
"socket.io-client": "^4.8.1" "socket.io-client": "^4.8.1"