const bcrypt = require("bcryptjs") const database = require("../modules/database") const utils = require("../modules/utils") 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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) { return utils.handleDBError(error) } } 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 }