diff --git a/README.md b/README.md index 8c25edd..325827a 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# Modun \ No newline at end of file +# Yggdrasil \ No newline at end of file diff --git a/modules/utils.js b/modules/utils.js index 07a8dcd..0e81c13 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -1,6 +1,8 @@ const path = require("node:path") const Logger = require("./logger") const logger = Logger.createLogger(path.join(__dirname, "..")) +const certificatesManager = require("./certificatesManager") +const serverKeys = certificatesManager.getKeys() async function getRegistrationCountryFromIp(ipAddress) { const apiUrl = `https://ip-api.com/json/${ipAddress}?fields=countryCode` @@ -24,6 +26,20 @@ async function getRegistrationCountryFromIp(ipAddress) { } } +function signProfileData(dataBase64) { + try { + const privateKey = serverKeys.playerCertificateKeys.private + const signer = crypto.createSign("SHA1") + signer.update(dataBase64) + signer.end() + return signer.sign(privateKey, "base64") + } catch (err) { + console.error("Signing failed:", err) + return null + } +} + module.exports = { - getRegistrationCountryFromIp + getRegistrationCountryFromIp, + signProfileData } \ No newline at end of file diff --git a/repositories/sessionRepository.js b/repositories/sessionRepository.js new file mode 100644 index 0000000..bae91a4 --- /dev/null +++ b/repositories/sessionRepository.js @@ -0,0 +1,165 @@ +const path = require("node:path") +const Logger = require("../modules/logger") +const logger = Logger.createLogger(path.join(__dirname, "..")) +const database = require("../modules/database") +const { DefaultError } = require("../errors/errors") + +async function insertLegacyClientSessions(sessionId, uuid) { + try { + await database.query(`DELETE FROM legacyClientSessions WHERE uuid = ?`, [uuid]) + + const sql = `INSERT INTO legacyClientSessions (sessionId, uuid) VALUES (?, ?)` + const result = await database.query(sql, [sessionId, uuid]) + + if (result.affectedRows > 0) { + return { code: 200, sessionId, uuid } + } else { + throw new DefaultError(500, "Internal Server Error", "Unknown DB Error") + } + } catch (error) { + if (error instanceof DefaultError) throw error + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function validateLegacyClientSession(sessionId, uuid) { + try { + const sql = `SELECT * FROM legacyClientSessions WHERE sessionId = ? AND uuid = ?` + const rows = await database.query(sql, [sessionId, uuid]) + + const session = rows[0] + if (session) { + return { + code: 200, + message: "Client session valid." + } + } else { + return { + code: 404, + message: "Client session not found for this accessToken/clientToken combination" + } + } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function getBlockedServers() { + try { + const sql = `SELECT * FROM blockedServers` + const blockedServers = await database.query(sql) + + return { + code: 200, + blockedServers: blockedServers.map(bannedServer => ({ sha1: bannedServer.hashedIp })) + } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function getActiveSkin(uuid) { + try { + const sql = ` + SELECT t.url, ps.variant + FROM playersSkins ps + JOIN textures t ON ps.assetHash = t.hash + WHERE ps.playerUuid = ? AND ps.isSelected = 1 + ` + const rows = await database.query(sql, [uuid]) + const skin = rows[0] + + return { code: 200, data: skin || null } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function getActiveCape(uuid) { + try { + const sql = ` + SELECT t.url + FROM playersCapes pc + JOIN textures t ON pc.assetHash = t.hash + WHERE pc.playerUuid = ? AND pc.isSelected = 1 + ` + const rows = await database.query(sql, [uuid]) + const cape = rows[0] + + return { code: 200, data: cape || null } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function getProfileActionsList(uuid) { + try { + const cleanUuid = uuid.replace(/-/g, "") + const sql = "SELECT action FROM playerProfileActions WHERE uuid = ?" + const rows = await database.query(sql, [cleanUuid]) + + const actions = rows.map(row => row.action) + + return { code: 200, data: actions } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function saveServerSession(uuid, accessToken, serverId, ip) { + try { + const sql = ` + INSERT INTO serverSessions (uuid, accessToken, serverId, ip, createdAt) + VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) + ON DUPLICATE KEY UPDATE + accessToken = VALUES(accessToken), + serverId = VALUES(serverId), + ip = VALUES(ip), + createdAt = CURRENT_TIMESTAMP + ` + const result = await database.query(sql, [uuid, accessToken, serverId, ip]) + + return { code: 200, success: result.affectedRows > 0 } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +async function getServerSession(uuid, serverId) { + try { + const sql = ` + SELECT ip + FROM serverSessions + WHERE uuid = ? AND serverId = ? + ` + const rows = await database.query(sql, [uuid, serverId]) + const session = rows[0] + + if (!session) { + return { code: 404, valid: false } + } + + return { code: 200, valid: true, ip: session.ip } + } catch (error) { + logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"]) + throw new DefaultError(500, "Internal Server Error", "Please contact an administrator.") + } +} + +module.exports = { + insertLegacyClientSessions, + validateLegacyClientSession, + getBlockedServers, + getActiveSkin, + getActiveCape, + getProfileActionsList, + saveServerSession, + getServerSession +} \ No newline at end of file