diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..c18c684 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/package.json b/package.json index 1497340..12e5b75 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "private": true, "license": "MIT", "scripts": { - "bun:dev": "bun run --watch src/app.ts", + "bun:dev": "bun run --allow-ffi --watch src/app.ts", "bun:check": "bunx biome check --skip-errors --apply src" }, "dependencies": { @@ -24,6 +24,7 @@ "mysql2": "^3.9.7", "randomatic": "^3.1.1", "react-hook-form": "^7.51.4", + "sharp": "^0.33.4", "tslog": "^4.9.2", "uuid": "^9.0.1" }, diff --git a/src/controllers/auth.controller.ts b/src/controllers/auth.controller.ts index f76914f..293fb6e 100644 --- a/src/controllers/auth.controller.ts +++ b/src/controllers/auth.controller.ts @@ -5,6 +5,11 @@ import {IRegisterInput} from "@interfaces/services/register.types"; import ValidatorsUtils from "@utils/validators.util"; import UsersService from "@services/users.service"; import RegisterService from "@services/authentication/register.service"; +import {HeaderUtil} from "@utils/headers.util"; +import JwtService from "@services/authentication/jwt.service"; +import {JWTPayload} from "jose"; +import {UserInDatabase} from "@interfaces/db/mariadb.interface"; +import ConvertersUtils from "@utils/converters.util"; const logs = new LogsUtils('AuthController') @@ -62,9 +67,29 @@ async function registerController(req: Request, res: Response) { }); } +async function GetSelfController(req: Request, res: Response) { + const originToken = await HeaderUtil.getToken(req) as string; + const token = await JwtService.verify(originToken) as JWTPayload; + const userInDatabases = await UsersService.get.byId(token.sub as string) as Array; + if (userInDatabases.length === 0 || !userInDatabases[0]) { + logs.warn('User not found', req.ip); + return res.status(HttpStatusCode.Gone).json({ error: 'User not found' }); + } + const User = userInDatabases[0] + return res.status(HttpStatusCode.Found).json({ + id: User.id, + username: User.username, + email: User.email, + displayName: User.display_name, + isAdmin: ConvertersUtils.bufferToBool(User.admin as Buffer), + followers: await UsersService.get.followers(User.id), + following: await UsersService.get.following(User.id), + }); +} const AuthController = { - register: registerController + register: registerController, + me: GetSelfController } export default AuthController; \ No newline at end of file diff --git a/src/middlewares/authentication.middleware.ts b/src/middlewares/authentication.middleware.ts index ae2cd79..043261b 100644 --- a/src/middlewares/authentication.middleware.ts +++ b/src/middlewares/authentication.middleware.ts @@ -3,57 +3,50 @@ import JwtService from "@services/authentication/jwt.service"; import {DatabasesService} from "@services/databases/databases.service"; import {UserInDatabase} from "@interfaces/db/mariadb.interface"; import {HttpStatusCode} from "axios"; +import {HeaderUtil} from "@utils/headers.util"; const db = new DatabasesService('OnlyDevs'); -async function getTokenFromHeader(req: Request) { - const token: string | undefined = req.headers.authorization?.split(" ")[1]; - if (!token ||token.length <= 0) { - return false - } - return token; -} - - async function UserMiddleware(req: Request, res: Response, next: NextFunction) { - const originToken = getTokenFromHeader(req); + const originToken = await HeaderUtil.getToken(req); if (!originToken) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized" }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized" }); } const tokenPayload = await JwtService.verify(`${originToken}`); if (!tokenPayload || !tokenPayload.sub) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized" }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized" }); } const UserFound = await db.getUserById(tokenPayload.sub) const User: UserInDatabase | undefined = UserFound[0] as UserInDatabase if (!User) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized, you dont exist." }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized, you dont exist." }); } if (User.email_activation) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "You should verify your email first."}) + return res.status(HttpStatusCode.Forbidden).json({ message: "You should verify your email first."}) } return next() } async function AdminMiddleware(req: Request, res: Response, next: NextFunction) { - const originToken = getTokenFromHeader(req); + const originToken = await HeaderUtil.getToken(req); if (!originToken) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized" }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized" }); } const tokenPayload = await JwtService.verify(`${originToken}`); if (!tokenPayload || !tokenPayload.sub) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized" }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized" }); } const UserFound = await db.getUserById(tokenPayload.sub) const User: UserInDatabase | undefined = UserFound[0] as UserInDatabase if (!User) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized, you dont exist." }); + return res.status(HttpStatusCode.Forbidden).json({ message: "Unauthorized, you dont exist." }); } if (User.email_activation) { - return res.status(HttpStatusCode.PreconditionRequired).json({ message: "You should verify your email first."}) + return res.status(HttpStatusCode.Forbidden).json({ message: "You should verify your email first."}) } const adminState = User.admin + console.log(adminState); if (!adminState) { return res.status(HttpStatusCode.PreconditionRequired).json({ message: "Unauthorized, you are not an admin." }); diff --git a/src/routers/auth.router.ts b/src/routers/auth.router.ts index df1e91c..78d5a1f 100644 --- a/src/routers/auth.router.ts +++ b/src/routers/auth.router.ts @@ -1,10 +1,12 @@ import AuthController from "@controllers/auth.controller"; import express, {type Router} from "express"; +import {AuthMiddleware} from "src/middlewares/authentication.middleware"; const AuthRouter: Router = express.Router(); //AuthRouter.route("/login").post(AuthController.login); AuthRouter.route("/register").post(AuthController.register); +AuthRouter.route("/me").get(AuthMiddleware.user, AuthController.me); export default AuthRouter; \ No newline at end of file diff --git a/src/services/authentication/register.service.ts b/src/services/authentication/register.service.ts index a24ec55..d3b1404 100644 --- a/src/services/authentication/register.service.ts +++ b/src/services/authentication/register.service.ts @@ -10,8 +10,9 @@ const db = new DatabasesService('OnlyDevs') //TODO Logs async function registerService(data: IRegisterInput): Promise { + const uuid = v4().toString() const User: UserInDatabase = { - id: v4(), + id: `${uuid}`, username: data.username, display_name: data.displayName || data.username, hash: await CredentialService.hash(data.password), @@ -24,7 +25,7 @@ async function registerService(data: IRegisterInput): Promise { if (dbResult) { //await sendActivationEmail(User.email, User.email_activation); const token = await JwtService.sign({ - sub: User.id, + sub: uuid, iat: Date.now(), }, { alg: "HS256" diff --git a/src/services/databases/databases.service.ts b/src/services/databases/databases.service.ts index 5f62999..2b99ce1 100644 --- a/src/services/databases/databases.service.ts +++ b/src/services/databases/databases.service.ts @@ -1,7 +1,7 @@ import {MariadbService} from "@services/databases/mariadb.service"; //import {MongodbService} from "@services/databases/mongodb.service"; import {LogsUtils} from "@utils/logs.util"; -import {UserInDatabase} from "@interfaces/db/mariadb.interface"; +import {FollowInDatabase, UserInDatabase} from "@interfaces/db/mariadb.interface"; interface MariaDbStatusResult { fieldCount: number; @@ -26,29 +26,41 @@ export class DatabasesService { } async getAllUsers() { - const result: Array = await this.maria.query("SELECT * FROM users") as unknown as Array; + const result = await this.maria.query("SELECT * FROM users") as unknown as Array; this.logs.debug('Fetching users from database...', `${result?.length} user(s) found.`) return result; } async getUserById(id: string) { - const result: Array = await this.maria.execute(`SELECT * FROM users WHERE id = ?`, [id]) as unknown as Array; + const result = await this.maria.execute(`SELECT * FROM users WHERE id = ?`, [id]) as unknown as Array; this.logs.debug(`Fetching user with id ${id} from database...`, `${result?.length} user(s) found.`); return result; } async getUserByUsername(username: string) { - const result: Array = await this.maria.execute(`SELECT * FROM users WHERE username = ?`, [username]) as unknown as Array; + const result = await this.maria.execute(`SELECT * FROM users WHERE username = ?`, [username]) as unknown as Array; this.logs.debug(`Fetching user with username "${username}" from database...`, `${result?.length} user(s) found.`); return result; } async getUserByEmail(email: string) { - const result: Array = await this.maria.execute(`SELECT * FROM users WHERE email = ?`, [email]) as unknown as Array; + const result = await this.maria.execute(`SELECT * FROM users WHERE email = ?`, [email]) as unknown as Array; this.logs.debug(`Fetching user with email "${email}" from database...`, `${result?.length} user(s) found.`); return result; } + async getFollowingById(id: string) { + const result = await this.maria.execute(`SELECT * FROM follows WHERE source_id = ?`, [id]) as unknown as Array; + this.logs.debug(`Fetching followed users for user with id ${id} from database...`, `${result?.length} user(s) found.`); + return result; + } + + async getFollowersById(id:string) { + const result = await this.maria.execute(`SELECT * FROM follows WHERE target_id = ?`, [id]) as unknown as Array; + this.logs.debug(`Fetching followers for user with id ${id} from database...`, `${result?.length} user(s) found.`); + return result; + } + async insertUser(user: UserInDatabase): Promise { const factorized = await this.maria.factorize({ values: user, diff --git a/src/services/databases/mariadb.service.ts b/src/services/databases/mariadb.service.ts index 07fe910..2fb26bb 100644 --- a/src/services/databases/mariadb.service.ts +++ b/src/services/databases/mariadb.service.ts @@ -26,7 +26,7 @@ export class MariadbService { if (err) { this.logs.error(`Error connecting to MySQL:`, err); } - this.logs.info('Connected to MariaDB', this.envs.get('MYSQL_DATABASE')) + this.logs.debug('Connected to MariaDB', this.envs.get('MYSQL_DATABASE')) }); } closeConnection() { diff --git a/src/services/databases/mongodb.service.ts b/src/services/databases/mongodb.service.ts index c7122f2..a1af8ca 100644 --- a/src/services/databases/mongodb.service.ts +++ b/src/services/databases/mongodb.service.ts @@ -16,7 +16,7 @@ export class MongodbService { this.client .connect() .then(() => { - this.logs.info("Connected to MongoDB", 'All databases'); + this.logs.debug("Connected to MongoDB", 'All databases'); }) } catch (error) { this.logs.error(`Error connecting to MongoDB:`, error); diff --git a/src/services/users.service.ts b/src/services/users.service.ts index 3e2df0d..b379f14 100644 --- a/src/services/users.service.ts +++ b/src/services/users.service.ts @@ -15,10 +15,25 @@ async function getAll() { return db.getAllUsers() } +async function getById(id: string) { + return await db.getUserById(id) +} + +async function getFollowers(id: string) { + return await db.getFollowersById(id) +} + +async function getFollowing(id: string) { + return await db.getFollowingById(id) +} + const get = { byUsername: getByUsername, byEmail: getByEmail, - all: getAll + byId: getById, + all: getAll, + followers: getFollowers, + following: getFollowing } const UsersService = { diff --git a/src/utils/headers.util.ts b/src/utils/headers.util.ts new file mode 100644 index 0000000..6bbd4c8 --- /dev/null +++ b/src/utils/headers.util.ts @@ -0,0 +1,14 @@ +import type {Request} from "express"; + + +async function getTokenFromHeader(req: Request) { + const token: string | undefined = req.headers.authorization?.split(" ")[1]; + if (!token ||token.length <= 0) { + return false + } + return token; +} + +export const HeaderUtil = { + getToken: getTokenFromHeader, +} \ No newline at end of file