Add base project files including environment example, license, README, .gitignore, error classes, ESLint config, database modules, texture assets, repositories, routes, schemas, services, and server entry point. This establishes the foundational structure for a Yggdrasil-compatible REST API with modular error handling, database setup, and route organization.
208 lines
7.7 KiB
JavaScript
208 lines
7.7 KiB
JavaScript
const logger = require("../modules/logger")
|
|
const bcrypt = require("bcryptjs")
|
|
const database = require("../modules/database")
|
|
const { DefaultError } = require("../errors/errors")
|
|
|
|
async function getUser(identifier, requirePassword = false) {
|
|
try {
|
|
const sql = `SELECT * FROM players WHERE uuid = ? OR email = ? OR username = ?`
|
|
const rows = await database.query(sql, [identifier, identifier, identifier])
|
|
const user = rows[0]
|
|
if (!user) {
|
|
throw new DefaultError(404, "User not found")
|
|
}
|
|
|
|
delete user.email
|
|
if (!requirePassword) {
|
|
delete user.password
|
|
}
|
|
return { code: 200, user }
|
|
|
|
} 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 register(email, username, password) {
|
|
try {
|
|
const sql = `INSERT INTO players (email, username, password, uuid) VALUES (?, ?, ?, ?)`
|
|
const uuid = crypto.randomUUID()
|
|
const hashedPassword = await bcrypt.hash(password, 10)
|
|
const result = await database.query(sql, [email, username, hashedPassword, uuid])
|
|
if (result.affectedRows > 0) {
|
|
return { code: 200, email, username, uuid }
|
|
} else {
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof DefaultError) throw error
|
|
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
console.log(error)
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
}
|
|
|
|
async function insertClientSession(accessToken, clientToken, uuid) {
|
|
try {
|
|
const sql = `INSERT INTO clientSessions (accessToken, clientToken, uuid) VALUES (?, ?, ?)`
|
|
const result = await database.query(sql, [accessToken, clientToken, uuid])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return { code: 204, accessToken, clientToken }
|
|
} else {
|
|
throw new DefaultError(500, "Please contact an administrator.", "InternalServerError")
|
|
}
|
|
} catch (error) {
|
|
logger.log("Internal Server Error".bold + " : " + error.toString(), ["MariaDB", "yellow"])
|
|
}
|
|
}
|
|
|
|
async function getPlayerProperties(uuid) {
|
|
try {
|
|
const sql = `SELECT * FROM playersProperties WHERE uuid = ?`
|
|
const properties = await database.query(sql, [uuid])
|
|
|
|
if (properties.length === 0) {
|
|
throw new DefaultError(404, "Properties not found for this user.", "InternalServerError")
|
|
}
|
|
return { code: 200, properties: properties.map(property => { return { 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 getClientSession(accessToken, clientToken) {
|
|
try {
|
|
const sql = `SELECT * FROM clientSessions WHERE accessToken = ? AND clientToken = ?`
|
|
const rows = await database.query(sql, [accessToken, clientToken])
|
|
|
|
const session = rows[0]
|
|
if (session) {
|
|
return {
|
|
code: 200,
|
|
session: session
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Client session not found")
|
|
}
|
|
} 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 validateClientSession(accessToken, clientToken) {
|
|
try {
|
|
const sql = `SELECT * FROM clientSessions WHERE accessToken = ? AND clientToken = ?`
|
|
const rows = await database.query(sql, [accessToken, clientToken])
|
|
|
|
const session = rows[0]
|
|
if (session) {
|
|
return {
|
|
code: 200,
|
|
message: "Client session valid."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Client session not found for this accessToken/clientToken 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 validateClientSessionWithoutClientToken(accessToken) {
|
|
try {
|
|
const sql = `SELECT * FROM clientSessions WHERE accessToken = ?`
|
|
const rows = await database.query(sql, [accessToken])
|
|
|
|
const session = rows[0]
|
|
if (session) {
|
|
return {
|
|
code: 200,
|
|
message: "Client session valid."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Client session not found for this accessToken.")
|
|
}
|
|
} 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 invalidateClientSession(accessToken, clientToken) {
|
|
try {
|
|
const sql = `DELETE FROM clientSessions WHERE accessToken = ? AND clientToken = ?`
|
|
const result = await database.query(sql, [accessToken, clientToken])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "Client session successfully invalidated."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "Client session not found for this accessToken/clientToken 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 revokeAccessTokens(uuid) {
|
|
try {
|
|
const sql = `DELETE FROM clientSessions WHERE uuid = ?`
|
|
const result = await database.query(sql, [uuid])
|
|
|
|
if (result.affectedRows > 0) {
|
|
return {
|
|
code: 200,
|
|
message: "Access tokens successfully revoked."
|
|
}
|
|
} else {
|
|
throw new DefaultError(404, "No access token found for this user.")
|
|
}
|
|
} 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 getUsernamesRules() {
|
|
try {
|
|
const rows = await database.query("SELECT rule, type FROM usernameRules")
|
|
return rows.map(row => {
|
|
if (row.type === 1) {
|
|
return { type: "regex", pattern: new RegExp(row.rule, "i") }
|
|
} else {
|
|
return { type: "literal", value: row.rule.toLowerCase() }
|
|
}
|
|
})
|
|
} catch (err) {
|
|
throw err
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getUser,
|
|
register,
|
|
getClientSession,
|
|
getUsernamesRules,
|
|
revokeAccessTokens,
|
|
insertClientSession,
|
|
getPlayerProperties,
|
|
validateClientSession,
|
|
invalidateClientSession,
|
|
validateClientSessionWithoutClientToken
|
|
} |