2025-11-12 10:13:24 -05:00
const express = require ( "express" ) ;
2026-01-25 01:36:32 -05:00
const sqlite = require ( "better-sqlite3" ) ;
2025-11-12 10:13:24 -05:00
const bcrypt = require ( "bcrypt" ) ;
const cors = require ( "cors" ) ;
const jwt = require ( "jsonwebtoken" )
2026-01-25 01:36:32 -05:00
const dotenv = require ( "dotenv" ) ;
const Database = require ( "better-sqlite3" ) ;
2025-11-12 10:13:24 -05:00
2026-03-09 20:42:28 +00:00
const serverPort = 3006 ;
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
]
} ) ) ;
2026-01-25 01:36:32 -05:00
const db = new Database ( "project.db" ) ;
db . pragma ( "journal_mode = WAL" )
2025-11-12 10:13:24 -05:00
dotenv . config ( ) ;
const JWT _SECRET = process . env . JWT _SECRET ;
if ( ! JWT _SECRET ) {
throw new Error ( "JWT_SECRET not set in environment." ) ;
}
app . post ( "/register" , async ( req , res ) => {
2026-03-09 16:31:40 -04:00
const { username , password , role , salt } = req . body ;
2025-11-12 10:13:24 -05:00
try {
const hash = await bcrypt . hash ( password , 10 ) ;
2026-01-25 01:36:32 -05:00
const inputs = {
username : username ,
hash : hash ,
2026-03-09 16:31:40 -04:00
role : role ,
salt : salt
2026-01-25 01:36:32 -05:00
}
2026-03-09 16:31:40 -04:00
const query = db . prepare ( "INSERT INTO Users (Username, PasswordHash, Role, CreatedAt, Salt) VALUES (@username, @hash, @role, datetime('now'), @salt)" ) ;
2026-01-25 01:36:32 -05:00
query . run ( inputs ) ;
2025-11-12 10:13:24 -05:00
res . send ( { success : true , message : "User registered" } )
2026-01-25 01:36:32 -05:00
2025-11-12 10:13:24 -05:00
} catch ( err ) {
2026-03-09 16:31:40 -04:00
if ( err . message . includes ( "UNIQUE" ) ) {
2025-11-12 10:13:24 -05:00
res . status ( 500 ) . send ( { success : false , message : ` Username " ${ username } " is already taken. ` } ) ;
2026-03-09 16:31:40 -04:00
return ;
2025-11-12 10:13:24 -05:00
}
res . status ( 500 ) . send ( { success : false , message : err . message } ) ;
}
} ) ;
app . post ( "/login" , async ( req , res ) => {
const { username , password } = req . body ;
2026-03-09 16:31:40 -04:00
//try {
2026-01-25 01:36:32 -05:00
const query = db . prepare ( "SELECT * FROM Users WHERE Username = @username" ) ;
const results = query . all ( { username : username } ) ;
2025-11-12 10:13:24 -05:00
2026-01-25 01:36:32 -05:00
if ( results . length == 0 ) return res . status ( 400 ) . send ( { message : "User not found" } ) ;
2025-11-12 10:13:24 -05:00
2026-01-25 01:36:32 -05:00
const hash = results [ 0 ] . PasswordHash ;
const isDeleted = results [ 0 ] . IsDeleted ;
2025-11-12 10:13:24 -05:00
if ( isDeleted === true ) {
return res . status ( 400 ) . json ( { message : "User not found (deleted)" } )
}
const match = await bcrypt . compare ( password , hash ) ;
if ( match ) {
2026-01-25 01:36:32 -05:00
const token = jwt . sign ( results [ 0 ] , JWT _SECRET , { expiresIn : "1h" } ) ;
2025-11-12 10:13:24 -05:00
res . send ( {
success : true ,
message : "Login successful" ,
2026-03-09 16:31:40 -04:00
token ,
salt : results [ 0 ] . Salt
2025-11-12 10:13:24 -05:00
} ) ;
2026-01-25 01:36:32 -05:00
const update = db . prepare ( "UPDATE Users SET LastLogin = datetime('now') WHERE Username = @username" ) ;
update . run ( { username : username } ) ;
2025-11-12 10:13:24 -05:00
console . log ( "Issued token: " + JSON . stringify ( token ) )
}
else res . status ( 401 ) . send ( { success : false , message : "Invalid credentials" } ) ;
2026-03-09 16:31:40 -04:00
//} catch (err) {
// res.status(500).send({ success: false, message: err.message });
//}
2025-11-12 10:13:24 -05:00
} ) ;
2026-03-09 16:31:40 -04:00
app . post ( "/getSalt" , async ( req , res ) => {
const { username } = req . body ;
try {
const query = db . prepare ( "SELECT * FROM Users WHERE Username = @username" ) ;
const results = query . all ( { username : username } ) ;
if ( results . length == 0 ) return res . status ( 400 ) . send ( { message : "User not found" } ) ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
const isDeleted = results [ 0 ] . IsDeleted ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
if ( isDeleted === true ) {
return res . status ( 400 ) . json ( { message : "User not found (deleted)" } )
}
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
res . send ( {
salt : results [ 0 ] . Salt
} ) ;
} catch ( err ) {
res . status ( 500 ) . send ( { success : false , message : err . message } ) ;
}
2025-11-26 21:10:22 -05:00
} ) ;
2026-03-09 16:31:40 -04:00
app . post ( "/setPassword" , authenticate , async ( req , res ) => {
try {
const { name , iv , password } = req . body ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
const inputs = {
name : name ,
userID : req . user . Id ,
iv : iv ,
password : password
}
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
const query = db . prepare ( "INSERT INTO Passwords (Name, UserID, Password, IV) VALUES (@name, @userID, @password, @iv)" ) ;
query . run ( inputs ) ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
res . status ( 200 ) . json ( { success : true , message : "Success" } ) ;
} catch ( err ) {
res . status ( 500 ) . json ( { success : false , message : err . message } ) ;
2025-11-26 21:10:22 -05:00
}
} ) ;
2026-03-09 16:31:40 -04:00
app . post ( "/updatePassword" , authenticate , async ( req , res ) => {
try {
const { name , iv , password } = req . body ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
const inputs = {
name : name ,
userID : req . user . Id ,
iv : iv ,
password : password
}
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
const query = db . prepare ( "UPDATE Passwords SET Password = @password, IV = @iv WHERE UserID = @userID AND Name = @name" ) ;
query . run ( inputs ) ;
2025-11-26 21:10:22 -05:00
2026-03-09 16:31:40 -04:00
res . status ( 200 ) . json ( { success : true , message : "Success" } ) ;
} catch ( err ) {
res . status ( 500 ) . json ( { success : false , message : err . message } ) ;
}
2025-11-28 13:54:57 -05:00
} ) ;
2026-03-09 16:31:40 -04:00
app . post ( "/getPassword" , authenticate , async ( req , res ) => {
try {
const { name } = req . body ;
2025-11-28 13:54:57 -05:00
2026-03-09 16:31:40 -04:00
const query = db . prepare ( "SELECT * FROM Passwords WHERE UserID = @userID AND Name = @name" ) ;
const results = query . all ( { userID : req . user . Id , name : name } ) ;
2025-11-28 13:54:57 -05:00
2026-03-09 16:31:40 -04:00
if ( results . length == 0 ) {
res . status ( 500 ) . json ( { success : false , message : ` No password with name ${ name } ` } ) ;
return ;
}
2025-11-28 13:54:57 -05:00
2026-03-09 16:31:40 -04:00
if ( results . length > 1 ) {
res . status ( 500 ) . json ( { success : false , message : ` More than one password with name ${ name } ` } ) ;
return ;
}
2025-11-28 13:54:57 -05:00
2026-03-09 16:31:40 -04:00
res . status ( 200 ) . json ( { password : results [ 0 ] . Password , iv : results [ 0 ] . IV , success : true , message : "Success" } ) ;
} catch ( err ) {
res . status ( 500 ) . json ( { success : false , message : err . message } ) ;
}
2025-11-28 11:10:09 -05:00
} ) ;
2026-03-09 16:31:40 -04:00
2025-11-28 11:10:09 -05:00
2026-03-09 16:31:40 -04:00
app . post ( "/getWatchlist" , authenticate , async ( req , res ) => {
2025-11-18 21:16:35 -05:00
const { id } = req . body ;
2026-03-09 16:31:40 -04:00
const query = db . prepare ( ` SELECT Player.PlayerName, Player.Team, Player.Position, Player.PlayerID FROM Watch JOIN Player ON Watch.PlayerID = Player.PlayerID WHERE UserID = @userID ORDER BY Player.PlayerName ` ) ;
const watchlist = query . all ( {
userID : req . user . Id ,
id : id
} ) ;
2025-11-18 21:16:35 -05:00
2026-03-09 16:31:40 -04:00
res . status ( 200 ) . json ( { watchlist : watchlist } ) ;
2025-11-18 21:16:35 -05:00
} ) ;
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 ( "/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 } ` ) ;
2026-01-25 01:36:32 -05:00
const query = ( "UPDATE Users SET IsDeleted = 1, DeletedAt = datetime('now'), DeletedBy = @actor WHERE Username = @username" ) ;
query . run ( {
username : username ,
actor : actor
} ) ;
2025-11-12 10:13:24 -05:00
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" ) ;
} )
2026-01-25 01:36:32 -05:00
2025-11-12 10:13:24 -05:00
app . listen ( serverPort , "0.0.0.0" , ( ) => console . log ( ` Running ${ dev ? "dev " : "" } server on port ${ serverPort } ` ) ) ;
2026-01-25 01:36:32 -05:00