First commit
This commit is contained in:
313
controllers/db.js
Normal file
313
controllers/db.js
Normal file
@@ -0,0 +1,313 @@
|
||||
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
|
||||
}
|
||||
33
controllers/keys.js
Normal file
33
controllers/keys.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const fs = require("node:fs")
|
||||
const path = require("node:path")
|
||||
const crypto = require("node:crypto")
|
||||
const logger = require("../modules/logger")
|
||||
require("colors")
|
||||
|
||||
function initKeys() {
|
||||
if (!isExists("private.pem") && isExists("public.pem")) {
|
||||
logger.log(`[${"RSA Keys".blue}] Public key is missing.`)
|
||||
fs.unlinkSync("public.pem")
|
||||
}
|
||||
if (!isExists("public.pem") && isExists("private.pem")) {
|
||||
logger.log(`[${"RSA Keys".blue}] Private key is missing`)
|
||||
fs.unlinkSync("private.pem")
|
||||
}
|
||||
if (!isExists("private.pem") && !isExists("public.pem")) {
|
||||
logger.log(`[${"RSA Keys".blue}] RSA Keys are missings, generating`)
|
||||
const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
|
||||
modulusLength: 2048
|
||||
})
|
||||
fs.writeFileSync(path.join(__dirname, "..", "keys", "private.pem"), privateKey.export({ type: "pkcs1", format: "pem" }))
|
||||
fs.writeFileSync(path.join(__dirname, "..", "keys", "public.pem"), publicKey.export({ type: "spki", format: "pem" }))
|
||||
logger.log(`[${"RSA Keys".blue}] RSA Keys generated`)
|
||||
}
|
||||
}
|
||||
|
||||
function isExists(filename) {
|
||||
return fs.existsSync(path.join(__dirname, "keys", filename))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initKeys
|
||||
}
|
||||
Reference in New Issue
Block a user