diff --git a/.env.exemple b/.env.exemple
index 85966a4..17ad8bc 100644
--- a/.env.exemple
+++ b/.env.exemple
@@ -2,6 +2,9 @@ APP_PORT: 3000
DEBUG: true
CONTEXT: dev
+HASH_SECRET: ''
+JWT_SECRET: ''
+
MYSQL_PORT: 3434
MYSQL_HOST: 'localhost'
MYSQL_USERNAME: 'apdbqixmwnsesdj'
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
index 34395df..b35b44f 100644
--- a/.idea/sqldialects.xml
+++ b/.idea/sqldialects.xml
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/maria.sql b/maria.sql
index 31a1058..c3a456b 100644
--- a/maria.sql
+++ b/maria.sql
@@ -6,7 +6,7 @@ create table follows
target_id varchar(36) not null comment 'identifier of the followed user',
iat timestamp default current_timestamp() not null comment 'timestamp of the follow action'
)
- comment 'follows of users';
+ comment 'follows of users' collate = utf8mb4_unicode_ci;
create table users
(
diff --git a/package.json b/package.json
index 20151fe..1497340 100644
--- a/package.json
+++ b/package.json
@@ -13,13 +13,17 @@
},
"dependencies": {
"@node-rs/argon2": "^1.8.3",
+ "axios": "^1.6.8",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.19.2",
"helmet": "^7.1.0",
+ "jose": "^5.3.0",
"mongodb": "^6.6.1",
"morgan": "^1.10.0",
"mysql2": "^3.9.7",
+ "randomatic": "^3.1.1",
+ "react-hook-form": "^7.51.4",
"tslog": "^4.9.2",
"uuid": "^9.0.1"
},
@@ -29,6 +33,7 @@
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20.12.11",
+ "@types/randomatic": "^3.1.5",
"@types/uuid": "^9.0.8",
"arkit": "^1.6.4"
}
diff --git a/src/app.ts b/src/app.ts
index 4e36e07..5f3213f 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -5,7 +5,7 @@ import compression from "compression";
import cors from "cors";
import express, { type Express } from "express";
import helmet from "helmet";
-import {justForTesting} from "@services/databases/databases.service";
+import AuthRouter from "@routers/auth.router";
console.log("\n\n> Starting...\n\n\n\n");
@@ -26,10 +26,10 @@ app.use(
);
app.use(helmet.xXssProtection());
-// parse json request body
+// parse json requests body
app.use(express.json());
-// parse urlencoded request body
+// parse urlencoded requests body
app.use(
express.urlencoded({
extended: true,
@@ -40,7 +40,7 @@ app.use(
app.use(compression());
try {
- //app.use("/auth", AuthRouter);
+ app.use("/auth", AuthRouter);
logger.info("Routers loaded !");
} catch (err) {
logger.error(err);
@@ -61,6 +61,4 @@ try {
} catch (error) {
logger.error(`Server failed to start: ${error}`);
process.exit(1);
-}
-
-justForTesting.getAllUsers().then(()=>{})
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/controllers/auth.controller.ts b/src/controllers/auth.controller.ts
new file mode 100644
index 0000000..9d77d6e
--- /dev/null
+++ b/src/controllers/auth.controller.ts
@@ -0,0 +1,66 @@
+import {Request, Response} from "express";
+import {LogsUtils} from "@utils/logs.util";
+import {HttpStatusCode} from "axios";
+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";
+
+const logs = new LogsUtils('AuthController')
+
+async function registerController(req: Request, res: Response) {
+ const body = req.body;
+ if (!body.username || !body.email || !body.password) {
+ logs.warn('Missing required fields', req.ip);
+ return res.status(HttpStatusCode.BadRequest).json({ error: 'Missing required fields' });
+ }
+ if (!ValidatorsUtils.isEmail(body.email)) {
+ logs.warn('Invalid email format', req.ip);
+ return res.status(HttpStatusCode.BadRequest).json({ error: 'Invalid email format' });
+ }
+ if (!ValidatorsUtils.isUsername(body.username)) {
+ logs.warn('Invalid username format', req.ip);
+ return res.status(HttpStatusCode.BadRequest).json({ error: 'Invalid username format' });
+ }
+ if (!ValidatorsUtils.isPassword(body.password)) {
+ logs.warn('Invalid password format', req.ip);
+ return res.status(HttpStatusCode.BadRequest).json({ error: 'Invalid password format' });
+ }
+
+ const UserIfExist = {
+ byEmail: await UsersService.get.byEmail(body.email),
+ byUsername: await UsersService.get.byUsername(body.username)
+ }
+
+ if (UserIfExist.byEmail.length > 0 || UserIfExist.byUsername.length > 0) {
+ logs.warn('User already exists', req.ip);
+ return res.status(HttpStatusCode.Found).json({ error: 'User already exists' });
+ }
+
+ const data: IRegisterInput = {
+ username: body.username,
+ email: body.email,
+ password: body.password
+ }
+ if (body.displayName) data.displayName = body.displayName;
+
+ const registerResult = await RegisterService(data)
+
+ if (!registerResult.success) {
+ logs.error(registerResult.message, req.ip);
+ return res.status(HttpStatusCode.InternalServerError).json({ error: registerResult.message });
+ }
+ logs.info('User registered successfully', req.ip);
+ return res.status(HttpStatusCode.Created).json({
+ message: 'User registered successfully',
+ token: registerResult.token,
+ id: registerResult.id
+ });
+}
+
+
+const AuthController = {
+ register: registerController
+}
+
+export default AuthController;
\ No newline at end of file
diff --git a/src/interfaces/services/register.types.ts b/src/interfaces/services/register.types.ts
new file mode 100644
index 0000000..e3fe094
--- /dev/null
+++ b/src/interfaces/services/register.types.ts
@@ -0,0 +1,13 @@
+export interface IRegisterInput {
+ username: string,
+ displayName?: string,
+ email: string,
+ password: string
+}
+
+export interface IRegisterOutput {
+ success: boolean,
+ message: string
+ id?: string,
+ token?: string
+}
\ No newline at end of file
diff --git a/src/routers/auth.router.ts b/src/routers/auth.router.ts
new file mode 100644
index 0000000..df1e91c
--- /dev/null
+++ b/src/routers/auth.router.ts
@@ -0,0 +1,10 @@
+import AuthController from "@controllers/auth.controller";
+import express, {type Router} from "express";
+
+
+const AuthRouter: Router = express.Router();
+
+//AuthRouter.route("/login").post(AuthController.login);
+AuthRouter.route("/register").post(AuthController.register);
+
+export default AuthRouter;
\ No newline at end of file
diff --git a/src/services/authentication/intcode.service.ts b/src/services/authentication/intcode.service.ts
index 13fcb74..b8742ab 100644
--- a/src/services/authentication/intcode.service.ts
+++ b/src/services/authentication/intcode.service.ts
@@ -1,9 +1,10 @@
-import randomatic from "randomatic";
-
-
const IntCodeService = {
generate: () => {
- return randomatic('0', 6)
+ const a = Math.floor(Math.random() * Date.now());
+ const b = a.toString().replace(/0/g, '');
+ const c = b.split('')
+ const code = c.join('').slice(0, 6).toString()
+ return Number.parseInt(code)
}
}
diff --git a/src/services/authentication/register.service.ts b/src/services/authentication/register.service.ts
new file mode 100644
index 0000000..a24ec55
--- /dev/null
+++ b/src/services/authentication/register.service.ts
@@ -0,0 +1,46 @@
+import {IRegisterInput, IRegisterOutput} from "@interfaces/services/register.types";
+import {UserInDatabase} from "@interfaces/db/mariadb.interface";
+import CredentialService from "@services/authentication/credentials.service";
+import IntCodeService from "@services/authentication/intcode.service";
+import {v4} from "uuid";
+import {DatabasesService} from "@services/databases/databases.service";
+import JwtService from "@services/authentication/jwt.service";
+
+const db = new DatabasesService('OnlyDevs')
+//TODO Logs
+
+async function registerService(data: IRegisterInput): Promise {
+ const User: UserInDatabase = {
+ id: v4(),
+ username: data.username,
+ display_name: data.displayName || data.username,
+ hash: await CredentialService.hash(data.password),
+ email: data.email,
+ email_activation: IntCodeService.generate()
+ }
+
+ const dbResult = await db.insertUser(User)
+
+ if (dbResult) {
+ //await sendActivationEmail(User.email, User.email_activation);
+ const token = await JwtService.sign({
+ sub: User.id,
+ iat: Date.now(),
+ }, {
+ alg: "HS256"
+ }, '7d', 'Registered user')
+ return {
+ success: true,
+ message: "User registered successfully",
+ id: User.id,
+ token: token
+ };
+ } else {
+ return {
+ success: false,
+ message: "Failed to register user",
+ };
+ }
+}
+
+export default registerService;
\ No newline at end of file
diff --git a/src/services/databases/databases.service.ts b/src/services/databases/databases.service.ts
index 77dd59b..357e839 100644
--- a/src/services/databases/databases.service.ts
+++ b/src/services/databases/databases.service.ts
@@ -1,6 +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";
interface MariaDbStatusResult {
fieldCount: number;
@@ -12,7 +13,7 @@ interface MariaDbStatusResult {
changedRows: number;
}
-class DatabasesService {
+export class DatabasesService {
private readonly _appName;
private readonly maria: MariadbService;
private readonly mongo: MongodbService;
@@ -25,10 +26,49 @@ class DatabasesService {
}
async getAllUsers() {
- const result = await this.maria.query("SELECT * FROM users");
- this.logs.debug('Fetching users from database...', result)
+ const result: Array