feat: Add getSelf endpoint and improve user service
This commit introduces a new endpoint, `GetSelfController`, for fetching authenticated user information in the `AuthController`. It also improves token handling by refactoring token retrieval from headers into a utility function. Additionally, the User service has been extended with new methods for getting a user by ID and for fetching follower and following information. Token UUID handling during registration has been tweaked for consistency. Improvements in logging levels and responses status codes have been made as well.
This commit is contained in:
parent
cb7a396636
commit
b640dc7671
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="97" name="TypeScript" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -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"
|
||||
},
|
||||
|
@ -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<UserInDatabase>;
|
||||
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;
|
@ -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." });
|
||||
|
@ -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;
|
@ -10,8 +10,9 @@ const db = new DatabasesService('OnlyDevs')
|
||||
//TODO Logs
|
||||
|
||||
async function registerService(data: IRegisterInput): Promise<IRegisterOutput> {
|
||||
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<IRegisterOutput> {
|
||||
if (dbResult) {
|
||||
//await sendActivationEmail(User.email, User.email_activation);
|
||||
const token = await JwtService.sign({
|
||||
sub: User.id,
|
||||
sub: uuid,
|
||||
iat: Date.now(),
|
||||
}, {
|
||||
alg: "HS256"
|
||||
|
@ -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<object> = await this.maria.query("SELECT * FROM users") as unknown as Array<object>;
|
||||
const result = await this.maria.query("SELECT * FROM users") as unknown as Array<UserInDatabase>;
|
||||
this.logs.debug('Fetching users from database...', `${result?.length} user(s) found.`)
|
||||
return result;
|
||||
}
|
||||
|
||||
async getUserById(id: string) {
|
||||
const result: Array<object> = await this.maria.execute(`SELECT * FROM users WHERE id = ?`, [id]) as unknown as Array<object>;
|
||||
const result = await this.maria.execute(`SELECT * FROM users WHERE id = ?`, [id]) as unknown as Array<UserInDatabase>;
|
||||
this.logs.debug(`Fetching user with id ${id} from database...`, `${result?.length} user(s) found.`);
|
||||
return result;
|
||||
}
|
||||
|
||||
async getUserByUsername(username: string) {
|
||||
const result: Array<object> = await this.maria.execute(`SELECT * FROM users WHERE username = ?`, [username]) as unknown as Array<object>;
|
||||
const result = await this.maria.execute(`SELECT * FROM users WHERE username = ?`, [username]) as unknown as Array<UserInDatabase>;
|
||||
this.logs.debug(`Fetching user with username "${username}" from database...`, `${result?.length} user(s) found.`);
|
||||
return result;
|
||||
}
|
||||
|
||||
async getUserByEmail(email: string) {
|
||||
const result: Array<object> = await this.maria.execute(`SELECT * FROM users WHERE email = ?`, [email]) as unknown as Array<object>;
|
||||
const result = await this.maria.execute(`SELECT * FROM users WHERE email = ?`, [email]) as unknown as Array<UserInDatabase>;
|
||||
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<FollowInDatabase>;
|
||||
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<FollowInDatabase>;
|
||||
this.logs.debug(`Fetching followers for user with id ${id} from database...`, `${result?.length} user(s) found.`);
|
||||
return result;
|
||||
}
|
||||
|
||||
async insertUser(user: UserInDatabase): Promise<boolean> {
|
||||
const factorized = await this.maria.factorize({
|
||||
values: user,
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
14
src/utils/headers.util.ts
Normal file
14
src/utils/headers.util.ts
Normal file
@ -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,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user