Introduces zod-based validation schemas for Minecraft and Mojang API endpoints. Refactors texture route to support hash-based file serving and removes the old static texture route. Updates database schema for player properties and adds an event to clean expired certificates. Improves ValidationError formatting, adjusts skin/cape URL construction, and adds SSRF protection for skin uploads.
704 lines
25 KiB
JavaScript
704 lines
25 KiB
JavaScript
const crypto = require("node:crypto")
|
|
const logger = require("../modules/logger")
|
|
const database = require("../modules/database")
|
|
const { DefaultError } = require("../errors/errors")
|
|
|
|
async function addPropertyToPlayer(key, value, uuid) {
|
|
try {
|
|
const sql = `
|
|
INSERT INTO playersProperties (name, value, uuid)
|
|
VALUES (?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE value = VALUES(value)
|
|
`
|
|
const result = await database.query(sql, [key, value, uuid])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return { code: 200, key, value, uuid }
|
|
} else {
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function deletePropertyToPlayer(key, uuid) {
|
|
try {
|
|
const sql = `DELETE FROM playersProperties WHERE name = ? AND uuid = ?`
|
|
const result = await database.query(sql, [key, uuid])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return { code: 200, key, uuid }
|
|
} else {
|
|
throw new DefaultError(500, "Property not found for this user/key combination.")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function updatePropertyToPlayer(key, value, uuid) {
|
|
try {
|
|
const sql = `UPDATE playersProperties SET value = ? WHERE name = ? AND uuid = ?`
|
|
const result = await database.query(sql, [value, key, uuid])
|
|
if (result.affectedRows > 0) {
|
|
return { code: 200, key, value, uuid }
|
|
} else {
|
|
throw new DefaultError(404, "Property not found for this user/key combination")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerProperties(uuid) {
|
|
try {
|
|
const sql = `SELECT * FROM playersProperties WHERE uuid = ?`
|
|
const rows = await database.query(sql, [uuid])
|
|
if (rows.length === 0) {
|
|
throw new DefaultError(404, "Properties not found for this user")
|
|
}
|
|
return {
|
|
code: 200,
|
|
properties: rows.map(property => ({ name: property.name, value: property.value }))
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerProperty(key, uuid) {
|
|
try {
|
|
const sql = `SELECT * FROM playersProperties WHERE name = ? AND uuid = ?`
|
|
const rows = await database.query(sql, [key, uuid])
|
|
const property = rows[0]
|
|
if (!property) {
|
|
throw new DefaultError(404, "Property not found for this user/key combination")
|
|
}
|
|
return { code: 200, property }
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerSettingsSchema() {
|
|
const RAW_SCHEMA_CACHE = {
|
|
privileges: {},
|
|
preferences: {}
|
|
}
|
|
try {
|
|
const privilegesRows = await database.query("DESCRIBE playersPrivileges")
|
|
const preferencesRows = await database.query("DESCRIBE playersPreferences")
|
|
RAW_SCHEMA_CACHE.privileges = privilegesRows.map(c => c.Field).filter(n => n !== "uuid")
|
|
RAW_SCHEMA_CACHE.preferences = preferencesRows.map(c => c.Field).filter(n => n !== "uuid")
|
|
return RAW_SCHEMA_CACHE
|
|
} catch (err) {
|
|
logger.log("Database Schema Error: " + err.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Schema Error")
|
|
}
|
|
}
|
|
|
|
async function updatePlayerPreferences(uuid, updates) {
|
|
try {
|
|
const keys = Object.keys(updates)
|
|
if (keys.length === 0) {
|
|
throw new DefaultError(400, "No fields provided for update.")
|
|
}
|
|
const setClause = keys.map(key => `\`${key}\` = ?`).join(', ')
|
|
const sql = `UPDATE playersPreferences SET ${setClause} WHERE uuid = ?`
|
|
const values = keys.map(key => updates[key])
|
|
values.push(uuid)
|
|
const result = await database.query(sql, values)
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "Preferences updated successfully."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Player preferences not found or no changes made.")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerPreferences(uuid) {
|
|
try {
|
|
const sql = `SELECT profanityFilter FROM playersPreferences WHERE uuid = ?`
|
|
const rows = await database.query(sql, [uuid])
|
|
const data = rows[0]
|
|
|
|
if (data) {
|
|
return {
|
|
code: 200,
|
|
message: "Preferences retrieved successfully.",
|
|
data: data
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Preferences not found for this UUID.")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerPrivileges(uuid) {
|
|
try {
|
|
const sql = `
|
|
SELECT onlineChat, multiplayerServer, multiplayerRealms, telemetry
|
|
FROM playersPrivileges
|
|
WHERE uuid = ?
|
|
`
|
|
const rows = await database.query(sql, [uuid])
|
|
const data = rows[0]
|
|
if (data) {
|
|
return {
|
|
code: 200,
|
|
message: "Privileges retrieved successfully.",
|
|
data: data
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Privileges not found for this UUID.")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function updatePlayerPrivileges(uuid, updates) {
|
|
try {
|
|
const keys = Object.keys(updates)
|
|
if (keys.length === 0) {
|
|
throw new DefaultError(404, "No fields provided for update.")
|
|
}
|
|
const setClause = keys.map(key => `\`${key}\` = ?`).join(', ')
|
|
const sql = `UPDATE playersPrivileges SET ${setClause} WHERE uuid = ?`
|
|
const values = keys.map(key => updates[key])
|
|
values.push(uuid)
|
|
const result = await database.query(sql, values)
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "Privileges updated successfully."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Player privileges not found or no changes made.")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function banUser(uuid, { reasonKey, reasonMessage, expires = null }) {
|
|
try {
|
|
if (!uuid || !reasonKey) {
|
|
throw new DefaultError(400, "Missing uuid or reasonKey.")
|
|
}
|
|
|
|
let reasonId
|
|
const reasonRows = await database.query("SELECT id FROM banReasons WHERE reason_key = ?", [reasonKey])
|
|
if (reasonRows.length > 0) {
|
|
reasonId = reasonRows[0].id
|
|
} else {
|
|
const insertReason = await database.query("INSERT INTO banReasons (reason_key) VALUES (?)", [reasonKey])
|
|
reasonId = insertReason.insertId
|
|
}
|
|
|
|
const banId = crypto.randomUUID()
|
|
const insertSql = `
|
|
INSERT INTO bans (banId, uuid, reason, reasonMessage, expires)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
`
|
|
const result = await database.query(insertSql, [banId, uuid, reasonId, reasonMessage || "Banned by operator", expires])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "User successfully banned.",
|
|
banId: banId
|
|
}
|
|
} else {
|
|
throw new DefaultError(500, "Failed to ban user.")
|
|
}
|
|
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
if (error.code === "ER_NO_REFERENCED_ROW_2" || error.toString().includes("foreign key constraint")) {
|
|
throw new DefaultError(404, "User not found (cannot ban a ghost).")
|
|
}
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", error.toString())
|
|
}
|
|
}
|
|
|
|
async function unbanUser(uuid) {
|
|
try {
|
|
if (!uuid) {
|
|
throw new DefaultError(400, "Missing uuid.")
|
|
}
|
|
const sql = "DELETE FROM bans WHERE uuid = ?"
|
|
const result = await database.query(sql, [uuid])
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "User successfully unbanned.",
|
|
count: result.affectedRows
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "User was not banned.")
|
|
}
|
|
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function getPlayerBans(uuid) {
|
|
try {
|
|
const sql = `
|
|
SELECT
|
|
b.banId,
|
|
b.expires,
|
|
b.reasonMessage,
|
|
r.reason_key as reason
|
|
FROM bans b
|
|
JOIN banReasons r ON b.reason = r.id
|
|
WHERE b.uuid = ?
|
|
ORDER BY b.expires ASC
|
|
`
|
|
const rows = await database.query(sql, [uuid])
|
|
|
|
if (rows.length > 0) {
|
|
return { code: 200, bans: rows }
|
|
} else {
|
|
return { code: 204 }
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function changeUsername(uuid, newName) {
|
|
try {
|
|
const sql = "UPDATE players SET username = ? WHERE uuid = ?"
|
|
const result = await database.query(sql, [newName, uuid])
|
|
if (result.affectedRows > 0) {
|
|
return { code: 200, message: "Username changed successfully" }
|
|
} else {
|
|
throw new DefaultError(404, "User not found")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
if (error.code === "ER_DUP_ENTRY" || error.errno === 1062) {
|
|
throw new DefaultError(409, "Username already taken", "ForbiddenOperationException")
|
|
}
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", error.toString())
|
|
}
|
|
}
|
|
|
|
async function createTexture(uuid, hash, type, url, alias) {
|
|
try {
|
|
const sql = `
|
|
INSERT INTO textures (uuid, hash, type, url, alias)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
`
|
|
await database.query(sql, [uuid, hash, type, url, alias])
|
|
return true
|
|
} catch (error) {
|
|
if (error.code === 'ER_DUP_ENTRY') {
|
|
return false
|
|
}
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
|
|
async function getTextureByUuid(textureUuid) {
|
|
try {
|
|
const sql = "SELECT hash FROM textures WHERE uuid = ?"
|
|
const rows = await database.query(sql, [textureUuid])
|
|
return rows[0] || null
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getTextureByHash(hash) {
|
|
try {
|
|
const sql = "SELECT uuid FROM textures WHERE hash = ?"
|
|
const rows = await database.query(sql, [hash])
|
|
return rows[0]
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function resetSkin(uuid, hash, variant) {
|
|
try {
|
|
const insertSql = `
|
|
INSERT IGNORE INTO playersSkins (playerUuid, assetHash, variant, isSelected)
|
|
VALUES (?, ?, ?, 0)
|
|
`
|
|
await database.query(insertSql, [uuid, hash, variant])
|
|
const updateSql = `
|
|
UPDATE playersSkins
|
|
SET isSelected = (assetHash = ?)
|
|
WHERE playerUuid = ?
|
|
`
|
|
await database.query(updateSql, [hash, uuid])
|
|
return { code: 200 }
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function hideCape(uuid) {
|
|
try {
|
|
const sql = "UPDATE playersCapes SET isSelected = 0 WHERE playerUuid = ?"
|
|
await database.query(sql, [uuid])
|
|
return { code: 200 }
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function showCape(uuid, hash) {
|
|
try {
|
|
const sql = `
|
|
UPDATE playersCapes
|
|
SET isSelected = (assetHash = ?)
|
|
WHERE playerUuid = ?
|
|
`
|
|
const result = await database.query(sql, [hash, uuid])
|
|
return { code: 200, changed: result.affectedRows > 0 }
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function checkCapeOwnership(uuid, hash) {
|
|
try {
|
|
const sql = "SELECT 1 FROM playersCapes WHERE playerUuid = ? AND assetHash = ?"
|
|
const rows = await database.query(sql, [uuid, hash])
|
|
return rows.length > 0
|
|
} catch (error) {
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getPlayerMeta(uuid) {
|
|
try {
|
|
const sql = `SELECT createdAt, nameChangeAllowed FROM players WHERE uuid = ?`
|
|
const rows = await database.query(sql, [uuid])
|
|
return rows[0]
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getLastNameChange(uuid) {
|
|
try {
|
|
const sql = `
|
|
SELECT changedAt
|
|
FROM uuidToNameHistory
|
|
WHERE uuid = ? AND changedAt IS NOT NULL
|
|
ORDER BY changedAt DESC
|
|
LIMIT 1
|
|
`
|
|
const rows = await database.query(sql, [uuid])
|
|
return rows[0]
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getPlayerCertificate(uuid) {
|
|
try {
|
|
const sql = "SELECT * FROM playerCertificates WHERE uuid = ?"
|
|
const rows = await database.query(sql, [uuid])
|
|
return rows[0]
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function savePlayerCertificate(uuid, privateKey, publicKey, signatureV2, expiresAt, refreshedAfter) {
|
|
try {
|
|
const sql = `
|
|
REPLACE INTO playerCertificates
|
|
(uuid, privateKey, publicKey, publicKeySignatureV2, expiresAt, refreshedAfter)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
`
|
|
const result = await database.query(sql, [uuid, privateKey, publicKey, signatureV2, expiresAt, refreshedAfter])
|
|
return result.affectedRows > 0
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function deleteExpiredCertificates(isoDate) {
|
|
try {
|
|
const sql = "DELETE FROM playerCertificates WHERE expiresAt < ?"
|
|
const result = await database.query(sql, [isoDate])
|
|
return result.affectedRows
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function addProfileAction(uuid, actionCode) {
|
|
try {
|
|
const cleanUuid = uuid.replace(/-/g, "")
|
|
const sql = "INSERT IGNORE INTO playerProfileActions (uuid, action) VALUES (?, ?)"
|
|
const result = await database.query(sql, [cleanUuid, actionCode])
|
|
return result.affectedRows > 0
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function removeProfileAction(uuid, actionCode) {
|
|
try {
|
|
const cleanUuid = uuid.replace(/-/g, "")
|
|
const sql = "DELETE FROM playerProfileActions WHERE uuid = ? AND action = ?"
|
|
const result = await database.query(sql, [cleanUuid, actionCode])
|
|
return result.affectedRows
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getPlayerActions(uuid) {
|
|
try {
|
|
const cleanUuid = uuid.replace(/-/g, "")
|
|
const sql = "SELECT action FROM playerProfileActions WHERE uuid = ?"
|
|
const rows = await database.query(sql, [cleanUuid])
|
|
return rows.map(r => r.action)
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function clearAllPlayerActions(uuid) {
|
|
try {
|
|
const cleanUuid = uuid.replace(/-/g, "")
|
|
const sql = "DELETE FROM playerProfileActions WHERE uuid = ?"
|
|
const result = await database.query(sql, [cleanUuid])
|
|
return result.affectedRows
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function blockPlayer(blockerUuid, blockedUuid) {
|
|
try {
|
|
const sql = `INSERT IGNORE INTO playersBlockslist (blockerUuid, blockedUuid) VALUES (?, ?)`
|
|
const result = await database.query(sql, [blockerUuid, blockedUuid])
|
|
return result.affectedRows > 0
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function unblockPlayer(blockerUuid, blockedUuid) {
|
|
try {
|
|
const sql = `DELETE FROM playersBlockslist WHERE blockerUuid = ? AND blockedUuid = ?`
|
|
const result = await database.query(sql, [blockerUuid, blockedUuid])
|
|
return result.affectedRows > 0
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getBlockedUuids(blockerUuid) {
|
|
try {
|
|
const sql = `SELECT blockedUuid FROM playersBlockslist WHERE blockerUuid = ?`
|
|
const rows = await database.query(sql, [blockerUuid])
|
|
return rows.map(r => r.blockedUuid)
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function isBlocked(blockerUuid, targetUuid) {
|
|
try {
|
|
const sql = `SELECT 1 FROM playersBlockslist WHERE blockerUuid = ? AND blockedUuid = ? LIMIT 1`
|
|
const rows = await database.query(sql, [blockerUuid, targetUuid])
|
|
return rows.length > 0
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getUsersByNames(usernames) {
|
|
try {
|
|
if (!usernames || usernames.length === 0) return []
|
|
const uniqueNames = [...new Set(usernames)]
|
|
|
|
const placeholders = uniqueNames.map(() => "?").join(", ")
|
|
const sql = `SELECT uuid, username FROM players WHERE username IN (${placeholders})`
|
|
|
|
const rows = await database.query(sql, uniqueNames)
|
|
return rows
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getUuidAndUsername(username) {
|
|
try {
|
|
const sql = "SELECT uuid, username FROM players WHERE username = ?"
|
|
const rows = await database.query(sql, [username])
|
|
|
|
return rows[0] || null
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getProfileByUsername(username) {
|
|
try {
|
|
const sql = "SELECT uuid, username FROM players WHERE username = ?"
|
|
const rows = await database.query(sql, [username])
|
|
return rows[0] || null
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getProfileByHistory(username, isoDate) {
|
|
try {
|
|
const sql = `
|
|
SELECT uuid, username
|
|
FROM uuidToNameHistory
|
|
WHERE username = ?
|
|
AND (changedAt <= ? OR changedAt IS NULL)
|
|
ORDER BY changedAt DESC
|
|
LIMIT 1
|
|
`
|
|
const rows = await database.query(sql, [username, isoDate])
|
|
return rows[0] || null
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function getNameHistory(uuid) {
|
|
try {
|
|
const sql = `
|
|
SELECT username, changedAt
|
|
FROM uuidToNameHistory
|
|
WHERE uuid = ?
|
|
ORDER BY changedAt ASC
|
|
`
|
|
const rows = await database.query(sql, [uuid])
|
|
return rows
|
|
} catch (error) {
|
|
logger.log("Database Error: " + error.toString(), ["MariaDB", "red"])
|
|
throw new DefaultError(500, "Internal Server Error", "Database Error")
|
|
}
|
|
}
|
|
|
|
async function setSkin(uuid, hash, variant) {
|
|
const insertSql = `
|
|
INSERT INTO playersSkins (playerUuid, assetHash, variant, isSelected)
|
|
VALUES (?, ?, ?, 1)
|
|
ON DUPLICATE KEY UPDATE isSelected = 1, variant = ?
|
|
`
|
|
await database.query(insertSql, [uuid, hash, variant, variant])
|
|
const updateSql = `
|
|
UPDATE playersSkins
|
|
SET isSelected = 0
|
|
WHERE playerUuid = ? AND assetHash != ?
|
|
`
|
|
await database.query(updateSql, [uuid, hash])
|
|
return true
|
|
}
|
|
|
|
module.exports = {
|
|
setSkin,
|
|
banUser,
|
|
showCape,
|
|
hideCape,
|
|
resetSkin,
|
|
isBlocked,
|
|
unbanUser,
|
|
blockPlayer,
|
|
createTexture,
|
|
getPlayerBans,
|
|
getPlayerMeta,
|
|
unblockPlayer,
|
|
changeUsername,
|
|
getNameHistory,
|
|
getBlockedUuids,
|
|
getUsersByNames,
|
|
getPlayerActions,
|
|
getTextureByUuid,
|
|
getTextureByHash,
|
|
addProfileAction,
|
|
getLastNameChange,
|
|
getPlayerProperty,
|
|
getUuidAndUsername,
|
|
checkCapeOwnership,
|
|
getProfileByHistory,
|
|
getPlayerPrivileges,
|
|
getPlayerProperties,
|
|
removeProfileAction,
|
|
addPropertyToPlayer,
|
|
getProfileByUsername,
|
|
getPlayerPreferences,
|
|
getPlayerCertificate,
|
|
clearAllPlayerActions,
|
|
savePlayerCertificate,
|
|
updatePlayerPrivileges,
|
|
deletePropertyToPlayer,
|
|
updatePropertyToPlayer,
|
|
getPlayerSettingsSchema,
|
|
updatePlayerPreferences,
|
|
deleteExpiredCertificates,
|
|
} |