Add session service with profile and session management
Introduces sessionService.js providing functions for legacy session registration and validation, profile retrieval with skin/cape data, server join handling, and blocked server listing. Integrates with auth and session repositories and includes error handling for various session operations.
This commit is contained in:
parent
bdb6457d1d
commit
64d632eac9
162
services/sessionService.js
Normal file
162
services/sessionService.js
Normal file
@ -0,0 +1,162 @@
|
||||
const utils = require("../modules/utils")
|
||||
const authRepository = require("../repositories/authRepository")
|
||||
const sessionRepository = require("../repositories/sessionRepository")
|
||||
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,
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user