Files
PasswordManager/server.js

250 lines
7.4 KiB
JavaScript
Raw Normal View History

2025-11-12 10:13:24 -05:00
const express = require("express");
const sql = require("mssql");
const bcrypt = require("bcrypt");
const cors = require("cors");
const jwt = require("jsonwebtoken")
const dotenv = require("dotenv")
2025-11-12 10:15:10 -05:00
const serverPort = 3001;
2025-11-12 10:13:24 -05:00
const dev = process.argv.length > 2 && process.argv[2] == "-dev";
const app = express();
app.use(express.json());
2025-11-18 21:16:35 -05:00
app.use((req, res, next) =>{
if (req.path.endsWith(".html")) {
res.redirect(req.path.replace(".html", ""));
return;
}
next();
})
2025-11-12 10:13:24 -05:00
app.use(express.static("public"))
app.use(cors({
origin: [
"https://project.rochesterx.dev",
2025-11-12 10:15:10 -05:00
"https://localhost:3001"
2025-11-12 10:13:24 -05:00
]
}));
let dbConfig = null;
dbConfig = {
user: "server",
password: "TorusField1*",
server: "mssql.rochesterx.dev",
database: "ProjectTest",
options: { trustServerCertificate: true }
};
let pool = null;
setupPool();
dotenv.config();
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET) {
throw new Error("JWT_SECRET not set in environment.");
}
async function setupPool() {
pool = await sql.connect(dbConfig);
}
app.post("/register", async (req, res) => {
const { username, password, role } = req.body;
try {
const hash = await bcrypt.hash(password, 10);
await pool.request()
.input("username", sql.VarChar, username)
.input("hash", sql.VarChar, hash)
.input("role", sql.VarChar, role)
.query("INSERT INTO Users (Username, PasswordHash, Role, CreatedAt) VALUES (@username, @hash, @role, SYSUTCDATETIME())");
res.send({ success: true, message: "User registered" })
} catch (err) {
if (err.message.includes("Violation of UNIQUE KEY constraint")) {
res.status(500).send({ success: false, message: `Username "${username}" is already taken.` });
}
res.status(500).send({ success: false, message: err.message });
}
});
app.post("/login", async (req, res) => {
const { username, password } = req.body;
try {
const result = await pool.request()
.input("username", sql.VarChar, username)
.query("SELECT * FROM Users WHERE Username = @username");
if (result.recordset.length == 0) return res.status(400).send({ message: "User not found" });
const hash = result.recordset[0].PasswordHash;
const isDeleted = result.recordset[0].IsDeleted;
if (isDeleted === true) {
return res.status(400).json({ message: "User not found (deleted)" })
}
const match = await bcrypt.compare(password, hash);
if (match){
const token = jwt.sign(result.recordset[0], JWT_SECRET, { expiresIn: "1h" });
res.send({
success: true,
message: "Login successful",
token
});
await pool.request()
.input("username", sql.VarChar, username)
.query("UPDATE Users SET LastLogin = SYSUTCDATETIME() WHERE Username = @username");
console.log("Issued token: " + JSON.stringify(token))
}
else res.status(401).send({ success: false, message: "Invalid credentials" });
} catch (err) {
res.status(500).send({ success: false, message: err.message });
}
});
2025-11-17 18:56:31 -05:00
app.post("/getPlayers", authenticate, async (req, res) => {
const { player } = req.body;
2025-11-12 10:13:24 -05:00
const result = await pool.request()
2025-11-17 18:56:31 -05:00
.input("query", sql.VarChar, player)
2025-11-18 21:16:35 -05:00
.query(`SELECT * FROM Player WHERE player_name LIKE '%' + @query + '%'`);
2025-11-12 10:13:24 -05:00
2025-11-17 18:56:31 -05:00
res.status(200).json({ query: player, matches: result.recordset });
2025-11-12 10:13:24 -05:00
});
2025-11-18 21:16:35 -05:00
app.post("/getPlayer", authenticate, async (req, res) => {
const { id } = req.body;
const result = await pool.request()
.input("query", sql.VarChar, id)
.query(`SELECT * FROM Player WHERE player_id = @query`);
if (result.recordset.length !== 1) {
res.status(400).json({ success: false })
return;
}
res.status(200).json({ success: true, match: result.recordset[0] });
});
2025-11-12 10:13:24 -05:00
app.post("/getInfo", authenticate, async (req, res) => {
const userData = req.user;
res.status(200).json(userData);
});
app.post("/getCourses", authenticate, async (req, res) => {
const result = await pool.request()
.query("SELECT * FROM Courses");
const courses = result.recordset;
res.status(200).json(courses);
});
app.post("/setInfo", authenticate, async (req, res) => {
const { firstName, lastName, dob } = req.body;
try {
await pool.request()
.input("username", sql.VarChar, req.user.Username)
.input("firstName", sql.NVarChar(50), firstName)
.input("lastName", sql.NVarChar(50), lastName)
.input("dob", sql.Date, dob)
.query(`
UPDATE Users
SET FirstName = @firstName,
LastName = @lastName,
DOB = @dob
WHERE Username = @username
`);
} catch (error) {
console.log(error);
res.status(500).json({ message: "Update request failed" })
}
2025-11-18 21:16:35 -05:00
var updatedUser = req.user;
updatedUser.FirstName = firstName;
updatedUser.LastName = lastName;
updatedUser.DOB = dob;
const token = jwt.sign(updatedUser, JWT_SECRET);
console.log("Issued token: " + JSON.stringify(token))
res.status(200).send({
success: true,
message: "Information updated successfully",
token
});
2025-11-12 10:13:24 -05:00
});
app.post("/delete", authenticate, async (req, res) => {
let { username, actor } = req.body;
if (username === true) {
username = req.user.Username;
}
if (actor === true) {
actor = req.user.Username;
}
console.log(`Deleting user ${username}`);
await pool.request()
.input("username", sql.VarChar, username)
.input("actor", sql.VarChar, actor)
.query("UPDATE Users SET IsDeleted = 1, DeletedAt = SYSUTCDATETIME(), DeletedBy = @actor WHERE Username = @username");
console.log(`User ${username} deleted`);
res.status(200).json({ message: `User "${username}" deleted.` });
});
async function authenticate(req, res, next) {
try {
const authenticationHeader = req.headers["authorization"];
2025-11-18 21:16:35 -05:00
console.log("authenticationheader: " + authenticationHeader);
2025-11-12 10:13:24 -05:00
const token = authenticationHeader.split(" ")[1];
console.log(JSON.stringify(authenticationHeader));
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded;
console.log(req.user);
console.log(decoded.Username + " authenticated");
} catch (error) {
console.log("Authentication header missing");
2025-11-18 21:16:35 -05:00
console.log(error);
2025-11-12 10:13:24 -05:00
res.status(401).json({ message: "You are not logged in", error: error, logout: true });
return;
}
next();
}
2025-11-18 21:16:35 -05:00
app.get("/player/:id", (req, res) => {
res.sendFile(__dirname + "/public/player.html");
})
app.get("/search", (req, res) => {
res.sendFile(__dirname + "/public/search.html");
})
app.get("/home", (req, res) => {
res.sendFile(__dirname + "/public/home.html");
})
app.get("/info", (req, res) => {
res.sendFile(__dirname + "/public/info.html");
})
app.get("/register", (req, res) => {
res.sendFile(__dirname + "/public/register.html");
})
app.get("/login", (req, res) => {
res.sendFile(__dirname + "/public/login.html");
})
2025-11-12 10:13:24 -05:00
app.listen(serverPort, "0.0.0.0", () => console.log(`Running ${dev ? "dev " : ""}server on port ${serverPort}`));