-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Features/ban unban #27
Changes from 3 commits
6be8d41
a49ab4a
1a2c65a
6f7dd2a
55f5b7b
78fee6d
fef4cf6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,13 @@ | ||
import type express from "express"; | ||
import type SocketIO from "socket.io"; | ||
import express from "express"; | ||
import nodemailer from "nodemailer"; | ||
import { | ||
generateAuthenticationToken, | ||
generateAuthorizationToken, | ||
verifyAuthorizationToken, | ||
} from "../auth/tokenUtils"; | ||
import { PrismaClient } from "@prisma/client"; | ||
const prisma = new PrismaClient(); | ||
|
||
class AccountController { | ||
/** | ||
|
@@ -8,12 +17,16 @@ class AccountController { | |
* @param req The Express request object | ||
* @param res The Express response object | ||
*/ | ||
public static async sendMagicLink(req: express.Request, res: express.Response) { | ||
public static async sendMagicLink( | ||
req: express.Request, | ||
res: express.Response | ||
) { | ||
// TODO: Send a magic link containing the AUTHORIZATION token to the user's email | ||
/** | ||
* VALIDATION | ||
* * Validate the user email (must be a Devinci email) | ||
* | ||
|
||
* PROCESS | ||
* * Generate an AUTHORIZATION token | ||
* * Send the magic link to the user's email | ||
|
@@ -22,6 +35,44 @@ class AccountController { | |
* * Send a success message | ||
* * Send an error message if the email is invalid | ||
*/ | ||
const { email } = req.body; | ||
|
||
const isDevinciEmail = (email: string): boolean => { | ||
const expression: RegExp = /^[a-zA-Z0-9._-]+@edu\.devinci.fr$/; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Il manque un \ sur le point // Regex actuel
const expression: RegExp = /^[a-zA-Z0-9._-]+@edu\.devinci.fr$/;
// Regex juste
const expression: RegExp = /^[a-zA-Z0-9._-]+@edu\.devinci\.fr$/; |
||
|
||
return expression.test(email); | ||
}; | ||
|
||
if (isDevinciEmail(email) == true) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pas besoin de sur-vérifié la boolean |
||
const token: string = generateAuthorizationToken(email); | ||
const link: string = `url/login?token=${token}`; | ||
|
||
const transporter = nodemailer.createTransport({ | ||
host: "your_host", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. plus judicieux de mettre une variable d'environnement (exemple. |
||
port: 587, | ||
secure: true, | ||
auth: { | ||
user: "your_email_address", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
pass: "your_email_password", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
}, | ||
}); | ||
|
||
const message = { | ||
from: "your_email", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
to: email, | ||
subject: "Lien pour se connecter", | ||
html: `Clique pour te connecter: <a href="${link}">${link}</a>`, | ||
}; | ||
|
||
try { | ||
await transporter.sendMail(message); | ||
res.status(200).send("Lien envoyé. Regarder vos mails."); | ||
} catch (error) { | ||
res.status(500).send("Une erreur s'est produite."); | ||
} | ||
} else { | ||
res.send("Email non valide"); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -32,19 +83,30 @@ class AccountController { | |
* @param res The Express response object | ||
*/ | ||
public static async login(req: express.Request, res: express.Response) { | ||
// TODO: Log the user | ||
/** | ||
* VALIDATION | ||
* * Validate AUTHORIZATION token | ||
* | ||
* PROCESS | ||
* * Generate an AUTHENTICATION token | ||
* | ||
* RESPONSE | ||
* * Send the AUTHENTICATION token | ||
* * Send an error message if the AUTHORIZATION token is invalid | ||
* * Send an error message if the AUTHORIZATION token is expired | ||
*/ | ||
const { token, email } = req.body; | ||
if (!verifyAuthorizationToken(token, email)) { | ||
return res.status(401).send("Invalid token"); | ||
} | ||
|
||
try { | ||
const user = await prisma.account.findFirst({ | ||
where: { | ||
devinciEmail: email, | ||
}, | ||
}); | ||
|
||
if (!user) { | ||
await prisma.account.create({ | ||
data: { | ||
devinciEmail: email, | ||
}, | ||
}); | ||
} | ||
} catch (error) { | ||
return res.status(500).send("Unable to connect to the database"); | ||
} | ||
|
||
return res.status(200).send(generateAuthenticationToken(email)); | ||
} | ||
|
||
// Admin routes | ||
|
@@ -92,7 +154,81 @@ class AccountController { | |
* * Send a success message | ||
* * Send an error message if the user ID is invalid | ||
*/ | ||
const { user, target } = req.body; | ||
|
||
const isUserAdmin = (id: number): boolean => { | ||
try { | ||
const user = prisma.account.findUnique({ | ||
where: { id: id }, | ||
select: { isAdmin: true } | ||
}); | ||
|
||
return user?.isAdmin ?? false; | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
|
||
const isUserBanned = (id: number): boolean => { | ||
try { | ||
const user = prisma.account.findUnique({ | ||
where: { id: id }, | ||
select: { isBanned: true } | ||
}); | ||
|
||
return user?.isAdmin ?? false; | ||
} catch (error) { | ||
console.log(error); | ||
return false; | ||
} | ||
} | ||
|
||
if (isUserAdmin(user.id) == false) { | ||
res.send("User is not an admin"); | ||
return; | ||
} | ||
|
||
|
||
try { | ||
if (isUserBanned(target.id) == true) { | ||
await prisma.account.update({ | ||
where: { id: target.id }, | ||
data: { isBanned: false } | ||
}); | ||
|
||
res.send("User unbanned successfully"); | ||
} else if (isUserBanned(target.id) == false) { | ||
await prisma.account.update({ | ||
where: { id: target.id }, | ||
data: { isBanned: true } | ||
}); | ||
|
||
res.send("User banned successfully"); | ||
} | ||
} catch (error) { | ||
console.error(error); | ||
res.status(500).send("Error banning/unbanning user"); | ||
return; | ||
} | ||
} | ||
|
||
/** | ||
* Auth a websocket client | ||
* @server WebSocket | ||
* | ||
* @param socket The client socket | ||
* @param data The payload | ||
*/ | ||
public static async authSocket(socket: SocketIO.Socket, [token, email]: [string, string]) { | ||
if (verifyAuthenticationToken(token, email)) { | ||
socket.data.token = token; | ||
socket.data.email = email; | ||
|
||
socket.emit("auth-callback", true); | ||
} else { | ||
socket.emit("auth-callback", false); | ||
} | ||
} | ||
} | ||
|
||
export default AccountController; | ||
export default AccountController; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,12 @@ | ||
module.exports = { | ||
root: true, | ||
env: { browser: true, es2020: true }, | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:react-hooks/recommended', | ||
], | ||
ignorePatterns: ['dist', '.eslintrc.cjs'], | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['react-refresh'], | ||
rules: { | ||
'react-refresh/only-export-components': [ | ||
'warn', | ||
{ allowConstantExport: true }, | ||
], | ||
}, | ||
} | ||
root: true, | ||
env: { browser: true, es2020: true }, | ||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"], | ||
ignorePatterns: ["dist", ".eslintrc.cjs"], | ||
parser: "@typescript-eslint/parser", | ||
plugins: ["react-refresh"], | ||
rules: { | ||
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }], | ||
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,28 @@ | ||
{ | ||
"name": "frontend", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc && vite build", | ||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.43", | ||
"@types/react-dom": "^18.2.17", | ||
"@typescript-eslint/eslint-plugin": "^6.14.0", | ||
"@typescript-eslint/parser": "^6.14.0", | ||
"@vitejs/plugin-react-swc": "^3.5.0", | ||
"eslint": "^8.55.0", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.5", | ||
"typescript": "^5.2.2", | ||
"vite": "^5.0.8" | ||
} | ||
"name": "frontend", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc && vite build", | ||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.43", | ||
"@types/react-dom": "^18.2.17", | ||
"@typescript-eslint/eslint-plugin": "^6.14.0", | ||
"@typescript-eslint/parser": "^6.14.0", | ||
"@vitejs/plugin-react-swc": "^3.5.0", | ||
"eslint": "^8.55.0", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.5", | ||
"typescript": "^5.2.2", | ||
"vite": "^5.0.8" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pas besoin de faire une fonction si elle n'est utilisé qu'une fois