Yggdrasil/services/sessionsService.js
azures04 439094013d Add admin API, permissions, and player management routes
Introduces admin database tables, repository, and service for managing administrators and permissions. Adds new admin routes for banning players, managing cosmetics (capes), changing player passwords and usernames, and handling player textures. Updates user and session services to support admin actions and permission checks. Adds related schema validation for new endpoints.
2026-01-05 04:44:56 +01:00

213 lines
6.5 KiB
JavaScript

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, $uuid = utils.addDashesToUUID(uuid)
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: (process.env.TEXTURES_ENDPOINTS || `http://localhost:${process.env.WEB_PORT}/textures`) + activeSkin.url,
metadata: activeSkin.variant === "SLIM" ? { model: "slim" } : undefined
} : undefined
const capeNode = hasValidCape ? {
url: (process.env.TEXTURES_ENDPOINTS || `http://localhost:${process.env.WEB_PORT}/textures`) + 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")
}
const existingSession = await sessionRepository.getServerSessionByUuid(selectedProfile)
if (existingSession && existingSession.serverId !== serverId) {
throw new DefaultError(403, "Already logged in on another server.", "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
})
}
async function joinLegacyServer({ name, sessionId, serverId }) {
try {
await validateLegacySession({ name, sessionId })
} catch (error) {
throw new DefaultError(403, "Bad login", "ForbiddenOperationException")
}
const userResult = await authRepository.getUser(name)
const uuid = userResult.user.uuid
await sessionRepository.saveServerSession(uuid, sessionId, serverId, "0.0.0.0")
return { code: 200, message: "OK" }
}
async function getActiveSkin({ username }) {
try {
const dbUser = await authRepository.getUser(username)
const activeSkin = await sessionRepository.getActiveSkin(dbUser.user.uuid)
return activeSkin
} catch (error) {
if (!(error instanceof DefaultError)) {
throw new DefaultError(400, "Bad Request", error.toString())
}
throw error
}
}
async function getActiveCape({ username }) {
try {
const dbUser = await authRepository.getUser(username)
const activeCape = await sessionRepository.getActiveCape(dbUser.user.uuid)
return activeCape
} catch (error) {
if (!(error instanceof DefaultError)) {
throw new DefaultError(400, "Bad Request", error.toString())
}
throw error
}
}
module.exports = {
getProfile,
joinServer,
getActiveCape,
getActiveSkin,
hasJoinedServer,
joinLegacyServer,
getBlockedServers,
registerLegacySession,
validateLegacySession,
}