diff --git a/.env.example b/.env.example index 60a9048..dcb1420 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ # Server configuration ENV=development PORT=4000 -DATABASE_URL="mysql://root@localhost:3306/nq" \ No newline at end of file +DATABASE_URL="mysql://root@localhost:3306/nq" +JWT_SECRET="secret" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2b71126..1ae384e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", "prisma": "^5.13.0", "socket.io": "^4.7.5", "ts-node": "^10.9.2", @@ -18,6 +19,7 @@ "devDependencies": { "@types/bcryptjs": "^2.4.6", "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.6", "@types/node": "^20.12.11", "@types/socket.io": "^3.0.2", "nodemon": "^3.1.0" @@ -229,6 +231,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -436,6 +448,12 @@ "node": ">=8" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -617,6 +635,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1043,6 +1070,97 @@ "node": ">=0.12.0" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -1374,7 +1492,6 @@ "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/package.json b/package.json index 4ced17d..b2ab58d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", "prisma": "^5.13.0", "socket.io": "^4.7.5", "ts-node": "^10.9.2", @@ -18,6 +19,7 @@ "devDependencies": { "@types/bcryptjs": "^2.4.6", "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.6", "@types/node": "^20.12.11", "@types/socket.io": "^3.0.2", "nodemon": "^3.1.0" diff --git a/src/app/UserManager.ts b/src/app/UserManager.ts index 28bc5da..a12c2e4 100644 --- a/src/app/UserManager.ts +++ b/src/app/UserManager.ts @@ -1,11 +1,11 @@ import {User} from "@prisma/client"; -interface ILoggedInUsers { +type TLoggedInUsers = { users: User[]; } class UserManager { - private loggedInUsers: ILoggedInUsers[] = []; + private loggedInUsers: TLoggedInUsers[] = []; // Method to initialize user manager public async boot() { diff --git a/src/app/ZoneManager.ts b/src/app/ZoneManager.ts index ba727f2..8dee26d 100644 --- a/src/app/ZoneManager.ts +++ b/src/app/ZoneManager.ts @@ -1,14 +1,14 @@ import {Character, Zone} from "@prisma/client"; -import ZoneRepository from "./repositories/zone.repository"; -import ZoneService from "./services/zone.service"; +import ZoneRepository from "./repositories/ZoneRepository"; +import ZoneService from "./services/ZoneService"; -interface ILoadedZone { +type TLoadedZone = { zone: Zone; characters: Character[]; } class ZoneManager { - private loadedZones: ILoadedZone[] = []; + private loadedZones: TLoadedZone[] = []; // Method to initialize zone manager public async boot() { diff --git a/src/app/events/CharacterConnect.ts b/src/app/events/CharacterConnect.ts new file mode 100644 index 0000000..f005674 --- /dev/null +++ b/src/app/events/CharacterConnect.ts @@ -0,0 +1,8 @@ +import { Socket, Server } from "socket.io"; +import {TSocket} from "../types/TSocket"; + +export default function CharacterConnect(socket: TSocket, io: Server) { + socket.on('character:connect', (data: any) => { + console.log(`---User ${socket.user?.id} has joined.`); + }); +} \ No newline at end of file diff --git a/src/app/events/character.zone.load.ts b/src/app/events/CharacterZoneLoad.ts similarity index 89% rename from src/app/events/character.zone.load.ts rename to src/app/events/CharacterZoneLoad.ts index 2cc8c0e..a7f5cd1 100644 --- a/src/app/events/character.zone.load.ts +++ b/src/app/events/CharacterZoneLoad.ts @@ -1,5 +1,5 @@ import { Socket, Server } from "socket.io"; -import ZoneRepository from "../repositories/zone.repository"; +import ZoneRepository from "../repositories/ZoneRepository"; import ZoneManager from "../ZoneManager"; import {Zone} from "@prisma/client"; @@ -14,7 +14,7 @@ interface IZoneLoad { * @param socket * @param io */ -export default function characterZoneLoad(socket: Socket, io: Server) { +export default function CharacterZoneLoad(socket: Socket, io: Server) { socket.on('character:zone:load', async (data: IZoneLoad) => { console.log(`---User ${socket.id} has requested zone.`); diff --git a/src/app/events/CharactersGet.ts b/src/app/events/CharactersGet.ts new file mode 100644 index 0000000..1ba7e2d --- /dev/null +++ b/src/app/events/CharactersGet.ts @@ -0,0 +1,8 @@ +import { Socket, Server } from "socket.io"; +import {TSocket} from "../types/TSocket"; + +export default function CharactersGet(socket: TSocket, io: Server) { + socket.on('characters:get', async (data: any) => { + console.log(socket.user); + }); +} \ No newline at end of file diff --git a/src/app/events/disconnect.ts b/src/app/events/Disconnect.ts similarity index 51% rename from src/app/events/disconnect.ts rename to src/app/events/Disconnect.ts index 7c68868..a87a5ed 100644 --- a/src/app/events/disconnect.ts +++ b/src/app/events/Disconnect.ts @@ -1,7 +1,7 @@ import { Socket, Server } from "socket.io"; -export default function user_connect(socket: Socket, io: Server) { - socket.on('disconnect', (data) => { +export default function Disconnect(socket: Socket, io: Server) { + socket.on('disconnect', (data: any) => { console.log(`---User ${socket.id} has disconnected.`); }); } \ No newline at end of file diff --git a/src/app/events/Login.ts b/src/app/events/Login.ts new file mode 100644 index 0000000..1edc23e --- /dev/null +++ b/src/app/events/Login.ts @@ -0,0 +1,7 @@ +import { Socket, Server } from "socket.io"; + +export default function Login(socket: Socket, io: Server) { + socket.on('login', (data: any) => { + console.log(`---User ${socket.id} has logged in.`); + }); +} \ No newline at end of file diff --git a/src/app/events/character.connect.ts b/src/app/events/character.connect.ts deleted file mode 100644 index bf4291d..0000000 --- a/src/app/events/character.connect.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Socket, Server } from "socket.io"; -import {ISocket} from "../interfaces/socket"; - -export default function characterConnect(socket: ISocket, io: Server) { - socket.on('character:connect', (data) => { - socket.user.username = 'hello' - console.log(`---User ${socket.id} has joined.`); - }); -} \ No newline at end of file diff --git a/src/app/events/characters.get.ts b/src/app/events/characters.get.ts deleted file mode 100644 index 5fdfc06..0000000 --- a/src/app/events/characters.get.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Socket, Server } from "socket.io"; -import {ISocket} from "../interfaces/socket"; - -export default function characterConnect(socket: ISocket, io: Server) { - socket.on('characters:get', async (data) => { - console.log(socket.user.username) - console.log(`---characters requested.`); - }); -} \ No newline at end of file diff --git a/src/app/index.d.ts b/src/app/index.d.ts new file mode 100644 index 0000000..096ee31 --- /dev/null +++ b/src/app/index.d.ts @@ -0,0 +1,17 @@ +import "socket.io"; + +declare module "socket.io" { + interface Socket { + data: { + user: { + id: string; + username: string; + }; + }; + handshake: { + headers: { + cookie: string; + }; + }; + } +} \ No newline at end of file diff --git a/src/app/interfaces/socket.ts b/src/app/interfaces/socket.ts deleted file mode 100644 index 6785b6e..0000000 --- a/src/app/interfaces/socket.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {Socket} from "socket.io"; - -export interface ISocket extends Socket { - user?: any; -} \ No newline at end of file diff --git a/src/app/interfaces/zoneCharacters.ts b/src/app/interfaces/zoneCharacters.ts deleted file mode 100644 index 6624fd1..0000000 --- a/src/app/interfaces/zoneCharacters.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {Character} from "@prisma/client"; - -interface zoneCharacters extends Character -{ - -} \ No newline at end of file diff --git a/src/app/middleware/Authentication.ts b/src/app/middleware/Authentication.ts new file mode 100644 index 0000000..d012f38 --- /dev/null +++ b/src/app/middleware/Authentication.ts @@ -0,0 +1,37 @@ +// socket io jwt auth middleware +import { verify } from 'jsonwebtoken'; +import { TSocket } from '../types/TSocket'; +import config from "../utilities/Config"; +import UserRepository from "../repositories/UserRepository"; +import {User} from "@prisma/client"; + +export async function Authentication (socket: TSocket, next: any) { + + if (!socket.request.headers.cookie) { + console.log('No cookie provided'); + return next(new Error('Authentication error')); + } + + const cookies = socket.request.headers.cookie.split('; ').reduce((prev: any, current: any) => { + const [name, value] = current.split('='); + prev[name] = value; + return prev; + }, {}); + + const token = cookies['token']; + + if (token) { + verify(token, config.JWT_SECRET, async (err: any, decoded: any) => { + if (err) { + console.log('err'); + return next(new Error('Authentication error')); + } + + socket.user = await UserRepository.getById(decoded.id) as User; + next(); + }); + } else { + console.log('No token provided'); + next(new Error('Authentication error')); + } +} \ No newline at end of file diff --git a/src/app/repositories/character.repository.ts b/src/app/repositories/CharacterRepository.ts similarity index 86% rename from src/app/repositories/character.repository.ts rename to src/app/repositories/CharacterRepository.ts index 325528d..074dc3f 100644 --- a/src/app/repositories/character.repository.ts +++ b/src/app/repositories/CharacterRepository.ts @@ -1,6 +1,6 @@ -import prisma from '../utilities/prisma'; // Import the global Prisma instance +import prisma from '../utilities/Prisma'; // Import the global Prisma instance import {Character} from '@prisma/client'; -import CharacterService from "../services/character.service"; +import CharacterService from "../services/CharacterService"; class CharacterRepository { async getByUserId(userId: number): Promise { diff --git a/src/app/repositories/user.repository.ts b/src/app/repositories/UserRepository.ts similarity index 65% rename from src/app/repositories/user.repository.ts rename to src/app/repositories/UserRepository.ts index df42a37..8469697 100644 --- a/src/app/repositories/user.repository.ts +++ b/src/app/repositories/UserRepository.ts @@ -1,7 +1,19 @@ -import prisma from '../utilities/prisma'; // Import the global Prisma instance +import prisma from '../utilities/Prisma'; // Import the global Prisma instance import { User } from '@prisma/client'; class UserRepository { + async getById(id: number): Promise { + try { + return await prisma.user.findUnique({ + where: { + id, + }, + }); + } catch (error: any) { + // Handle error + throw new Error(`Failed to get user by ID: ${error.message}`); + } + } async getByUsername(username: string): Promise { try { return await prisma.user.findUnique({ @@ -14,7 +26,6 @@ class UserRepository { throw new Error(`Failed to get user by username: ${error.message}`); } } - async create(username: string, password: string): Promise { try { return await prisma.user.create({ diff --git a/src/app/repositories/zone.repository.ts b/src/app/repositories/ZoneRepository.ts similarity index 93% rename from src/app/repositories/zone.repository.ts rename to src/app/repositories/ZoneRepository.ts index 402529a..d18e585 100644 --- a/src/app/repositories/zone.repository.ts +++ b/src/app/repositories/ZoneRepository.ts @@ -1,5 +1,5 @@ import { Zone } from '@prisma/client'; -import prisma from '../utilities/prisma'; // Import the global Prisma instance +import prisma from '../utilities/Prisma'; // Import the global Prisma instance class ZoneRepository { async getFirst(): Promise { diff --git a/src/app/services/character.service.ts b/src/app/services/CharacterService.ts similarity index 100% rename from src/app/services/character.service.ts rename to src/app/services/CharacterService.ts diff --git a/src/app/services/user.service.ts b/src/app/services/UserService.ts similarity index 86% rename from src/app/services/user.service.ts rename to src/app/services/UserService.ts index f405a7b..c9fa407 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/UserService.ts @@ -1,6 +1,6 @@ import bcrypt from "bcryptjs"; -import UserRepository from "../repositories/user.repository"; -import CharacterRepository from "../repositories/character.repository"; +import UserRepository from "../repositories/UserRepository"; +import CharacterRepository from "../repositories/CharacterRepository"; class UserService { async login(username: string, password: string): Promise { diff --git a/src/app/services/zone.service.ts b/src/app/services/ZoneService.ts similarity index 88% rename from src/app/services/zone.service.ts rename to src/app/services/ZoneService.ts index 22ad5c3..0860cca 100644 --- a/src/app/services/zone.service.ts +++ b/src/app/services/ZoneService.ts @@ -1,5 +1,5 @@ import {Zone} from "@prisma/client"; -import ZoneRepository from "../repositories/zone.repository"; +import ZoneRepository from "../repositories/ZoneRepository"; class ZoneService { diff --git a/src/app/interfaces/character.ts b/src/app/types/TCharacter.ts similarity index 79% rename from src/app/interfaces/character.ts rename to src/app/types/TCharacter.ts index d23e1bc..c67b3b9 100644 --- a/src/app/interfaces/character.ts +++ b/src/app/types/TCharacter.ts @@ -1,8 +1,7 @@ import { Socket } from 'socket.io'; import {Character as ICharacter, User} from "@prisma/client"; -interface Character extends Socket -{ +export type TCharacter = Socket & { user?: User, character?: ICharacter } \ No newline at end of file diff --git a/src/app/types/TSocket.ts b/src/app/types/TSocket.ts new file mode 100644 index 0000000..8a4e8d8 --- /dev/null +++ b/src/app/types/TSocket.ts @@ -0,0 +1,16 @@ +import {Socket} from "socket.io"; +import { User } from '@prisma/client'; + +export type TSocket = Socket & { + user?: User + handshake?: { + query?: { + token?: any + } + } + request?: { + headers?: { + cookie?: any + } + } +} \ No newline at end of file diff --git a/src/app/types/TZoneCharacter.ts b/src/app/types/TZoneCharacter.ts new file mode 100644 index 0000000..ffbd108 --- /dev/null +++ b/src/app/types/TZoneCharacter.ts @@ -0,0 +1,5 @@ +import {Character} from "@prisma/client"; + +export type TZoneCharacter = Character & { + +} \ No newline at end of file diff --git a/src/app/utilities/config.ts b/src/app/utilities/Config.ts similarity index 68% rename from src/app/utilities/config.ts rename to src/app/utilities/Config.ts index b69e9fb..a68e8fd 100644 --- a/src/app/utilities/config.ts +++ b/src/app/utilities/Config.ts @@ -5,6 +5,7 @@ dotenv.config(); class config { static ENV: string = process.env.ENV || "prod"; static PORT: number = process.env.PORT ? parseInt(process.env.PORT) : 5000; + static JWT_SECRET: string = process.env.JWT_SECRET || "secret"; } export default config; \ No newline at end of file diff --git a/src/app/utilities/api.ts b/src/app/utilities/Http.ts similarity index 52% rename from src/app/utilities/api.ts rename to src/app/utilities/Http.ts index aabe027..2f78302 100644 --- a/src/app/utilities/api.ts +++ b/src/app/utilities/Http.ts @@ -1,7 +1,15 @@ -import { Request, Response } from 'express'; -import UserService from '../services/user.service'; +/** + * Resources: + * https://stackoverflow.com/questions/76131891/what-is-the-best-method-for-socket-io-authentication + * + */ -async function addAuthRoutes(app: any) { +import {Application, Request, Response} from 'express'; +import UserService from '../services/UserService'; +import jwt from "jsonwebtoken"; +import config from "./Config"; + +async function addAuthRoutes(app: Application) { app.post('/login', async (req: Request, res: Response) => { const { username, password } = req.body; @@ -9,7 +17,8 @@ async function addAuthRoutes(app: any) { const user = await userService.login(username, password); if (user) { - return res.status(200).json(user); + const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' }); + return res.status(200).json({ token }); } return res.status(401).json({ message: 'Invalid credentials' }); }); @@ -21,7 +30,8 @@ async function addAuthRoutes(app: any) { const user = await userService.register(username, password); if (user) { - return res.status(201).json(user); + const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' }); + return res.status(201).json({ token }); } return res.status(400).json({ message: 'Failed to register user' }); }); @@ -29,4 +39,4 @@ async function addAuthRoutes(app: any) { console.log('[✅] Auth routes added'); } -export default { addAuthRoutes }; \ No newline at end of file +export { addAuthRoutes }; \ No newline at end of file diff --git a/src/app/utilities/prisma.ts b/src/app/utilities/Prisma.ts similarity index 100% rename from src/app/utilities/prisma.ts rename to src/app/utilities/Prisma.ts diff --git a/src/server.ts b/src/server.ts index c68279e..680750a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,19 +1,21 @@ import fs from "fs"; import path from "path"; import express, {Application} from 'express'; -import http from 'http'; +import {createServer as httpServer} from 'http'; +import {addAuthRoutes} from './app/utilities/Http'; import cors from 'cors'; -import {Server as SocketServer, Socket} from 'socket.io'; -import config from './app/utilities/config'; -import prisma from './app/utilities/prisma'; -import api from "./app/utilities/api"; +import {Server as SocketServer} from 'socket.io'; +import {TSocket} from "./app/types/TSocket"; +import config from './app/utilities/Config'; +import prisma from './app/utilities/Prisma'; import ZoneManager from "./app/ZoneManager"; import UserManager from "./app/UserManager"; +import {Authentication} from "./app/middleware/Authentication"; export class Server { private readonly app: Application; - private readonly server: any; + private readonly http: any; private readonly io: SocketServer; /** @@ -24,8 +26,9 @@ export class Server this.app.use(cors()); this.app.use(express.json()); this.app.use(express.urlencoded({ extended: true })); - this.server = http.createServer(this.app) - this.io = new SocketServer(this.server); + this.http = httpServer(this.app) + this.io = new SocketServer(this.http); + this.io.use(Authentication) } /** @@ -46,14 +49,14 @@ export class Server // Start the server try { - await this.server.listen(config.PORT); + await this.http.listen(config.PORT); console.log('[✅] Socket.IO running on port', config.PORT); } catch (error: any) { throw new Error(`[❌] Socket.IO failed to start: ${error.message}`); } - // Add API routes - await api.addAuthRoutes(this.app); + // Add http API routes + await addAuthRoutes(this.app); // Load user manager await UserManager.boot(); @@ -70,7 +73,7 @@ export class Server * @param socket * @private */ - private async handleConnection(socket: Socket) { + private async handleConnection(socket: TSocket) { const eventsPath = path.join(__dirname, 'app', 'events'); try { const files: string[] = await fs.promises.readdir(eventsPath); diff --git a/tsconfig.json b/tsconfig.json index 805c534..bb206eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,7 @@ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "typeRoots": ["./node_modules/@types", "./src/app"], /* Specify multiple folders that act like './node_modules/@types'. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */