Add session server routes and SessionError class

Introduces new session server endpoints for hasJoined and profile lookup, adds a SessionError class for improved error handling, and updates error exports. Also renames sessionRepository and sessionService files to sessionsRepository and sessionsService for consistency, and sets max listeners in logger.
This commit is contained in:
2025-12-24 02:35:04 +01:00
parent 64d632eac9
commit 80bca31d9a
9 changed files with 82 additions and 8 deletions
+162
View File
@@ -0,0 +1,162 @@
const utils = require("../modules/utils")
const authRepository = require("../repositories/authRepository")
const sessionRepository = require("../repositories/sessionsRepository")
const { DefaultError } = require("../errors/errors")
async function registerLegacySession({ uuid, sessionId }) {
try {
await sessionRepository.insertLegacyClientSessions(sessionId, uuid)
return { code: 200 }
} catch (error) {
if (error instanceof DefaultError) throw error
throw new DefaultError(500, "Internal Server Error", error.toString())
}
}
async function validateLegacySession({ name, sessionId }) {
let userResult
try {
userResult = await authRepository.getUser(name)
} catch (error) {
if (error.code === 404) {
throw error
}
throw error
}
try {
await sessionRepository.validateLegacyClientSession(sessionId, userResult.user.uuid)
return { code: 200 }
} catch (error) {
if (error.code === 404) {
throw new DefaultError(403, "Invalid session.", "ForbiddenOperationException")
}
throw error
}
}
async function getBlockedServers() {
try {
return await sessionRepository.getBlockedServers()
} catch (error) {
throw new DefaultError(500, "Unable to fetch blocked servers.", error.toString())
}
}
async function getProfile({ uuid, unsigned = false }) {
let userResult
try {
userResult = await authRepository.getUser(uuid, false)
} catch (error) {
if (error.code === 404) {
return { code: 204, message: "User not found" }
}
throw error
}
const dbUser = userResult.user
const username = dbUser.username
const cleanUuid = dbUser.uuid.replace(/-/g, "")
const [skinResult, capeResult, actionsResult] = await Promise.all([
sessionRepository.getActiveSkin(dbUser.uuid).catch(() => ({ data: null })),
sessionRepository.getActiveCape(dbUser.uuid).catch(() => ({ data: null })),
sessionRepository.getProfileActionsList(dbUser.uuid).catch(() => ({ data: [] }))
])
const activeSkin = skinResult.data
const activeCape = capeResult.data
const profileActions = actionsResult.data || []
const isSkinBanned = profileActions.includes("USING_BANNED_SKIN")
const hasValidSkin = activeSkin && !isSkinBanned
const hasValidCape = !!activeCape
const skinNode = hasValidSkin ? {
url: activeSkin.url,
metadata: activeSkin.variant === "SLIM" ? { model: "slim" } : undefined
} : undefined
const capeNode = hasValidCape ? {
url: activeCape.url
} : undefined
const texturesObject = {
...(skinNode && { SKIN: skinNode }),
...(capeNode && { CAPE: capeNode })
}
const texturePayload = {
timestamp: Date.now(),
profileId: cleanUuid,
profileName: username,
signatureRequired: !unsigned,
textures: texturesObject
}
const payloadJson = JSON.stringify(texturePayload)
const base64Value = Buffer.from(payloadJson).toString("base64")
const signature = unsigned ? null : utils.signProfileData(base64Value)
const propertyNode = {
name: "textures",
value: base64Value,
...(signature && { signature: signature })
}
return {
code: 200,
data: {
id: cleanUuid,
name: username,
properties: [propertyNode],
profileActions: profileActions
}
}
}
async function joinServer({ accessToken, selectedProfile, clientToken, serverId, ip }) {
try {
await authRepository.validateClientSession(accessToken, clientToken)
} catch (error) {
throw new DefaultError(403, "Invalid access token", "ForbiddenOperationException")
}
await sessionRepository.saveServerSession(selectedProfile, accessToken, serverId, ip)
return { code: 204 }
}
async function hasJoinedServer({ username, serverId, ip }) {
let userResult
try {
userResult = await authRepository.getUser(username, false)
} catch (error) {
if (error.code === 404) return { code: 204, message: "User not found" }
throw error
}
const { uuid } = userResult.user
const joinCheck = await sessionRepository.getServerSession(uuid, serverId)
if (joinCheck.code !== 200 || !joinCheck.valid) {
return { code: 204, message: "Join verification failed" }
}
if (ip && ip.trim() !== "" && joinCheck.ip !== ip) {
return { code: 204, message: "Invalid IP address" }
}
return await getProfile({
uuid: uuid,
unsigned: false
})
}
module.exports = {
getProfile,
joinServer,
hasJoinedServer,
getBlockedServers,
registerLegacySession,
validateLegacySession,
}