diff --git a/routes/admin/index.js b/routes/admin/index.js index 4c2ef61..e8c1545 100644 --- a/routes/admin/index.js +++ b/routes/admin/index.js @@ -1,4 +1,21 @@ const express = require("express") -const router = express.Router() +const router = express.Router() +const adminService = require("../../services/adminService") + +router.post("/login", async (req, res) => { + const { username, password } = req.body + const result = await adminService.loginAdmin(username, password) + return res.status(200).json(result) +}) + +router.patch("/password", async (req, res) => { + const token = req.headers.authorization.replace("Bearer ", "") + const profile = await adminService.getAdminProfileByToken(token) + + const { newPassword } = req.body + + const result = await adminService.changeAdminPassword(profile.id, newPassword) + return res.status(200).json(result) +}) module.exports = router \ No newline at end of file diff --git a/schemas/admin/ban/[uuid]/actions.js b/schemas/admin/ban/[uuid]/actions.js index d258b18..b7c133c 100644 --- a/schemas/admin/ban/[uuid]/actions.js +++ b/schemas/admin/ban/[uuid]/actions.js @@ -2,6 +2,10 @@ const z = require("zod") module.exports = { GET: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: z.object({ uuid: z.string().uuid() }) diff --git a/schemas/admin/ban/[uuid]/history.js b/schemas/admin/ban/[uuid]/history.js index d258b18..b7c133c 100644 --- a/schemas/admin/ban/[uuid]/history.js +++ b/schemas/admin/ban/[uuid]/history.js @@ -2,6 +2,10 @@ const z = require("zod") module.exports = { GET: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: z.object({ uuid: z.string().uuid() }) diff --git a/schemas/admin/ban/[uuid]/index.js b/schemas/admin/ban/[uuid]/index.js index 2532a8f..06caa18 100644 --- a/schemas/admin/ban/[uuid]/index.js +++ b/schemas/admin/ban/[uuid]/index.js @@ -6,9 +6,17 @@ const uuidSchema = z.object({ module.exports = { GET: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: uuidSchema }, PUT: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), body: z.object({ reasonKey: z.string().min(1), reasonMessage: z.string().optional(), @@ -21,6 +29,10 @@ module.exports = { } }, DELETE: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: uuidSchema } } \ No newline at end of file diff --git a/schemas/admin/cosmetics/capes/[hash].js b/schemas/admin/cosmetics/capes/[hash].js index f518227..a3e76ea 100644 --- a/schemas/admin/cosmetics/capes/[hash].js +++ b/schemas/admin/cosmetics/capes/[hash].js @@ -2,6 +2,10 @@ const z = require("zod") module.exports = { DELETE: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: z.object({ hash: z.string().length(64) }) diff --git a/schemas/admin/login.js b/schemas/admin/login.js new file mode 100644 index 0000000..af0dc7f --- /dev/null +++ b/schemas/admin/login.js @@ -0,0 +1,17 @@ +const z = require("zod") + +module.exports = { + POST: { + headers: { + "content-type": z.string().regex(/application\/json/i) + }, + body: { + username: z.string() + .min(1), + password: z.string() + .min(8, { message: "The password must be at least 8 characters long." }) + .regex(/[A-Z]/, { message: "The password must contain a capital letter." }) + .regex(/[0-9]/, { message: "The password must contain a number." }) + } + } +} \ No newline at end of file diff --git a/schemas/admin/password.js b/schemas/admin/password.js new file mode 100644 index 0000000..0403332 --- /dev/null +++ b/schemas/admin/password.js @@ -0,0 +1,16 @@ +const z = require("zod") + +module.exports = { + PATCH: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), + body: z.object({ + newPassword: z.string() + .min(8, { message: "The password must be at least 8 characters long." }) + .regex(/[A-Z]/, { message: "The password must contain a capital letter." }) + .regex(/[0-9]/, { message: "The password must contain a number." }) + }) + } +} \ No newline at end of file diff --git a/schemas/admin/players/password/[uuid].js b/schemas/admin/players/password/[uuid].js index ef84376..142955e 100644 --- a/schemas/admin/players/password/[uuid].js +++ b/schemas/admin/players/password/[uuid].js @@ -2,6 +2,10 @@ const z = require("zod") module.exports = { PATCH: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), body: z.object({ newPassword: z.string() .min(8, { message: "The password must be at least 8 characters long." }) diff --git a/schemas/admin/players/textures/cape/[uuid]/[hash].js b/schemas/admin/players/textures/cape/[uuid]/[hash].js index 1cabf15..dd7cb86 100644 --- a/schemas/admin/players/textures/cape/[uuid]/[hash].js +++ b/schemas/admin/players/textures/cape/[uuid]/[hash].js @@ -2,12 +2,20 @@ const z = require("zod") module.exports = { PUT: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: z.object({ uuid: z.string().uuid(), hash: z.string().length(64) }) }, DELETE: { + headers: z.object({ + "content-type": z.string().regex(/application\/json/i), + "authorization": z.string().startsWith("Bearer ") + }), query: z.object({ uuid: z.string().uuid(), hash: z.string().length(64) diff --git a/services/adminService.js b/services/adminService.js index 355d03b..72b9b0f 100644 --- a/services/adminService.js +++ b/services/adminService.js @@ -1,6 +1,7 @@ +const jwt = require("jsonwebtoken") +const bcrypt = require("bcryptjs") const userRepository = require("../repositories/userRepository") const adminRepository = require("../repositories/adminRepository") -const bcrypt = require("bcryptjs") const { DefaultError } = require("../errors/errors") const ADMIN_JWT_SECRET = process.env.ADMIN_JWT_SECRET || "udjJLGCOq7m3NmGpdVLJ@#" @@ -28,7 +29,7 @@ async function checkAdminAccess(adminId, requiredPermission) { } async function changeAdminPassword(adminId, newPlainPassword) { - if (!newPlainPassword || newPlainPassword.length < 6) { + if (!newPlainPassword || newPlainPassword.length < 8) { throw new DefaultError(400, "Le mot de passe doit contenir au moins 6 caractères.") } @@ -52,6 +53,15 @@ async function getAdminProfile(adminId) { } } +async function getAdminProfileByToken(accessToken) { + try { + const decoded = jwt.verify(accessToken, { complete: true, json: true }) + return getAdminProfile(decoded.sub) + } catch (error) { + throw error + } +} + async function grantPermission(adminId, permissionKey) { return await adminRepository.assignPermission(adminId, permissionKey) } @@ -74,7 +84,7 @@ async function loginAdmin(username, password) { const token = jwt.sign( { id: admin.id, username: admin.username, type: "admin" }, ADMIN_JWT_SECRET, - { expiresIn: "8h" } + { expiresIn: "8h", subject: admin.id, issuer: "Yggdrasil" } ) return { token } @@ -147,5 +157,6 @@ module.exports = { logPlayerAction, revokePermission, checkAdminAccess, - changeAdminPassword + changeAdminPassword, + getAdminProfileByToken } \ No newline at end of file