313 lines
10 KiB
JavaScript
313 lines
10 KiB
JavaScript
const Database = require("better-sqlite3")
|
|
const logger = require("../modules/logger")
|
|
const path = require("node:path")
|
|
const jwt = require("jsonwebtoken")
|
|
const fs = require("node:fs")
|
|
require("colors")
|
|
|
|
const db = new Database(path.join(__dirname, "..", "data", "lobby.db"), { verbose: (message) => logger.log(`[${"SQLite".yellow}] ${message}`) })
|
|
const privateKey = fs.readFileSync(path.join(__dirname, "..", "keys", "private.pem"))
|
|
|
|
function initDB() {
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS rooms (
|
|
externalGuid TEXT PRIMARY KEY,
|
|
id TEXT NOT NULL,
|
|
address TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
description TEXT NOT NULL,
|
|
owner TEXT NOT NULL,
|
|
port INTEGER NOT NULL,
|
|
preferredGameName TEXT NOT NULL,
|
|
preferredGameId INTEGER NOT NULL,
|
|
maxPlayers INTEGER NOT NULL,
|
|
netVersion TEXT NOT NULL,
|
|
hasPassword BOOLEAN NOT NULL DEFAULT 0,
|
|
password TEXT DEFAULT ""
|
|
)
|
|
`)
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
discordId TEXT NOT NULL,
|
|
username TEXT NOT NULL PRIMARY KEY,
|
|
nickname TEXT NOT NULL,
|
|
avatarUrl TEXT NOT NULL,
|
|
token TEXT NOT NULL
|
|
)
|
|
`)
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS players (
|
|
nickname TEXT NOT NULL,
|
|
username TEXT NOT NULL,
|
|
avatarUrl TEXT NOT NULL,
|
|
roomId TEXT NOT NULL,
|
|
gameId INTEGER NOT NULL,
|
|
FOREIGN KEY(roomId) REFERENCES rooms(externalGuid)
|
|
)
|
|
`)
|
|
}
|
|
|
|
function loginWithTokenAndToken(username, token) {
|
|
const stmt = db.prepare("SELECT * FROM users WHERE username = ?")
|
|
const user = stmt.get(username)
|
|
if (user) {
|
|
if (user.token == token) {
|
|
delete user.token
|
|
return user
|
|
} else {
|
|
return { success: false, error: "Invalid token", code: 401 }
|
|
}
|
|
} else {
|
|
return { success: false, error: "No user found with that username.", code: 404 }
|
|
}
|
|
}
|
|
|
|
function loginWithToken(token) {
|
|
try {
|
|
const payload = jwt.verify(token, privateKey)
|
|
const stmt = db.prepare("SELECT * FROM users WHERE username = ?")
|
|
const user = stmt.get(payload.username)
|
|
if (user) {
|
|
delete user.token
|
|
return user
|
|
} else {
|
|
return { success: false, error: "No user found with that username.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Invalid token.", code: 401 }
|
|
}
|
|
}
|
|
|
|
function login(req, res, next) {
|
|
const xToken = req.headers["x-token"]
|
|
const xUsername = req.headers["x-username"]
|
|
const bearer = res.headers["authorization"]
|
|
const token = bearer && bearer.startsWith("Bearer ") ? bearer.split(" ")[1] : null
|
|
if (!xToken && !xUsername && !token) {
|
|
return res.status(401).json({ error: "No token or/and username provided." })
|
|
}
|
|
if (!xToken || !xUsername) {
|
|
return res.status(422).json({ error: "No token or/and username provided." })
|
|
}
|
|
if (token) {
|
|
const user = loginWithToken(token)
|
|
if (user.error) {
|
|
return res.status(user.code).json({ error: user.error })
|
|
} else {
|
|
req.user = user
|
|
next()
|
|
}
|
|
} else {
|
|
const user = loginWithTokenAndToken(xUsername, xToken)
|
|
if (user.error) {
|
|
return res.status(user.code).json({ error: user.error })
|
|
} else {
|
|
req.user = user
|
|
next()
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function getPlayersFromRoom(roomId) {
|
|
const stmt = db.prepare("SELECT * FROM players WHERE roomId = ?")
|
|
const players = stmt.all(roomId)
|
|
if (players) {
|
|
return { success: true, players: players }
|
|
} else {
|
|
return { success: false, error: "No players found in that room.", code: 404 }
|
|
}
|
|
}
|
|
|
|
function putPlayerInRoom(username, roomId, nickname, avatarUrl, gameId) {
|
|
const stmt = db.prepare("INSERT INTO players (username, roomId, nickname, avatarUrl, gameId) VALUES (?, ?, ?, ?, ?)")
|
|
try {
|
|
stmt.run(username, roomId, nickname, avatarUrl, gameId)
|
|
return { success: true }
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to add player to the room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function addRoomToLobby(externalGuid, id, address, name, description, owner, port, preferredGameName, preferredGameId, maxPlayers, netVersion, hasPassword, password) {
|
|
const stmt = db.prepare("INSERT INTO rooms (externalGuid, id, address, name, description, owner, port, preferredGameName, preferredGameId, maxPlayers, netVersion, hasPassword, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
|
try {
|
|
stmt.run(externalGuid, id, address, name, description, owner, port, preferredGameName, preferredGameId, maxPlayers, netVersion, hasPassword, password)
|
|
return { success: true }
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to room to lobby", code: 500 }
|
|
}
|
|
}
|
|
|
|
function movePlayerAnotherRoom(username, roomId) {
|
|
const stmt = db.prepare("UPDATE players SET roomId = ? WHERE username = ?")
|
|
try {
|
|
const result = stmt.run(roomId, username)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Player not found or already in the specified room.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to move player to another room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function removePlayer(username, roomId) {
|
|
const stmt = db.prepare("DELETE FROM players WHERE username = ? AND roomId = ?")
|
|
try {
|
|
const result = stmt.run(username, roomId)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Player not found in the specified room.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to remove player from the room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function listRooms() {
|
|
const stmt = db.prepare("SELECT * FROM rooms")
|
|
try {
|
|
const rooms = stmt.all()
|
|
return { success: true, rooms: rooms, code: 200 }
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to retrieve rooms.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function deleteRoom(roomId) {
|
|
const stmt = db.prepare("DELETE FROM rooms WHERE id = ?")
|
|
try {
|
|
stmt.run(roomId)
|
|
return { success: true, code: 204 }
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to delete room", code: 500 }
|
|
}
|
|
}
|
|
|
|
function getRoom(roomId) {
|
|
const stmt = db.prepare("SELECT * FROM rooms WHERE id = ?")
|
|
const room = stmt.get(roomId)
|
|
if (room) {
|
|
return { success: true, code: 200, room }
|
|
} else {
|
|
return { success: false, error: "No room found with that ID.", code: 404 }
|
|
}
|
|
}
|
|
|
|
function updateKeyAndValueForRoom(roomId, key, value) {
|
|
const stmt = db.prepare(`UPDATE rooms SET ${key} = ? WHERE id = ?`)
|
|
try {
|
|
const result = stmt.run(value, roomId)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Room not found or no changes made.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to update room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function addUser(discordId, username, nickname, avatarUrl) {
|
|
const stmt = db.prepare("INSERT INTO users (discordId, username, nickname, avatarUrl, token) VALUES (?, ?, ?, ?, ?)")
|
|
try {
|
|
const token = jwt.sign({ username, nickname, avatarUrl }, privateKey, { algorithm: "RS256", expiresIn: "168h" })
|
|
stmt.run(discordId, username, nickname, avatarUrl, token)
|
|
return { success: true, user: { username, nickname, avatarUrl, token } }
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to register user.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function removeUser(username) {
|
|
const stmt = db.prepare("DELETE FROM users WHERE username = ?")
|
|
try {
|
|
stmt.run(username)
|
|
return { success: true, code: 204 }
|
|
} catch (error) {
|
|
console.error(error)
|
|
return { success: false, error: "Failed to delete user", code: 500 }
|
|
}
|
|
}
|
|
|
|
function updateUserNickname(nickname, discordId) {
|
|
const stmt = db.prepare("UPDATE users SET nickname = ? WHERE discordId = ?")
|
|
try {
|
|
const result = stmt.run(nickname, discordId)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Player not found or already in the specified room.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to move player to another room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function updateUserUsername(username, discordId) {
|
|
const stmt = db.prepare("UPDATE users SET username = ? WHERE discordId = ?")
|
|
try {
|
|
const result = stmt.run(username, discordId)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Player not found or already in the specified room.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to move player to another room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function updateUserAvatar(avatarUrl, discordId) {
|
|
const stmt = db.prepare("UPDATE users SET avatarUrl = ? WHERE discordId = ?")
|
|
try {
|
|
const result = stmt.run(avatarUrl, discordId)
|
|
if (result.changes > 0) {
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: "Player not found or already in the specified room.", code: 404 }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: "Failed to move player to another room.", code: 500 }
|
|
}
|
|
}
|
|
|
|
function getUser(userId) {
|
|
const stmt = db.prepare("SELECT * FROM users WHERE discordId = ?")
|
|
const user = stmt.get(userId)
|
|
if (user) {
|
|
return { success: true, code: 200, user }
|
|
} else {
|
|
return { success: false, error: "No user found with that ID.", code: 404 }
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
initDB,
|
|
login,
|
|
loginWithToken,
|
|
loginWithTokenAndToken,
|
|
getPlayersFromRoom,
|
|
putPlayerInRoom,
|
|
movePlayerAnotherRoom,
|
|
removePlayer,
|
|
listRooms,
|
|
addRoomToLobby,
|
|
deleteRoom,
|
|
getRoom,
|
|
updateKeyAndValueForRoom,
|
|
removeUser,
|
|
addUser,
|
|
updateUserAvatar,
|
|
updateUserNickname,
|
|
updateUserUsername,
|
|
getUser
|
|
} |