Introduces a new addPlayerAction method in adminRepository and logPlayerAction in adminService to record admin actions on player accounts. Updates relevant admin routes to log actions such as bans, unbans, forced name changes, and skin resets. Also improves error messages in adminService for consistency and clarity.
151 lines
4.7 KiB
JavaScript
151 lines
4.7 KiB
JavaScript
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@#"
|
|
|
|
async function registerAdmin(username, plainPassword, permissions = []) {
|
|
const hashedPassword = await bcrypt.hash(plainPassword, 10)
|
|
|
|
const result = await adminRepository.createAdmin(username, hashedPassword)
|
|
|
|
if (permissions.length > 0) {
|
|
for (const perm of permissions) {
|
|
await adminRepository.assignPermission(result.id, perm)
|
|
}
|
|
}
|
|
|
|
return { id: result.id, username, message: "Administrateur créé avec succès." }
|
|
}
|
|
|
|
async function checkAdminAccess(adminId, requiredPermission) {
|
|
if (!adminId || !requiredPermission) {
|
|
throw new DefaultError(400, "ID administrateur ou permission manquante.")
|
|
}
|
|
|
|
return await adminRepository.hasPermission(adminId, requiredPermission)
|
|
}
|
|
|
|
async function changeAdminPassword(adminId, newPlainPassword) {
|
|
if (!newPlainPassword || newPlainPassword.length < 6) {
|
|
throw new DefaultError(400, "Le mot de passe doit contenir au moins 6 caractères.")
|
|
}
|
|
|
|
const hashed = await bcrypt.hash(newPlainPassword, 10)
|
|
return await adminRepository.updateAdminPassword(adminId, hashed)
|
|
}
|
|
|
|
async function getAdminProfile(adminId) {
|
|
const admin = await adminRepository.getAdminById(adminId)
|
|
if (!admin) {
|
|
throw new DefaultError(404, "Administrateur introuvable.")
|
|
}
|
|
|
|
const permissions = await adminRepository.getAdminPermissions(adminId)
|
|
|
|
return {
|
|
id: admin.id,
|
|
username: admin.username,
|
|
createdAt: admin.createdAt,
|
|
permissions: permissions
|
|
}
|
|
}
|
|
|
|
async function grantPermission(adminId, permissionKey) {
|
|
return await adminRepository.assignPermission(adminId, permissionKey)
|
|
}
|
|
|
|
async function revokePermission(adminId, permissionKey) {
|
|
return await adminRepository.revokePermission(adminId, permissionKey)
|
|
}
|
|
|
|
async function loginAdmin(username, password) {
|
|
const admin = await adminRepository.getAdminByUsername(username)
|
|
if (!admin) {
|
|
throw new DefaultError(403, "Invalid credentials.")
|
|
}
|
|
|
|
const isMatch = await bcrypt.compare(password, admin.password)
|
|
if (!isMatch) {
|
|
throw new DefaultError(403, "Invalid credentials.")
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
{ id: admin.id, username: admin.username, type: "admin" },
|
|
ADMIN_JWT_SECRET,
|
|
{ expiresIn: "8h" }
|
|
)
|
|
|
|
return { token }
|
|
}
|
|
|
|
function hasPermission(requiredPermission) {
|
|
return async (req, res, next) => {
|
|
try {
|
|
const authHeader = req.headers.authorization
|
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
throw new DefaultError(401, "Admin auth required.")
|
|
}
|
|
|
|
const token = authHeader.split(" ")[1]
|
|
|
|
const decoded = jwt.verify(token, ADMIN_JWT_SECRET)
|
|
if (decoded.type !== "admin") {
|
|
throw new DefaultError(403, "Invalid token.")
|
|
}
|
|
|
|
const hasAccess = await adminService.checkAdminAccess(decoded.id, requiredPermission)
|
|
if (!hasAccess) {
|
|
throw new DefaultError(403, `Missing permission : ${requiredPermission}`)
|
|
}
|
|
|
|
req.admin = decoded
|
|
next()
|
|
|
|
} catch (err) {
|
|
if (err.name === "JsonWebTokenError") {
|
|
return next(new DefaultError(401, "Invalid session."))
|
|
}
|
|
next(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
async function uploadCape(fileObject, alias = null) {
|
|
const buffer = await fs.readFile(fileObject.path)
|
|
const hash = crypto.createHash("sha256").update(buffer).digest("hex")
|
|
|
|
const existing = await userRepository.getTextureByHash(hash)
|
|
if (existing) throw new DefaultError(409, "Cape already existing.")
|
|
|
|
const textureUrl = `/texture/${hash}`
|
|
await userRepository.createTexture(crypto.randomUUID(), hash, "CAPE", textureUrl, alias)
|
|
|
|
return { hash, url: textureUrl }
|
|
}
|
|
|
|
async function deleteGlobalCape(hash) {
|
|
const success = await userRepository.deleteTexture(hash)
|
|
if (!success) throw new DefaultError(404, "Cape not found.")
|
|
|
|
return { message: "Texture removed." }
|
|
}
|
|
|
|
async function logPlayerAction(playerUuid, actionCode) {
|
|
return await adminRepository.addPlayerAction(playerUuid, actionCode)
|
|
}
|
|
|
|
module.exports = {
|
|
loginAdmin,
|
|
uploadCape,
|
|
registerAdmin,
|
|
hasPermission,
|
|
getAdminProfile,
|
|
grantPermission,
|
|
revokePermission,
|
|
checkAdminAccess,
|
|
deleteGlobalCape,
|
|
logPlayerAction,
|
|
changeAdminPassword,
|
|
} |